Compare commits
55 Commits
dboreham/s
...
main
Author | SHA1 | Date | |
---|---|---|---|
81c0402803 | |||
322d6f188b | |||
1ea6d6b647 | |||
d65dcce302 | |||
1833b14e25 | |||
02991c7135 | |||
348ae680c6 | |||
965d7dbb66 | |||
e7bab9b971 | |||
28b9207bbe | |||
055cfb2255 | |||
776799ea02 | |||
9c240f1a0c | |||
ec70c9f36b | |||
ed81bba3ed | |||
ae07fc0147 | |||
588c52c0b2 | |||
c407145c31 | |||
8077a7a85a | |||
47d086111d | |||
880367d5df | |||
0adc932400 | |||
d57743bfd5 | |||
20a6828bb5 | |||
976a97234f | |||
072b174c9b | |||
|
a5681191a5 | ||
|
1cdf15595e | ||
|
2cc5df02e0 | ||
|
703f146c5b | ||
|
763dab712f | ||
|
e2178894ef | ||
|
dca3ccb47c | ||
|
2c883282bc | ||
|
b8d6300e4d | ||
|
42fdc97c1c | ||
|
5f6a9f56bb | ||
|
71c15cd2eb | ||
|
c227a38e9a | ||
|
15c9ade06d | ||
|
4b318822d9 | ||
|
c61f268329 | ||
|
facd64a14b | ||
|
6945792aea | ||
|
5af22471a8 | ||
|
5e7a890adb | ||
|
9ec237e41f | ||
b57ad7d5fa | |||
|
c3138a2615 | ||
02e9080094 | |||
|
747088deb0 | ||
|
ab2ea51aac | ||
|
cb104e0b10 | ||
|
fac5a95679 | ||
78c513d0fd |
113
.clang-format
113
.clang-format
@ -1,115 +1,6 @@
|
|||||||
---
|
---
|
||||||
Language: Proto
|
Language: Proto
|
||||||
# BasedOnStyle: LLVM
|
|
||||||
AccessModifierOffset: -2
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignConsecutiveAssignments: true
|
|
||||||
AlignConsecutiveDeclarations: true
|
|
||||||
AlignEscapedNewlines: Right
|
|
||||||
AlignOperands: true
|
|
||||||
AlignTrailingComments: true
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: true
|
|
||||||
AllowShortBlocksOnASingleLine: true
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: Empty
|
|
||||||
AllowShortIfStatementsOnASingleLine: false
|
|
||||||
AllowShortLoopsOnASingleLine: false
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
|
||||||
AlwaysBreakTemplateDeclarations: false
|
|
||||||
BinPackArguments: true
|
|
||||||
BinPackParameters: true
|
|
||||||
BraceWrapping:
|
|
||||||
AfterClass: false
|
|
||||||
AfterControlStatement: false
|
|
||||||
AfterEnum: false
|
|
||||||
AfterFunction: false
|
|
||||||
AfterNamespace: false
|
|
||||||
AfterObjCDeclaration: false
|
|
||||||
AfterStruct: false
|
|
||||||
AfterUnion: false
|
|
||||||
AfterExternBlock: false
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: true
|
|
||||||
SplitEmptyRecord: true
|
|
||||||
SplitEmptyNamespace: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeBraces: Attach
|
|
||||||
BreakBeforeInheritanceComma: false
|
|
||||||
BreakBeforeTernaryOperators: true
|
|
||||||
BreakConstructorInitializersBeforeComma: false
|
|
||||||
BreakConstructorInitializers: BeforeColon
|
|
||||||
BreakAfterJavaFieldAnnotations: false
|
|
||||||
BreakStringLiterals: true
|
|
||||||
ColumnLimit: 120
|
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
|
||||||
CompactNamespaces: false
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
DisableFormat: false
|
|
||||||
ExperimentalAutoDetectBinPacking: false
|
|
||||||
FixNamespaceComments: true
|
|
||||||
ForEachMacros:
|
|
||||||
- foreach
|
|
||||||
- Q_FOREACH
|
|
||||||
- BOOST_FOREACH
|
|
||||||
IncludeBlocks: Preserve
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
|
||||||
Priority: 2
|
|
||||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
|
||||||
Priority: 3
|
|
||||||
- Regex: '.*'
|
|
||||||
Priority: 1
|
|
||||||
IncludeIsMainRegex: '(Test)?$'
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentWidth: 2
|
|
||||||
IndentWrappedFunctionNames: false
|
|
||||||
JavaScriptQuotes: Leave
|
|
||||||
JavaScriptWrapImports: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
|
||||||
MacroBlockBegin: ''
|
|
||||||
MacroBlockEnd: ''
|
|
||||||
MaxEmptyLinesToKeep: 1
|
|
||||||
NamespaceIndentation: None
|
|
||||||
ObjCBlockIndentWidth: 2
|
|
||||||
ObjCSpaceAfterProperty: false
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
PenaltyBreakAssignment: 2
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 19
|
|
||||||
PenaltyBreakComment: 300
|
|
||||||
PenaltyBreakFirstLessLess: 120
|
|
||||||
PenaltyBreakString: 1000
|
|
||||||
PenaltyExcessCharacter: 1000000
|
|
||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
|
||||||
PointerAlignment: Right
|
|
||||||
RawStringFormats:
|
|
||||||
- Delimiters:
|
|
||||||
- pb
|
|
||||||
Language: TextProto
|
|
||||||
BasedOnStyle: google
|
BasedOnStyle: google
|
||||||
ReflowComments: true
|
ColumnLimit: 120
|
||||||
SortIncludes: true
|
IndentWidth: 2
|
||||||
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
|
|
||||||
...
|
...
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# localnet-setup
|
Dockerfile
|
||||||
localnet-setup
|
|
||||||
|
**/node_modules
|
||||||
|
init.sh
|
||||||
|
|
||||||
# build
|
|
||||||
build
|
build
|
||||||
|
localnet-setup
|
5
.flake8
Normal file
5
.flake8
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[flake8]
|
||||||
|
ignore = BLK100, W503
|
||||||
|
max-line-length = 88
|
||||||
|
extend-ignore = E203
|
||||||
|
exclude = .git,__pycache__,node_modules,.direnv
|
17
.gitea/workflows/build.yml
Normal file
17
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
name: Build
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.21
|
||||||
|
check-latest: true
|
||||||
|
- run: |
|
||||||
|
make build
|
20
.gitea/workflows/deploy-contract.yml
Normal file
20
.gitea/workflows/deploy-contract.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: Deploy Contract
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.21
|
||||||
|
check-latest: true
|
||||||
|
- name: Test contract
|
||||||
|
run: |
|
||||||
|
make contract-tools
|
||||||
|
# This seems to be an empty placeholder.
|
||||||
|
make test-contract
|
@ -1,4 +1,4 @@
|
|||||||
name: Publish onn release
|
name: Publish on release
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Tag docker image
|
- name: Tag docker image
|
||||||
run: docker tag git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.sha}} git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.tag}}
|
run: docker tag git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.sha}} git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.tag}}
|
||||||
- name: Docker Login
|
- name: Docker Login
|
||||||
run: echo ${{ secrets.GITEA_TOKEN }} | docker login https://git.vdb.to -u cerccicd --password-stdin
|
run: echo ${{ secrets.CICD_PUBLISH_TOKEN }} | docker login https://git.vdb.to -u cerccicd --password-stdin
|
||||||
- name: Docker Push
|
- name: Docker Push
|
||||||
run: docker push git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.sha}}
|
run: docker push git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.sha}}
|
||||||
- name: Docker Push TAGGED
|
- name: Docker Push TAGGED
|
@ -13,15 +13,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.18
|
go-version: 1.21
|
||||||
|
check-latest: true
|
||||||
- name: release dry run
|
- name: release dry run
|
||||||
run: make release-dry-run
|
run: make release-dry-run
|
||||||
- name: setup release environment
|
- name: setup release environment
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.CICD_PUBLISH_TOKEN }}
|
||||||
run: |-
|
run: |-
|
||||||
echo 'GITHUB_TOKEN=${{secrets.GITHUB_TOKEN}}' > .release-env
|
echo 'GITHUB_TOKEN=${{secrets.CICD_PUBLISH_TOKEN}}' > .release-env
|
||||||
- name: release publish
|
- name: release publish
|
||||||
run: make release
|
run: make release
|
42
.gitea/workflows/lint.yml
Normal file
42
.gitea/workflows/lint.yml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
name: Lint
|
||||||
|
# Lint runs golangci-lint over the entire ethermint repository This workflow is
|
||||||
|
# run on every pull request and push to main The `golangci` will pass without
|
||||||
|
# running if no *.{go, mod, sum} files have been changed.
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
jobs:
|
||||||
|
golangci:
|
||||||
|
name: Run golangci-lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
# Required: setup-go, for all versions v3.0.0+ of golangci-lint
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.21
|
||||||
|
check-latest: true
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: golangci/golangci-lint-action@v3.3.1
|
||||||
|
with:
|
||||||
|
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||||
|
version: latest
|
||||||
|
args: --timeout 10m
|
||||||
|
github-token: ${{ secrets.github_token }}
|
||||||
|
|
||||||
|
python-lint:
|
||||||
|
# For compatibility with Gitea
|
||||||
|
env:
|
||||||
|
USER: root
|
||||||
|
name: Run flake8 on python integration tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: cachix/install-nix-action@v20
|
||||||
|
- uses: cachix/cachix-action@v12
|
||||||
|
with:
|
||||||
|
name: ethermint
|
||||||
|
- run: |
|
||||||
|
nix-shell -I nixpkgs=./nix -p test-env --run "make lint-py"
|
28
.gitea/workflows/proto.yml
Normal file
28
.gitea/workflows/proto.yml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: Protobuf
|
||||||
|
# Protobuf runs buf (https://buf.build/) lint and check-breakage
|
||||||
|
# This workflow is only run when a .proto file has been changed
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "proto/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 5
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: bufbuild/buf-setup-action@v1.9.0
|
||||||
|
- uses: bufbuild/buf-lint-action@v1
|
||||||
|
with:
|
||||||
|
input: "proto"
|
||||||
|
|
||||||
|
break-check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: bufbuild/buf-setup-action@v1.9.0
|
||||||
|
- uses: bufbuild/buf-breaking-action@v1
|
||||||
|
with:
|
||||||
|
input: "proto"
|
||||||
|
against: "https://github.com/${{ github.repository }}.git#branch=${{ github.event.pull_request.base.ref }},ref=HEAD~1,subdir=proto"
|
21
.gitea/workflows/test-importer.yml
Normal file
21
.gitea/workflows/test-importer.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- release/**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-importer:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.21
|
||||||
|
check-latest: true
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: test-importer
|
||||||
|
run: |
|
||||||
|
make test-import
|
21
.gitea/workflows/test-rpc.yml
Normal file
21
.gitea/workflows/test-rpc.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- release/**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-rpc:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 15
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.21
|
||||||
|
check-latest: true
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Test rpc endpoint
|
||||||
|
run: |
|
||||||
|
make test-rpc
|
40
.gitea/workflows/test-sdk-auction.yml
Normal file
40
.gitea/workflows/test-sdk-auction.yml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
name: Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- release/**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sdk_tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Checkout laconic-sdk
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: "./laconic-sdk/"
|
||||||
|
repository: cerc-io/laconic-sdk
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: main
|
||||||
|
- name: Environment
|
||||||
|
run: ls -tlh && env
|
||||||
|
|
||||||
|
- name: Build laconicd container
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
run: ./build-laconicd-container.sh
|
||||||
|
|
||||||
|
- name: Build laconic-sdk container
|
||||||
|
working-directory: laconic-sdk
|
||||||
|
run: ./scripts/build-sdk-test-container.sh
|
||||||
|
|
||||||
|
- name: Start containers (auctions enabled)
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
env:
|
||||||
|
TEST_AUCTION_ENABLED: true
|
||||||
|
run: docker compose up -d
|
||||||
|
|
||||||
|
- name: Run auction tests
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
run: ./run-tests.sh test:auctions
|
40
.gitea/workflows/test-sdk-nameservice.yml
Normal file
40
.gitea/workflows/test-sdk-nameservice.yml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
name: Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- release/**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sdk_tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Checkout laconic-sdk
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: "./laconic-sdk/"
|
||||||
|
repository: cerc-io/laconic-sdk
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: main
|
||||||
|
- name: Environment
|
||||||
|
run: ls -tlh && env
|
||||||
|
|
||||||
|
- name: Build laconicd container
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
run: ./build-laconicd-container.sh
|
||||||
|
|
||||||
|
- name: Build laconic-sdk container
|
||||||
|
working-directory: laconic-sdk
|
||||||
|
run: ./scripts/build-sdk-test-container.sh
|
||||||
|
|
||||||
|
- name: Start containers (expiry enabled)
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
env:
|
||||||
|
TEST_REGISTRY_EXPIRY: true
|
||||||
|
run: docker compose up -d
|
||||||
|
|
||||||
|
- name: Run nameservice expiry tests
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
run: ./run-tests.sh test:nameservice-expiry
|
38
.gitea/workflows/test-sdk.yml
Normal file
38
.gitea/workflows/test-sdk.yml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- release/**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sdk_tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Checkout laconic-sdk
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: "./laconic-sdk/"
|
||||||
|
repository: cerc-io/laconic-sdk
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: main
|
||||||
|
- name: Environment
|
||||||
|
run: ls -tlh && env
|
||||||
|
|
||||||
|
- name: Build laconicd container
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
run: ./build-laconicd-container.sh
|
||||||
|
|
||||||
|
- name: Build laconic-sdk container
|
||||||
|
working-directory: laconic-sdk
|
||||||
|
run: ./scripts/build-sdk-test-container.sh
|
||||||
|
|
||||||
|
- name: Start containers
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
run: docker compose up -d
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: tests/sdk_tests
|
||||||
|
run: ./run-tests.sh
|
23
.gitea/workflows/test-unit.yml
Normal file
23
.gitea/workflows/test-unit.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: Tests
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- release/**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-unit:
|
||||||
|
# This test case doesn't work in CI, run as root.
|
||||||
|
env:
|
||||||
|
SKIP_UNIT_TESTS: TestInitConfigNonNotExistError
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.21
|
||||||
|
check-latest: true
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
make test-unit
|
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
@ -1,4 +0,0 @@
|
|||||||
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
|
|
||||||
|
|
||||||
# Primary repo maintainers
|
|
||||||
* @fedekunze @khoslaventures @jolube
|
|
18
.github/ISSUE_TEMPLATE/bug-report.md
vendored
18
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug Report
|
|
||||||
about: create a bug report
|
|
||||||
---
|
|
||||||
|
|
||||||
__System info:__ [Include Ethermint commit, operating system name, and other relevant details]
|
|
||||||
|
|
||||||
__Steps to reproduce:__
|
|
||||||
|
|
||||||
1. [First Step]
|
|
||||||
2. [Second Step]
|
|
||||||
3. [and so on...]
|
|
||||||
|
|
||||||
__Expected behavior:__ [What you expected to happen]
|
|
||||||
|
|
||||||
__Actual behavior:__ [What actually happened]
|
|
||||||
|
|
||||||
__Additional info:__ [Include gist of relevant config, logs, etc.]
|
|
15
.github/ISSUE_TEMPLATE/feature-request.md
vendored
15
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Opening a feature request kicks off a discussion
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
__Proposal:__ [Description of the feature]
|
|
||||||
|
|
||||||
__Current behavior:__ [What currently happens]
|
|
||||||
|
|
||||||
__Desired behavior:__ [What you would like to happen]
|
|
||||||
|
|
||||||
__Use case:__ [Why is this important (helps with prioritizing requests)]
|
|
||||||
|
|
||||||
Requests may be closed if we're not actively planning to work on them.
|
|
34
.github/PULL_REQUEST_TEMPLATE.md
vendored
34
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,34 +0,0 @@
|
|||||||
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
|
|
||||||
v ✰ Thanks for creating a PR! ✰
|
|
||||||
v Before smashing the submit button please review the checkboxes.
|
|
||||||
v If a checkbox is n/a - please still include it but + a little note why
|
|
||||||
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
|
|
||||||
|
|
||||||
Closes: #XXX
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!-- Add a description of the changes that this PR introduces and the files that
|
|
||||||
are the most critical to review.
|
|
||||||
-->
|
|
||||||
|
|
||||||
______
|
|
||||||
|
|
||||||
For contributor use:
|
|
||||||
|
|
||||||
- [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
|
|
||||||
- [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
|
|
||||||
- [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md).
|
|
||||||
- [ ] Wrote unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
|
|
||||||
- [ ] Updated relevant documentation (`docs/`) or specification (`x/<module>/spec/`)
|
|
||||||
- [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code).
|
|
||||||
- [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md`
|
|
||||||
- [ ] Re-reviewed `Files changed` in the Github PR explorer
|
|
||||||
|
|
||||||
______
|
|
||||||
|
|
||||||
For admin use:
|
|
||||||
|
|
||||||
- [ ] Added appropriate labels to PR (ex. `WIP`, `R4R`, `docs`, etc)
|
|
||||||
- [ ] Reviewers assigned
|
|
||||||
- [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr))
|
|
37
.github/labeler.yml
vendored
37
.github/labeler.yml
vendored
@ -1,37 +0,0 @@
|
|||||||
"C:Crypto":
|
|
||||||
- crypto/**/*
|
|
||||||
"C:Encoding":
|
|
||||||
- encoding/**/*
|
|
||||||
"C:JSON-RPC":
|
|
||||||
- ethereum/rpc/**/*
|
|
||||||
"C:Proto":
|
|
||||||
- proto/**/*
|
|
||||||
- third_party/**/*
|
|
||||||
- /**/*.pb.go
|
|
||||||
- /**/*.pb.gw.go
|
|
||||||
"C:Types":
|
|
||||||
- types/**/*
|
|
||||||
"C:x/evm":
|
|
||||||
- x/evm/**/*/
|
|
||||||
"Type: Build":
|
|
||||||
- Makefile
|
|
||||||
- Dockerfile
|
|
||||||
- docker-compose.yml
|
|
||||||
- scripts/*
|
|
||||||
- config.yml
|
|
||||||
"Type: CI":
|
|
||||||
- .github/**/*.yml
|
|
||||||
- buf.yaml
|
|
||||||
- .mergify.yml
|
|
||||||
- .golangci.yml
|
|
||||||
"C:CLI":
|
|
||||||
- client/**/*
|
|
||||||
- x/*/client/**/*
|
|
||||||
"Type: Tests":
|
|
||||||
- tests/**/*
|
|
||||||
- /**/*/*_test.go
|
|
||||||
"Type: Docs":
|
|
||||||
- docs/**/*
|
|
||||||
- x/*/spec/**/*
|
|
||||||
"Type: ADR":
|
|
||||||
- docs/architecture/**/*
|
|
32
.github/workflows/build.yml
vendored
32
.github/workflows/build.yml
vendored
@ -1,32 +0,0 @@
|
|||||||
name: Build
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cleanup-runs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: rokroskar/workflow-run-cleanup-action@master
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main'"
|
|
||||||
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: 1.18
|
|
||||||
- uses: technote-space/get-diff-action@v6.0.1
|
|
||||||
id: git_diff
|
|
||||||
with:
|
|
||||||
SUFFIX_FILTER: |
|
|
||||||
.go
|
|
||||||
.mod
|
|
||||||
.sum
|
|
||||||
- run: |
|
|
||||||
make build
|
|
||||||
if: env.GIT_DIFF
|
|
71
.github/workflows/codeql-analysis.yml
vendored
71
.github/workflows/codeql-analysis.yml
vendored
@ -1,71 +0,0 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ main ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ main ]
|
|
||||||
schedule:
|
|
||||||
- cron: '37 21 * * 4'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'go', 'javascript' ]
|
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
|
||||||
# Learn more:
|
|
||||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v1
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v1
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 https://git.io/JvXDl
|
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
||||||
# and modify them (or add more) to build your code if your project
|
|
||||||
# uses a compiled language
|
|
||||||
|
|
||||||
#- run: |
|
|
||||||
# make bootstrap
|
|
||||||
# make release
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v1
|
|
38
.github/workflows/deploy-contract.yml
vendored
38
.github/workflows/deploy-contract.yml
vendored
@ -1,38 +0,0 @@
|
|||||||
name: Deploy Contract
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cleanup-runs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: rokroskar/workflow-run-cleanup-action@master
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main'"
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Use Node.js
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: '12.x'
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm install
|
|
||||||
- uses: technote-space/get-diff-action@v6.0.1
|
|
||||||
id: git_diff
|
|
||||||
with:
|
|
||||||
SUFFIX_FILTER: |
|
|
||||||
.go
|
|
||||||
.mod
|
|
||||||
.sum
|
|
||||||
.sol
|
|
||||||
- name: Test contract
|
|
||||||
run: |
|
|
||||||
sudo make contract-tools
|
|
||||||
sudo make test-contract
|
|
||||||
if: env.GIT_DIFF
|
|
29
.github/workflows/issues-notion-sync.yml
vendored
29
.github/workflows/issues-notion-sync.yml
vendored
@ -1,29 +0,0 @@
|
|||||||
name: Notion Sync
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
issues:
|
|
||||||
types:
|
|
||||||
[
|
|
||||||
opened,
|
|
||||||
edited,
|
|
||||||
labeled,
|
|
||||||
unlabeled,
|
|
||||||
assigned,
|
|
||||||
unassigned,
|
|
||||||
milestoned,
|
|
||||||
demilestoned,
|
|
||||||
reopened,
|
|
||||||
closed,
|
|
||||||
]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
notion_job:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Add GitHub Issues to Notion
|
|
||||||
steps:
|
|
||||||
- name: Add GitHub Issues to Notion
|
|
||||||
uses: vulcanize/notion-github-action@v1.2.4-issueid
|
|
||||||
with:
|
|
||||||
notion-token: ${{ secrets.NOTION_TOKEN }}
|
|
||||||
notion-db: ${{ secrets.NOTION_DATABASE }}
|
|
14
.github/workflows/labeler.yml
vendored
14
.github/workflows/labeler.yml
vendored
@ -1,14 +0,0 @@
|
|||||||
name: "Pull Request Labeler"
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
triage:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/labeler@v4
|
|
||||||
with:
|
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
12
.github/workflows/linkchecker.yml
vendored
12
.github/workflows/linkchecker.yml
vendored
@ -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"
|
|
32
.github/workflows/lint.yml
vendored
32
.github/workflows/lint.yml
vendored
@ -1,32 +0,0 @@
|
|||||||
name: Lint
|
|
||||||
# Lint runs golangci-lint over the entire ethermint repository This workflow is
|
|
||||||
# run on every pull request and push to main The `golangci` will pass without
|
|
||||||
# running if no *.{go, mod, sum} files have been changed.
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
jobs:
|
|
||||||
golangci:
|
|
||||||
name: Run golangci-lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: 1.18
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: technote-space/get-diff-action@v6.1.0
|
|
||||||
with:
|
|
||||||
PATTERNS: |
|
|
||||||
**/**.go
|
|
||||||
go.mod
|
|
||||||
go.sum
|
|
||||||
- uses: golangci/golangci-lint-action@v3
|
|
||||||
with:
|
|
||||||
version: v1.48.0
|
|
||||||
args: --timeout 10m
|
|
||||||
github-token: ${{ secrets.github_token }}
|
|
||||||
# Check only if there are differences in the source code
|
|
||||||
if: "env.GIT_DIFF"
|
|
30
.github/workflows/proto.yml
vendored
30
.github/workflows/proto.yml
vendored
@ -1,30 +0,0 @@
|
|||||||
name: Protobuf
|
|
||||||
# Protobuf runs buf (https://buf.build/) lint and check-breakage
|
|
||||||
# This workflow is only run when a .proto file has been changed
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 5
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: technote-space/get-diff-action@v6.0.1
|
|
||||||
with:
|
|
||||||
PATTERNS: |
|
|
||||||
**/**.proto
|
|
||||||
- name: lint
|
|
||||||
run: make proto-lint
|
|
||||||
if: env.GIT_DIFF
|
|
||||||
breakage:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: technote-space/get-diff-action@v6.0.1
|
|
||||||
with:
|
|
||||||
PATTERNS: |
|
|
||||||
**/**.proto
|
|
||||||
- name: check-breakage
|
|
||||||
run: make proto-check-breaking
|
|
||||||
if: env.GIT_DIFF
|
|
34
.github/workflows/security.yml
vendored
34
.github/workflows/security.yml
vendored
@ -1,34 +0,0 @@
|
|||||||
name: Run Gosec
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Gosec:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
GO111MODULE: on
|
|
||||||
steps:
|
|
||||||
- name: Checkout Source
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Get Diff
|
|
||||||
uses: technote-space/get-diff-action@v6.0.1
|
|
||||||
with:
|
|
||||||
PATTERNS: |
|
|
||||||
**/*.go
|
|
||||||
go.mod
|
|
||||||
go.sum
|
|
||||||
- name: Run Gosec Security Scanner
|
|
||||||
uses: cosmos/gosec@master
|
|
||||||
with:
|
|
||||||
# we let the report trigger content trigger a failure using the GitHub Security features.
|
|
||||||
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
|
|
||||||
with:
|
|
||||||
# Path to SARIF file relative to the root of the repository
|
|
||||||
sarif_file: results.sarif
|
|
||||||
if: "env.GIT_DIFF_FILTERED != ''"
|
|
41
.github/workflows/semgrep.yml
vendored
41
.github/workflows/semgrep.yml
vendored
@ -1,41 +0,0 @@
|
|||||||
name: Semgrep
|
|
||||||
on:
|
|
||||||
# Scan changed files in PRs, block on new issues only (existing issues ignored)
|
|
||||||
pull_request: {}
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- .github/workflows/semgrep.yml
|
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * 0'
|
|
||||||
jobs:
|
|
||||||
semgrep:
|
|
||||||
name: Scan
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: (github.actor != 'dependabot[bot]')
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Get Diff
|
|
||||||
uses: technote-space/get-diff-action@v6.0.1
|
|
||||||
with:
|
|
||||||
PATTERNS: |
|
|
||||||
**/*.go
|
|
||||||
**/*.js
|
|
||||||
**/*.ts
|
|
||||||
**/*.sol
|
|
||||||
go.mod
|
|
||||||
go.sum
|
|
||||||
- uses: returntocorp/semgrep-action@v1
|
|
||||||
with:
|
|
||||||
publishToken: ${{ secrets.SEMGREP_APP_TOKEN }}
|
|
||||||
# Upload findings to GitHub Advanced Security Dashboard [step 1/2]
|
|
||||||
# See also the next step.
|
|
||||||
generateSarif: "1"
|
|
||||||
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
|
|
||||||
with:
|
|
||||||
sarif_file: semgrep.sarif
|
|
||||||
if: "env.GIT_DIFF_FILTERED != ''"
|
|
230
.github/workflows/test.yml
vendored
230
.github/workflows/test.yml
vendored
@ -1,230 +0,0 @@
|
|||||||
name: Tests
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- release/**
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cleanup-runs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: rokroskar/workflow-run-cleanup-action@master
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main'"
|
|
||||||
|
|
||||||
test-unit-cover:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
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 and Create Coverage Report
|
|
||||||
run: |
|
|
||||||
make test-unit-cover
|
|
||||||
if: env.GIT_DIFF
|
|
||||||
- uses: codecov/codecov-action@v3
|
|
||||||
with:
|
|
||||||
file: ./coverage.txt
|
|
||||||
fail_ci_if_error: true
|
|
||||||
if: env.GIT_DIFF
|
|
||||||
|
|
||||||
test-importer:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
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
|
|
||||||
id: git_diff
|
|
||||||
with:
|
|
||||||
PATTERNS: |
|
|
||||||
**/**.go
|
|
||||||
go.mod
|
|
||||||
go.sum
|
|
||||||
- name: test-importer
|
|
||||||
run: |
|
|
||||||
make test-import
|
|
||||||
if: env.GIT_DIFF
|
|
||||||
|
|
||||||
test-rpc:
|
|
||||||
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 rpc endpoint
|
|
||||||
run: |
|
|
||||||
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
|
|
||||||
# with:
|
|
||||||
# name: ethermint
|
|
||||||
# signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}"
|
|
||||||
# - uses: technote-space/get-diff-action@v6.1.1
|
|
||||||
# with:
|
|
||||||
# PATTERNS: |
|
|
||||||
# **/**.sol
|
|
||||||
# **/**.go
|
|
||||||
# go.mod
|
|
||||||
# go.sum
|
|
||||||
# tests/integration_tests/**
|
|
||||||
# - name: Run integration tests
|
|
||||||
# run: make run-integration-tests
|
|
||||||
# if: env.GIT_DIFF
|
|
||||||
# - name: 'Tar debug files'
|
|
||||||
# if: failure()
|
|
||||||
# run: tar cfz debug_files.tar.gz -C /tmp/pytest-of-runner .
|
|
||||||
# - uses: actions/upload-artifact@v3
|
|
||||||
# if: failure()
|
|
||||||
# with:
|
|
||||||
# name: debug-files
|
|
||||||
# path: debug_files.tar.gz
|
|
||||||
# if-no-files-found: ignore
|
|
||||||
|
|
||||||
# upload-cache:
|
|
||||||
# if: github.event_name == 'push'
|
|
||||||
# needs: ["integration_tests"]
|
|
||||||
# strategy:
|
|
||||||
# matrix:
|
|
||||||
# os: [macos-latest]
|
|
||||||
# runs-on: ${{ matrix.os }}
|
|
||||||
# steps:
|
|
||||||
# - uses: actions/checkout@v2
|
|
||||||
# - uses: cachix/install-nix-action@v18
|
|
||||||
# - uses: cachix/cachix-action@v11
|
|
||||||
# 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
|
|
15
.gitignore
vendored
15
.gitignore
vendored
@ -13,6 +13,7 @@
|
|||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
.dccache
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
*.test
|
*.test
|
||||||
@ -34,10 +35,14 @@ keyring_test_cosmos
|
|||||||
./**/node_modules
|
./**/node_modules
|
||||||
./**/dist
|
./**/dist
|
||||||
secret.yml
|
secret.yml
|
||||||
|
artifacts/*
|
||||||
|
tmp-swagger-gen
|
||||||
|
github.com/
|
||||||
# vue/
|
# vue/
|
||||||
|
|
||||||
# Local docker volume mappings
|
# Local docker volume mappings
|
||||||
localnet-setup
|
localnet-setup
|
||||||
|
.testnets
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
coverage.txt
|
coverage.txt
|
||||||
@ -45,6 +50,7 @@ coverage.txt
|
|||||||
sim_log_file
|
sim_log_file
|
||||||
tests/**/tmp/*
|
tests/**/tmp/*
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
x/auction/client/testutil/bidder-bafyre*
|
||||||
|
|
||||||
# Vagrant
|
# Vagrant
|
||||||
.vagrant/
|
.vagrant/
|
||||||
@ -55,6 +61,7 @@ vagrant
|
|||||||
# IDE
|
# IDE
|
||||||
.idea/
|
.idea/
|
||||||
*.iml
|
*.iml
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
# Graphviz
|
# Graphviz
|
||||||
dependency-graph.png
|
dependency-graph.png
|
||||||
@ -69,6 +76,8 @@ dependency-graph.png
|
|||||||
*.abi
|
*.abi
|
||||||
|
|
||||||
# Node.js
|
# Node.js
|
||||||
tests/**/node_modules/*
|
**/node_modules
|
||||||
tests-solidity/**/node_modules/*
|
|
||||||
**/**.json
|
|
||||||
|
# OpenZeppelin contracts
|
||||||
|
contracts/@openzeppelin/*
|
||||||
|
2766
.gitleaks.toml
Normal file
2766
.gitleaks.toml
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,47 +6,34 @@ run:
|
|||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- deadcode
|
# - depguard # 20231120 disable until https://github.com/golangci/golangci-lint/issues/3906 is released
|
||||||
- depguard
|
|
||||||
- dogsled
|
- dogsled
|
||||||
- dupl
|
|
||||||
- errcheck
|
- errcheck
|
||||||
- goconst
|
- goconst
|
||||||
- gocritic
|
- gocritic
|
||||||
- gofmt
|
- gofumpt
|
||||||
- goimports
|
# - revive # 20231120 overly sensitive unused detection
|
||||||
- revive
|
|
||||||
- gosec
|
- gosec
|
||||||
- gosimple
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
- ineffassign
|
- ineffassign
|
||||||
# - lll TODO: enable
|
- lll
|
||||||
- misspell
|
- misspell
|
||||||
- nakedret
|
- nakedret
|
||||||
- prealloc
|
- prealloc
|
||||||
- exportloopref
|
- exportloopref
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- structcheck
|
|
||||||
- stylecheck
|
- stylecheck
|
||||||
# - typecheck #TODO: enable
|
- typecheck
|
||||||
- unconvert
|
- unconvert
|
||||||
- unparam
|
- unparam
|
||||||
- unused
|
- unused
|
||||||
- varcheck
|
|
||||||
- nolintlint
|
- nolintlint
|
||||||
- asciicheck
|
- asciicheck
|
||||||
# - exhaustive
|
|
||||||
- exportloopref
|
- exportloopref
|
||||||
- gofumpt
|
- gofumpt
|
||||||
- gomodguard
|
- gomodguard
|
||||||
# - nestif
|
- whitespace
|
||||||
# - nlreturn
|
|
||||||
- noctx
|
|
||||||
- rowserrcheck
|
|
||||||
# - whitespace
|
|
||||||
# - wsl
|
|
||||||
disable:
|
|
||||||
- typecheck
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
@ -59,6 +46,8 @@ issues:
|
|||||||
max-same-issues: 50
|
max-same-issues: 50
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
|
lll:
|
||||||
|
line-length: 150
|
||||||
dogsled:
|
dogsled:
|
||||||
max-blank-identifiers: 3
|
max-blank-identifiers: 3
|
||||||
golint:
|
golint:
|
||||||
@ -73,7 +62,7 @@ linters-settings:
|
|||||||
require-explanation: false
|
require-explanation: false
|
||||||
require-specific: false
|
require-specific: false
|
||||||
gofumpt:
|
gofumpt:
|
||||||
lang-version: "1.17"
|
lang-version: "1.19"
|
||||||
gomodguard:
|
gomodguard:
|
||||||
blocked:
|
blocked:
|
||||||
versions: # List of blocked module version constraints
|
versions: # List of blocked module version constraints
|
||||||
|
21
.markdownlint.yml
Normal file
21
.markdownlint.yml
Normal 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
3
.markdownlintignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
CHANGELOG.md
|
||||||
|
docs/api/proto-docs.md
|
||||||
|
docs/node_modules
|
28
.mergify.yml
28
.mergify.yml
@ -4,7 +4,7 @@ queue_rules:
|
|||||||
- "#approved-reviews-by>1"
|
- "#approved-reviews-by>1"
|
||||||
|
|
||||||
pull_request_rules:
|
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:
|
conditions:
|
||||||
- "#approved-reviews-by>1"
|
- "#approved-reviews-by>1"
|
||||||
- base=main
|
- base=main
|
||||||
@ -12,22 +12,30 @@ pull_request_rules:
|
|||||||
actions:
|
actions:
|
||||||
queue:
|
queue:
|
||||||
name: default
|
name: default
|
||||||
merge:
|
|
||||||
method: squash
|
method: squash
|
||||||
commit_message: title+body
|
commit_message_template: |
|
||||||
- name: backport patches to v0.9.x branch
|
{{ title }} (#{{ number }})
|
||||||
|
{{ body }}
|
||||||
|
- name: backport patches to main branch
|
||||||
conditions:
|
conditions:
|
||||||
- base=main
|
- label=backport/main
|
||||||
- label=backport/0.9.x
|
|
||||||
actions:
|
actions:
|
||||||
backport:
|
backport:
|
||||||
branches:
|
branches:
|
||||||
- release/v0.9.x
|
- main
|
||||||
- name: backport patches to v0.7.x branch
|
- name: backport patches to v0.20.x branch
|
||||||
conditions:
|
conditions:
|
||||||
- base=main
|
- base=main
|
||||||
- label=backport/0.7.x
|
- label=backport/0.20.x
|
||||||
actions:
|
actions:
|
||||||
backport:
|
backport:
|
||||||
branches:
|
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
174
.protolint.yml
Normal 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
|
@ -19,6 +19,9 @@ test/
|
|||||||
tests/
|
tests/
|
||||||
*_test.go
|
*_test.go
|
||||||
|
|
||||||
|
# false positive; TODO: https://github.com/cerc-io/laconicd/issues/104
|
||||||
|
testutil/network/network.go
|
||||||
|
|
||||||
# Semgrep rules folder
|
# Semgrep rules folder
|
||||||
.semgrep
|
.semgrep
|
||||||
|
|
||||||
|
3
.solhint.json
Normal file
3
.solhint.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "solhint:default"
|
||||||
|
}
|
31
.yamllint
Normal file
31
.yamllint
Normal 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
|
75
CHANGELOG.md
75
CHANGELOG.md
@ -36,7 +36,57 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
|
|
||||||
# Changelog
|
# 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
|
### State Machine Breaking
|
||||||
|
|
||||||
@ -63,11 +113,30 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
|
|
||||||
### Bug Fixes
|
### 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) [#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) [#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) [#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.
|
* (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.
|
* (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
|
## [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.
|
* (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.
|
* (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
|
* (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
|
## [v0.15.0] - 2022-05-09
|
||||||
|
|
||||||
@ -633,7 +702,7 @@ the Tracer type used to collect execution traces from the EVM transaction execut
|
|||||||
|
|
||||||
### Improvements
|
### 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+.
|
* (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.
|
* (evm) [tharsis#603](https://github.com/cosmos/ethermint/pull/603) Add state transition params that enable or disable the EVM `Call` and `Create` operations.
|
||||||
* (deps) [tharsis#602](https://github.com/cosmos/ethermint/pull/602) Bump tendermint version to [v0.33.9](https://github.com/tendermint/tendermint/releases/tag/v0.33.9)
|
* (deps) [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)
|
||||||
|
16
Dockerfile
16
Dockerfile
@ -1,14 +1,14 @@
|
|||||||
FROM golang:alpine AS build-env
|
FROM golang:alpine AS build-env
|
||||||
|
|
||||||
# Set up dependencies
|
# Install dependencies
|
||||||
ENV PACKAGES git build-base
|
RUN apk add --update git build-base linux-headers
|
||||||
|
|
||||||
# Set working directory for the build
|
# Set working directory for the build
|
||||||
WORKDIR /go/src/github.com/cerc-io/laconicd
|
WORKDIR /go/src/github.com/cerc-io/laconicd
|
||||||
|
|
||||||
# Install dependencies
|
# Cache Go modules
|
||||||
RUN apk add --update $PACKAGES
|
COPY go.mod go.sum ./
|
||||||
RUN apk add linux-headers
|
RUN go mod download
|
||||||
|
|
||||||
# Add source files
|
# Add source files
|
||||||
COPY . .
|
COPY . .
|
||||||
@ -17,14 +17,14 @@ COPY . .
|
|||||||
RUN make build
|
RUN make build
|
||||||
|
|
||||||
# Final image
|
# Final image
|
||||||
FROM alpine:3.16.2
|
FROM alpine:3.17.0
|
||||||
|
|
||||||
# Install ca-certificates
|
# Install ca-certificates
|
||||||
RUN apk add --update ca-certificates jq
|
RUN apk add --update ca-certificates jq curl
|
||||||
WORKDIR /
|
|
||||||
|
|
||||||
# Copy over binaries from the build-env
|
# Copy over binaries from the build-env
|
||||||
COPY --from=build-env /go/src/github.com/cerc-io/laconicd/build/laconicd /usr/bin/laconicd
|
COPY --from=build-env /go/src/github.com/cerc-io/laconicd/build/laconicd /usr/bin/laconicd
|
||||||
|
|
||||||
|
WORKDIR /
|
||||||
# Run laconicd by default
|
# Run laconicd by default
|
||||||
CMD ["laconicd"]
|
CMD ["laconicd"]
|
||||||
|
167
Makefile
Executable file → Normal file
167
Makefile
Executable file → Normal file
@ -14,7 +14,6 @@ SIMAPP = ./app
|
|||||||
HTTPS_GIT := https://github.com/cerc-io/laconicd.git
|
HTTPS_GIT := https://github.com/cerc-io/laconicd.git
|
||||||
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
|
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
|
||||||
DOCKER := $(shell which docker)
|
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.
|
# 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.
|
# Instead, it must be explicitly enabled and we warn when it is not.
|
||||||
ENABLE_ROCKSDB ?= false
|
ENABLE_ROCKSDB ?= false
|
||||||
@ -73,7 +72,7 @@ ifeq ($(ENABLE_ROCKSDB),true)
|
|||||||
BUILD_TAGS += rocksdb_build
|
BUILD_TAGS += rocksdb_build
|
||||||
test_tags += rocksdb_build
|
test_tags += rocksdb_build
|
||||||
else
|
else
|
||||||
$(warning RocksDB support is disabled; to build and test with RocksDB support, set ENABLE_ROCKSDB=true)
|
$(info RocksDB support is disabled; to build and test with RocksDB support, set ENABLE_ROCKSDB=true)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# DB backend selection
|
# DB backend selection
|
||||||
@ -111,6 +110,12 @@ ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
|
|||||||
BUILD_FLAGS += -trimpath
|
BUILD_FLAGS += -trimpath
|
||||||
endif
|
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.
|
# # The below include contains the tools and runsim targets.
|
||||||
# include contrib/devtools/Makefile
|
# include contrib/devtools/Makefile
|
||||||
|
|
||||||
@ -140,7 +145,7 @@ docker-build:
|
|||||||
# update old container
|
# update old container
|
||||||
docker rm laconicd || true
|
docker rm laconicd || true
|
||||||
# create a new container from the latest image
|
# create a new container from the latest image
|
||||||
docker create --name laconic -t -i cerc-io/laconicd:latest laconicd
|
docker create --name laconic -t -i ${DOCKER_IMAGE}:${DOCKER_TAG} laconicd
|
||||||
# move the binaries to the ./build directory
|
# move the binaries to the ./build directory
|
||||||
mkdir -p ./build/
|
mkdir -p ./build/
|
||||||
docker cp laconic:/usr/bin/laconicd ./build/
|
docker cp laconic:/usr/bin/laconicd ./build/
|
||||||
@ -158,7 +163,7 @@ clean:
|
|||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
build-all: tools build lint test
|
build-all: tools build lint test vulncheck
|
||||||
|
|
||||||
.PHONY: distclean clean build-all
|
.PHONY: distclean clean build-all
|
||||||
|
|
||||||
@ -167,7 +172,7 @@ build-all: tools build lint test
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
PACKAGE_NAME:=github.com/cerc-io/laconicd
|
PACKAGE_NAME:=github.com/cerc-io/laconicd
|
||||||
GOLANG_CROSS_VERSION = v1.18
|
GOLANG_CROSS_VERSION = v1.19
|
||||||
GOPATH ?= '$(HOME)/go'
|
GOPATH ?= '$(HOME)/go'
|
||||||
release-dry-run:
|
release-dry-run:
|
||||||
docker run \
|
docker run \
|
||||||
@ -232,7 +237,7 @@ endif
|
|||||||
|
|
||||||
ifeq (, $(shell which go-bindata))
|
ifeq (, $(shell which go-bindata))
|
||||||
@echo "Installing go-bindata..."
|
@echo "Installing go-bindata..."
|
||||||
@go get github.com/kevinburke/go-bindata/go-bindata
|
@go get github.com/kevinburke/go-bindata/go-bindata@v3
|
||||||
else
|
else
|
||||||
@echo "go-bindata already installed; skipping..."
|
@echo "go-bindata already installed; skipping..."
|
||||||
endif
|
endif
|
||||||
@ -276,6 +281,10 @@ go.sum: go.mod
|
|||||||
go mod verify
|
go mod verify
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
|
||||||
|
vulncheck: $(BUILDDIR)/
|
||||||
|
GOBIN=$(BUILDDIR) go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||||
|
$(BUILDDIR)/govulncheck ./...
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
### Documentation ###
|
### Documentation ###
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@ -307,7 +316,7 @@ TEST_TARGETS := test-unit test-unit-cover test-race
|
|||||||
# Test runs-specific rules. To add a new test target, just add
|
# Test runs-specific rules. To add a new test target, just add
|
||||||
# a new rule, customise ARGS or TEST_PACKAGES ad libitum, and
|
# a new rule, customise ARGS or TEST_PACKAGES ad libitum, and
|
||||||
# append the new rule to the TEST_TARGETS list.
|
# append the new rule to the TEST_TARGETS list.
|
||||||
test-unit: ARGS=-timeout=10m -race
|
test-unit: ARGS=-timeout=10m -race -test.v -skip $(SKIP_UNIT_TESTS)
|
||||||
test-unit: TEST_PACKAGES=$(PACKAGES_UNIT)
|
test-unit: TEST_PACKAGES=$(PACKAGES_UNIT)
|
||||||
|
|
||||||
test-race: ARGS=-race
|
test-race: ARGS=-race
|
||||||
@ -325,13 +334,10 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
test-import:
|
test-import:
|
||||||
go test -run TestImporterTestSuite -v --vet=off github.com/cerc-io/laconicd/tests/importer
|
go test -run TestImporterTestSuite -timeout=20m -v --vet=off github.com/cerc-io/laconicd/tests/importer
|
||||||
|
|
||||||
test-rpc:
|
test-rpc:
|
||||||
./scripts/integration-test-all.sh -t "rpc" -q 1 -z 1 -s 2 -m "rpc" -r "true"
|
./scripts/integration-test-all.sh -t "rpc" -q 1 -z 1 -s 10 -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:
|
run-integration-tests:
|
||||||
@nix-shell ./tests/integration_tests/shell.nix --run ./scripts/run-integration-tests.sh
|
@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)
|
.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:
|
benchmark:
|
||||||
@go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION)
|
@go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION)
|
||||||
@ -427,74 +388,62 @@ format-fix:
|
|||||||
### Protobuf ###
|
### 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)
|
protoImageName=tendermintdev/sdk-proto-gen:$(protoVer)
|
||||||
containerProtoGen=$(PROJECT_NAME)-proto-gen-$(protoVer)
|
protoImage=$(DOCKER) run --network host --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName)
|
||||||
containerProtoGenAny=$(PROJECT_NAME)-proto-gen-any-$(protoVer)
|
# ------
|
||||||
containerProtoGenSwagger=$(PROJECT_NAME)-proto-gen-swagger-$(protoVer)
|
# NOTE: cosmos/proto-builder image is needed because clang-format is not installed
|
||||||
containerProtoFmt=$(PROJECT_NAME)-proto-fmt-$(protoVer)
|
# 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-all: proto-format proto-lint proto-gen
|
||||||
|
|
||||||
proto-gen:
|
proto-gen:
|
||||||
@echo "Generating Protobuf files"
|
@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) \
|
$(protoImage) sh ./scripts/protocgen.sh
|
||||||
sh ./scripts/protocgen.sh; fi
|
|
||||||
|
|
||||||
proto-swagger-gen:
|
|
||||||
@echo "Generating Protobuf Swagger"
|
# TODO: Rethink API docs generation
|
||||||
@./scripts/proto-tools-installer.sh
|
# proto-swagger-gen:
|
||||||
@./scripts/protoc-swagger-gen.sh
|
# @echo "Generating Protobuf Swagger"
|
||||||
|
# $(protoImage) sh ./scripts/protoc-swagger-gen.sh
|
||||||
|
|
||||||
proto-format:
|
proto-format:
|
||||||
@echo "Formatting Protobuf files"
|
@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 \
|
$(protoCosmosImage) find ./ -name *.proto -exec clang-format -i {} \;
|
||||||
find ./ -not -path "./third_party/*" -name "*.proto" -exec clang-format -i {} \; ; fi
|
|
||||||
|
|
||||||
|
# NOTE: The linter configuration lives in .protolint.yaml
|
||||||
proto-lint:
|
proto-lint:
|
||||||
@$(DOCKER_BUF) lint --error-format=json
|
@echo "Linting Protobuf files"
|
||||||
|
$(protolintImage) lint ./proto
|
||||||
|
|
||||||
proto-check-breaking:
|
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
|
.PHONY: proto-all proto-gen proto-gen-any proto-format proto-lint proto-check-breaking
|
||||||
GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos
|
|
||||||
COSMOS_SDK_URL = https://raw.githubusercontent.com/cosmos/cosmos-sdk/v0.43.0
|
|
||||||
COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master
|
|
||||||
|
|
||||||
TM_CRYPTO_TYPES = third_party/proto/tendermint/crypto
|
|
||||||
TM_ABCI_TYPES = third_party/proto/tendermint/abci
|
|
||||||
TM_TYPES = third_party/proto/tendermint/types
|
|
||||||
|
|
||||||
GOGO_PROTO_TYPES = third_party/proto/gogoproto
|
|
||||||
|
|
||||||
COSMOS_PROTO_TYPES = third_party/proto/cosmos_proto
|
|
||||||
|
|
||||||
proto-update-deps:
|
|
||||||
@mkdir -p $(GOGO_PROTO_TYPES)
|
|
||||||
@curl -sSL $(GOGO_PROTO_URL)/gogoproto/gogo.proto > $(GOGO_PROTO_TYPES)/gogo.proto
|
|
||||||
|
|
||||||
@mkdir -p $(COSMOS_PROTO_TYPES)
|
|
||||||
@curl -sSL $(COSMOS_PROTO_URL)/cosmos.proto > $(COSMOS_PROTO_TYPES)/cosmos.proto
|
|
||||||
|
|
||||||
## Importing of tendermint protobuf definitions currently requires the
|
|
||||||
## use of `sed` in order to build properly with cosmos-sdk's proto file layout
|
|
||||||
## (which is the standard Buf.build FILE_LAYOUT)
|
|
||||||
## Issue link: https://github.com/tendermint/tendermint/issues/5021
|
|
||||||
@mkdir -p $(TM_ABCI_TYPES)
|
|
||||||
@curl -sSL $(TM_URL)/abci/types.proto > $(TM_ABCI_TYPES)/types.proto
|
|
||||||
|
|
||||||
@mkdir -p $(TM_TYPES)
|
|
||||||
@curl -sSL $(TM_URL)/types/types.proto > $(TM_TYPES)/types.proto
|
|
||||||
|
|
||||||
@mkdir -p $(TM_CRYPTO_TYPES)
|
|
||||||
@curl -sSL $(TM_URL)/crypto/proof.proto > $(TM_CRYPTO_TYPES)/proof.proto
|
|
||||||
@curl -sSL $(TM_URL)/crypto/keys.proto > $(TM_CRYPTO_TYPES)/keys.proto
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.PHONY: proto-all proto-gen proto-gen-any proto-swagger-gen proto-format proto-lint proto-check-breaking proto-update-deps
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
### Localnet ###
|
### Localnet ###
|
||||||
|
10
README.md
10
README.md
@ -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.
|
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
|
## Installation
|
||||||
|
|
||||||
@ -15,6 +15,14 @@ The Source of Proof. Laconic is a next generation data availability & verifiabil
|
|||||||
make install
|
make install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
To quickly get started with a single node fixture, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./init.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
The following chat channels and forums are a great spot to ask questions about Ethermint:
|
The following chat channels and forums are a great spot to ask questions about Ethermint:
|
||||||
|
@ -6,8 +6,10 @@ import (
|
|||||||
|
|
||||||
tmlog "github.com/tendermint/tendermint/libs/log"
|
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"
|
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/types/tx/signing"
|
||||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
@ -44,14 +46,14 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
|||||||
// handle as *evmtypes.MsgEthereumTx
|
// handle as *evmtypes.MsgEthereumTx
|
||||||
anteHandler = newEthAnteHandler(options)
|
anteHandler = newEthAnteHandler(options)
|
||||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
// Deprecated: Handle as normal Cosmos SDK tx, except signature is checked for Legacy EIP712 representation
|
||||||
anteHandler = newCosmosAnteHandlerEip712(options)
|
anteHandler = NewLegacyCosmosAnteHandlerEip712(options)
|
||||||
case "/ethermint.types.v1.ExtensionOptionDynamicFeeTx":
|
case "/ethermint.types.v1.ExtensionOptionDynamicFeeTx":
|
||||||
// cosmos-sdk tx with dynamic fee extension
|
// cosmos-sdk tx with dynamic fee extension
|
||||||
anteHandler = newCosmosAnteHandler(options)
|
anteHandler = newCosmosAnteHandler(options)
|
||||||
default:
|
default:
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
sdkerrors.ErrUnknownExtensionOptions,
|
errortypes.ErrUnknownExtensionOptions,
|
||||||
"rejecting tx with unsupported extension option: %s", typeURL,
|
"rejecting tx with unsupported extension option: %s", typeURL,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -65,7 +67,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
|||||||
case sdk.Tx:
|
case sdk.Tx:
|
||||||
anteHandler = newCosmosAnteHandler(options)
|
anteHandler = newCosmosAnteHandler(options)
|
||||||
default:
|
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)
|
return anteHandler(ctx, tx, sim)
|
||||||
@ -74,7 +76,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
|||||||
|
|
||||||
func Recover(logger tmlog.Logger, err *error) {
|
func Recover(logger tmlog.Logger, err *error) {
|
||||||
if r := recover(); r != nil {
|
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 {
|
if e, ok := r.(error); ok {
|
||||||
logger.Error(
|
logger.Error(
|
||||||
@ -99,12 +101,48 @@ var _ authante.SignatureVerificationGasConsumer = DefaultSigVerificationGasConsu
|
|||||||
func DefaultSigVerificationGasConsumer(
|
func DefaultSigVerificationGasConsumer(
|
||||||
meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params,
|
meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params,
|
||||||
) error {
|
) error {
|
||||||
// support for ethereum ECDSA secp256k1 keys
|
pubkey := sig.PubKey
|
||||||
_, ok := sig.PubKey.(*ethsecp256k1.PubKey)
|
switch pubkey := pubkey.(type) {
|
||||||
if ok {
|
case *ethsecp256k1.PubKey:
|
||||||
meter.ConsumeGas(secp256k1VerifyCost, "ante verify: eth_secp256k1")
|
meter.ConsumeGas(secp256k1VerifyCost, "ante verify: eth_secp256k1")
|
||||||
return nil
|
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)
|
return authante.DefaultSigVerificationGasConsumer(meter, sig, params)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature
|
||||||
|
func ConsumeMultisignatureVerificationGas(
|
||||||
|
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
|
||||||
|
params authtypes.Params, accSeq uint64,
|
||||||
|
) error {
|
||||||
|
size := sig.BitArray.Count()
|
||||||
|
sigIndex := 0
|
||||||
|
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
if !sig.BitArray.GetIndex(i) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sigV2 := signing.SignatureV2{
|
||||||
|
PubKey: pubkey.GetPubKeys()[i],
|
||||||
|
Data: sig.Signatures[sigIndex],
|
||||||
|
Sequence: accSeq,
|
||||||
|
}
|
||||||
|
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sigIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -2,24 +2,36 @@ package ante_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdkmath "cosmossdk.io/math"
|
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/types/tx/signing"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
||||||
|
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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"
|
"github.com/cerc-io/laconicd/tests"
|
||||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
ethparams "github.com/ethereum/go-ethereum/params"
|
ethparams "github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
|
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (suite AnteTestSuite) TestAnteHandler() {
|
func (suite AnteTestSuite) TestAnteHandler() {
|
||||||
@ -337,6 +349,17 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
return txBuilder.GetTx()
|
return txBuilder.GetTx()
|
||||||
}, false, false, true,
|
}, 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",
|
"success- DeliverTx EIP712 MsgSubmitProposal",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
@ -364,7 +387,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
from, grantee, &banktypes.SendAuthorization{SpendLimit: gasAmount}, &expiresAt,
|
from, grantee, &banktypes.SendAuthorization{SpendLimit: gasAmount}, &expiresAt,
|
||||||
)
|
)
|
||||||
suite.Require().NoError(err)
|
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,
|
}, false, false, true,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -397,10 +420,65 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||||
amount := sdk.NewCoins(coinAmount)
|
amount := sdk.NewCoins(coinAmount)
|
||||||
gas := uint64(200000)
|
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()
|
return txBuilder.GetTx()
|
||||||
}, false, false, true,
|
}, 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",
|
"fails - DeliverTx EIP712 signed Cosmos Tx with wrong Chain ID",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
@ -496,6 +574,301 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
return tx
|
return tx
|
||||||
}, true, false, false,
|
}, 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 {
|
for _, tc := range testCases {
|
||||||
@ -914,3 +1287,93 @@ func (suite AnteTestSuite) TestAnteHandlerWithParams() {
|
|||||||
}
|
}
|
||||||
suite.evmParamsOption = nil
|
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
|
||||||
|
}
|
||||||
|
@ -3,15 +3,17 @@ package ante
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/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"
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
||||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
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/crypto/ethsecp256k1"
|
||||||
"github.com/cerc-io/laconicd/ethereum/eip712"
|
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||||
@ -19,6 +21,7 @@ import (
|
|||||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ethermintCodec codec.ProtoCodecMarshaler
|
var ethermintCodec codec.ProtoCodecMarshaler
|
||||||
@ -29,19 +32,47 @@ func init() {
|
|||||||
ethermintCodec = codec.NewProtoCodec(registry)
|
ethermintCodec = codec.NewProtoCodec(registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eip712SigVerificationDecorator Verify all signatures for a tx and return an error if any are invalid. Note,
|
// Deprecated: NewLegacyCosmosAnteHandlerEip712 creates an AnteHandler to process legacy EIP-712
|
||||||
// the Eip712SigVerificationDecorator decorator will not get executed on ReCheck.
|
// 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: Pubkeys are set in context for all signers before this decorator runs
|
||||||
// CONTRACT: Tx must implement SigVerifiableTx interface
|
// CONTRACT: Tx must implement SigVerifiableTx interface
|
||||||
type Eip712SigVerificationDecorator struct {
|
type LegacyEip712SigVerificationDecorator struct {
|
||||||
ak evmtypes.AccountKeeper
|
ak evmtypes.AccountKeeper
|
||||||
signModeHandler authsigning.SignModeHandler
|
signModeHandler authsigning.SignModeHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEip712SigVerificationDecorator creates a new Eip712SigVerificationDecorator
|
// Deprecated: NewLegacyEip712SigVerificationDecorator creates a new LegacyEip712SigVerificationDecorator
|
||||||
func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandler authsigning.SignModeHandler) Eip712SigVerificationDecorator {
|
func NewLegacyEip712SigVerificationDecorator(
|
||||||
return Eip712SigVerificationDecorator{
|
ak evmtypes.AccountKeeper,
|
||||||
|
signModeHandler authsigning.SignModeHandler,
|
||||||
|
) LegacyEip712SigVerificationDecorator {
|
||||||
|
return LegacyEip712SigVerificationDecorator{
|
||||||
ak: ak,
|
ak: ak,
|
||||||
signModeHandler: signModeHandler,
|
signModeHandler: signModeHandler,
|
||||||
}
|
}
|
||||||
@ -49,7 +80,7 @@ func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandle
|
|||||||
|
|
||||||
// AnteHandle handles validation of EIP712 signed cosmos txs.
|
// AnteHandle handles validation of EIP712 signed cosmos txs.
|
||||||
// it is not run on RecheckTx
|
// it is not run on RecheckTx
|
||||||
func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
|
func (svd LegacyEip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
|
||||||
tx sdk.Tx,
|
tx sdk.Tx,
|
||||||
simulate bool,
|
simulate bool,
|
||||||
next sdk.AnteHandler,
|
next sdk.AnteHandler,
|
||||||
@ -61,12 +92,12 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
|
|||||||
|
|
||||||
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
||||||
if !ok {
|
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)
|
authSignTx, ok := tx.(authsigning.Tx)
|
||||||
if !ok {
|
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.
|
// 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
|
// EIP712 allows just one signature
|
||||||
if len(sigs) != 1 {
|
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
|
// check that signer length and signature length are the same
|
||||||
if len(sigs) != len(signerAddrs) {
|
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
|
// 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
|
// retrieve pubkey
|
||||||
pubKey := acc.GetPubKey()
|
pubKey := acc.GetPubKey()
|
||||||
if !simulate && pubKey == nil {
|
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.
|
// Check account sequence number.
|
||||||
if sig.Sequence != acc.GetSequence() {
|
if sig.Sequence != acc.GetSequence() {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
sdkerrors.ErrWrongSequence,
|
errortypes.ErrWrongSequence,
|
||||||
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
|
"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 {
|
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)
|
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)
|
return next(ctx, tx, simulate)
|
||||||
@ -150,12 +185,12 @@ func VerifySignature(
|
|||||||
switch data := sigData.(type) {
|
switch data := sigData.(type) {
|
||||||
case *signing.SingleSignatureData:
|
case *signing.SingleSignatureData:
|
||||||
if data.SignMode != signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON {
|
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 {
|
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),
|
// @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()
|
msgs := tx.GetMsgs()
|
||||||
if len(msgs) == 0 {
|
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(
|
txBytes := legacytx.StdSignBytes(
|
||||||
@ -180,33 +215,33 @@ func VerifySignature(
|
|||||||
|
|
||||||
signerChainID, err := ethermint.ParseChainID(signerData.ChainID)
|
signerChainID, err := ethermint.ParseChainID(signerData.ChainID)
|
||||||
if err != nil {
|
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)
|
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
|
||||||
if !ok {
|
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()
|
opts := txWithExtensions.GetExtensionOptions()
|
||||||
if len(opts) != 1 {
|
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)
|
extOpt, ok := opts[0].GetCachedValue().(*ethermint.ExtensionOptionsWeb3Tx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidChainID, "unknown extension option")
|
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "unknown extension option")
|
||||||
}
|
}
|
||||||
|
|
||||||
if extOpt.TypedDataChainID != signerChainID.Uint64() {
|
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 {
|
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)
|
feePayer, err := sdk.AccAddressFromBech32(extOpt.FeePayer)
|
||||||
if err != nil {
|
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{
|
feeDelegation := &eip712.FeeDelegationOptions{
|
||||||
@ -215,17 +250,17 @@ func VerifySignature(
|
|||||||
|
|
||||||
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
|
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
|
||||||
if err != nil {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
feePayerSig := extOpt.FeePayerSig
|
feePayerSig := extOpt.FeePayerSig
|
||||||
if len(feePayerSig) != ethcrypto.SignatureLength {
|
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)
|
// Remove the recovery offset if needed (ie. Metamask eip712 signature)
|
||||||
@ -235,12 +270,12 @@ func VerifySignature(
|
|||||||
|
|
||||||
feePayerPubkey, err := secp256k1.RecoverPubkey(sigHash, feePayerSig)
|
feePayerPubkey, err := secp256k1.RecoverPubkey(sigHash, feePayerSig)
|
||||||
if err != nil {
|
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)
|
ecPubKey, err := ethcrypto.UnmarshalPubkey(feePayerPubkey)
|
||||||
if err != nil {
|
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 := ðsecp256k1.PubKey{
|
pk := ðsecp256k1.PubKey{
|
||||||
@ -248,23 +283,23 @@ func VerifySignature(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !pubKey.Equals(pk) {
|
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())
|
recoveredFeePayerAcc := sdk.AccAddress(pk.Address().Bytes())
|
||||||
|
|
||||||
if !recoveredFeePayerAcc.Equals(feePayer) {
|
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]
|
// VerifySignature of ethsecp256k1 accepts 64 byte signature [R||S]
|
||||||
// WARNING! Under NO CIRCUMSTANCES try to use pubKey.VerifySignature there
|
// WARNING! Under NO CIRCUMSTANCES try to use pubKey.VerifySignature there
|
||||||
if !secp256k1.VerifySignature(pubKey.Bytes(), sigHash, feePayerSig[:len(feePayerSig)-1]) {
|
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
|
return nil
|
||||||
default:
|
default:
|
||||||
return sdkerrors.Wrapf(sdkerrors.ErrTooManySignatures, "unexpected SignatureData %T", sigData)
|
return errorsmod.Wrapf(errortypes.ErrTooManySignatures, "unexpected SignatureData %T", sigData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
450
app/ante/eth.go
450
app/ante/eth.go
@ -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
|
package ante
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
sdkmath "cosmossdk.io/math"
|
sdkmath "cosmossdk.io/math"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/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"
|
|
||||||
|
|
||||||
ethermint "github.com/cerc-io/laconicd/types"
|
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"
|
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||||
|
|
||||||
@ -21,61 +34,6 @@ import (
|
|||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
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
|
// EthAccountVerificationDecorator validates an account balance checks
|
||||||
type EthAccountVerificationDecorator struct {
|
type EthAccountVerificationDecorator struct {
|
||||||
ak evmtypes.AccountKeeper
|
ak evmtypes.AccountKeeper
|
||||||
@ -109,35 +67,35 @@ func (avd EthAccountVerificationDecorator) AnteHandle(
|
|||||||
for i, msg := range tx.GetMsgs() {
|
for i, msg := range tx.GetMsgs() {
|
||||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
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)
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||||
if err != nil {
|
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
|
// sender address should be in the tx cache from the previous AnteHandle call
|
||||||
from := msgEthTx.GetFrom()
|
from := msgEthTx.GetFrom()
|
||||||
if from.Empty() {
|
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
|
// check whether the sender address is EOA
|
||||||
fromAddr := common.BytesToAddress(from)
|
fromAddr := common.BytesToAddress(from)
|
||||||
acct := avd.evmKeeper.GetAccount(ctx, fromAddr) //nolint: all
|
acct := avd.evmKeeper.GetAccount(ctx, fromAddr)
|
||||||
|
|
||||||
if acct == nil {
|
if acct == nil {
|
||||||
acc := avd.ak.NewAccountWithAddress(ctx, from)
|
acc := avd.ak.NewAccountWithAddress(ctx, from)
|
||||||
avd.ak.SetAccount(ctx, acc)
|
avd.ak.SetAccount(ctx, acc)
|
||||||
acct = statedb.NewEmptyAccount()
|
acct = statedb.NewEmptyAccount()
|
||||||
} else if acct.IsContract() {
|
} 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)
|
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := evmkeeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
|
if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
|
||||||
return ctx, sdkerrors.Wrap(err, "failed to check sender balance")
|
return ctx, errorsmod.Wrap(err, "failed to check sender balance")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return next(ctx, tx, simulate)
|
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.
|
// (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
|
// 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.
|
// of data supplied with the transaction.
|
||||||
//
|
//
|
||||||
// This AnteHandler decorator will fail if:
|
// 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)
|
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
|
||||||
// - transaction or block gas meter runs out of gas
|
// - transaction or block gas meter runs out of gas
|
||||||
// - sets the gas meter limit
|
// - 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) {
|
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())
|
blockHeight := big.NewInt(ctx.BlockHeight())
|
||||||
homestead := ethCfg.IsHomestead(blockHeight)
|
homestead := ethCfg.IsHomestead(blockHeight)
|
||||||
istanbul := ethCfg.IsIstanbul(blockHeight)
|
istanbul := ethCfg.IsIstanbul(blockHeight)
|
||||||
london := ethCfg.IsLondon(blockHeight)
|
|
||||||
evmDenom := params.EvmDenom
|
|
||||||
gasWanted := uint64(0)
|
|
||||||
var events sdk.Events
|
var events sdk.Events
|
||||||
|
|
||||||
// Use the lowest priority of all the messages as the final one.
|
// Use the lowest priority of all the messages as the final one.
|
||||||
minPriority := int64(math.MaxInt64)
|
minPriority := int64(math.MaxInt64)
|
||||||
|
baseFee := egcd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||||
|
|
||||||
for _, msg := range tx.GetMsgs() {
|
for _, msg := range tx.GetMsgs() {
|
||||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
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)
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||||
if err != nil {
|
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 {
|
if ctx.IsCheckTx() && egcd.maxGasWanted != 0 {
|
||||||
@ -213,45 +183,59 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
|||||||
gasWanted += txData.GetGas()
|
gasWanted += txData.GetGas()
|
||||||
}
|
}
|
||||||
|
|
||||||
fees, priority, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
|
evmDenom := egcd.evmKeeper.GetEVMDenom(ctx)
|
||||||
ctx,
|
|
||||||
*msgEthTx,
|
fees, err := keeper.VerifyFee(txData, evmDenom, baseFee, homestead, istanbul, ctx.IsCheckTx())
|
||||||
txData,
|
|
||||||
evmDenom,
|
|
||||||
homestead,
|
|
||||||
istanbul,
|
|
||||||
london,
|
|
||||||
)
|
|
||||||
if err != nil {
|
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 {
|
if priority < minPriority {
|
||||||
minPriority = priority
|
minPriority = priority
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: change to typed events
|
|
||||||
ctx.EventManager().EmitEvents(events)
|
ctx.EventManager().EmitEvents(events)
|
||||||
|
|
||||||
// TODO: deprecate after https://github.com/cosmos/cosmos-sdk/issues/9514 is fixed on SDK
|
|
||||||
blockGasLimit := ethermint.BlockGasLimit(ctx)
|
blockGasLimit := ethermint.BlockGasLimit(ctx)
|
||||||
|
|
||||||
// NOTE: safety check
|
// return error if the tx gas is greater than the block limit (max gas)
|
||||||
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
|
// NOTE: it's important here to use the gas wanted instead of the gas consumed
|
||||||
// if current gas consumed is greater than the limit, this funcion panics and the error is recovered on the Baseapp
|
// from the tx gas pool. The later only has the value so far since the
|
||||||
gasPool := sdk.NewGasMeter(blockGasLimit)
|
// EthSetupContextDecorator so it will never exceed the block gas limit.
|
||||||
gasPool.ConsumeGas(ctx.GasMeter().GasConsumedToLimit(), "gas pool check")
|
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)
|
// Set tx GasMeter with a limit of GasWanted (i.e gas limit from the Ethereum tx).
|
||||||
gasConsumed := ctx.GasMeter().GasConsumed()
|
// The gas consumed will be then reset to the gas used by the state transition
|
||||||
ctx = ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
|
// in the EVM.
|
||||||
ctx.GasMeter().ConsumeGas(gasConsumed, "copy gas consumed")
|
|
||||||
|
|
||||||
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
|
// we know that we have enough gas on the pool to cover the intrinsic gas
|
||||||
return next(newCtx, tx, simulate)
|
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() {
|
for _, msg := range tx.GetMsgs() {
|
||||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
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)
|
baseFee := ctd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||||
|
|
||||||
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
|
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
err,
|
err,
|
||||||
"failed to create an ethereum core.Message from signer %T", signer,
|
"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
|
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
|
||||||
cfg := &evmtypes.EVMConfig{
|
cfg := &evmtypes.EVMConfig{
|
||||||
ChainConfig: ethCfg,
|
ChainConfig: ethCfg,
|
||||||
@ -300,35 +300,20 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
|
|||||||
CoinBase: common.Address{},
|
CoinBase: common.Address{},
|
||||||
BaseFee: baseFee,
|
BaseFee: baseFee,
|
||||||
}
|
}
|
||||||
|
|
||||||
stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
|
stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
|
||||||
evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB)
|
evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB)
|
||||||
|
|
||||||
// check that caller has enough balance to cover asset transfer for **topmost** call
|
// 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
|
// 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()) {
|
if coreMsg.Value().Sign() > 0 && !evm.Context().CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
sdkerrors.ErrInsufficientFunds,
|
errortypes.ErrInsufficientFunds,
|
||||||
"failed to transfer %s from address %s using the EVM block context transfer function",
|
"failed to transfer %s from address %s using the EVM block context transfer function",
|
||||||
coreMsg.Value(),
|
coreMsg.Value(),
|
||||||
coreMsg.From(),
|
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)
|
return next(ctx, tx, simulate)
|
||||||
@ -353,19 +338,19 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
|
|||||||
for _, msg := range tx.GetMsgs() {
|
for _, msg := range tx.GetMsgs() {
|
||||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
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)
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||||
if err != nil {
|
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
|
// increase sequence of sender
|
||||||
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
|
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
sdkerrors.ErrUnknownAddress,
|
errortypes.ErrUnknownAddress,
|
||||||
"account %s is nil", common.BytesToAddress(msgEthTx.GetFrom().Bytes()),
|
"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
|
// we merged the nonce verification to nonce increment, so when tx includes multiple messages
|
||||||
// with same sender, they'll be accepted.
|
// with same sender, they'll be accepted.
|
||||||
if txData.GetNonce() != nonce {
|
if txData.GetNonce() != nonce {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
sdkerrors.ErrInvalidSequence,
|
errortypes.ErrInvalidSequence,
|
||||||
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
|
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := acc.SetSequence(nonce + 1); err != nil {
|
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)
|
issd.ak.SetAccount(ctx, acc)
|
||||||
@ -389,216 +374,3 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
|
|||||||
|
|
||||||
return next(ctx, tx, simulate)
|
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)
|
|
||||||
}
|
|
||||||
|
@ -9,65 +9,13 @@ import (
|
|||||||
"github.com/cerc-io/laconicd/app/ante"
|
"github.com/cerc-io/laconicd/app/ante"
|
||||||
"github.com/cerc-io/laconicd/server/config"
|
"github.com/cerc-io/laconicd/server/config"
|
||||||
"github.com/cerc-io/laconicd/tests"
|
"github.com/cerc-io/laconicd/tests"
|
||||||
|
ethermint "github.com/cerc-io/laconicd/types"
|
||||||
"github.com/cerc-io/laconicd/x/evm/statedb"
|
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||||
|
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/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() {
|
func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||||
dec := ante.NewEthAccountVerificationDecorator(
|
dec := ante.NewEthAccountVerificationDecorator(
|
||||||
suite.app.AccountKeeper, suite.app.EvmKeeper,
|
suite.app.AccountKeeper, suite.app.EvmKeeper,
|
||||||
@ -233,6 +181,9 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
|||||||
tx2.From = addr.Hex()
|
tx2.From = addr.Hex()
|
||||||
tx2Priority := int64(1)
|
tx2Priority := int64(1)
|
||||||
|
|
||||||
|
tx3GasLimit := ethermint.BlockGasLimit(suite.ctx) + uint64(1)
|
||||||
|
tx3 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx3GasLimit, gasPrice, nil, nil, nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
||||||
|
|
||||||
dynamicFeeTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit,
|
dynamicFeeTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit,
|
||||||
nil, // gasPrice
|
nil, // gasPrice
|
||||||
new(big.Int).Add(baseFee, big.NewInt(evmtypes.DefaultPriorityReduction.Int64()*2)), // gasFeeCap
|
new(big.Int).Add(baseFee, big.NewInt(evmtypes.DefaultPriorityReduction.Int64()*2)), // gasFeeCap
|
||||||
@ -269,6 +220,14 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
|||||||
false, false,
|
false, false,
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"gas limit above block gas limit",
|
||||||
|
tx3,
|
||||||
|
math.MaxUint64,
|
||||||
|
func() {},
|
||||||
|
false, false,
|
||||||
|
0,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"not enough balance for fees",
|
"not enough balance for fees",
|
||||||
tx2,
|
tx2,
|
||||||
@ -320,6 +279,17 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
|||||||
true, false,
|
true, false,
|
||||||
dynamicFeeTxPriority,
|
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 {
|
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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,12 +4,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
sdkmath "cosmossdk.io/math"
|
sdkmath "cosmossdk.io/math"
|
||||||
|
|
||||||
ethermint "github.com/cerc-io/laconicd/types"
|
ethermint "github.com/cerc-io/laconicd/types"
|
||||||
"github.com/cerc-io/laconicd/x/evm/types"
|
"github.com/cerc-io/laconicd/x/evm/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/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"
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ func NewDynamicFeeChecker(k DynamicFeeEVMKeeper) authante.TxFeeChecker {
|
|||||||
baseFeeInt := sdkmath.NewIntFromBigInt(baseFee)
|
baseFeeInt := sdkmath.NewIntFromBigInt(baseFee)
|
||||||
|
|
||||||
if feeCap.LT(baseFeeInt) {
|
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.
|
// 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) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ package ante
|
|||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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
|
// 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) {
|
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)
|
chainCfg := gwd.evmKeeper.GetChainConfig(ctx)
|
||||||
ethCfg := params.ChainConfig.EthereumConfig(gwd.evmKeeper.ChainID())
|
ethCfg := chainCfg.EthereumConfig(gwd.evmKeeper.ChainID())
|
||||||
|
|
||||||
blockHeight := big.NewInt(ctx.BlockHeight())
|
blockHeight := big.NewInt(ctx.BlockHeight())
|
||||||
isLondon := ethCfg.IsLondon(blockHeight)
|
isLondon := ethCfg.IsLondon(blockHeight)
|
||||||
@ -39,12 +39,12 @@ func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
gasWanted := feeTx.GetGas()
|
gasWanted := feeTx.GetGas()
|
||||||
feeMktParams := gwd.feeMarketKeeper.GetParams(ctx)
|
isBaseFeeEnabled := gwd.feeMarketKeeper.GetBaseFeeEnabled(ctx)
|
||||||
|
|
||||||
// Add total gasWanted to cumulative in block transientStore in FeeMarket module
|
// 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 {
|
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
118
app/ante/fees.go
118
app/ante/fees.go
@ -3,8 +3,9 @@ package ante
|
|||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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"
|
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
@ -20,14 +21,50 @@ type MinGasPriceDecorator struct {
|
|||||||
evmKeeper EVMKeeper
|
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 {
|
func NewMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) MinGasPriceDecorator {
|
||||||
return MinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
|
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) {
|
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)
|
feeTx, ok := tx.(sdk.FeeTx)
|
||||||
if !ok {
|
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
|
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)
|
return next(ctx, tx, simulate)
|
||||||
}
|
}
|
||||||
|
|
||||||
evmParams := mpd.evmKeeper.GetParams(ctx)
|
evmDenom := mpd.evmKeeper.GetEVMDenom(ctx)
|
||||||
minGasPrices := sdk.DecCoins{
|
minGasPrices := sdk.DecCoins{
|
||||||
{
|
{
|
||||||
Denom: evmParams.EvmDenom,
|
Denom: evmDenom,
|
||||||
Amount: minGasPrice,
|
Amount: minGasPrice,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -62,7 +99,7 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !feeCoins.IsAnyGTE(requiredFees) {
|
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.",
|
"provided fee < minimum global fee (%s < %s). Please increase the gas price.",
|
||||||
feeCoins,
|
feeCoins,
|
||||||
requiredFees)
|
requiredFees)
|
||||||
@ -71,20 +108,8 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
|
|||||||
return next(ctx, tx, simulate)
|
return next(ctx, tx, simulate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthMinGasPriceDecorator will check if the transaction's fee is at least as large
|
// AnteHandle ensures that the that the effective fee from the transaction is greater than the
|
||||||
// as the MinGasPrices param. If fee is too low, decorator returns error and tx
|
// minimum global fee, which is defined by the MinGasPrice (parameter) * GasLimit (tx argument).
|
||||||
// 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}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
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
|
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)
|
return next(ctx, tx, simulate)
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsEvm := empd.evmKeeper.GetParams(ctx)
|
chainCfg := empd.evmKeeper.GetChainConfig(ctx)
|
||||||
ethCfg := paramsEvm.ChainConfig.EthereumConfig(empd.evmKeeper.ChainID())
|
ethCfg := chainCfg.EthereumConfig(empd.evmKeeper.ChainID())
|
||||||
baseFee := empd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
baseFee := empd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||||
|
|
||||||
for _, msg := range tx.GetMsgs() {
|
for _, msg := range tx.GetMsgs() {
|
||||||
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
sdkerrors.ErrUnknownRequest,
|
errortypes.ErrUnknownRequest,
|
||||||
"invalid message type %T, expected %T",
|
"invalid message type %T, expected %T",
|
||||||
msg, (*evmtypes.MsgEthereumTx)(nil),
|
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)
|
txData, err := evmtypes.UnpackTxData(ethMsg.Data)
|
||||||
if err != nil {
|
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 {
|
if txData.TxType() != ethtypes.LegacyTxType {
|
||||||
@ -133,8 +158,8 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
|
|||||||
fee := sdk.NewDecFromBigInt(feeAmt)
|
fee := sdk.NewDecFromBigInt(feeAmt)
|
||||||
|
|
||||||
if fee.LT(requiredFee) {
|
if fee.LT(requiredFee) {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
sdkerrors.ErrInsufficientFee,
|
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
|
"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(),
|
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)
|
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)
|
||||||
|
}
|
||||||
|
@ -42,7 +42,7 @@ func (s AnteTestSuite) TestMinGasPriceDecorator() {
|
|||||||
return &invalidTx{}
|
return &invalidTx{}
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
"must be a FeeTx",
|
"invalid transaction type",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -345,3 +345,7 @@ func (s AnteTestSuite) TestEthMinGasPriceDecorator() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite AnteTestSuite) TestEthMempoolFeeDecorator() {
|
||||||
|
// TODO: add test
|
||||||
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package ante
|
package ante
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/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"
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||||
@ -20,7 +21,7 @@ type HandlerOptions struct {
|
|||||||
AccountKeeper evmtypes.AccountKeeper
|
AccountKeeper evmtypes.AccountKeeper
|
||||||
BankKeeper evmtypes.BankKeeper
|
BankKeeper evmtypes.BankKeeper
|
||||||
IBCKeeper *ibckeeper.Keeper
|
IBCKeeper *ibckeeper.Keeper
|
||||||
FeeMarketKeeper evmtypes.FeeMarketKeeper
|
FeeMarketKeeper FeeMarketKeeper
|
||||||
EvmKeeper EVMKeeper
|
EvmKeeper EVMKeeper
|
||||||
FeegrantKeeper ante.FeegrantKeeper
|
FeegrantKeeper ante.FeegrantKeeper
|
||||||
SignModeHandler authsigning.SignModeHandler
|
SignModeHandler authsigning.SignModeHandler
|
||||||
@ -31,20 +32,20 @@ type HandlerOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (options HandlerOptions) validate() error {
|
func (options HandlerOptions) validate() error {
|
||||||
if options.AccountKeeper == evmtypes.AccountKeeper(nil) {
|
if options.AccountKeeper == nil {
|
||||||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler")
|
return errorsmod.Wrap(errortypes.ErrLogic, "account keeper is required for AnteHandler")
|
||||||
}
|
}
|
||||||
if options.BankKeeper == evmtypes.BankKeeper(nil) {
|
if options.BankKeeper == nil {
|
||||||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler")
|
return errorsmod.Wrap(errortypes.ErrLogic, "bank keeper is required for AnteHandler")
|
||||||
}
|
}
|
||||||
if options.SignModeHandler == authsigning.SignModeHandler(nil) {
|
if options.SignModeHandler == nil {
|
||||||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
|
return errorsmod.Wrap(errortypes.ErrLogic, "sign mode handler is required for ante builder")
|
||||||
}
|
}
|
||||||
if options.FeeMarketKeeper == evmtypes.FeeMarketKeeper(nil) {
|
if options.FeeMarketKeeper == nil {
|
||||||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "fee market keeper is required for AnteHandler")
|
return errorsmod.Wrap(errortypes.ErrLogic, "fee market keeper is required for AnteHandler")
|
||||||
}
|
}
|
||||||
if options.EvmKeeper == EVMKeeper(nil) {
|
if options.EvmKeeper == nil {
|
||||||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for AnteHandler")
|
return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -70,9 +71,9 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
|||||||
RejectMessagesDecorator{}, // reject MsgEthereumTxs
|
RejectMessagesDecorator{}, // reject MsgEthereumTxs
|
||||||
ante.NewSetUpContextDecorator(),
|
ante.NewSetUpContextDecorator(),
|
||||||
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
|
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
|
||||||
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
|
|
||||||
ante.NewValidateBasicDecorator(),
|
ante.NewValidateBasicDecorator(),
|
||||||
ante.NewTxTimeoutHeightDecorator(),
|
ante.NewTxTimeoutHeightDecorator(),
|
||||||
|
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
|
||||||
ante.NewValidateMemoDecorator(options.AccountKeeper),
|
ante.NewValidateMemoDecorator(options.AccountKeeper),
|
||||||
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
|
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
|
||||||
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
|
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),
|
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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@ -28,12 +28,15 @@ type EVMKeeper interface {
|
|||||||
DynamicFeeEVMKeeper
|
DynamicFeeEVMKeeper
|
||||||
|
|
||||||
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM
|
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM
|
||||||
DeductTxCostsFromUserBalance(
|
DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error
|
||||||
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
|
|
||||||
) (fees sdk.Coins, priority int64, err error)
|
|
||||||
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
|
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
|
||||||
ResetTransientGasUsed(ctx sdk.Context)
|
ResetTransientGasUsed(ctx sdk.Context)
|
||||||
GetTxIndexTransient(ctx sdk.Context) uint64
|
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 {
|
type protoTxProvider interface {
|
||||||
@ -44,4 +47,5 @@ type protoTxProvider interface {
|
|||||||
type FeeMarketKeeper interface {
|
type FeeMarketKeeper interface {
|
||||||
GetParams(ctx sdk.Context) (params feemarkettypes.Params)
|
GetParams(ctx sdk.Context) (params feemarkettypes.Params)
|
||||||
AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error)
|
AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error)
|
||||||
|
GetBaseFeeEnabled(ctx sdk.Context) bool
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package ante
|
package ante
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/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
|
// 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) {
|
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() {
|
for _, msg := range tx.GetMsgs() {
|
||||||
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
|
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, errorsmod.Wrapf(
|
||||||
sdkerrors.ErrInvalidType,
|
errortypes.ErrInvalidType,
|
||||||
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
|
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
189
app/ante/setup.go
Normal file
189
app/ante/setup.go
Normal 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
42
app/ante/setup_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
64
app/ante/signverify_test.go
Normal file
64
app/ante/signverify_test.go
Normal 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
65
app/ante/sigverify.go
Normal 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)
|
||||||
|
}
|
@ -15,26 +15,32 @@ import (
|
|||||||
"github.com/cerc-io/laconicd/types"
|
"github.com/cerc-io/laconicd/types"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
||||||
types2 "github.com/cosmos/cosmos-sdk/x/bank/types"
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
types3 "github.com/cosmos/cosmos-sdk/x/staking/types"
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
cryptocodec "github.com/cerc-io/laconicd/crypto/codec"
|
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"
|
||||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
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"
|
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/simapp"
|
||||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
||||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
"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"
|
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
|
authz "github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
|
|
||||||
"github.com/cerc-io/laconicd/app"
|
"github.com/cerc-io/laconicd/app"
|
||||||
ante "github.com/cerc-io/laconicd/app/ante"
|
ante "github.com/cerc-io/laconicd/app/ante"
|
||||||
@ -46,7 +52,8 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||||
evtypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
|
evtypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/feegrant"
|
"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"
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||||
)
|
)
|
||||||
@ -92,6 +99,8 @@ func (suite *AnteTestSuite) SetupTest() {
|
|||||||
evmGenesis.Params.ChainConfig.ArrowGlacierBlock = &maxInt
|
evmGenesis.Params.ChainConfig.ArrowGlacierBlock = &maxInt
|
||||||
evmGenesis.Params.ChainConfig.GrayGlacierBlock = &maxInt
|
evmGenesis.Params.ChainConfig.GrayGlacierBlock = &maxInt
|
||||||
evmGenesis.Params.ChainConfig.MergeNetsplitBlock = &maxInt
|
evmGenesis.Params.ChainConfig.MergeNetsplitBlock = &maxInt
|
||||||
|
evmGenesis.Params.ChainConfig.ShanghaiBlock = &maxInt
|
||||||
|
evmGenesis.Params.ChainConfig.CancunBlock = &maxInt
|
||||||
}
|
}
|
||||||
if suite.evmParamsOption != nil {
|
if suite.evmParamsOption != nil {
|
||||||
suite.evmParamsOption(&evmGenesis.Params)
|
suite.evmParamsOption(&evmGenesis.Params)
|
||||||
@ -111,6 +120,7 @@ func (suite *AnteTestSuite) SetupTest() {
|
|||||||
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
||||||
// We're using TestMsg amino encoding in some tests, so register it here.
|
// We're using TestMsg amino encoding in some tests, so register it here.
|
||||||
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
|
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
|
||||||
|
eip712.SetEncodingConfig(encodingConfig)
|
||||||
|
|
||||||
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
|
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 {
|
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||||
// Build MsgSend
|
// Build MsgSend
|
||||||
recipient := sdk.AccAddress(common.Address{}.Bytes())
|
recipient := sdk.AccAddress(common.Address{}.Bytes())
|
||||||
msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
||||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
|
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 {
|
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||||
// Build MsgSend
|
// Build MsgSend
|
||||||
valEthAddr := tests.GenerateAddress()
|
valEthAddr := tests.GenerateAddress()
|
||||||
valAddr := sdk.ValAddress(valEthAddr.Bytes())
|
valAddr := sdk.ValAddress(valEthAddr.Bytes())
|
||||||
msgSend := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
msgSend := stakingtypes.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
||||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
|
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 {
|
func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||||
// Build MsgCreateValidator
|
// Build MsgCreateValidator
|
||||||
valAddr := sdk.ValAddress(from.Bytes())
|
valAddr := sdk.ValAddress(from.Bytes())
|
||||||
privEd := ed25519.GenPrivKey()
|
privEd := ed25519.GenPrivKey()
|
||||||
msgCreate, err := types3.NewMsgCreateValidator(
|
msgCreate, err := stakingtypes.NewMsgCreateValidator(
|
||||||
valAddr,
|
valAddr,
|
||||||
privEd.PubKey(),
|
privEd.PubKey(),
|
||||||
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)),
|
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)),
|
||||||
// TODO: can this values be empty strings?
|
stakingtypes.NewDescription("moniker", "indentity", "website", "security_contract", "details"),
|
||||||
types3.NewDescription("moniker", "indentity", "website", "security_contract", "details"),
|
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
|
||||||
types3.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
|
|
||||||
sdk.OneInt(),
|
sdk.OneInt(),
|
||||||
)
|
)
|
||||||
suite.Require().NoError(err)
|
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 {
|
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)
|
suite.Require().True(ok)
|
||||||
msgSubmit, err := types5.NewMsgSubmitProposal(proposal, deposit, from)
|
msgSubmit, err := govtypes.NewMsgSubmitProposal(proposal, deposit, from)
|
||||||
suite.Require().NoError(err)
|
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 {
|
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())
|
grantedAddr := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, granted.Bytes())
|
||||||
msgGrant, err := feegrant.NewMsgGrantAllowance(basic, from, grantedAddr.GetAddress())
|
msgGrant, err := feegrant.NewMsgGrantAllowance(basic, from, grantedAddr.GetAddress())
|
||||||
suite.Require().NoError(err)
|
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 {
|
func (suite *AnteTestSuite) CreateTestEIP712MsgEditValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||||
valAddr := sdk.ValAddress(from.Bytes())
|
valAddr := sdk.ValAddress(from.Bytes())
|
||||||
msgEdit := types3.NewMsgEditValidator(
|
msgEdit := stakingtypes.NewMsgEditValidator(
|
||||||
valAddr,
|
valAddr,
|
||||||
types3.NewDescription("moniker", "identity", "website", "security_contract", "details"),
|
stakingtypes.NewDescription("moniker", "identity", "website", "security_contract", "details"),
|
||||||
nil,
|
nil,
|
||||||
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 {
|
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)
|
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.
|
// 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)
|
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,
|
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 {
|
) client.TxBuilder {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -398,13 +495,13 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
|
|||||||
fee := legacytx.NewStdFee(gas, gasAmount)
|
fee := legacytx.NewStdFee(gas, gasAmount)
|
||||||
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
|
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
|
||||||
|
|
||||||
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "", nil)
|
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, msgs, "", nil)
|
||||||
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msg, data, &eip712.FeeDelegationOptions{
|
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msgs[0], data, &eip712.FeeDelegationOptions{
|
||||||
FeePayer: from,
|
FeePayer: from,
|
||||||
})
|
})
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
sigHash, err := eip712.ComputeTypedDataHash(typedData)
|
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
// Sign typedData
|
// Sign typedData
|
||||||
@ -442,12 +539,189 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
|
|||||||
err = builder.SetSignatures(sigsV2)
|
err = builder.SetSignatures(sigsV2)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
err = builder.SetMsgs(msg)
|
err = builder.SetMsgs(msgs...)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
return builder
|
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) {
|
func NextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
|
||||||
return ctx, nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
|
45
app/app.go
45
app/app.go
@ -2,6 +2,7 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -18,6 +19,7 @@ import (
|
|||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"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/client/grpc/tmservice"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
@ -26,6 +28,7 @@ import (
|
|||||||
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
||||||
"github.com/cosmos/cosmos-sdk/simapp"
|
"github.com/cosmos/cosmos-sdk/simapp"
|
||||||
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
|
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
|
||||||
|
"github.com/cosmos/cosmos-sdk/store/streaming"
|
||||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/types/module"
|
"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/client/docs/statik"
|
||||||
|
|
||||||
"github.com/cerc-io/laconicd/app/ante"
|
"github.com/cerc-io/laconicd/app/ante"
|
||||||
|
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||||
srvflags "github.com/cerc-io/laconicd/server/flags"
|
srvflags "github.com/cerc-io/laconicd/server/flags"
|
||||||
ethermint "github.com/cerc-io/laconicd/types"
|
ethermint "github.com/cerc-io/laconicd/types"
|
||||||
"github.com/cerc-io/laconicd/x/evm"
|
"github.com/cerc-io/laconicd/x/evm"
|
||||||
@ -184,7 +188,7 @@ var (
|
|||||||
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
|
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||||
govtypes.ModuleName: {authtypes.Burner},
|
govtypes.ModuleName: {authtypes.Burner},
|
||||||
ibctransfertypes.ModuleName: {authtypes.Minter, 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.ModuleName: nil,
|
||||||
auctiontypes.AuctionBurnModuleAccountName: nil,
|
auctiontypes.AuctionBurnModuleAccountName: nil,
|
||||||
registrytypes.ModuleName: nil,
|
registrytypes.ModuleName: nil,
|
||||||
@ -199,8 +203,6 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ simapp.App = (*EthermintApp)(nil)
|
|
||||||
|
|
||||||
// var _ server.Application (*EthermintApp)(nil)
|
// var _ server.Application (*EthermintApp)(nil)
|
||||||
|
|
||||||
// EthermintApp implements an extended ABCI application. It is an application
|
// EthermintApp implements an extended ABCI application. It is an application
|
||||||
@ -256,9 +258,6 @@ type EthermintApp struct {
|
|||||||
// the module manager
|
// the module manager
|
||||||
mm *module.Manager
|
mm *module.Manager
|
||||||
|
|
||||||
// simulation manager
|
|
||||||
sm *module.SimulationManager
|
|
||||||
|
|
||||||
// the configurator
|
// the configurator
|
||||||
configurator module.Configurator
|
configurator module.Configurator
|
||||||
}
|
}
|
||||||
@ -280,6 +279,8 @@ func NewEthermintApp(
|
|||||||
cdc := encodingConfig.Amino
|
cdc := encodingConfig.Amino
|
||||||
interfaceRegistry := encodingConfig.InterfaceRegistry
|
interfaceRegistry := encodingConfig.InterfaceRegistry
|
||||||
|
|
||||||
|
eip712.SetEncodingConfig(encodingConfig)
|
||||||
|
|
||||||
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||||
bApp := baseapp.NewBaseApp(
|
bApp := baseapp.NewBaseApp(
|
||||||
appName,
|
appName,
|
||||||
@ -313,6 +314,12 @@ func NewEthermintApp(
|
|||||||
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey)
|
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey)
|
||||||
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
|
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{
|
app := &EthermintApp{
|
||||||
BaseApp: bApp,
|
BaseApp: bApp,
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
@ -658,17 +665,6 @@ func NewEthermintApp(
|
|||||||
// add test gRPC service for testing gRPC queries in isolation
|
// add test gRPC service for testing gRPC queries in isolation
|
||||||
// testdata.RegisterTestServiceServer(app.GRPCQueryRouter(), testdata.TestServiceImpl{})
|
// 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
|
// initialize stores
|
||||||
app.MountKVStores(keys)
|
app.MountKVStores(keys)
|
||||||
app.MountTransientStores(tkeys)
|
app.MountTransientStores(tkeys)
|
||||||
@ -718,6 +714,8 @@ func (app *EthermintApp) setAnteHandler(txConfig client.TxConfig, maxGasWanted u
|
|||||||
EvmKeeper: app.EvmKeeper,
|
EvmKeeper: app.EvmKeeper,
|
||||||
FeeMarketKeeper: app.FeeMarketKeeper,
|
FeeMarketKeeper: app.FeeMarketKeeper,
|
||||||
MaxTxGasWanted: maxGasWanted,
|
MaxTxGasWanted: maxGasWanted,
|
||||||
|
ExtensionOptionChecker: ethermint.HasDynamicFeeExtensionOption,
|
||||||
|
// TxFeeChecker: ante.NewDynamicFeeChecker(app.EvmKeeper),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -838,11 +836,6 @@ func (app *EthermintApp) GetSubspace(moduleName string) paramstypes.Subspace {
|
|||||||
return 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
|
// RegisterAPIRoutes registers all application module routes with the provided
|
||||||
// API server.
|
// API server.
|
||||||
func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
|
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)
|
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||||
// Register new tendermint queries routes from grpc-gateway.
|
// Register new tendermint queries routes from grpc-gateway.
|
||||||
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||||
|
// Register node gRPC service for grpc-gateway.
|
||||||
|
node.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||||
|
|
||||||
// Register grpc-gateway routes for all modules.
|
// Register grpc-gateway routes for all modules.
|
||||||
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
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
|
// RegisterSwaggerAPI registers swagger route with API Server
|
||||||
func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) {
|
func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) {
|
||||||
statikFS, err := fs.New()
|
statikFS, err := fs.New()
|
||||||
|
@ -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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
127
app/utils.go
127
app/utils.go
@ -5,27 +5,21 @@ import (
|
|||||||
"math/rand" // #nosec G702
|
"math/rand" // #nosec G702
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
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/crypto/keys/secp256k1"
|
||||||
"github.com/cosmos/cosmos-sdk/simapp"
|
"github.com/cosmos/cosmos-sdk/simapp"
|
||||||
"github.com/cosmos/cosmos-sdk/testutil/mock"
|
"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"
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
|
|
||||||
"github.com/cerc-io/laconicd/encoding"
|
"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"
|
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"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||||
@ -83,7 +77,7 @@ func SetupWithDB(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.Genesis
|
|||||||
// Initialize the chain
|
// Initialize the chain
|
||||||
app.InitChain(
|
app.InitChain(
|
||||||
abci.RequestInitChain{
|
abci.RequestInitChain{
|
||||||
ChainId: "ethermint_9000-1",
|
ChainId: "laconic_9000-1",
|
||||||
Validators: []abci.ValidatorUpdate{},
|
Validators: []abci.ValidatorUpdate{},
|
||||||
ConsensusParams: DefaultConsensusParams,
|
ConsensusParams: DefaultConsensusParams,
|
||||||
AppStateBytes: stateBytes,
|
AppStateBytes: stateBytes,
|
||||||
@ -94,96 +88,6 @@ func SetupWithDB(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.Genesis
|
|||||||
return app
|
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 := ðermint.EthAccount{
|
|
||||||
BaseAccount: bacc,
|
|
||||||
CodeHash: common.BytesToHash(emptyCodeHash).String(),
|
|
||||||
}
|
|
||||||
genesisAccs[i] = ethacc
|
|
||||||
}
|
|
||||||
|
|
||||||
return genesisAccs
|
|
||||||
}
|
|
||||||
|
|
||||||
// RandomAccounts creates random accounts with an ethsecp256k1 private key
|
|
||||||
// TODO: replace secp256k1.GenPrivKeyFromSecret() with similar function in go-ethereum
|
|
||||||
func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {
|
|
||||||
accs := make([]simtypes.Account, n)
|
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
// don't need that much entropy for simulation
|
|
||||||
privkeySeed := make([]byte, 15)
|
|
||||||
_, _ = r.Read(privkeySeed)
|
|
||||||
|
|
||||||
prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
|
|
||||||
ethPrv := ðsecp256k1.PrivKey{}
|
|
||||||
_ = ethPrv.UnmarshalAmino(prv.Bytes()) // UnmarshalAmino simply copies the bytes and assigns them to ethPrv.Key
|
|
||||||
accs[i].PrivKey = ethPrv
|
|
||||||
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
|
||||||
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
|
||||||
|
|
||||||
accs[i].ConsKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
|
|
||||||
}
|
|
||||||
|
|
||||||
return accs
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
// NewTestGenesisState generate genesis state with single validator
|
||||||
func NewTestGenesisState(codec codec.Codec) simapp.GenesisState {
|
func NewTestGenesisState(codec codec.Codec) simapp.GenesisState {
|
||||||
privVal := mock.NewPV()
|
privVal := mock.NewPV()
|
||||||
@ -207,6 +111,29 @@ func NewTestGenesisState(codec codec.Codec) simapp.GenesisState {
|
|||||||
return genesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
|
return genesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandomAccounts creates random accounts with an ethsecp256k1 private key
|
||||||
|
// TODO: replace secp256k1.GenPrivKeyFromSecret() with similar function in go-ethereum
|
||||||
|
func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {
|
||||||
|
accs := make([]simtypes.Account, n)
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
// don't need that much entropy for simulation
|
||||||
|
privkeySeed := make([]byte, 15)
|
||||||
|
_, _ = r.Read(privkeySeed)
|
||||||
|
|
||||||
|
prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
|
||||||
|
ethPrv := ðsecp256k1.PrivKey{}
|
||||||
|
_ = ethPrv.UnmarshalAmino(prv.Bytes()) // UnmarshalAmino simply copies the bytes and assigns them to ethPrv.Key
|
||||||
|
accs[i].PrivKey = ethPrv
|
||||||
|
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
||||||
|
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
||||||
|
|
||||||
|
accs[i].ConsKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return accs
|
||||||
|
}
|
||||||
|
|
||||||
func genesisStateWithValSet(codec codec.Codec, genesisState simapp.GenesisState,
|
func genesisStateWithValSet(codec codec.Codec, genesisState simapp.GenesisState,
|
||||||
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount,
|
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount,
|
||||||
balances ...banktypes.Balance,
|
balances ...banktypes.Balance,
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
version: v1
|
version: v1
|
||||||
directories:
|
directories:
|
||||||
- proto
|
- proto
|
||||||
- third_party/proto
|
|
||||||
|
@ -13,57 +13,6 @@
|
|||||||
"Params": "EvmParams"
|
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
4
client/docs/statik/statik.go
vendored
4
client/docs/statik/statik.go
vendored
File diff suppressed because one or more lines are too long
272
client/docs/swagger-ui/swagger.yaml
vendored
272
client/docs/swagger-ui/swagger.yaml
vendored
@ -154,10 +154,13 @@ paths:
|
|||||||
Example 4: Pack and unpack a message in Go
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
|
<<<<<<< HEAD
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := ptypes.MarshalAny(foo)
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
foo := &pb.Foo{}
|
||||||
if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
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
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
required: false
|
||||||
type: string
|
type: string
|
||||||
format: uint64
|
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:
|
tags:
|
||||||
- Query
|
- Query
|
||||||
/ethermint/evm/v1/eth_call:
|
/ethermint/evm/v1/eth_call:
|
||||||
@ -1524,10 +1561,13 @@ paths:
|
|||||||
Example 4: Pack and unpack a message in Go
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
required: false
|
||||||
type: string
|
type: string
|
||||||
format: uint64
|
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:
|
tags:
|
||||||
- Query
|
- Query
|
||||||
/ethermint/evm/v1/params:
|
/ethermint/evm/v1/params:
|
||||||
@ -1713,11 +1765,24 @@ paths:
|
|||||||
title: >-
|
title: >-
|
||||||
Eip-4345 (bomb delay) switch block (nil = no fork, 0 =
|
Eip-4345 (bomb delay) switch block (nil = no fork, 0 =
|
||||||
already activated)
|
already activated)
|
||||||
|
<<<<<<< HEAD
|
||||||
merge_fork_block:
|
merge_fork_block:
|
||||||
type: string
|
type: string
|
||||||
title: >-
|
title: >-
|
||||||
EIP-3675 (TheMerge) switch block (nil = no fork, 0 =
|
EIP-3675 (TheMerge) switch block (nil = no fork, 0 =
|
||||||
already in merge proceedings)
|
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: >-
|
description: >-
|
||||||
ChainConfig defines the Ethereum ChainConfig parameters
|
ChainConfig defines the Ethereum ChainConfig parameters
|
||||||
using *sdk.Int values
|
using *sdk.Int values
|
||||||
@ -1727,7 +1792,11 @@ paths:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: >-
|
description: >-
|
||||||
Allow unprotected transactions defines if replay-protected
|
Allow unprotected transactions defines if replay-protected
|
||||||
|
<<<<<<< HEAD
|
||||||
(i.e non EIP155
|
(i.e non EIP155
|
||||||
|
=======
|
||||||
|
(i.e non EIP155
|
||||||
|
>>>>>>> v0.20.0
|
||||||
|
|
||||||
signed) transactions can be executed on the state machine.
|
signed) transactions can be executed on the state machine.
|
||||||
title: Params defines the EVM module parameters
|
title: Params defines the EVM module parameters
|
||||||
@ -1861,10 +1930,13 @@ paths:
|
|||||||
Example 4: Pack and unpack a message in Go
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
<<<<<<< HEAD
|
||||||
- name: trace_config.overrides.merge_fork_block
|
- name: trace_config.overrides.merge_fork_block
|
||||||
description: >-
|
description: >-
|
||||||
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
|
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
|
||||||
merge proceedings).
|
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
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
@ -2498,6 +2588,11 @@ paths:
|
|||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
- name: trace_config.tracer_json_config
|
||||||
|
description: tracer config.
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
- name: block_number
|
- name: block_number
|
||||||
description: block number.
|
description: block number.
|
||||||
in: query
|
in: query
|
||||||
@ -2515,6 +2610,18 @@ paths:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
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:
|
tags:
|
||||||
- Query
|
- Query
|
||||||
/ethermint/evm/v1/trace_tx:
|
/ethermint/evm/v1/trace_tx:
|
||||||
@ -2659,10 +2766,13 @@ paths:
|
|||||||
Example 4: Pack and unpack a message in Go
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
type: string
|
||||||
format: byte
|
format: byte
|
||||||
- name: msg.size
|
- name: msg.size
|
||||||
description: encoded storage size of the transaction.
|
description: 'DEPRECATED: encoded storage size of the transaction.'
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: number
|
type: number
|
||||||
@ -2927,10 +3037,22 @@ paths:
|
|||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
<<<<<<< HEAD
|
||||||
- name: trace_config.overrides.merge_fork_block
|
- name: trace_config.overrides.merge_fork_block
|
||||||
description: >-
|
description: >-
|
||||||
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
|
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
|
||||||
merge proceedings).
|
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
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
@ -2944,6 +3066,11 @@ paths:
|
|||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
- name: trace_config.tracer_json_config
|
||||||
|
description: tracer config.
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
- name: block_number
|
- name: block_number
|
||||||
description: block number of requested transaction.
|
description: block number of requested transaction.
|
||||||
in: query
|
in: query
|
||||||
@ -2961,6 +3088,18 @@ paths:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
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:
|
tags:
|
||||||
- Query
|
- Query
|
||||||
/ethermint/evm/v1/validator_account/{cons_address}:
|
/ethermint/evm/v1/validator_account/{cons_address}:
|
||||||
@ -3120,10 +3259,13 @@ paths:
|
|||||||
Example 4: Pack and unpack a message in Go
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
type: string
|
||||||
tags:
|
tags:
|
||||||
- Query
|
- Query
|
||||||
|
<<<<<<< HEAD
|
||||||
/cosmos/auth/v1beta1/accounts:
|
/cosmos/auth/v1beta1/accounts:
|
||||||
get:
|
get:
|
||||||
summary: Accounts returns all the existing accounts
|
summary: Accounts returns all the existing accounts
|
||||||
@ -14052,6 +14195,8 @@ paths:
|
|||||||
type: boolean
|
type: boolean
|
||||||
tags:
|
tags:
|
||||||
- Query
|
- Query
|
||||||
|
=======
|
||||||
|
>>>>>>> v0.20.0
|
||||||
definitions:
|
definitions:
|
||||||
ethermint.evm.v1.ChainConfig:
|
ethermint.evm.v1.ChainConfig:
|
||||||
type: object
|
type: object
|
||||||
@ -14111,11 +14256,22 @@ definitions:
|
|||||||
title: >-
|
title: >-
|
||||||
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
|
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
|
||||||
activated)
|
activated)
|
||||||
|
<<<<<<< HEAD
|
||||||
merge_fork_block:
|
merge_fork_block:
|
||||||
type: string
|
type: string
|
||||||
title: >-
|
title: >-
|
||||||
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in merge
|
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in merge
|
||||||
proceedings)
|
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: >-
|
description: >-
|
||||||
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
|
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
|
||||||
values
|
values
|
||||||
@ -14287,10 +14443,13 @@ definitions:
|
|||||||
Example 4: Pack and unpack a message in Go
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
foo := &pb.Foo{}
|
||||||
if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
if err := any.UnmarshalTo(foo); err != nil {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14344,7 +14503,7 @@ definitions:
|
|||||||
size:
|
size:
|
||||||
type: number
|
type: number
|
||||||
format: double
|
format: double
|
||||||
title: encoded storage size of the transaction
|
title: 'DEPRECATED: encoded storage size of the transaction'
|
||||||
hash:
|
hash:
|
||||||
type: string
|
type: string
|
||||||
title: transaction hash in hex format
|
title: transaction hash in hex format
|
||||||
@ -14515,11 +14674,22 @@ definitions:
|
|||||||
title: >-
|
title: >-
|
||||||
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
|
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
|
||||||
activated)
|
activated)
|
||||||
|
<<<<<<< HEAD
|
||||||
merge_fork_block:
|
merge_fork_block:
|
||||||
type: string
|
type: string
|
||||||
title: >-
|
title: >-
|
||||||
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
|
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
|
||||||
merge proceedings)
|
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: >-
|
description: >-
|
||||||
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
|
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
|
||||||
values
|
values
|
||||||
@ -14529,7 +14699,11 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: >-
|
description: >-
|
||||||
Allow unprotected transactions defines if replay-protected (i.e non
|
Allow unprotected transactions defines if replay-protected (i.e non
|
||||||
|
<<<<<<< HEAD
|
||||||
EIP155
|
EIP155
|
||||||
|
=======
|
||||||
|
EIP155
|
||||||
|
>>>>>>> v0.20.0
|
||||||
|
|
||||||
signed) transactions can be executed on the state machine.
|
signed) transactions can be executed on the state machine.
|
||||||
title: Params defines the EVM module parameters
|
title: Params defines the EVM module parameters
|
||||||
@ -14684,11 +14858,22 @@ definitions:
|
|||||||
title: >-
|
title: >-
|
||||||
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
|
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
|
||||||
activated)
|
activated)
|
||||||
|
<<<<<<< HEAD
|
||||||
merge_fork_block:
|
merge_fork_block:
|
||||||
type: string
|
type: string
|
||||||
title: >-
|
title: >-
|
||||||
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already
|
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already
|
||||||
in merge proceedings)
|
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: >-
|
description: >-
|
||||||
ChainConfig defines the Ethereum ChainConfig parameters using
|
ChainConfig defines the Ethereum ChainConfig parameters using
|
||||||
*sdk.Int values
|
*sdk.Int values
|
||||||
@ -14698,7 +14883,11 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: >-
|
description: >-
|
||||||
Allow unprotected transactions defines if replay-protected (i.e
|
Allow unprotected transactions defines if replay-protected (i.e
|
||||||
|
<<<<<<< HEAD
|
||||||
non EIP155
|
non EIP155
|
||||||
|
=======
|
||||||
|
non EIP155
|
||||||
|
>>>>>>> v0.20.0
|
||||||
|
|
||||||
signed) transactions can be executed on the state machine.
|
signed) transactions can be executed on the state machine.
|
||||||
title: Params defines the EVM module parameters
|
title: Params defines the EVM module parameters
|
||||||
@ -14839,11 +15028,22 @@ definitions:
|
|||||||
title: >-
|
title: >-
|
||||||
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
|
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
|
||||||
activated)
|
activated)
|
||||||
|
<<<<<<< HEAD
|
||||||
merge_fork_block:
|
merge_fork_block:
|
||||||
type: string
|
type: string
|
||||||
title: >-
|
title: >-
|
||||||
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
|
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
|
||||||
merge proceedings)
|
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: >-
|
description: >-
|
||||||
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
|
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
|
||||||
values
|
values
|
||||||
@ -14855,6 +15055,9 @@ definitions:
|
|||||||
enable_return_data:
|
enable_return_data:
|
||||||
type: boolean
|
type: boolean
|
||||||
title: enable return data capture
|
title: enable return data capture
|
||||||
|
tracer_json_config:
|
||||||
|
type: string
|
||||||
|
title: tracer config
|
||||||
description: TraceConfig holds extra parameters to trace functions.
|
description: TraceConfig holds extra parameters to trace functions.
|
||||||
google.protobuf.Any:
|
google.protobuf.Any:
|
||||||
type: object
|
type: object
|
||||||
@ -14958,10 +15161,13 @@ definitions:
|
|||||||
Example 4: Pack and unpack a message in Go
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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
|
Example 4: Pack and unpack a message in Go
|
||||||
|
|
||||||
foo := &pb.Foo{...}
|
foo := &pb.Foo{...}
|
||||||
any, err := ptypes.MarshalAny(foo)
|
any, err := anypb.New(foo)
|
||||||
|
if err != nil {
|
||||||
|
...
|
||||||
|
}
|
||||||
...
|
...
|
||||||
foo := &pb.Foo{}
|
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",
|
"@type": "type.googleapis.com/google.protobuf.Duration",
|
||||||
"value": "1.212s"
|
"value": "1.212s"
|
||||||
}
|
}
|
||||||
|
<<<<<<< HEAD
|
||||||
cosmos.auth.v1beta1.Params:
|
cosmos.auth.v1beta1.Params:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -21145,3 +21355,5 @@ definitions:
|
|||||||
application's
|
application's
|
||||||
|
|
||||||
state transition machine.
|
state transition machine.
|
||||||
|
=======
|
||||||
|
>>>>>>> v0.20.0
|
||||||
|
@ -50,18 +50,32 @@ output
|
|||||||
- armor encrypted private key (saved to file)
|
- armor encrypted private key (saved to file)
|
||||||
*/
|
*/
|
||||||
func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error {
|
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]
|
name := args[0]
|
||||||
|
|
||||||
interactive, _ := cmd.Flags().GetBool(flagInteractive)
|
interactive, _ := cmd.Flags().GetBool(flagInteractive)
|
||||||
noBackup, _ := cmd.Flags().GetBool(flagNoBackup)
|
noBackup, _ := cmd.Flags().GetBool(flagNoBackup)
|
||||||
|
useLedger, _ := cmd.Flags().GetBool(flags.FlagUseLedger)
|
||||||
|
algoStr, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
|
||||||
|
|
||||||
showMnemonic := !noBackup
|
showMnemonic := !noBackup
|
||||||
kb := ctx.Keyring
|
kb := ctx.Keyring
|
||||||
outputFormat := ctx.OutputFormat
|
outputFormat := ctx.OutputFormat
|
||||||
|
|
||||||
keyringAlgos, _ := kb.SupportedAlgorithms()
|
keyringAlgos, ledgerAlgos := kb.SupportedAlgorithms()
|
||||||
algoStr, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
|
|
||||||
algo, err := keyring.NewSigningAlgoFromString(algoStr, keyringAlgos)
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -144,7 +158,6 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
|||||||
account, _ := cmd.Flags().GetUint32(flagAccount)
|
account, _ := cmd.Flags().GetUint32(flagAccount)
|
||||||
index, _ := cmd.Flags().GetUint32(flagIndex)
|
index, _ := cmd.Flags().GetUint32(flagIndex)
|
||||||
hdPath, _ := cmd.Flags().GetString(flagHDPath)
|
hdPath, _ := cmd.Flags().GetString(flagHDPath)
|
||||||
useLedger, _ := cmd.Flags().GetBool(flags.FlagUseLedger)
|
|
||||||
|
|
||||||
if len(hdPath) == 0 {
|
if len(hdPath) == 0 {
|
||||||
hdPath = hd.CreateHDPath(coinType, account, index).String()
|
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 we're using ledger, only thing we need is the path and the bech32 prefix.
|
||||||
if useLedger {
|
if useLedger {
|
||||||
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,7 @@ import (
|
|||||||
"github.com/cerc-io/laconicd/version"
|
"github.com/cerc-io/laconicd/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const flagLong = "long"
|
||||||
flagLong = "long"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
infoCmd.Flags().Bool(flagLong, false, "Print full information")
|
infoCmd.Flags().Bool(flagLong, false, "Print full information")
|
||||||
|
@ -32,7 +32,7 @@ const (
|
|||||||
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
|
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
|
||||||
func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command {
|
func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command {
|
||||||
cmd := &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",
|
Short: "Add a genesis account to genesis.json",
|
||||||
Long: `Add a genesis account to genesis.json. The provided account must specify
|
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,
|
the account address or key name and a list of initial coins. If a key name is given,
|
||||||
|
@ -37,13 +37,14 @@ import (
|
|||||||
"github.com/cerc-io/laconicd/client/debug"
|
"github.com/cerc-io/laconicd/client/debug"
|
||||||
"github.com/cerc-io/laconicd/crypto/hd"
|
"github.com/cerc-io/laconicd/crypto/hd"
|
||||||
"github.com/cerc-io/laconicd/encoding"
|
"github.com/cerc-io/laconicd/encoding"
|
||||||
|
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||||
"github.com/cerc-io/laconicd/server"
|
"github.com/cerc-io/laconicd/server"
|
||||||
servercfg "github.com/cerc-io/laconicd/server/config"
|
servercfg "github.com/cerc-io/laconicd/server/config"
|
||||||
srvflags "github.com/cerc-io/laconicd/server/flags"
|
srvflags "github.com/cerc-io/laconicd/server/flags"
|
||||||
ethermint "github.com/cerc-io/laconicd/types"
|
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
|
// NewRootCmd creates a new root command for simd. It is called once in the
|
||||||
// main function.
|
// main function.
|
||||||
@ -61,9 +62,11 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
|
|||||||
WithKeyringOptions(hd.EthSecp256k1Option()).
|
WithKeyringOptions(hd.EthSecp256k1Option()).
|
||||||
WithViper(EnvPrefix)
|
WithViper(EnvPrefix)
|
||||||
|
|
||||||
|
eip712.SetEncodingConfig(encodingConfig)
|
||||||
|
|
||||||
rootCmd := &cobra.Command{
|
rootCmd := &cobra.Command{
|
||||||
Use: "laconicd",
|
Use: "laconicd",
|
||||||
Short: "Ethermint Daemon",
|
Short: "Laconic Daemon",
|
||||||
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
|
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
|
||||||
// set the default command outputs
|
// set the default command outputs
|
||||||
cmd.SetOut(cmd.OutOrStdout())
|
cmd.SetOut(cmd.OutOrStdout())
|
||||||
@ -182,6 +185,7 @@ func txCommand() *cobra.Command {
|
|||||||
authcmd.GetBroadcastCommand(),
|
authcmd.GetBroadcastCommand(),
|
||||||
authcmd.GetEncodeCommand(),
|
authcmd.GetEncodeCommand(),
|
||||||
authcmd.GetDecodeCommand(),
|
authcmd.GetDecodeCommand(),
|
||||||
|
authcmd.GetAuxToFeeCommand(),
|
||||||
)
|
)
|
||||||
|
|
||||||
app.ModuleBasics.AddTxCommands(cmd)
|
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.SetTrace(cast.ToBool(appOpts.Get(sdkserver.FlagTrace))),
|
||||||
baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(sdkserver.FlagIndexEvents))),
|
baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(sdkserver.FlagIndexEvents))),
|
||||||
baseapp.SetSnapshot(snapshotStore, snapshotOptions),
|
baseapp.SetSnapshot(snapshotStore, snapshotOptions),
|
||||||
|
baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(sdkserver.FlagIAVLCacheSize))),
|
||||||
|
baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(sdkserver.FlagDisableIAVLFastNode))),
|
||||||
)
|
)
|
||||||
|
|
||||||
return ethermintApp
|
return ethermintApp
|
||||||
|
@ -6,11 +6,12 @@ import (
|
|||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
|
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
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"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
||||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -182,7 +183,7 @@ func (pubKey PubKey) MarshalAmino() ([]byte, error) {
|
|||||||
// UnmarshalAmino overrides Amino binary marshaling.
|
// UnmarshalAmino overrides Amino binary marshaling.
|
||||||
func (pubKey *PubKey) UnmarshalAmino(bz []byte) error {
|
func (pubKey *PubKey) UnmarshalAmino(bz []byte) error {
|
||||||
if len(bz) != PubKeySize {
|
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
|
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
|
// VerifySignature verifies that the ECDSA public key created a given signature over
|
||||||
// the provided message. It will calculate the Keccak256 hash of the message
|
// 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.
|
// CONTRACT: The signature should be in [R || S] format.
|
||||||
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
|
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 {
|
if len(sig) == crypto.SignatureLength {
|
||||||
// remove recovery ID (V) if contained in the signature
|
// remove recovery ID (V) if contained in the signature
|
||||||
sig = sig[:len(sig)-1]
|
sig = sig[:len(sig)-1]
|
||||||
|
4
crypto/ethsecp256k1/keys.pb.go
generated
4
crypto/ethsecp256k1/keys.pb.go
generated
@ -5,7 +5,7 @@ package ethsecp256k1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
fmt "fmt"
|
fmt "fmt"
|
||||||
_ "github.com/gogo/protobuf/gogoproto"
|
_ "github.com/cosmos/gogoproto/gogoproto"
|
||||||
proto "github.com/gogo/protobuf/proto"
|
proto "github.com/gogo/protobuf/proto"
|
||||||
io "io"
|
io "io"
|
||||||
math "math"
|
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
|
// Tendermint's PubKey interface. It represents the 33-byte compressed public
|
||||||
// key format.
|
// key format.
|
||||||
type PubKey struct {
|
type PubKey struct {
|
||||||
|
// key is the public key in byte form
|
||||||
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
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
|
// PrivKey defines a type alias for an ecdsa.PrivateKey that implements
|
||||||
// Tendermint's PrivateKey interface.
|
// Tendermint's PrivateKey interface.
|
||||||
type PrivKey struct {
|
type PrivKey struct {
|
||||||
|
// key is the private key in byte form
|
||||||
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package hd
|
package hd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -10,7 +11,6 @@ import (
|
|||||||
|
|
||||||
hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
|
hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
amino "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/codec/types"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||||
@ -20,10 +20,10 @@ import (
|
|||||||
ethermint "github.com/cerc-io/laconicd/types"
|
ethermint "github.com/cerc-io/laconicd/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var TestCodec codec.Codec
|
var TestCodec amino.Codec
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cdc := codec.NewLegacyAmino()
|
cdc := amino.NewLegacyAmino()
|
||||||
cryptocodec.RegisterCrypto(cdc)
|
cryptocodec.RegisterCrypto(cdc)
|
||||||
|
|
||||||
interfaceRegistry := types.NewInterfaceRegistry()
|
interfaceRegistry := types.NewInterfaceRegistry()
|
||||||
@ -31,12 +31,18 @@ func init() {
|
|||||||
enccodec.RegisterInterfaces(interfaceRegistry)
|
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) {
|
func TestKeyring(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
mockIn := strings.NewReader("")
|
mockIn := strings.NewReader("")
|
||||||
|
|
||||||
kr, err := keyring.New("ethermint", keyring.BackendTest, dir, mockIn, TestCodec, EthSecp256k1Option())
|
kr, err := keyring.New("ethermint", keyring.BackendTest, dir, mockIn, TestCodec, EthSecp256k1Option())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -68,7 +74,9 @@ func TestKeyring(t *testing.T) {
|
|||||||
privkey := EthSecp256k1.Generate()(bz)
|
privkey := EthSecp256k1.Generate()(bz)
|
||||||
addr := common.BytesToAddress(privkey.PubKey().Address().Bytes())
|
addr := common.BytesToAddress(privkey.PubKey().Address().Bytes())
|
||||||
|
|
||||||
|
os.Setenv(hdWalletFixEnv, "true")
|
||||||
wallet, err := hdwallet.NewFromMnemonic(mnemonic)
|
wallet, err := hdwallet.NewFromMnemonic(mnemonic)
|
||||||
|
os.Setenv(hdWalletFixEnv, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
path := hdwallet.MustParseDerivationPath(hdPath)
|
path := hdwallet.MustParseDerivationPath(hdPath)
|
||||||
|
@ -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 |
|
| `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_memory` | [bool](#bool) | | enable memory capture |
|
||||||
| `enable_return_data` | [bool](#bool) | | enable return data 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. |
|
| `args` | [bytes](#bytes) | | same json format as the json rpc api. |
|
||||||
| `gas_cap` | [uint64](#uint64) | | the default gas cap to be used |
|
| `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_number` | [int64](#int64) | | block number |
|
||||||
| `block_hash` | [string](#string) | | block hex hash |
|
| `block_hash` | [string](#string) | | block hex hash |
|
||||||
| `block_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | block time |
|
| `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_number` | [int64](#int64) | | block number of requested transaction |
|
||||||
| `block_hash` | [string](#string) | | block hex hash 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 |
|
| `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 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1914,9 +1921,9 @@ Tx defines the gRPC tx interface
|
|||||||
|
|
||||||
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
|
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
|
||||||
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
|
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
|
||||||
| `CreateAuction` | [MsgCreateAuction](#vulcanize.auction.v1beta1.MsgCreateAuction) | [MsgCreateAuctionResponse](#vulcanize.auction.v1beta1.MsgCreateAuctionResponse) | CreateAuction is the command for creating an auction | |
|
| `CreateAuction` | [MsgCreateAuction](#vulcanize.auction.v1beta1.MsgCreateAuction) | [MsgCreateAuctionResponse](#vulcanize.auction.v1beta1.MsgCreateAuctionResponse) | CreateAuction is the command for creating an auction | POST|/vulcanize/auction/v1beta1/create_auction|
|
||||||
| `CommitBid` | [MsgCommitBid](#vulcanize.auction.v1beta1.MsgCommitBid) | [MsgCommitBidResponse](#vulcanize.auction.v1beta1.MsgCommitBidResponse) | CommitBid is the command for committing a bid | |
|
| `CommitBid` | [MsgCommitBid](#vulcanize.auction.v1beta1.MsgCommitBid) | [MsgCommitBidResponse](#vulcanize.auction.v1beta1.MsgCommitBidResponse) | CommitBid is the command for committing a bid | POST|/vulcanize/auction/v1beta1/commit_bid|
|
||||||
| `RevealBid` | [MsgRevealBid](#vulcanize.auction.v1beta1.MsgRevealBid) | [MsgRevealBidResponse](#vulcanize.auction.v1beta1.MsgRevealBidResponse) | RevealBid is the command for revealing a bid | |
|
| `RevealBid` | [MsgRevealBid](#vulcanize.auction.v1beta1.MsgRevealBid) | [MsgRevealBidResponse](#vulcanize.auction.v1beta1.MsgRevealBidResponse) | RevealBid is the command for revealing a bid | POST|/vulcanize/auction/v1beta1/reveal_bid|
|
||||||
|
|
||||||
<!-- end services -->
|
<!-- end services -->
|
||||||
|
|
||||||
@ -2306,10 +2313,10 @@ Msg defines the bond Msg service.
|
|||||||
|
|
||||||
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
|
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
|
||||||
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
|
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
|
||||||
| `CreateBond` | [MsgCreateBond](#vulcanize.bond.v1beta1.MsgCreateBond) | [MsgCreateBondResponse](#vulcanize.bond.v1beta1.MsgCreateBondResponse) | CreateBond defines a method for creating a new bond. | |
|
| `CreateBond` | [MsgCreateBond](#vulcanize.bond.v1beta1.MsgCreateBond) | [MsgCreateBondResponse](#vulcanize.bond.v1beta1.MsgCreateBondResponse) | CreateBond defines a method for creating a new bond. | POST|/vulcanize/bond/v1beta1/create_bond|
|
||||||
| `RefillBond` | [MsgRefillBond](#vulcanize.bond.v1beta1.MsgRefillBond) | [MsgRefillBondResponse](#vulcanize.bond.v1beta1.MsgRefillBondResponse) | RefillBond defines a method for refilling amount for bond. | |
|
| `RefillBond` | [MsgRefillBond](#vulcanize.bond.v1beta1.MsgRefillBond) | [MsgRefillBondResponse](#vulcanize.bond.v1beta1.MsgRefillBondResponse) | RefillBond defines a method for refilling amount for bond. | POST|/vulcanize/bond/v1beta1/refill_bond|
|
||||||
| `WithdrawBond` | [MsgWithdrawBond](#vulcanize.bond.v1beta1.MsgWithdrawBond) | [MsgWithdrawBondResponse](#vulcanize.bond.v1beta1.MsgWithdrawBondResponse) | WithdrawBond defines a method for withdrawing amount from bond. | |
|
| `WithdrawBond` | [MsgWithdrawBond](#vulcanize.bond.v1beta1.MsgWithdrawBond) | [MsgWithdrawBondResponse](#vulcanize.bond.v1beta1.MsgWithdrawBondResponse) | WithdrawBond defines a method for withdrawing amount from bond. | POST|/vulcanize/bond/v1beta1/withdraw_bond|
|
||||||
| `CancelBond` | [MsgCancelBond](#vulcanize.bond.v1beta1.MsgCancelBond) | [MsgCancelBondResponse](#vulcanize.bond.v1beta1.MsgCancelBondResponse) | CancelBond defines a method for cancelling a bond. | |
|
| `CancelBond` | [MsgCancelBond](#vulcanize.bond.v1beta1.MsgCancelBond) | [MsgCancelBondResponse](#vulcanize.bond.v1beta1.MsgCancelBondResponse) | CancelBond defines a method for cancelling a bond. | POST|/vulcanize/bond/v1beta1/cancel_bond|
|
||||||
|
|
||||||
<!-- end services -->
|
<!-- end services -->
|
||||||
|
|
||||||
@ -2334,6 +2341,7 @@ Msg defines the bond Msg service.
|
|||||||
| `laconic_id` | [string](#string) | | |
|
| `laconic_id` | [string](#string) | | |
|
||||||
| `x500` | [X500](#vulcanize.registry.v1beta1.X500) | | |
|
| `x500` | [X500](#vulcanize.registry.v1beta1.X500) | | |
|
||||||
| `type` | [string](#string) | | |
|
| `type` | [string](#string) | | |
|
||||||
|
| `version` | [string](#string) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2353,6 +2361,7 @@ Msg defines the bond Msg service.
|
|||||||
| `build_artifact_cid` | [string](#string) | | |
|
| `build_artifact_cid` | [string](#string) | | |
|
||||||
| `tls_cert_cid` | [string](#string) | | |
|
| `tls_cert_cid` | [string](#string) | | |
|
||||||
| `type` | [string](#string) | | |
|
| `type` | [string](#string) | | |
|
||||||
|
| `version` | [string](#string) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -3378,16 +3387,16 @@ Msg
|
|||||||
|
|
||||||
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
|
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
|
||||||
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
|
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
|
||||||
| `SetRecord` | [MsgSetRecord](#vulcanize.registry.v1beta1.MsgSetRecord) | [MsgSetRecordResponse](#vulcanize.registry.v1beta1.MsgSetRecordResponse) | SetRecord will records a new record with given payload and bond id | |
|
| `SetRecord` | [MsgSetRecord](#vulcanize.registry.v1beta1.MsgSetRecord) | [MsgSetRecordResponse](#vulcanize.registry.v1beta1.MsgSetRecordResponse) | SetRecord will records a new record with given payload and bond id | POST|/vulcanize/registry/v1beta1/set_record|
|
||||||
| `RenewRecord` | [MsgRenewRecord](#vulcanize.registry.v1beta1.MsgRenewRecord) | [MsgRenewRecordResponse](#vulcanize.registry.v1beta1.MsgRenewRecordResponse) | Renew Record will renew the expire record | |
|
| `RenewRecord` | [MsgRenewRecord](#vulcanize.registry.v1beta1.MsgRenewRecord) | [MsgRenewRecordResponse](#vulcanize.registry.v1beta1.MsgRenewRecordResponse) | Renew Record will renew the expire record | POST|/vulcanize/registry/v1beta1/renew_record|
|
||||||
| `AssociateBond` | [MsgAssociateBond](#vulcanize.registry.v1beta1.MsgAssociateBond) | [MsgAssociateBondResponse](#vulcanize.registry.v1beta1.MsgAssociateBondResponse) | AssociateBond | |
|
| `AssociateBond` | [MsgAssociateBond](#vulcanize.registry.v1beta1.MsgAssociateBond) | [MsgAssociateBondResponse](#vulcanize.registry.v1beta1.MsgAssociateBondResponse) | AssociateBond | POST|/vulcanize/registry/v1beta1/associate_bond|
|
||||||
| `DissociateBond` | [MsgDissociateBond](#vulcanize.registry.v1beta1.MsgDissociateBond) | [MsgDissociateBondResponse](#vulcanize.registry.v1beta1.MsgDissociateBondResponse) | DissociateBond | |
|
| `DissociateBond` | [MsgDissociateBond](#vulcanize.registry.v1beta1.MsgDissociateBond) | [MsgDissociateBondResponse](#vulcanize.registry.v1beta1.MsgDissociateBondResponse) | DissociateBond | POST|/vulcanize/registry/v1beta1/dissociate_bond|
|
||||||
| `DissociateRecords` | [MsgDissociateRecords](#vulcanize.registry.v1beta1.MsgDissociateRecords) | [MsgDissociateRecordsResponse](#vulcanize.registry.v1beta1.MsgDissociateRecordsResponse) | DissociateRecords | |
|
| `DissociateRecords` | [MsgDissociateRecords](#vulcanize.registry.v1beta1.MsgDissociateRecords) | [MsgDissociateRecordsResponse](#vulcanize.registry.v1beta1.MsgDissociateRecordsResponse) | DissociateRecords | POST|/vulcanize/registry/v1beta1/dissociate_records|
|
||||||
| `ReAssociateRecords` | [MsgReAssociateRecords](#vulcanize.registry.v1beta1.MsgReAssociateRecords) | [MsgReAssociateRecordsResponse](#vulcanize.registry.v1beta1.MsgReAssociateRecordsResponse) | ReAssociateRecords | |
|
| `ReAssociateRecords` | [MsgReAssociateRecords](#vulcanize.registry.v1beta1.MsgReAssociateRecords) | [MsgReAssociateRecordsResponse](#vulcanize.registry.v1beta1.MsgReAssociateRecordsResponse) | ReAssociateRecords | POST|/vulcanize/registry/v1beta1/reassociate_records|
|
||||||
| `SetName` | [MsgSetName](#vulcanize.registry.v1beta1.MsgSetName) | [MsgSetNameResponse](#vulcanize.registry.v1beta1.MsgSetNameResponse) | SetName will store the name with given crn and name | |
|
| `SetName` | [MsgSetName](#vulcanize.registry.v1beta1.MsgSetName) | [MsgSetNameResponse](#vulcanize.registry.v1beta1.MsgSetNameResponse) | SetName will store the name with given crn and name | POST|/vulcanize/registry/v1beta1/set_name|
|
||||||
| `ReserveName` | [MsgReserveAuthority](#vulcanize.registry.v1beta1.MsgReserveAuthority) | [MsgReserveAuthorityResponse](#vulcanize.registry.v1beta1.MsgReserveAuthorityResponse) | Reserve name | |
|
| `ReserveName` | [MsgReserveAuthority](#vulcanize.registry.v1beta1.MsgReserveAuthority) | [MsgReserveAuthorityResponse](#vulcanize.registry.v1beta1.MsgReserveAuthorityResponse) | Reserve name | POST|/vulcanize/registry/v1beta1/reserve_name|
|
||||||
| `DeleteName` | [MsgDeleteNameAuthority](#vulcanize.registry.v1beta1.MsgDeleteNameAuthority) | [MsgDeleteNameAuthorityResponse](#vulcanize.registry.v1beta1.MsgDeleteNameAuthorityResponse) | Delete Name method will remove authority name | |
|
| `DeleteName` | [MsgDeleteNameAuthority](#vulcanize.registry.v1beta1.MsgDeleteNameAuthority) | [MsgDeleteNameAuthorityResponse](#vulcanize.registry.v1beta1.MsgDeleteNameAuthorityResponse) | Delete Name method will remove authority name | POST|/vulcanize/registry/v1beta1/delete_name|
|
||||||
| `SetAuthorityBond` | [MsgSetAuthorityBond](#vulcanize.registry.v1beta1.MsgSetAuthorityBond) | [MsgSetAuthorityBondResponse](#vulcanize.registry.v1beta1.MsgSetAuthorityBondResponse) | SetAuthorityBond | |
|
| `SetAuthorityBond` | [MsgSetAuthorityBond](#vulcanize.registry.v1beta1.MsgSetAuthorityBond) | [MsgSetAuthorityBondResponse](#vulcanize.registry.v1beta1.MsgSetAuthorityBondResponse) | SetAuthorityBond | POST|/vulcanize/registry/v1beta1/set_authority_bond|
|
||||||
|
|
||||||
<!-- end services -->
|
<!-- end services -->
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package eip712
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -9,38 +10,21 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
sdkmath "cosmossdk.io/math"
|
sdkmath "cosmossdk.io/math"
|
||||||
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
"golang.org/x/text/cases"
|
"golang.org/x/text/cases"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ComputeTypedDataHash computes keccak hash of typed data for signing.
|
const bytesStr = "bytes"
|
||||||
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
|
// WrapTxToTypedData is an ultimate method that wraps Amino-encoded Cosmos Tx JSON data
|
||||||
// into an EIP712-compatible TypedData request.
|
// into an EIP712-compatible TypedData request.
|
||||||
@ -51,12 +35,6 @@ func WrapTxToTypedData(
|
|||||||
data []byte,
|
data []byte,
|
||||||
feeDelegation *FeeDelegationOptions,
|
feeDelegation *FeeDelegationOptions,
|
||||||
) (apitypes.TypedData, error) {
|
) (apitypes.TypedData, error) {
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
domain := apitypes.TypedDataDomain{
|
domain := apitypes.TypedDataDomain{
|
||||||
Name: "Cosmos Web3",
|
Name: "Cosmos Web3",
|
||||||
Version: "1.0.0",
|
Version: "1.0.0",
|
||||||
@ -70,10 +48,19 @@ func WrapTxToTypedData(
|
|||||||
return apitypes.TypedData{}, err
|
return apitypes.TypedData{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txData := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal(data, &txData); err != nil {
|
||||||
|
return apitypes.TypedData{}, errorsmod.Wrap(errortypes.ErrJSONUnmarshal, "failed to JSON unmarshal data")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := patchTxData(txData, msgTypes, "Tx"); err != nil {
|
||||||
|
return apitypes.TypedData{}, errorsmod.Wrap(errortypes.ErrJSONUnmarshal, "failed to patch JSON data")
|
||||||
|
}
|
||||||
|
|
||||||
if feeDelegation != nil {
|
if feeDelegation != nil {
|
||||||
feeInfo, ok := txData["fee"].(map[string]interface{})
|
feeInfo, ok := txData["fee"].(map[string]interface{})
|
||||||
if !ok {
|
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()
|
feeInfo["feePayer"] = feeDelegation.FeePayer.String()
|
||||||
@ -206,7 +193,11 @@ func traverseFields(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
var field reflect.Value
|
var (
|
||||||
|
field reflect.Value
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
if v.IsValid() {
|
if v.IsValid() {
|
||||||
field = v.Field(i)
|
field = v.Field(i)
|
||||||
}
|
}
|
||||||
@ -215,23 +206,15 @@ func traverseFields(
|
|||||||
fieldName := jsonNameFromTag(t.Field(i).Tag)
|
fieldName := jsonNameFromTag(t.Field(i).Tag)
|
||||||
|
|
||||||
if fieldType == cosmosAnyType {
|
if fieldType == cosmosAnyType {
|
||||||
any, ok := field.Interface().(*codectypes.Any)
|
// Unpack field, value as Any
|
||||||
if !ok {
|
if fieldType, field, err = unpackAny(cdc, field); err != nil {
|
||||||
return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "%T", field.Interface())
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
anyWrapper := &cosmosAnyWrapper{
|
// If field is an empty value, do not include in types, since it will not be present in the object
|
||||||
Type: any.TypeUrl,
|
if field.IsZero() {
|
||||||
}
|
continue
|
||||||
|
|
||||||
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 its a nil pointer, do not include in types
|
// If its a nil pointer, do not include in types
|
||||||
@ -273,6 +256,12 @@ func traverseFields(
|
|||||||
fieldType = fieldType.Elem()
|
fieldType = fieldType.Elem()
|
||||||
field = field.Index(0)
|
field = field.Index(0)
|
||||||
isCollection = true
|
isCollection = true
|
||||||
|
|
||||||
|
if fieldType == cosmosAnyType {
|
||||||
|
if fieldType, field, err = unpackAny(cdc, field); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -304,10 +293,15 @@ func traverseFields(
|
|||||||
ethTyp := typToEth(fieldType)
|
ethTyp := typToEth(fieldType)
|
||||||
if len(ethTyp) > 0 {
|
if len(ethTyp) > 0 {
|
||||||
// Support array of uint64
|
// Support array of uint64
|
||||||
if isCollection && fieldType.Kind() != reflect.Slice && fieldType.Kind() != reflect.Array {
|
if isCollection {
|
||||||
|
if fieldType.Kind() != reflect.Slice && fieldType.Kind() != reflect.Array {
|
||||||
ethTyp += "[]"
|
ethTyp += "[]"
|
||||||
}
|
}
|
||||||
|
// convert uint8[] to bytes
|
||||||
|
if fieldType.Kind() == reflect.Uint8 {
|
||||||
|
ethTyp = bytesStr
|
||||||
|
}
|
||||||
|
}
|
||||||
if prefix == typeDefPrefix {
|
if prefix == typeDefPrefix {
|
||||||
typeMap[rootType] = append(typeMap[rootType], apitypes.Type{
|
typeMap[rootType] = append(typeMap[rootType], apitypes.Type{
|
||||||
Name: fieldName,
|
Name: fieldName,
|
||||||
@ -363,6 +357,27 @@ func jsonNameFromTag(tag reflect.StructTag) string {
|
|||||||
return parts[0]
|
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
|
// _.foo_bar.baz -> TypeFooBarBaz
|
||||||
//
|
//
|
||||||
// this is needed for Geth's own signing code which doesn't
|
// this is needed for Geth's own signing code which doesn't
|
||||||
@ -429,14 +444,13 @@ func typToEth(typ reflect.Type) string {
|
|||||||
return "uint32"
|
return "uint32"
|
||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
return "uint64"
|
return "uint64"
|
||||||
case reflect.Slice:
|
case reflect.Slice | reflect.Array:
|
||||||
|
// Note: this case may never be reached due to previous handling in traverseFields
|
||||||
ethName := typToEth(typ.Elem())
|
ethName := typToEth(typ.Elem())
|
||||||
if len(ethName) > 0 {
|
if len(ethName) > 0 {
|
||||||
return ethName + "[]"
|
if ethName == "uint8" {
|
||||||
|
return bytesStr
|
||||||
}
|
}
|
||||||
case reflect.Array:
|
|
||||||
ethName := typToEth(typ.Elem())
|
|
||||||
if len(ethName) > 0 {
|
|
||||||
return ethName + "[]"
|
return ethName + "[]"
|
||||||
}
|
}
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
@ -465,7 +479,7 @@ func typToEth(typ reflect.Type) string {
|
|||||||
func doRecover(err *error) {
|
func doRecover(err *error) {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
if e, ok := r.(error); ok {
|
if e, ok := r.(error); ok {
|
||||||
e = sdkerrors.Wrap(e, "panicked with error")
|
e = errorsmod.Wrap(e, "panicked with error")
|
||||||
*err = e
|
*err = e
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -473,3 +487,77 @@ func doRecover(err *error) {
|
|||||||
*err = fmt.Errorf("%v", r)
|
*err = fmt.Errorf("%v", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Performs extra type conversions on JSON-decoded data accoding to the provided type definitions
|
||||||
|
// for compatibility with Geth's encoding
|
||||||
|
func patchTxData(data map[string]any, schema apitypes.Types, rootType string) error {
|
||||||
|
// Scan the data for any types that need to be converted.
|
||||||
|
// This is adapted from TypedData.EncodeData
|
||||||
|
for _, field := range schema[rootType] {
|
||||||
|
encType := field.Type
|
||||||
|
encValue := data[field.Name]
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case encType[len(encType)-1:] == "]":
|
||||||
|
arrayValue, ok := encValue.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return dataMismatchError(encType, encValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedType := strings.Split(encType, "[")[0]
|
||||||
|
if schema[parsedType] != nil {
|
||||||
|
for _, item := range arrayValue {
|
||||||
|
mapValue, ok := item.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return dataMismatchError(parsedType, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := patchTxData(mapValue, schema, parsedType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i, item := range arrayValue {
|
||||||
|
converted, err := handleConversion(parsedType, item)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
arrayValue[i] = converted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case schema[encType] != nil:
|
||||||
|
mapValue, ok := encValue.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return dataMismatchError(encType, encValue)
|
||||||
|
}
|
||||||
|
err := patchTxData(mapValue, schema, encType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
converted, err := handleConversion(encType, encValue)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data[field.Name] = converted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleConversion(encType string, encValue any) (any, error) {
|
||||||
|
if encType == bytesStr {
|
||||||
|
// Protobuf encodes byte strings in base64
|
||||||
|
if v, ok := encValue.(string); ok {
|
||||||
|
return base64.StdEncoding.DecodeString(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return encValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataMismatchError generates an error for a mismatch between
|
||||||
|
// the provided type and data
|
||||||
|
func dataMismatchError(encType string, encValue any) error {
|
||||||
|
return fmt.Errorf("provided data '%v' doesn't match type '%s'", encValue, encType)
|
||||||
|
}
|
||||||
|
477
ethereum/eip712/eip712_test.go
Normal file
477
ethereum/eip712/eip712_test.go
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
package eip712_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"cosmossdk.io/math"
|
||||||
|
registrytypes "github.com/cerc-io/laconicd/x/registry/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/simapp/params"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/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"
|
||||||
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
|
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/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/cerc-io/laconicd/app"
|
||||||
|
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||||
|
"github.com/cerc-io/laconicd/encoding"
|
||||||
|
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 := ðsecp256k1.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,
|
||||||
|
},
|
||||||
|
|
||||||
|
// test laconic registry messages
|
||||||
|
{
|
||||||
|
title: "Succeeds - Standard MsgSetName",
|
||||||
|
fee: txtypes.Fee{
|
||||||
|
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
|
||||||
|
GasLimit: 100000,
|
||||||
|
},
|
||||||
|
memo: "",
|
||||||
|
msgs: []sdk.Msg{
|
||||||
|
registrytypes.NewMsgSetName(
|
||||||
|
"testcrn",
|
||||||
|
"testcid",
|
||||||
|
suite.createTestAddress(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
accountNumber: 25,
|
||||||
|
sequence: 78,
|
||||||
|
expectSuccess: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Succeeds - Standard MsgSetRecord",
|
||||||
|
fee: txtypes.Fee{
|
||||||
|
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
|
||||||
|
GasLimit: 100000,
|
||||||
|
},
|
||||||
|
memo: "",
|
||||||
|
msgs: []sdk.Msg{
|
||||||
|
registrytypes.NewMsgSetRecord(
|
||||||
|
registrytypes.Payload{
|
||||||
|
Record: ®istrytypes.Record{
|
||||||
|
Attributes: []byte("test attributes"),
|
||||||
|
},
|
||||||
|
Signatures: []registrytypes.Signature{
|
||||||
|
{
|
||||||
|
Sig: "fake sig",
|
||||||
|
PubKey: "fake pubkey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"testbondid",
|
||||||
|
suite.createTestAddress(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
accountNumber: 25,
|
||||||
|
sequence: 78,
|
||||||
|
expectSuccess: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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
299
ethereum/eip712/encoding.go
Normal 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
|
||||||
|
}
|
106
go.mod
106
go.mod
@ -1,20 +1,24 @@
|
|||||||
module github.com/cerc-io/laconicd
|
module github.com/cerc-io/laconicd
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cosmossdk.io/math v1.0.0-beta.3
|
cosmossdk.io/errors v1.0.0-beta.7
|
||||||
github.com/99designs/gqlgen v0.17.20
|
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/armon/go-metrics v0.4.1
|
||||||
github.com/btcsuite/btcd v0.22.1
|
github.com/btcsuite/btcd v0.22.1
|
||||||
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
|
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/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/davecgh/go-spew v1.1.1
|
||||||
github.com/deckarep/golang-set v1.8.0
|
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/gibson042/canonicaljson-go v1.0.3
|
||||||
|
github.com/go-chi/chi/v5 v5.0.7
|
||||||
github.com/gogo/protobuf v1.3.3
|
github.com/gogo/protobuf v1.3.3
|
||||||
github.com/golang/protobuf v1.5.2
|
github.com/golang/protobuf v1.5.2
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
@ -23,41 +27,37 @@ require (
|
|||||||
github.com/holiman/uint256 v1.2.1
|
github.com/holiman/uint256 v1.2.1
|
||||||
github.com/improbable-eng/grpc-web v0.15.0
|
github.com/improbable-eng/grpc-web v0.15.0
|
||||||
github.com/ipfs/go-cid v0.3.2
|
github.com/ipfs/go-cid v0.3.2
|
||||||
github.com/ipfs/go-ipld-cbor v0.0.6
|
github.com/ipld/go-ipld-prime v0.19.0
|
||||||
github.com/ipld/go-ipld-prime v0.18.0
|
|
||||||
github.com/miguelmota/go-ethereum-hdwallet v0.1.1
|
github.com/miguelmota/go-ethereum-hdwallet v0.1.1
|
||||||
github.com/multiformats/go-multihash v0.2.1
|
github.com/onsi/ginkgo/v2 v2.5.1
|
||||||
github.com/onsi/ginkgo/v2 v2.2.0
|
github.com/onsi/gomega v1.24.1
|
||||||
github.com/onsi/gomega v1.20.2
|
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rakyll/statik v0.1.7
|
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/rs/cors v1.8.2
|
||||||
github.com/spf13/cast v1.5.0
|
github.com/spf13/cast v1.5.0
|
||||||
github.com/spf13/cobra v1.5.0
|
github.com/spf13/cobra v1.6.1
|
||||||
github.com/spf13/viper v1.13.0
|
github.com/spf13/viper v1.14.0
|
||||||
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969
|
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969
|
||||||
github.com/stretchr/testify v1.8.0
|
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/tendermint/tm-db v0.6.7
|
||||||
github.com/tyler-smith/go-bip39 v1.1.0
|
github.com/tyler-smith/go-bip39 v1.1.0
|
||||||
github.com/vektah/gqlparser/v2 v2.5.1
|
github.com/vektah/gqlparser/v2 v2.5.1
|
||||||
golang.org/x/net v0.2.0
|
golang.org/x/net v0.7.0
|
||||||
golang.org/x/text v0.4.0
|
golang.org/x/text v0.7.0
|
||||||
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6
|
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c
|
||||||
google.golang.org/grpc v1.50.1
|
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
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
sigs.k8s.io/yaml v1.3.0
|
sigs.k8s.io/yaml v1.3.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.105.0 // indirect
|
cloud.google.com/go v0.105.0 // indirect
|
||||||
cloud.google.com/go/compute v1.12.1 // indirect
|
cloud.google.com/go/compute v1.13.0 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.2.1 // indirect
|
cloud.google.com/go/compute/metadata v0.2.1 // indirect
|
||||||
cloud.google.com/go/iam v0.7.0 // indirect
|
cloud.google.com/go/iam v0.8.0 // indirect
|
||||||
cloud.google.com/go/storage v1.27.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
|
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
|
||||||
github.com/99designs/keyring v1.2.1 // indirect
|
github.com/99designs/keyring v1.2.1 // indirect
|
||||||
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
|
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
|
||||||
@ -65,11 +65,11 @@ require (
|
|||||||
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
||||||
github.com/Workiva/go-datastructures v1.0.53 // indirect
|
github.com/Workiva/go-datastructures v1.0.53 // indirect
|
||||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.40.45 // indirect
|
github.com/aws/aws-sdk-go v1.44.122 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||||
github.com/bgentry/speakeasy v0.1.0 // 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/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||||
github.com/cespare/xxhash v1.1.0 // indirect
|
github.com/cespare/xxhash v1.1.0 // indirect
|
||||||
@ -77,13 +77,11 @@ require (
|
|||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
|
||||||
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
|
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
|
||||||
github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect
|
github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect
|
||||||
github.com/confio/ics23/go v0.7.0 // indirect
|
github.com/confio/ics23/go v0.9.0 // indirect
|
||||||
github.com/cosmos/btcutil v1.0.4 // indirect
|
github.com/cosmos/btcutil v1.0.5 // indirect
|
||||||
github.com/cosmos/cosmos-proto v1.0.0-alpha7 // indirect
|
|
||||||
github.com/cosmos/gorocksdb v1.2.0 // indirect
|
github.com/cosmos/gorocksdb v1.2.0 // indirect
|
||||||
github.com/cosmos/iavl v0.19.3 // indirect
|
github.com/cosmos/iavl v0.19.4 // indirect
|
||||||
github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect
|
github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect
|
||||||
github.com/cosmos/ledger-go v0.9.2 // indirect
|
|
||||||
github.com/creachadair/taskgroup v0.3.2 // indirect
|
github.com/creachadair/taskgroup v0.3.2 // indirect
|
||||||
github.com/danieljoos/wincred v1.1.2 // indirect
|
github.com/danieljoos/wincred v1.1.2 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||||
@ -97,11 +95,12 @@ require (
|
|||||||
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
|
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
|
||||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.1 // 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/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||||
github.com/go-kit/kit v0.12.0 // indirect
|
github.com/go-kit/kit v0.12.0 // indirect
|
||||||
github.com/go-kit/log v0.2.1 // indirect
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.5.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-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||||
github.com/go-stack/stack v1.8.0 // indirect
|
github.com/go-stack/stack v1.8.0 // indirect
|
||||||
@ -115,14 +114,14 @@ require (
|
|||||||
github.com/google/orderedcode v0.0.1 // indirect
|
github.com/google/orderedcode v0.0.1 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.6.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
|
||||||
github.com/gorilla/handlers v1.5.1 // indirect
|
github.com/gorilla/handlers v1.5.1 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||||
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
|
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
|
||||||
github.com/gtank/merlin v0.1.1 // indirect
|
github.com/gtank/merlin v0.1.1 // indirect
|
||||||
github.com/gtank/ristretto255 v0.1.2 // indirect
|
github.com/gtank/ristretto255 v0.1.2 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-getter v1.6.1 // indirect
|
github.com/hashicorp/go-getter v1.7.0 // indirect
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||||
@ -132,14 +131,12 @@ require (
|
|||||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||||
github.com/huin/goupnp v1.0.3 // indirect
|
github.com/huin/goupnp v1.0.3 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
github.com/ipfs/go-block-format v0.0.2 // indirect
|
|
||||||
github.com/ipfs/go-ipfs-util v0.0.1 // indirect
|
|
||||||
github.com/ipfs/go-ipld-format v0.0.1 // indirect
|
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||||
|
github.com/kevinburke/go-bindata v3.24.0+incompatible // indirect
|
||||||
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // 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/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||||
github.com/lib/pq v1.10.6 // indirect
|
github.com/lib/pq v1.10.6 // indirect
|
||||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||||
@ -153,13 +150,14 @@ require (
|
|||||||
github.com/minio/highwayhash v1.0.2 // indirect
|
github.com/minio/highwayhash v1.0.2 // indirect
|
||||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||||
github.com/mtibben/percent v0.2.1 // indirect
|
github.com/mtibben/percent v0.2.1 // indirect
|
||||||
github.com/multiformats/go-base32 v0.0.3 // indirect
|
github.com/multiformats/go-base32 v0.0.3 // indirect
|
||||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||||
github.com/multiformats/go-multibase v0.0.3 // indirect
|
github.com/multiformats/go-multibase v0.0.3 // indirect
|
||||||
|
github.com/multiformats/go-multihash v0.2.1 // indirect
|
||||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||||
@ -170,9 +168,10 @@ require (
|
|||||||
github.com/prometheus/client_golang v1.12.2 // indirect
|
github.com/prometheus/client_golang v1.12.2 // indirect
|
||||||
github.com/prometheus/client_model v0.2.0 // indirect
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
github.com/prometheus/common v0.34.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/prometheus/tsdb v0.7.1 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // 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/rjeczalik/notify v0.9.1 // indirect
|
||||||
github.com/rs/zerolog v1.27.0 // indirect
|
github.com/rs/zerolog v1.27.0 // indirect
|
||||||
github.com/sasha-s/go-deadlock v0.3.1 // indirect
|
github.com/sasha-s/go-deadlock v0.3.1 // indirect
|
||||||
@ -181,7 +180,7 @@ require (
|
|||||||
github.com/spf13/afero v1.9.2 // indirect
|
github.com/spf13/afero v1.9.2 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/stretchr/objx v0.4.0 // indirect
|
github.com/stretchr/objx v0.5.0 // indirect
|
||||||
github.com/subosito/gotenv v1.4.1 // indirect
|
github.com/subosito/gotenv v1.4.1 // indirect
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||||
github.com/tendermint/btcd v0.1.1 // indirect
|
github.com/tendermint/btcd v0.1.1 // indirect
|
||||||
@ -189,19 +188,19 @@ require (
|
|||||||
github.com/tendermint/go-amino v0.16.0 // indirect
|
github.com/tendermint/go-amino v0.16.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||||
github.com/ulikunitz/xz v0.5.8 // indirect
|
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 // indirect
|
github.com/zondax/hid v0.9.1 // indirect
|
||||||
github.com/zondax/hid v0.9.1-0.20220302062450-5552068d2266 // indirect
|
github.com/zondax/ledger-go v0.14.0 // indirect
|
||||||
go.etcd.io/bbolt v1.3.6 // indirect
|
go.etcd.io/bbolt v1.3.6 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
golang.org/x/crypto v0.3.0 // indirect
|
golang.org/x/crypto v0.4.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
|
golang.org/x/oauth2 v0.1.0 // indirect
|
||||||
golang.org/x/sync v0.1.0 // indirect
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
golang.org/x/sys v0.2.0 // indirect
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
golang.org/x/term v0.2.0 // indirect
|
golang.org/x/term v0.5.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||||
google.golang.org/api v0.102.0 // indirect
|
google.golang.org/api v0.103.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||||
@ -211,10 +210,13 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
|
// use cosmos keyring
|
||||||
github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76
|
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.
|
// Fix upstream GHSA-h395-qcrw-5vmq vulnerability.
|
||||||
// TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409
|
// TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409
|
||||||
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0
|
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
|
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
|
||||||
)
|
)
|
||||||
|
16
gometalinter.json
Normal file
16
gometalinter.json
Normal 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
|
||||||
|
}
|
269
gomod2nix.toml
269
gomod2nix.toml
@ -2,26 +2,32 @@ schema = 3
|
|||||||
|
|
||||||
[mod]
|
[mod]
|
||||||
[mod."cloud.google.com/go"]
|
[mod."cloud.google.com/go"]
|
||||||
version = "v0.102.1"
|
version = "v0.105.0"
|
||||||
hash = "sha256-rv3MHFvIrN6AcrmWcWGSQwgaZLbjJMmJFi3bsfHoiO4="
|
hash = "sha256-2nYtHjuN9ghGcM6aPlOxyNNarHebHtj0Xec48sWwdaI="
|
||||||
[mod."cloud.google.com/go/compute"]
|
[mod."cloud.google.com/go/compute"]
|
||||||
version = "v1.7.0"
|
version = "v1.12.1"
|
||||||
hash = "sha256-g+n7L36LC+NP4KaiEu9fCMn6S9fkxjp4PCLOp/oXV38="
|
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"]
|
[mod."cloud.google.com/go/iam"]
|
||||||
version = "v0.4.0"
|
version = "v0.7.0"
|
||||||
hash = "sha256-sPtj6QPPC/QrkDXJW4Y7rMIHk5l1y9XV/DgM47eEtvg="
|
hash = "sha256-2UTJ/BbZ+YMGJhyo3HRPUYVDXW6+B5znFdqiutboYtA="
|
||||||
[mod."cloud.google.com/go/storage"]
|
[mod."cloud.google.com/go/storage"]
|
||||||
version = "v1.22.1"
|
version = "v1.27.0"
|
||||||
hash = "sha256-YZt05wru0kacyi6moTgvocavActKpXx7FlLh+o0HGDs="
|
hash = "sha256-V4B6A1Ms8cemB5Cs6nAtUe1N1ldaI9oqTdzGU2FUhrc="
|
||||||
[mod."cosmossdk.io/errors"]
|
[mod."cosmossdk.io/errors"]
|
||||||
version = "v1.0.0-beta.7"
|
version = "v1.0.0-beta.7"
|
||||||
hash = "sha256-XblGvIx6Wvvq6wggXjp+KbeJGXoe7AZH7hXEdauCezU="
|
hash = "sha256-XblGvIx6Wvvq6wggXjp+KbeJGXoe7AZH7hXEdauCezU="
|
||||||
[mod."cosmossdk.io/math"]
|
[mod."cosmossdk.io/math"]
|
||||||
version = "v1.0.0-beta.3"
|
version = "v1.0.0-beta.4"
|
||||||
hash = "sha256-lTQ27ZlL+kWlc+S//sJmyiOwaf9qS+YLv61I4OXi9XE="
|
hash = "sha256-UYdq/46EubyjxkldGike8FlwJLWGCB576VB7th285ao="
|
||||||
[mod."filippo.io/edwards25519"]
|
[mod."filippo.io/edwards25519"]
|
||||||
version = "v1.0.0-rc.1"
|
version = "v1.0.0-rc.1"
|
||||||
hash = "sha256-3DboBqby2ejRU33FG96Z8JF5AJ8HP2rC/v++VyoQ2LQ="
|
hash = "sha256-3DboBqby2ejRU33FG96Z8JF5AJ8HP2rC/v++VyoQ2LQ="
|
||||||
|
[mod."github.com/99designs/gqlgen"]
|
||||||
|
version = "v0.17.22"
|
||||||
|
hash = "sha256-Cu3nAqFbsV7DH+4UZvX83ScxJtPlvOyD7ptUPXnwGng="
|
||||||
[mod."github.com/99designs/keyring"]
|
[mod."github.com/99designs/keyring"]
|
||||||
version = "v1.1.7-0.20210622111912-ef00f8ac3d76"
|
version = "v1.1.7-0.20210622111912-ef00f8ac3d76"
|
||||||
hash = "sha256-oCalyOZWegRgKHZ1GvYHNkrMKh51j8cOE/K4yBPM5Oc="
|
hash = "sha256-oCalyOZWegRgKHZ1GvYHNkrMKh51j8cOE/K4yBPM5Oc="
|
||||||
@ -38,6 +44,9 @@ schema = 3
|
|||||||
[mod."github.com/Workiva/go-datastructures"]
|
[mod."github.com/Workiva/go-datastructures"]
|
||||||
version = "v1.0.53"
|
version = "v1.0.53"
|
||||||
hash = "sha256-W6qOvqu8sokMlZrpOF1SWG138H0/BotywKNLlDF8Zug="
|
hash = "sha256-W6qOvqu8sokMlZrpOF1SWG138H0/BotywKNLlDF8Zug="
|
||||||
|
[mod."github.com/agnivade/levenshtein"]
|
||||||
|
version = "v1.1.1"
|
||||||
|
hash = "sha256-tgv2s8XIcWjscv1pP87TOIUV4vADT2px1Lo/MQCTBjM="
|
||||||
[mod."github.com/armon/go-metrics"]
|
[mod."github.com/armon/go-metrics"]
|
||||||
version = "v0.4.1"
|
version = "v0.4.1"
|
||||||
hash = "sha256-usxTUHA0QQMdM6sHi2z51nmnEKMbA0qUilxJFpWHlYE="
|
hash = "sha256-usxTUHA0QQMdM6sHi2z51nmnEKMbA0qUilxJFpWHlYE="
|
||||||
@ -57,8 +66,8 @@ schema = 3
|
|||||||
version = "v0.22.1"
|
version = "v0.22.1"
|
||||||
hash = "sha256-hBU+roIELcmbW2Gz7eGZzL9qNA1bakq5wNxqCgs4TKc="
|
hash = "sha256-hBU+roIELcmbW2Gz7eGZzL9qNA1bakq5wNxqCgs4TKc="
|
||||||
[mod."github.com/btcsuite/btcd/btcec/v2"]
|
[mod."github.com/btcsuite/btcd/btcec/v2"]
|
||||||
version = "v2.2.0"
|
version = "v2.3.2"
|
||||||
hash = "sha256-cwoIqi0SiAaGEBtuQKip9OVirKIeJw5fUoWo7x/xfOc="
|
hash = "sha256-natWs+yIAuD1UI07iZtjPilroQLfXizFn3lNOiOT83U="
|
||||||
[mod."github.com/btcsuite/btcd/chaincfg/chainhash"]
|
[mod."github.com/btcsuite/btcd/chaincfg/chainhash"]
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
hash = "sha256-vix0j/KGNvoKjhlKgVeSLY6un2FHeIEoZWMC4z3yvZ4="
|
hash = "sha256-vix0j/KGNvoKjhlKgVeSLY6un2FHeIEoZWMC4z3yvZ4="
|
||||||
@ -84,35 +93,36 @@ schema = 3
|
|||||||
version = "v0.7.9"
|
version = "v0.7.9"
|
||||||
hash = "sha256-ZWIXIXcHGjeCNgMrpXymry8/8esDDauGFfF/+gEoO1Y="
|
hash = "sha256-ZWIXIXcHGjeCNgMrpXymry8/8esDDauGFfF/+gEoO1Y="
|
||||||
[mod."github.com/confio/ics23/go"]
|
[mod."github.com/confio/ics23/go"]
|
||||||
version = "v0.7.0"
|
version = "v0.8.0"
|
||||||
hash = "sha256-FjUQfDKtX+/13+UjJzbYPAkgM4GPZ0vk+dKz7/iRetw="
|
hash = "sha256-mFKxFHp7RaE1L5NdtH9H9px2Cy6I5uOZVnFOgE8Nrew="
|
||||||
|
replaced = "github.com/cosmos/cosmos-sdk/ics23/go"
|
||||||
[mod."github.com/cosmos/btcutil"]
|
[mod."github.com/cosmos/btcutil"]
|
||||||
version = "v1.0.4"
|
version = "v1.0.5"
|
||||||
hash = "sha256-JvcBXBdjdmnaW/nyf/tw/uaOAGn1b78yxrtl2/Rs3kA="
|
hash = "sha256-t572Sr5iiHcuMKLMWa2i+LBAt192oa+G1oA371tG/eI="
|
||||||
[mod."github.com/cosmos/cosmos-proto"]
|
[mod."github.com/cosmos/cosmos-proto"]
|
||||||
version = "v1.0.0-alpha7"
|
version = "v1.0.0-beta.1"
|
||||||
hash = "sha256-2wCH+toTF2A6MfFjOa13muEH5oBCcxAhZEqirNOrBA0="
|
hash = "sha256-oATkuj+fM5eBn+ywO+w/tL0AFSIEkx0J3Yz+VhVe0QA="
|
||||||
[mod."github.com/cosmos/cosmos-sdk"]
|
[mod."github.com/cosmos/cosmos-sdk"]
|
||||||
version = "v0.46.2-0.20220920160224-9454b97ccb77"
|
version = "v0.46.7"
|
||||||
hash = "sha256-zwOsdcoPbEzn+q/UmW6/CauW65V6a4z/7k8DXPCvKb0="
|
hash = "sha256-54DCF8lrnA1oUmBJlbUlWXOP5UbenRInUROn5P5I9qI="
|
||||||
[mod."github.com/cosmos/go-bip39"]
|
[mod."github.com/cosmos/go-bip39"]
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
hash = "sha256-Qm2aC2vaS8tjtMUbHmlBSagOSqbduEEDwc51qvQaBmA="
|
hash = "sha256-Qm2aC2vaS8tjtMUbHmlBSagOSqbduEEDwc51qvQaBmA="
|
||||||
|
[mod."github.com/cosmos/gogoproto"]
|
||||||
|
version = "v1.4.3"
|
||||||
|
hash = "sha256-Y/NL76ay/oAl8mS3skkK5ula0/xudqbwW1o22lZjKRg="
|
||||||
[mod."github.com/cosmos/gorocksdb"]
|
[mod."github.com/cosmos/gorocksdb"]
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
hash = "sha256-209TcVuXc5s/TcOvNlaQ1HEJAUDTEK3nxPhs+d8TEcY="
|
hash = "sha256-209TcVuXc5s/TcOvNlaQ1HEJAUDTEK3nxPhs+d8TEcY="
|
||||||
[mod."github.com/cosmos/iavl"]
|
[mod."github.com/cosmos/iavl"]
|
||||||
version = "v0.19.2-0.20220916140702-9b6be3095313"
|
version = "v0.19.4"
|
||||||
hash = "sha256-49xr/7/4L1wZ45eW5lE7C4SlcbGf4gBY+662SfJiWPQ="
|
hash = "sha256-EmpRZ48pjPFq/fIHneut9Vyo5QJATfb3ZO7KzWnqs9g="
|
||||||
[mod."github.com/cosmos/ibc-go/v5"]
|
[mod."github.com/cosmos/ibc-go/v5"]
|
||||||
version = "v5.0.0"
|
version = "v5.2.0"
|
||||||
hash = "sha256-sDZdmuGohaaBF7bxrjo9PWJnmoF+VOkjySYhsFixPz4="
|
hash = "sha256-Gfqhdz9ZKEgb7LCkHiXCwYZYUYluQ+vMew/GkssfVj8="
|
||||||
[mod."github.com/cosmos/ledger-cosmos-go"]
|
[mod."github.com/cosmos/ledger-cosmos-go"]
|
||||||
version = "v0.11.1"
|
version = "v0.12.1"
|
||||||
hash = "sha256-yli+VvVtZmHo2LPvCY6lYVUfcCDn3sBLDL+a8KIlqDA="
|
hash = "sha256-9+nr+/r4MyiogddS0JcXOuriPqXP4nxln8ts+mYQRcg="
|
||||||
[mod."github.com/cosmos/ledger-go"]
|
|
||||||
version = "v0.9.2"
|
|
||||||
hash = "sha256-0YI+0A6wFBjiebBwzWOQjkgXkTakCrf7Gjg2xEaQdoM="
|
|
||||||
[mod."github.com/creachadair/taskgroup"]
|
[mod."github.com/creachadair/taskgroup"]
|
||||||
version = "v0.3.2"
|
version = "v0.3.2"
|
||||||
hash = "sha256-Y261IO/d9xjV0UScqHvo31broxvnKn4IQQC9Mu6jNkE="
|
hash = "sha256-Y261IO/d9xjV0UScqHvo31broxvnKn4IQQC9Mu6jNkE="
|
||||||
@ -156,17 +166,20 @@ schema = 3
|
|||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
hash = "sha256-k1DYvCqO3BKNcGEve/nMW0RxzMkK2tGfXbUbycqcVSo="
|
hash = "sha256-k1DYvCqO3BKNcGEve/nMW0RxzMkK2tGfXbUbycqcVSo="
|
||||||
[mod."github.com/ethereum/go-ethereum"]
|
[mod."github.com/ethereum/go-ethereum"]
|
||||||
version = "v1.10.19"
|
version = "v1.10.26"
|
||||||
hash = "sha256-7FPnTGcCb8Xd1QVR+6PmGTaHdTY1mm/8osFTW1JLuG8="
|
hash = "sha256-gkMEwJ4rOgn12amD4QpZ4th/10uyTTeoFmpseuKDQPs="
|
||||||
[mod."github.com/felixge/httpsnoop"]
|
[mod."github.com/felixge/httpsnoop"]
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
hash = "sha256-TNXnnC/ZGNY9lInAcES1cBGqIdEljKuh5LH/khVFjVk="
|
hash = "sha256-TNXnnC/ZGNY9lInAcES1cBGqIdEljKuh5LH/khVFjVk="
|
||||||
[mod."github.com/fsnotify/fsnotify"]
|
[mod."github.com/fsnotify/fsnotify"]
|
||||||
version = "v1.5.4"
|
version = "v1.6.0"
|
||||||
hash = "sha256-iPuInpDAJvDeSTr6to713J/fTOWdQIWlLXWAuWIs2Bw="
|
hash = "sha256-DQesOCweQPEwmAn6s7DCP/Dwy8IypC+osbpfsvpkdP0="
|
||||||
[mod."github.com/gballet/go-libpcsclite"]
|
[mod."github.com/gballet/go-libpcsclite"]
|
||||||
version = "v0.0.0-20190607065134-2772fd86a8ff"
|
version = "v0.0.0-20190607065134-2772fd86a8ff"
|
||||||
hash = "sha256-Nr5ocU9s1F2Lhx/Zq6/nIo+KkKEqMjDYOEs3yWRC48g="
|
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"]
|
[mod."github.com/go-kit/kit"]
|
||||||
version = "v0.12.0"
|
version = "v0.12.0"
|
||||||
hash = "sha256-5RkXo6s0oye8etgD5qy+AvkkkNsQ6jc0kWJj6flA4GM="
|
hash = "sha256-5RkXo6s0oye8etgD5qy+AvkkkNsQ6jc0kWJj6flA4GM="
|
||||||
@ -176,6 +189,9 @@ schema = 3
|
|||||||
[mod."github.com/go-logfmt/logfmt"]
|
[mod."github.com/go-logfmt/logfmt"]
|
||||||
version = "v0.5.1"
|
version = "v0.5.1"
|
||||||
hash = "sha256-t50m9ffvW8PiGvO+2svnLI+N/XaWaBS+ZlhwrEQn2gU="
|
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"]
|
[mod."github.com/go-ole/go-ole"]
|
||||||
version = "v1.2.6"
|
version = "v1.2.6"
|
||||||
hash = "sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs="
|
hash = "sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs="
|
||||||
@ -211,8 +227,8 @@ schema = 3
|
|||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
hash = "sha256-1PIeFGgUL4BK/StL/D12pg9bEQ5HfMT/fMLdus4pZTs="
|
hash = "sha256-1PIeFGgUL4BK/StL/D12pg9bEQ5HfMT/fMLdus4pZTs="
|
||||||
[mod."github.com/google/go-cmp"]
|
[mod."github.com/google/go-cmp"]
|
||||||
version = "v0.5.8"
|
version = "v0.5.9"
|
||||||
hash = "sha256-8zkIo+Sr1NXMnj3PNmvjX2sZKnAKWXOFvmnX7D9bwxQ="
|
hash = "sha256-lQc4O00R3QSMGs9LP8Sy7A9kj0cqV5rrUdpnGeipIyg="
|
||||||
[mod."github.com/google/orderedcode"]
|
[mod."github.com/google/orderedcode"]
|
||||||
version = "v0.0.1"
|
version = "v0.0.1"
|
||||||
hash = "sha256-KrExYovtUQrHGI1mPQf57jGw8soz7eWOC2xqEaV0uGk="
|
hash = "sha256-KrExYovtUQrHGI1mPQf57jGw8soz7eWOC2xqEaV0uGk="
|
||||||
@ -220,14 +236,11 @@ schema = 3
|
|||||||
version = "v1.3.0"
|
version = "v1.3.0"
|
||||||
hash = "sha256-QoR55eBtA94T2tBszyxfDtO7/pjZZSGb5vm7U0Xhs0Y="
|
hash = "sha256-QoR55eBtA94T2tBszyxfDtO7/pjZZSGb5vm7U0Xhs0Y="
|
||||||
[mod."github.com/googleapis/enterprise-certificate-proxy"]
|
[mod."github.com/googleapis/enterprise-certificate-proxy"]
|
||||||
version = "v0.1.0"
|
version = "v0.2.0"
|
||||||
hash = "sha256-fxaElfiGGh1mLmltkFpVFdiuaagrLZLTW9btVpK13wg="
|
hash = "sha256-5gxsS5kDLqNFBkQ4eK6GS/sNn+aFknm6jjfteO+6jl4="
|
||||||
[mod."github.com/googleapis/gax-go/v2"]
|
[mod."github.com/googleapis/gax-go/v2"]
|
||||||
version = "v2.4.0"
|
version = "v2.6.0"
|
||||||
hash = "sha256-zzat4+3iF2XBTQ6RZAUgsCbfK0HgO0nYhM4utA5dqz0="
|
hash = "sha256-sSsncbJmv0n5jB3G7tHY1Zr2ucCusIeTrXZH4A8QqYI="
|
||||||
[mod."github.com/googleapis/go-type-adapters"]
|
|
||||||
version = "v1.0.0"
|
|
||||||
hash = "sha256-u3ajruRV/EN2E1WKet/zoe3zmRrAy4C5F2Dx8bpQwoc="
|
|
||||||
[mod."github.com/gorilla/handlers"]
|
[mod."github.com/gorilla/handlers"]
|
||||||
version = "v1.5.1"
|
version = "v1.5.1"
|
||||||
hash = "sha256-GnBAARgOx1E+hDMQ63SI17hdhGtLQxb31lZOmn5j/pU="
|
hash = "sha256-GnBAARgOx1E+hDMQ63SI17hdhGtLQxb31lZOmn5j/pU="
|
||||||
@ -289,8 +302,26 @@ schema = 3
|
|||||||
version = "v0.15.0"
|
version = "v0.15.0"
|
||||||
hash = "sha256-9oqKb5Y3hjleOFE2BczbEzLH6q2Jg7kUTP/M8Yk4Ne4="
|
hash = "sha256-9oqKb5Y3hjleOFE2BczbEzLH6q2Jg7kUTP/M8Yk4Ne4="
|
||||||
[mod."github.com/inconshreveable/mousetrap"]
|
[mod."github.com/inconshreveable/mousetrap"]
|
||||||
version = "v1.0.0"
|
version = "v1.0.1"
|
||||||
hash = "sha256-ogTuLrV40FwS4ueo4hh6hi1wPywOI+LyIqfNjsibwNY="
|
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"]
|
[mod."github.com/jackpal/go-nat-pmp"]
|
||||||
version = "v1.0.2"
|
version = "v1.0.2"
|
||||||
hash = "sha256-L1D4Yoxnzihs795GZ+Q3AZsFP5c4iqyjTeyrudzPXtw="
|
hash = "sha256-L1D4Yoxnzihs795GZ+Q3AZsFP5c4iqyjTeyrudzPXtw="
|
||||||
@ -304,8 +335,11 @@ schema = 3
|
|||||||
version = "v0.0.0-20190712205309-48d3d31d256d"
|
version = "v0.0.0-20190712205309-48d3d31d256d"
|
||||||
hash = "sha256-bn04wkDnhQ0tb/YzmPf7MNJlApOl+z6+EAbUqH7Ti5Q="
|
hash = "sha256-bn04wkDnhQ0tb/YzmPf7MNJlApOl+z6+EAbUqH7Ti5Q="
|
||||||
[mod."github.com/klauspost/compress"]
|
[mod."github.com/klauspost/compress"]
|
||||||
version = "v1.15.9"
|
version = "v1.15.11"
|
||||||
hash = "sha256-ctPxlVq0c/SoNPVsP66RjxUjTHys3diW2Apxjyc9WdE="
|
hash = "sha256-9MXm0TObg6DyqnYMIw3IChrorHc2ILf5djZYoM0e1J0="
|
||||||
|
[mod."github.com/klauspost/cpuid/v2"]
|
||||||
|
version = "v2.0.9"
|
||||||
|
hash = "sha256-0rHlHzEVaDdkVbRJDhnAJjfJUmAHOYjXN5u7VoCi5uk="
|
||||||
[mod."github.com/lib/pq"]
|
[mod."github.com/lib/pq"]
|
||||||
version = "v1.10.6"
|
version = "v1.10.6"
|
||||||
hash = "sha256-8EhFwY/9YH5L/fd6l2beOnC3VvpegRAmCCsnDVJBqBM="
|
hash = "sha256-8EhFwY/9YH5L/fd6l2beOnC3VvpegRAmCCsnDVJBqBM="
|
||||||
@ -319,8 +353,8 @@ schema = 3
|
|||||||
version = "v0.9.0"
|
version = "v0.9.0"
|
||||||
hash = "sha256-Fe2OPoyRExZejwtUBivKhfJAJW7o9b1eyYpgDlWQ1No="
|
hash = "sha256-Fe2OPoyRExZejwtUBivKhfJAJW7o9b1eyYpgDlWQ1No="
|
||||||
[mod."github.com/mattn/go-colorable"]
|
[mod."github.com/mattn/go-colorable"]
|
||||||
version = "v0.1.12"
|
version = "v0.1.13"
|
||||||
hash = "sha256-Y1vCt0ShrCz4wSmwsppCfeLPLKrWusc2zM2lUFwDMyI="
|
hash = "sha256-qb3Qbo0CELGRIzvw7NVM1g/aayaz4Tguppk9MD2/OI8="
|
||||||
[mod."github.com/mattn/go-isatty"]
|
[mod."github.com/mattn/go-isatty"]
|
||||||
version = "v0.0.16"
|
version = "v0.0.16"
|
||||||
hash = "sha256-YMaPZvShDfA98vqw1+zWWl7M1IT4nHPGBrAt7kHo8Iw="
|
hash = "sha256-YMaPZvShDfA98vqw1+zWWl7M1IT4nHPGBrAt7kHo8Iw="
|
||||||
@ -334,11 +368,14 @@ schema = 3
|
|||||||
version = "v0.1.1"
|
version = "v0.1.1"
|
||||||
hash = "sha256-SoKy4Mwkbm0J2yQLDcIcBbo/J6auTNdlZslTvJrSknM="
|
hash = "sha256-SoKy4Mwkbm0J2yQLDcIcBbo/J6auTNdlZslTvJrSknM="
|
||||||
[mod."github.com/mimoo/StrobeGo"]
|
[mod."github.com/mimoo/StrobeGo"]
|
||||||
version = "v0.0.0-20181016162300-f8f6d4d2b643"
|
version = "v0.0.0-20210601165009-122bf33a46e0"
|
||||||
hash = "sha256-ih5WfC48IniPuAHUpC6upOabZA1/DssTAcxhZe6A/dE="
|
hash = "sha256-rmw70RHsbeOnema++aFCPdswADMVKtb7KGF3msOI7ak="
|
||||||
[mod."github.com/minio/highwayhash"]
|
[mod."github.com/minio/highwayhash"]
|
||||||
version = "v1.0.2"
|
version = "v1.0.2"
|
||||||
hash = "sha256-UeHeepKtToyA5e/w3KdmpbCn+4medesZG0cAcU6P2cY="
|
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"]
|
[mod."github.com/mitchellh/go-homedir"]
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
hash = "sha256-oduBKXHAQG8X6aqLEpqZHs5DOKe84u6WkBwi4W6cv3k="
|
hash = "sha256-oduBKXHAQG8X6aqLEpqZHs5DOKe84u6WkBwi4W6cv3k="
|
||||||
@ -348,18 +385,36 @@ schema = 3
|
|||||||
[mod."github.com/mitchellh/mapstructure"]
|
[mod."github.com/mitchellh/mapstructure"]
|
||||||
version = "v1.5.0"
|
version = "v1.5.0"
|
||||||
hash = "sha256-ztVhGQXs67MF8UadVvG72G3ly0ypQW0IRDdOOkjYwoE="
|
hash = "sha256-ztVhGQXs67MF8UadVvG72G3ly0ypQW0IRDdOOkjYwoE="
|
||||||
|
[mod."github.com/mr-tron/base58"]
|
||||||
|
version = "v1.2.0"
|
||||||
|
hash = "sha256-8FzMu3kHUbBX10pUdtGf59Ag7BNupx8ZHeUaodR1/Vk="
|
||||||
[mod."github.com/mtibben/percent"]
|
[mod."github.com/mtibben/percent"]
|
||||||
version = "v0.2.1"
|
version = "v0.2.1"
|
||||||
hash = "sha256-Zj1lpCP6mKQ0UUTMs2By4LC414ou+iJzKkK+eBHfEcc="
|
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"]
|
[mod."github.com/olekukonko/tablewriter"]
|
||||||
version = "v0.0.5"
|
version = "v0.0.5"
|
||||||
hash = "sha256-/5i70IkH/qSW5KjGzv8aQNKh9tHoz98tqtL0K2DMFn4="
|
hash = "sha256-/5i70IkH/qSW5KjGzv8aQNKh9tHoz98tqtL0K2DMFn4="
|
||||||
[mod."github.com/onsi/ginkgo/v2"]
|
[mod."github.com/onsi/ginkgo/v2"]
|
||||||
version = "v2.2.0"
|
version = "v2.5.1"
|
||||||
hash = "sha256-+VzAN6pB5DwEqT/KHdhgfPnWBtyIIcHi1J4HQkqCvvU="
|
hash = "sha256-VB29+H9k7l6il63oXJvsjamSUhsw/e99iI/BeTCderA="
|
||||||
[mod."github.com/onsi/gomega"]
|
[mod."github.com/onsi/gomega"]
|
||||||
version = "v1.20.2"
|
version = "v1.24.1"
|
||||||
hash = "sha256-3SGyvhWVlR3tYojnRSDr2SRToontAtw4hbZX+agn/Hs="
|
hash = "sha256-REfxQTDRcO23GnmJfOW8/MmPJf9oE2grVvvGiC1eSbo="
|
||||||
[mod."github.com/pelletier/go-toml"]
|
[mod."github.com/pelletier/go-toml"]
|
||||||
version = "v1.9.5"
|
version = "v1.9.5"
|
||||||
hash = "sha256-RJ9K1BTId0Mled7S66iGgxHkZ5JKEIsrrNaEfM8aImc="
|
hash = "sha256-RJ9K1BTId0Mled7S66iGgxHkZ5JKEIsrrNaEfM8aImc="
|
||||||
@ -375,6 +430,9 @@ schema = 3
|
|||||||
[mod."github.com/pmezard/go-difflib"]
|
[mod."github.com/pmezard/go-difflib"]
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
hash = "sha256-/FtmHnaGjdvEIKAJtrUfEhV7EVo5A/eYrtdnUkuxLDA="
|
hash = "sha256-/FtmHnaGjdvEIKAJtrUfEhV7EVo5A/eYrtdnUkuxLDA="
|
||||||
|
[mod."github.com/polydawn/refmt"]
|
||||||
|
version = "v0.0.0-20201211092308-30ac6d18308e"
|
||||||
|
hash = "sha256-oicfIWyK51U0LaNW0qgg5enH866TM6vsJExw98whjio="
|
||||||
[mod."github.com/prometheus/client_golang"]
|
[mod."github.com/prometheus/client_golang"]
|
||||||
version = "v1.12.2"
|
version = "v1.12.2"
|
||||||
hash = "sha256-d8xHyML/FImuPmFOy7UGW/y85NPLzJYL6IFhR3s7XzE="
|
hash = "sha256-d8xHyML/FImuPmFOy7UGW/y85NPLzJYL6IFhR3s7XzE="
|
||||||
@ -385,8 +443,8 @@ schema = 3
|
|||||||
version = "v0.34.0"
|
version = "v0.34.0"
|
||||||
hash = "sha256-M+v+7DntUBmiQNzfNmG3aLLufbl0XBQOubtYoNTzJDA="
|
hash = "sha256-M+v+7DntUBmiQNzfNmG3aLLufbl0XBQOubtYoNTzJDA="
|
||||||
[mod."github.com/prometheus/procfs"]
|
[mod."github.com/prometheus/procfs"]
|
||||||
version = "v0.7.3"
|
version = "v0.8.0"
|
||||||
hash = "sha256-ik0WpnpSjMwifPYfQTfu/eb5ilNj+eLJF0d5Dftp8A8="
|
hash = "sha256-hgrilokQsXCOCCvwgOSfuErxoFAQpXM/+zNJKcMVHyM="
|
||||||
[mod."github.com/prometheus/tsdb"]
|
[mod."github.com/prometheus/tsdb"]
|
||||||
version = "v0.7.1"
|
version = "v0.7.1"
|
||||||
hash = "sha256-BPz7YJbfMZgeR+u9YaeWeipVzHIS73EdgXD7VSJSLbA="
|
hash = "sha256-BPz7YJbfMZgeR+u9YaeWeipVzHIS73EdgXD7VSJSLbA="
|
||||||
@ -394,8 +452,8 @@ schema = 3
|
|||||||
version = "v0.1.7"
|
version = "v0.1.7"
|
||||||
hash = "sha256-/bfnXHBmN8vviPL7D85IzcEVXCaWyjbPPNyauzEcQ8Q="
|
hash = "sha256-/bfnXHBmN8vviPL7D85IzcEVXCaWyjbPPNyauzEcQ8Q="
|
||||||
[mod."github.com/rcrowley/go-metrics"]
|
[mod."github.com/rcrowley/go-metrics"]
|
||||||
version = "v0.0.0-20200313005456-10cdbea86bc0"
|
version = "v0.0.0-20201227073835-cf1acfcdf475"
|
||||||
hash = "sha256-xHqWWd4/RyAxqb80zjnrqHnHtWPfVTyByE+vDfbT52E="
|
hash = "sha256-10ytHQ1SpMKYTiKuOPdEMuOVa8HVvv9ryYSIF9BHEBI="
|
||||||
[mod."github.com/regen-network/cosmos-proto"]
|
[mod."github.com/regen-network/cosmos-proto"]
|
||||||
version = "v0.3.1"
|
version = "v0.3.1"
|
||||||
hash = "sha256-Bchbq/Hg72EA7Hevs8+PNuENuQaZAzk3qeVjMqFMUxc="
|
hash = "sha256-Bchbq/Hg72EA7Hevs8+PNuENuQaZAzk3qeVjMqFMUxc="
|
||||||
@ -409,20 +467,23 @@ schema = 3
|
|||||||
version = "v1.27.0"
|
version = "v1.27.0"
|
||||||
hash = "sha256-BxQtP2TROeSSpj9l1irocuSfxn55UL4ugzB/og7r8eE="
|
hash = "sha256-BxQtP2TROeSSpj9l1irocuSfxn55UL4ugzB/og7r8eE="
|
||||||
[mod."github.com/sasha-s/go-deadlock"]
|
[mod."github.com/sasha-s/go-deadlock"]
|
||||||
version = "v0.2.1-0.20190427202633-1595213edefa"
|
version = "v0.3.1"
|
||||||
hash = "sha256-BBOohTR+ktgJHAoYWh39/ui8MczcJECloc7tvxVBE50="
|
hash = "sha256-2CBEi9/iN/OMt7wEIG+hRjgDH6CRWIgibGGGy1dQ78I="
|
||||||
[mod."github.com/shirou/gopsutil"]
|
[mod."github.com/shirou/gopsutil"]
|
||||||
version = "v3.21.4-0.20210419000835-c7a38de76ee5+incompatible"
|
version = "v3.21.4-0.20210419000835-c7a38de76ee5+incompatible"
|
||||||
hash = "sha256-oqIqyFquWabIE6DID6uTEc8oFEmM1rVu2ATn3toiCEg="
|
hash = "sha256-oqIqyFquWabIE6DID6uTEc8oFEmM1rVu2ATn3toiCEg="
|
||||||
|
[mod."github.com/spaolacci/murmur3"]
|
||||||
|
version = "v1.1.0"
|
||||||
|
hash = "sha256-RWD4PPrlAsZZ8Xy356MBxpj+/NZI7w2XOU14Ob7/Y9M="
|
||||||
[mod."github.com/spf13/afero"]
|
[mod."github.com/spf13/afero"]
|
||||||
version = "v1.8.2"
|
version = "v1.9.2"
|
||||||
hash = "sha256-ERuG4GK1LOn72DRbT9URpo1QoVIm2A3mPtlf+xSPgx8="
|
hash = "sha256-R1mir7Fu95QK+YL99U14RGbLJzxqWRH5rSFpssgJvzA="
|
||||||
[mod."github.com/spf13/cast"]
|
[mod."github.com/spf13/cast"]
|
||||||
version = "v1.5.0"
|
version = "v1.5.0"
|
||||||
hash = "sha256-Pdp+wC5FWqyJKzyYHb7JCcV9BoJk/sxQw6nLyuLJvuQ="
|
hash = "sha256-Pdp+wC5FWqyJKzyYHb7JCcV9BoJk/sxQw6nLyuLJvuQ="
|
||||||
[mod."github.com/spf13/cobra"]
|
[mod."github.com/spf13/cobra"]
|
||||||
version = "v1.5.0"
|
version = "v1.6.1"
|
||||||
hash = "sha256-rcyHWrxshA5DVpxrSba5X4NjppqOGrJ64QkUKKnfW2E="
|
hash = "sha256-80B5HcYdFisz6QLYkTyka7f9Dr6AfcVyPwp3QChoXwU="
|
||||||
[mod."github.com/spf13/jwalterweatherman"]
|
[mod."github.com/spf13/jwalterweatherman"]
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
hash = "sha256-62BQtqTLF/eVrTOr7pUXE7AiHRjOVC8jQs3/Ehmflfs="
|
hash = "sha256-62BQtqTLF/eVrTOr7pUXE7AiHRjOVC8jQs3/Ehmflfs="
|
||||||
@ -430,17 +491,17 @@ schema = 3
|
|||||||
version = "v1.0.5"
|
version = "v1.0.5"
|
||||||
hash = "sha256-w9LLYzxxP74WHT4ouBspH/iQZXjuAh2WQCHsuvyEjAw="
|
hash = "sha256-w9LLYzxxP74WHT4ouBspH/iQZXjuAh2WQCHsuvyEjAw="
|
||||||
[mod."github.com/spf13/viper"]
|
[mod."github.com/spf13/viper"]
|
||||||
version = "v1.13.0"
|
version = "v1.14.0"
|
||||||
hash = "sha256-yHviS3lMo1hB6jwyiU3zpyGtxP6v9AsyZUKiLeCVz+k="
|
hash = "sha256-qn3VzD339HZIub5QP4aWVciSufAfVb9llbmQZ8pfDEs="
|
||||||
[mod."github.com/status-im/keycard-go"]
|
[mod."github.com/status-im/keycard-go"]
|
||||||
version = "v0.0.0-20200402102358-957c09536969"
|
version = "v0.0.0-20200402102358-957c09536969"
|
||||||
hash = "sha256-yddXXuu6mEFEO2/K6c1tWymeBKzOcvLQnNsFGRjtfXk="
|
hash = "sha256-yddXXuu6mEFEO2/K6c1tWymeBKzOcvLQnNsFGRjtfXk="
|
||||||
[mod."github.com/stretchr/objx"]
|
[mod."github.com/stretchr/objx"]
|
||||||
version = "v0.4.0"
|
version = "v0.5.0"
|
||||||
hash = "sha256-W6ycaeD/okr4udpCAGDsByr3OmiR0fuBzJUXHaHEFC0="
|
hash = "sha256-nY4mvP0f0Ry1IKMKQAYNuioA5h4red4mmQqeGZw6EF0="
|
||||||
[mod."github.com/stretchr/testify"]
|
[mod."github.com/stretchr/testify"]
|
||||||
version = "v1.8.0"
|
version = "v1.8.1"
|
||||||
hash = "sha256-LDxBAebK+A06y4vbH7cd1sVBOameIY81Xm8/9OPZh7o="
|
hash = "sha256-3e0vOJLgCMAan+GfaGN8RGZdarh5iCavM6flf6YMNPk="
|
||||||
[mod."github.com/subosito/gotenv"]
|
[mod."github.com/subosito/gotenv"]
|
||||||
version = "v1.4.1"
|
version = "v1.4.1"
|
||||||
hash = "sha256-aHAUs8Gh+BREUulljWr7vBZQg1BLu/M/8UfNK8CWSn8="
|
hash = "sha256-aHAUs8Gh+BREUulljWr7vBZQg1BLu/M/8UfNK8CWSn8="
|
||||||
@ -457,8 +518,8 @@ schema = 3
|
|||||||
version = "v0.16.0"
|
version = "v0.16.0"
|
||||||
hash = "sha256-JW4zO/0vMzf1dXLePOqaMtiLUZgNbuIseh9GV+jQlf0="
|
hash = "sha256-JW4zO/0vMzf1dXLePOqaMtiLUZgNbuIseh9GV+jQlf0="
|
||||||
[mod."github.com/tendermint/tendermint"]
|
[mod."github.com/tendermint/tendermint"]
|
||||||
version = "v0.34.21"
|
version = "v0.34.24"
|
||||||
hash = "sha256-C1KW6Wd4TwsFC09IHt8Jo3dozEk/Q2ZVdTapM8btEJ0="
|
hash = "sha256-3HFTv4XgN535RDaJ5OwUS+fnJHgkmLTwU7CNU2ilxEQ="
|
||||||
[mod."github.com/tendermint/tm-db"]
|
[mod."github.com/tendermint/tm-db"]
|
||||||
version = "v0.6.7"
|
version = "v0.6.7"
|
||||||
hash = "sha256-hl/3RrBrpkk2zA6dmrNlIYKs1/GfqegSscDSkA5Pjlo="
|
hash = "sha256-hl/3RrBrpkk2zA6dmrNlIYKs1/GfqegSscDSkA5Pjlo="
|
||||||
@ -474,9 +535,18 @@ schema = 3
|
|||||||
[mod."github.com/ulikunitz/xz"]
|
[mod."github.com/ulikunitz/xz"]
|
||||||
version = "v0.5.8"
|
version = "v0.5.8"
|
||||||
hash = "sha256-bfG3dssBUn+mSOAuKL+a/DTGGLUA+eASgLoGv/Gkqs0="
|
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"]
|
[mod."github.com/zondax/hid"]
|
||||||
version = "v0.9.1-0.20220302062450-5552068d2266"
|
version = "v0.9.1"
|
||||||
hash = "sha256-IZea8SHuLQxlltm1avieRVI054TWZg2jEoplodvNtwk="
|
hash = "sha256-hSVmN/f/lQHFhF60o6ej78ELC0MMoqQgqIX2hHjdTXg="
|
||||||
|
[mod."github.com/zondax/ledger-go"]
|
||||||
|
version = "v0.14.0"
|
||||||
|
hash = "sha256-RozTPSNs4RerZ4DQMBcGmvREjoRtH1G69xjhccYjIOk="
|
||||||
[mod."go.etcd.io/bbolt"]
|
[mod."go.etcd.io/bbolt"]
|
||||||
version = "v1.3.6"
|
version = "v1.3.6"
|
||||||
hash = "sha256-DenVAmyN22xUiivk6fdJp4C9ZnUJXCMDUf8E0goRRV4="
|
hash = "sha256-DenVAmyN22xUiivk6fdJp4C9ZnUJXCMDUf8E0goRRV4="
|
||||||
@ -484,47 +554,47 @@ schema = 3
|
|||||||
version = "v0.23.0"
|
version = "v0.23.0"
|
||||||
hash = "sha256-R3O9GyNtv6j0ic7s+2xkLLaLzbJEop0Otj1nJDFBjsg="
|
hash = "sha256-R3O9GyNtv6j0ic7s+2xkLLaLzbJEop0Otj1nJDFBjsg="
|
||||||
[mod."golang.org/x/crypto"]
|
[mod."golang.org/x/crypto"]
|
||||||
version = "v0.0.0-20220622213112-05595931fe9d"
|
version = "v0.3.0"
|
||||||
hash = "sha256-2c4wvwiQ0DJSJsApfmNoxCxx1siRCiJvW9hhrGlcvds="
|
hash = "sha256-Un9wPqz8u/xpV98T4IqE6RMXIPhGCIm2prsNkHP3cjg="
|
||||||
[mod."golang.org/x/exp"]
|
[mod."golang.org/x/exp"]
|
||||||
version = "v0.0.0-20220722155223-a9213eeb770e"
|
version = "v0.0.0-20220722155223-a9213eeb770e"
|
||||||
hash = "sha256-kNgzydWRpjm0sZl4uXEs3LX5L0xjJtJRAFf/CTlYUN4="
|
hash = "sha256-kNgzydWRpjm0sZl4uXEs3LX5L0xjJtJRAFf/CTlYUN4="
|
||||||
[mod."golang.org/x/net"]
|
[mod."golang.org/x/net"]
|
||||||
version = "v0.0.0-20220726230323-06994584191e"
|
version = "v0.4.0"
|
||||||
hash = "sha256-VFJB2BjvFZnp0zoJLX4iinV/P6Cn7XUlsKwBGCdVjlU="
|
hash = "sha256-7IwGZh/xg4mQz88cJio2Ov5d3jGRXKj1itlAja/EAbQ="
|
||||||
[mod."golang.org/x/oauth2"]
|
[mod."golang.org/x/oauth2"]
|
||||||
version = "v0.0.0-20220622183110-fd043fe589d2"
|
version = "v0.0.0-20221014153046-6fdb5e3db783"
|
||||||
hash = "sha256-VLffpTpx3DlUzXB8mKiJfFzm4ZmgnLSUuLB5Ir0WQUg="
|
hash = "sha256-IoygidVNqyAZmN+3macDeIefK8hhJToygpcqlwehdYQ="
|
||||||
[mod."golang.org/x/sync"]
|
[mod."golang.org/x/sync"]
|
||||||
version = "v0.0.0-20220722155255-886fb9371eb4"
|
version = "v0.1.0"
|
||||||
hash = "sha256-ZZyIlxh+nqsOiWHstW7eHXN7RhHnbSL2eDIzcve07Q0="
|
hash = "sha256-Hygjq9euZ0qz6TvHYQwOZEjNiTbTh1nSLRAWZ6KFGR8="
|
||||||
[mod."golang.org/x/sys"]
|
[mod."golang.org/x/sys"]
|
||||||
version = "v0.0.0-20220811171246-fbc7d0a398ab"
|
version = "v0.3.0"
|
||||||
hash = "sha256-acnc9aKY/SyebObLasV+gowfB0S+6ehz3hnUgAmQmSU="
|
hash = "sha256-TIHhfYbZ99sCU1ZMikxwomXH5AEtD/lA1VMMW+UAhbU="
|
||||||
[mod."golang.org/x/term"]
|
[mod."golang.org/x/term"]
|
||||||
version = "v0.0.0-20220722155259-a9ba230a4035"
|
version = "v0.3.0"
|
||||||
hash = "sha256-9uM1OONzbsa6bz2iKk767hAaCuafi58bdTF7at03fWY="
|
hash = "sha256-NKv2o8wz8DB/2W2h/muGEIHb+S06mBXZxhG254RpQ5s="
|
||||||
[mod."golang.org/x/text"]
|
[mod."golang.org/x/text"]
|
||||||
version = "v0.3.7"
|
version = "v0.5.0"
|
||||||
hash = "sha256-XH2pUzzQx95O0rak00grQvfACfL+EmZiV7ZzJBkX+XY="
|
hash = "sha256-ztH+xQyM/clOcQl+y/UEPcfNKbc3xApMbEPDDZ9up0o="
|
||||||
[mod."golang.org/x/xerrors"]
|
[mod."golang.org/x/xerrors"]
|
||||||
version = "v0.0.0-20220609144429-65e65417b02f"
|
version = "v0.0.0-20220907171357-04be3eba64a2"
|
||||||
hash = "sha256-tl8pv3oddbz2+KoIp7PFDKsxjQF8ocjPF8XPsY3sw38="
|
hash = "sha256-6+zueutgefIYmgXinOflz8qGDDDj0Zhv+2OkGhBTKno="
|
||||||
[mod."google.golang.org/api"]
|
[mod."google.golang.org/api"]
|
||||||
version = "v0.93.0"
|
version = "v0.102.0"
|
||||||
hash = "sha256-W17B79osAhObMbrCHlgywEPg9yIPx0ZISDhp9JwFE5A="
|
hash = "sha256-q8t08Wu0qzOQOmhY4GSoUrhqLTW/TeXiKhio+5ONfe4="
|
||||||
[mod."google.golang.org/appengine"]
|
[mod."google.golang.org/appengine"]
|
||||||
version = "v1.6.7"
|
version = "v1.6.7"
|
||||||
hash = "sha256-zIxGRHiq4QBvRqkrhMGMGCaVL4iM4TtlYpAi/hrivS4="
|
hash = "sha256-zIxGRHiq4QBvRqkrhMGMGCaVL4iM4TtlYpAi/hrivS4="
|
||||||
[mod."google.golang.org/genproto"]
|
[mod."google.golang.org/genproto"]
|
||||||
version = "v0.0.0-20220815135757-37a418bb8959"
|
version = "v0.0.0-20221116193143-41c2ba794472"
|
||||||
hash = "sha256-uS60VVZDdn6kNV24bmOmSTuwz4lBqVM+9XK176GGL2s="
|
hash = "sha256-uQuxuOvWRsdMii5M5QresisVd1E+Ss8s2WfR2n7QSXk="
|
||||||
[mod."google.golang.org/grpc"]
|
[mod."google.golang.org/grpc"]
|
||||||
version = "v1.49.0"
|
version = "v1.51.0"
|
||||||
hash = "sha256-x4+/XjxI2HY8fZYMiEV7Kv+2SrnlmaTJX3tBl+dPUoI="
|
hash = "sha256-RzH5DU13D/ulxxOouIKpdNt8eHdff7mrEnB+JUupbLU="
|
||||||
[mod."google.golang.org/protobuf"]
|
[mod."google.golang.org/protobuf"]
|
||||||
version = "v1.28.1"
|
version = "v1.28.2-0.20220831092852-f930b1dc76e8"
|
||||||
hash = "sha256-sTJYgvlv5is7vHNxcuigF2lNASp0QonhUgnrguhfHSU="
|
hash = "sha256-li5hXlXwTJ5LIZ8bVki1AZ6UFI2gXHl33JwdX1dOrtM="
|
||||||
[mod."gopkg.in/ini.v1"]
|
[mod."gopkg.in/ini.v1"]
|
||||||
version = "v1.67.0"
|
version = "v1.67.0"
|
||||||
hash = "sha256-V10ahGNGT+NLRdKUyRg1dos5RxLBXBk1xutcnquc/+4="
|
hash = "sha256-V10ahGNGT+NLRdKUyRg1dos5RxLBXBk1xutcnquc/+4="
|
||||||
@ -537,6 +607,9 @@ schema = 3
|
|||||||
[mod."gopkg.in/yaml.v3"]
|
[mod."gopkg.in/yaml.v3"]
|
||||||
version = "v3.0.1"
|
version = "v3.0.1"
|
||||||
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
|
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
|
||||||
|
[mod."lukechampine.com/blake3"]
|
||||||
|
version = "v1.1.6"
|
||||||
|
hash = "sha256-pKVTpuCcqGSn8s11Jq33yrXewQLvycuAoxKJEdbZ7rA="
|
||||||
[mod."nhooyr.io/websocket"]
|
[mod."nhooyr.io/websocket"]
|
||||||
version = "v1.8.6"
|
version = "v1.8.6"
|
||||||
hash = "sha256-DyaiCc/1iELrl6JSpz6WYMtFwUiSCOSoNF8IhSyP1ag="
|
hash = "sha256-DyaiCc/1iELrl6JSpz6WYMtFwUiSCOSoNF8IhSyP1ag="
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
# Reference to another record.
|
# Reference to another record.
|
||||||
type Reference {
|
scalar Link
|
||||||
id: String! # ID of linked record.
|
|
||||||
}
|
|
||||||
|
|
||||||
# Reference to another record.
|
|
||||||
input ReferenceInput {
|
|
||||||
id: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
# Bonds contain funds that are used to pay rent on record registration and renewal.
|
# Bonds contain funds that are used to pay rent on record registration and renewal.
|
||||||
type Bond {
|
type Bond {
|
||||||
@ -37,44 +30,71 @@ type Account {
|
|||||||
balance: [Coin!] # Current balance for each coin type.
|
balance: [Coin!] # Current balance for each coin type.
|
||||||
}
|
}
|
||||||
|
|
||||||
# Value of a given type.
|
# Value describes a DAG-JSON compatible value.
|
||||||
type Value {
|
union Value =
|
||||||
null: Boolean
|
BooleanValue
|
||||||
|
| IntValue
|
||||||
|
| FloatValue
|
||||||
|
| StringValue
|
||||||
|
| BytesValue
|
||||||
|
| LinkValue
|
||||||
|
| ArrayValue
|
||||||
|
| MapValue
|
||||||
|
|
||||||
int: Int
|
type BooleanValue {
|
||||||
float: Float
|
value: Boolean!
|
||||||
string: String
|
|
||||||
boolean: Boolean
|
|
||||||
json: String
|
|
||||||
|
|
||||||
reference: Reference
|
|
||||||
|
|
||||||
values: [Value]
|
|
||||||
}
|
}
|
||||||
# Value of a given type used as input to queries.
|
|
||||||
input ValueInput {
|
|
||||||
null: Boolean
|
|
||||||
|
|
||||||
int: Int
|
type IntValue {
|
||||||
float: Float
|
value: Int!
|
||||||
string: String
|
}
|
||||||
boolean: Boolean
|
|
||||||
|
|
||||||
reference: ReferenceInput
|
type FloatValue {
|
||||||
|
value: Float!
|
||||||
|
}
|
||||||
|
|
||||||
values: [ValueInput]
|
type StringValue {
|
||||||
|
value: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type BytesValue {
|
||||||
|
value: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayValue {
|
||||||
|
value: [Value]!
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinkValue {
|
||||||
|
value: Link!
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapValue {
|
||||||
|
value: [Attribute!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
# Key/value pair.
|
# Key/value pair.
|
||||||
type KeyValue {
|
type Attribute {
|
||||||
key: String!
|
key: String!
|
||||||
value: Value!
|
value: Value
|
||||||
|
}
|
||||||
|
|
||||||
|
# Value of a given type used as input to queries.
|
||||||
|
# Note: GQL doesn't allow union input types.
|
||||||
|
input ValueInput {
|
||||||
|
int: Int
|
||||||
|
float: Float
|
||||||
|
string: String
|
||||||
|
boolean: Boolean
|
||||||
|
link: Link
|
||||||
|
array: [ValueInput]
|
||||||
|
map: [KeyValueInput!]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Key/value pair for inputs.
|
# Key/value pair for inputs.
|
||||||
input KeyValueInput {
|
input KeyValueInput {
|
||||||
key: String!
|
key: String!
|
||||||
value: ValueInput!
|
value: ValueInput
|
||||||
}
|
}
|
||||||
|
|
||||||
# Status information about a node (https://docs.tendermint.com/master/rpc/#/Info/status).
|
# Status information about a node (https://docs.tendermint.com/master/rpc/#/Info/status).
|
||||||
@ -155,7 +175,7 @@ type Record {
|
|||||||
createTime: String! # Record create time.
|
createTime: String! # Record create time.
|
||||||
expiryTime: String! # Record expiry time.
|
expiryTime: String! # Record expiry time.
|
||||||
owners: [String!] # Addresses of record owners.
|
owners: [String!] # Addresses of record owners.
|
||||||
attributes: [KeyValue] # Record attributes.
|
attributes: [Attribute!] # Record attributes.
|
||||||
references: [Record] # Record references.
|
references: [Record] # Record references.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +215,7 @@ type Query {
|
|||||||
getBondsByIds(ids: [String!]): [Bond]
|
getBondsByIds(ids: [String!]): [Bond]
|
||||||
|
|
||||||
# Query bonds.
|
# Query bonds.
|
||||||
queryBonds(attributes: [KeyValueInput]): [Bond]
|
queryBonds(attributes: [KeyValueInput!]): [Bond]
|
||||||
|
|
||||||
# Query bonds by owner.
|
# Query bonds by owner.
|
||||||
queryBondsByOwner(ownerAddresses: [String!]): [OwnerBonds]
|
queryBondsByOwner(ownerAddresses: [String!]): [OwnerBonds]
|
||||||
@ -210,7 +230,7 @@ type Query {
|
|||||||
# Query records.
|
# Query records.
|
||||||
queryRecords(
|
queryRecords(
|
||||||
# Multiple attribute conditions are in a logical AND.
|
# Multiple attribute conditions are in a logical AND.
|
||||||
attributes: [KeyValueInput]
|
attributes: [KeyValueInput!]
|
||||||
|
|
||||||
# Whether to query all records, not just named ones (false by default).
|
# Whether to query all records, not just named ones (false by default).
|
||||||
all: Boolean
|
all: Boolean
|
9880
gql/generated.go
9880
gql/generated.go
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,3 @@
|
|||||||
# .gqlgen.yml example
|
|
||||||
#
|
|
||||||
# Refer to https://gqlgen.com/config/
|
# Refer to https://gqlgen.com/config/
|
||||||
# for detailed .gqlgen.yml documentation.
|
# for detailed .gqlgen.yml documentation.
|
||||||
|
|
||||||
@ -12,3 +10,8 @@ model:
|
|||||||
resolver:
|
resolver:
|
||||||
filename: resolver.go
|
filename: resolver.go
|
||||||
type: Resolver
|
type: Resolver
|
||||||
|
|
||||||
|
models:
|
||||||
|
Link:
|
||||||
|
model:
|
||||||
|
- github.com/cerc-io/laconicd/gql.Link
|
||||||
|
165
gql/graphiql.go
Normal file
165
gql/graphiql.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package gql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GraphiQL is an in-browser IDE for exploring GraphiQL APIs.
|
||||||
|
// This handler returns GraphiQL when requested.
|
||||||
|
//
|
||||||
|
// For more information, see https://github.com/graphql/graphiql.
|
||||||
|
|
||||||
|
func PlaygroundHandler(apiURL string) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "only GET requests are supported", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "text/html")
|
||||||
|
err := page.Execute(w, map[string]interface{}{
|
||||||
|
"apiURL": apiURL,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/graphql/graphiql/blob/main/examples/graphiql-cdn/index.html
|
||||||
|
var page = template.Must(template.New("graphiql").Parse(`
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>GraphiQL</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#graphiql {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This GraphiQL example depends on Promise and fetch, which are available in
|
||||||
|
modern browsers, but can be "polyfilled" for older browsers.
|
||||||
|
GraphiQL itself depends on React DOM.
|
||||||
|
If you do not want to rely on a CDN, you can host these files locally or
|
||||||
|
include them directly in your favored resource bundler.
|
||||||
|
-->
|
||||||
|
<script
|
||||||
|
src="https://unpkg.com/react@17/umd/react.development.js"
|
||||||
|
integrity="sha512-Vf2xGDzpqUOEIKO+X2rgTLWPY+65++WPwCHkX2nFMu9IcstumPsf/uKKRd5prX3wOu8Q0GBylRpsDB26R6ExOg=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"
|
||||||
|
integrity="sha512-Wr9OKCTtq1anK0hq5bY3X/AvDI5EflDSAh0mE9gma+4hl+kXdTJPKZ3TwLMBcrgUeoY0s3dq9JjhCQc7vddtFg=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
These two files can be found in the npm module, however you may wish to
|
||||||
|
copy them directly into your environment, or perhaps include them in your
|
||||||
|
favored resource bundler.
|
||||||
|
-->
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/graphiql/graphiql.min.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="graphiql">Loading...</div>
|
||||||
|
<script
|
||||||
|
src="https://unpkg.com/graphiql/graphiql.min.js"
|
||||||
|
type="application/javascript"
|
||||||
|
></script>
|
||||||
|
<script>
|
||||||
|
// https://github.com/graphql/graphiql/blob/main/packages/graphiql/resources/renderExample.js
|
||||||
|
|
||||||
|
// Parse the search string to get url parameters.
|
||||||
|
var search = window.location.search;
|
||||||
|
var parameters = {};
|
||||||
|
search
|
||||||
|
.substr(1)
|
||||||
|
.split('&')
|
||||||
|
.forEach(function (entry) {
|
||||||
|
var eq = entry.indexOf('=');
|
||||||
|
if (eq >= 0) {
|
||||||
|
parameters[decodeURIComponent(entry.slice(0, eq))] = decodeURIComponent(
|
||||||
|
entry.slice(eq + 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// When the query and variables string is edited, update the URL bar so
|
||||||
|
// that it can be easily shared.
|
||||||
|
function onEditQuery(newQuery) {
|
||||||
|
parameters.query = newQuery;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEditVariables(newVariables) {
|
||||||
|
parameters.variables = newVariables;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEditHeaders(newHeaders) {
|
||||||
|
parameters.headers = newHeaders;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTabChange(tabsState) {
|
||||||
|
const activeTab = tabsState.tabs[tabsState.activeTabIndex];
|
||||||
|
parameters.query = activeTab.query;
|
||||||
|
parameters.variables = activeTab.variables;
|
||||||
|
parameters.headers = activeTab.headers;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateURL() {
|
||||||
|
var newSearch =
|
||||||
|
'?' +
|
||||||
|
Object.keys(parameters)
|
||||||
|
.filter(function (key) {
|
||||||
|
return Boolean(parameters[key]);
|
||||||
|
})
|
||||||
|
.map(function (key) {
|
||||||
|
return (
|
||||||
|
encodeURIComponent(key) + '=' + encodeURIComponent(parameters[key])
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.join('&');
|
||||||
|
history.replaceState(null, null, newSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render <GraphiQL /> into the body.
|
||||||
|
// See the README in the top level of this module to learn more about
|
||||||
|
// how you can customize GraphiQL by providing different values or
|
||||||
|
// additional child elements.
|
||||||
|
ReactDOM.render(
|
||||||
|
React.createElement(GraphiQL, {
|
||||||
|
fetcher: GraphiQL.createFetcher({
|
||||||
|
url: {{.apiURL}}
|
||||||
|
}),
|
||||||
|
query: parameters.query,
|
||||||
|
variables: parameters.variables,
|
||||||
|
headers: parameters.headers,
|
||||||
|
defaultHeaders: parameters.defaultHeaders,
|
||||||
|
onEditQuery: onEditQuery,
|
||||||
|
onEditVariables: onEditVariables,
|
||||||
|
onEditHeaders: onEditHeaders,
|
||||||
|
defaultEditorToolsVisibility: true,
|
||||||
|
isHeadersEditorEnabled: true,
|
||||||
|
shouldPersistHeaders: true,
|
||||||
|
onTabChange,
|
||||||
|
}),
|
||||||
|
document.getElementById('graphiql'),
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`))
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
package gql
|
package gql
|
||||||
|
|
||||||
|
type Value interface {
|
||||||
|
IsValue()
|
||||||
|
}
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
PubKey *string `json:"pubKey"`
|
PubKey *string `json:"pubKey"`
|
||||||
@ -10,6 +14,17 @@ type Account struct {
|
|||||||
Balance []*Coin `json:"balance"`
|
Balance []*Coin `json:"balance"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ArrayValue struct {
|
||||||
|
Value []Value `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ArrayValue) IsValue() {}
|
||||||
|
|
||||||
|
type Attribute struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value Value `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
type Auction struct {
|
type Auction struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
@ -53,21 +68,52 @@ type Bond struct {
|
|||||||
Balance []*Coin `json:"balance"`
|
Balance []*Coin `json:"balance"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BooleanValue struct {
|
||||||
|
Value bool `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (BooleanValue) IsValue() {}
|
||||||
|
|
||||||
|
type BytesValue struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (BytesValue) IsValue() {}
|
||||||
|
|
||||||
type Coin struct {
|
type Coin struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Quantity string `json:"quantity"`
|
Quantity string `json:"quantity"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyValue struct {
|
type FloatValue struct {
|
||||||
Key string `json:"key"`
|
Value float64 `json:"value"`
|
||||||
Value *Value `json:"value"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (FloatValue) IsValue() {}
|
||||||
|
|
||||||
|
type IntValue struct {
|
||||||
|
Value int `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (IntValue) IsValue() {}
|
||||||
|
|
||||||
type KeyValueInput struct {
|
type KeyValueInput struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Value *ValueInput `json:"value"`
|
Value *ValueInput `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LinkValue struct {
|
||||||
|
Value Link `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (LinkValue) IsValue() {}
|
||||||
|
|
||||||
|
type MapValue struct {
|
||||||
|
Value []*Attribute `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (MapValue) IsValue() {}
|
||||||
|
|
||||||
type NameRecord struct {
|
type NameRecord struct {
|
||||||
Latest *NameRecordEntry `json:"latest"`
|
Latest *NameRecordEntry `json:"latest"`
|
||||||
History []*NameRecordEntry `json:"history"`
|
History []*NameRecordEntry `json:"history"`
|
||||||
@ -102,18 +148,10 @@ type Record struct {
|
|||||||
CreateTime string `json:"createTime"`
|
CreateTime string `json:"createTime"`
|
||||||
ExpiryTime string `json:"expiryTime"`
|
ExpiryTime string `json:"expiryTime"`
|
||||||
Owners []string `json:"owners"`
|
Owners []string `json:"owners"`
|
||||||
Attributes []*KeyValue `json:"attributes"`
|
Attributes []*Attribute `json:"attributes"`
|
||||||
References []*Record `json:"references"`
|
References []*Record `json:"references"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Reference struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReferenceInput struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Node *NodeInfo `json:"node"`
|
Node *NodeInfo `json:"node"`
|
||||||
@ -125,6 +163,12 @@ type Status struct {
|
|||||||
DiskUsage string `json:"disk_usage"`
|
DiskUsage string `json:"disk_usage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StringValue struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (StringValue) IsValue() {}
|
||||||
|
|
||||||
type SyncInfo struct {
|
type SyncInfo struct {
|
||||||
LatestBlockHash string `json:"latest_block_hash"`
|
LatestBlockHash string `json:"latest_block_hash"`
|
||||||
LatestBlockHeight string `json:"latest_block_height"`
|
LatestBlockHeight string `json:"latest_block_height"`
|
||||||
@ -138,23 +182,12 @@ type ValidatorInfo struct {
|
|||||||
ProposerPriority *string `json:"proposer_priority"`
|
ProposerPriority *string `json:"proposer_priority"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Value struct {
|
|
||||||
Null *bool `json:"null"`
|
|
||||||
Int *int `json:"int"`
|
|
||||||
Float *float64 `json:"float"`
|
|
||||||
String *string `json:"string"`
|
|
||||||
Boolean *bool `json:"boolean"`
|
|
||||||
JSON *string `json:"json"`
|
|
||||||
Reference *Reference `json:"reference"`
|
|
||||||
Values []*Value `json:"values"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ValueInput struct {
|
type ValueInput struct {
|
||||||
Null *bool `json:"null"`
|
|
||||||
Int *int `json:"int"`
|
Int *int `json:"int"`
|
||||||
Float *float64 `json:"float"`
|
Float *float64 `json:"float"`
|
||||||
String *string `json:"string"`
|
String *string `json:"string"`
|
||||||
Boolean *bool `json:"boolean"`
|
Boolean *bool `json:"boolean"`
|
||||||
Reference *ReferenceInput `json:"reference"`
|
Link *Link `json:"link"`
|
||||||
Values []*ValueInput `json:"values"`
|
Array []*ValueInput `json:"array"`
|
||||||
|
Map []*KeyValueInput `json:"map"`
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ func (q queryResolver) QueryRecords(ctx context.Context, attributes []*KeyValueI
|
|||||||
res, err := nsQueryClient.ListRecords(
|
res, err := nsQueryClient.ListRecords(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
®istrytypes.QueryListRecordsRequest{
|
®istrytypes.QueryListRecordsRequest{
|
||||||
Attributes: parseRequestAttributes(attributes),
|
Attributes: toRPCAttributes(attributes),
|
||||||
All: (all != nil && *all),
|
All: (all != nil && *all),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
33
gql/scalar.go
Normal file
33
gql/scalar.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package gql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Represents an IPLD link. Links are generally but not necessarily implemented as CIDs
|
||||||
|
type Link string
|
||||||
|
|
||||||
|
func (l Link) String() string {
|
||||||
|
return string(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalGQLContext implements the graphql.ContextUnmarshaler interface
|
||||||
|
func (l *Link) UnmarshalGQLContext(_ context.Context, v interface{}) error {
|
||||||
|
s, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Link must be a string")
|
||||||
|
}
|
||||||
|
*l = Link(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalGQLContext implements the graphql.ContextMarshaler interface
|
||||||
|
func (l Link) MarshalGQLContext(_ context.Context, w io.Writer) error {
|
||||||
|
encodable := map[string]string{
|
||||||
|
"/": l.String(),
|
||||||
|
}
|
||||||
|
return json.NewEncoder(w).Encode(encodable)
|
||||||
|
}
|
@ -5,9 +5,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql/handler"
|
"github.com/99designs/gqlgen/graphql/handler"
|
||||||
"github.com/99designs/gqlgen/graphql/playground"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/rs/cors"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,6 +17,16 @@ func Server(ctx client.Context) {
|
|||||||
if !viper.GetBool("gql-server") {
|
if !viper.GetBool("gql-server") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
router := chi.NewRouter()
|
||||||
|
|
||||||
|
// Add CORS middleware around every request
|
||||||
|
// See https://github.com/rs/cors for full option listing
|
||||||
|
router.Use(cors.New(cors.Options{
|
||||||
|
AllowedOrigins: []string{"*"},
|
||||||
|
Debug: false,
|
||||||
|
}).Handler)
|
||||||
|
|
||||||
logFile := viper.GetString("log-file")
|
logFile := viper.GetString("log-file")
|
||||||
|
|
||||||
port := viper.GetString("gql-port")
|
port := viper.GetString("gql-port")
|
||||||
@ -25,20 +36,20 @@ func Server(ctx client.Context) {
|
|||||||
logFile: logFile,
|
logFile: logFile,
|
||||||
}}))
|
}}))
|
||||||
|
|
||||||
http.Handle("/", playground.Handler("GraphQL playground", "/api"))
|
router.Handle("/", PlaygroundHandler("/api"))
|
||||||
|
|
||||||
if viper.GetBool("gql-playground") {
|
if viper.GetBool("gql-playground") {
|
||||||
apiBase := viper.GetString("gql-playground-api-base")
|
apiBase := viper.GetString("gql-playground-api-base")
|
||||||
|
|
||||||
http.Handle("/webui", playground.Handler("GraphQL playground", apiBase+"/api"))
|
router.Handle("/webui", PlaygroundHandler(apiBase+"/api"))
|
||||||
http.Handle("/console", playground.Handler("GraphQL playground", apiBase+"/graphql"))
|
router.Handle("/console", PlaygroundHandler(apiBase+"/graphql"))
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Handle("/api", srv)
|
router.Handle("/api", srv)
|
||||||
http.Handle("/graphql", srv)
|
router.Handle("/graphql", srv)
|
||||||
|
|
||||||
log.Info("Connect to GraphQL playground", "url", fmt.Sprintf("http://localhost:%s", port))
|
log.Info("Connect to GraphQL playground", "url", fmt.Sprintf("http://localhost:%s", port))
|
||||||
err := http.ListenAndServe(":"+port, nil) //nolint: all
|
err := http.ListenAndServe(":"+port, router) //nolint: all
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
254
gql/util.go
254
gql/util.go
@ -2,15 +2,15 @@ package gql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"fmt" // #nosec G702
|
||||||
"fmt"
|
|
||||||
"reflect" // #nosec G702
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
auctiontypes "github.com/cerc-io/laconicd/x/auction/types"
|
auctiontypes "github.com/cerc-io/laconicd/x/auction/types"
|
||||||
bondtypes "github.com/cerc-io/laconicd/x/bond/types"
|
bondtypes "github.com/cerc-io/laconicd/x/bond/types"
|
||||||
registrytypes "github.com/cerc-io/laconicd/x/registry/types"
|
registrytypes "github.com/cerc-io/laconicd/x/registry/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/ipld/go-ipld-prime"
|
||||||
|
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OwnerAttributeName denotes the owner attribute name for a bond.
|
// OwnerAttributeName denotes the owner attribute name for a bond.
|
||||||
@ -61,13 +61,21 @@ func getGQLRecord(ctx context.Context, resolver QueryResolver, record registryty
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
recordType := record.ToRecordType()
|
node, err := ipld.Decode(record.Attributes, dagjson.Decode)
|
||||||
attributes, err := getAttributes(&recordType)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if node.Kind() != ipld.Kind_Map {
|
||||||
|
return nil, fmt.Errorf("invalid record attributes")
|
||||||
|
}
|
||||||
|
|
||||||
|
var links []string
|
||||||
|
attributes, err := resolveIPLDNode(node, &links)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
references, err := getReferences(ctx, resolver, &recordType)
|
references, err := resolver.GetRecordsByIds(ctx, links)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -79,11 +87,96 @@ func getGQLRecord(ctx context.Context, resolver QueryResolver, record registryty
|
|||||||
ExpiryTime: record.GetExpiryTime(),
|
ExpiryTime: record.GetExpiryTime(),
|
||||||
Owners: record.GetOwners(),
|
Owners: record.GetOwners(),
|
||||||
Names: record.GetNames(),
|
Names: record.GetNames(),
|
||||||
Attributes: attributes,
|
Attributes: attributes.(MapValue).Value,
|
||||||
References: references,
|
References: references,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
|
||||||
|
switch node.Kind() {
|
||||||
|
case ipld.Kind_Map:
|
||||||
|
var entries []*Attribute
|
||||||
|
for itr := node.MapIterator(); !itr.Done(); {
|
||||||
|
k, v, err := itr.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if k.Kind() != ipld.Kind_String {
|
||||||
|
return nil, fmt.Errorf("invalid record attribute key type: %s", k.Kind())
|
||||||
|
}
|
||||||
|
s, err := k.AsString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
val, err := resolveIPLDNode(v, links)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries = append(entries, &Attribute{
|
||||||
|
Key: s,
|
||||||
|
Value: val,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return MapValue{entries}, nil
|
||||||
|
case ipld.Kind_List:
|
||||||
|
var values []Value
|
||||||
|
for itr := node.ListIterator(); !itr.Done(); {
|
||||||
|
_, v, err := itr.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
val, err := resolveIPLDNode(v, links)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
values = append(values, val)
|
||||||
|
}
|
||||||
|
return ArrayValue{values}, nil
|
||||||
|
case ipld.Kind_Null:
|
||||||
|
return nil, nil
|
||||||
|
case ipld.Kind_Bool:
|
||||||
|
val, err := node.AsBool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return BooleanValue{val}, nil
|
||||||
|
case ipld.Kind_Int:
|
||||||
|
val, err := node.AsInt()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// TODO: handle bigger ints
|
||||||
|
return IntValue{int(val)}, nil
|
||||||
|
case ipld.Kind_Float:
|
||||||
|
val, err := node.AsFloat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return FloatValue{val}, nil
|
||||||
|
case ipld.Kind_String:
|
||||||
|
val, err := node.AsString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return StringValue{val}, nil
|
||||||
|
case ipld.Kind_Bytes:
|
||||||
|
val, err := node.AsBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return BytesValue{string(val)}, nil
|
||||||
|
case ipld.Kind_Link:
|
||||||
|
val, err := node.AsLink()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
*links = append(*links, val.String())
|
||||||
|
return LinkValue{Link(val.String())}, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid node kind")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getGQLNameRecord(record *registrytypes.NameRecord) (*NameRecord, error) {
|
func getGQLNameRecord(record *registrytypes.NameRecord) (*NameRecord, error) {
|
||||||
if record == nil {
|
if record == nil {
|
||||||
return nil, fmt.Errorf("got nil record")
|
return nil, fmt.Errorf("got nil record")
|
||||||
@ -163,136 +256,47 @@ func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*Au
|
|||||||
return &gqlAuction, nil
|
return &gqlAuction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getReferences(ctx context.Context, resolver QueryResolver, r *registrytypes.RecordType) ([]*Record, error) {
|
func toRPCValue(value *ValueInput) *registrytypes.QueryListRecordsRequest_ValueInput {
|
||||||
var ids []string
|
var rpcval registrytypes.QueryListRecordsRequest_ValueInput
|
||||||
|
|
||||||
// #nosec G705
|
switch {
|
||||||
for key := range r.Attributes {
|
case value == nil:
|
||||||
//nolint: all
|
return nil
|
||||||
switch r.Attributes[key].(type) {
|
case value.Int != nil:
|
||||||
case interface{}:
|
rpcval.Value = ®istrytypes.QueryListRecordsRequest_ValueInput_Int{Int: int64(*value.Int)}
|
||||||
if obj, ok := r.Attributes[key].(map[string]interface{}); ok {
|
case value.Float != nil:
|
||||||
if _, ok := obj["/"]; ok && len(obj) == 1 {
|
rpcval.Value = ®istrytypes.QueryListRecordsRequest_ValueInput_Float{Float: *value.Float}
|
||||||
if _, ok := obj["/"].(string); ok {
|
case value.String != nil:
|
||||||
ids = append(ids, obj["/"].(string))
|
rpcval.Value = ®istrytypes.QueryListRecordsRequest_ValueInput_String_{String_: *value.String}
|
||||||
}
|
case value.Boolean != nil:
|
||||||
|
rpcval.Value = ®istrytypes.QueryListRecordsRequest_ValueInput_Boolean{Boolean: *value.Boolean}
|
||||||
|
case value.Link != nil:
|
||||||
|
rpcval.Value = ®istrytypes.QueryListRecordsRequest_ValueInput_Link{Link: value.Link.String()}
|
||||||
|
case value.Array != nil:
|
||||||
|
var contents registrytypes.QueryListRecordsRequest_ArrayInput
|
||||||
|
for _, val := range value.Array {
|
||||||
|
contents.Values = append(contents.Values, toRPCValue(val))
|
||||||
}
|
}
|
||||||
|
rpcval.Value = ®istrytypes.QueryListRecordsRequest_ValueInput_Array{Array: &contents}
|
||||||
|
case value.Map != nil:
|
||||||
|
var contents registrytypes.QueryListRecordsRequest_MapInput
|
||||||
|
for _, kv := range value.Map {
|
||||||
|
contents.Values[kv.Key] = toRPCValue(kv.Value)
|
||||||
}
|
}
|
||||||
|
rpcval.Value = ®istrytypes.QueryListRecordsRequest_ValueInput_Map{Map: &contents}
|
||||||
}
|
}
|
||||||
|
return &rpcval
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolver.GetRecordsByIds(ctx, ids)
|
func toRPCAttributes(attrs []*KeyValueInput) []*registrytypes.QueryListRecordsRequest_KeyValueInput {
|
||||||
}
|
|
||||||
|
|
||||||
func getAttributes(r *registrytypes.RecordType) ([]*KeyValue, error) {
|
|
||||||
return mapToKeyValuePairs(r.Attributes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mapToKeyValuePairs(attrs map[string]interface{}) ([]*KeyValue, error) {
|
|
||||||
kvPairs := []*KeyValue{}
|
|
||||||
|
|
||||||
trueVal := true
|
|
||||||
falseVal := false
|
|
||||||
|
|
||||||
// #nosec G705
|
|
||||||
for key, value := range attrs {
|
|
||||||
kvPair := &KeyValue{
|
|
||||||
Key: key,
|
|
||||||
Value: &Value{},
|
|
||||||
}
|
|
||||||
|
|
||||||
switch val := value.(type) {
|
|
||||||
case nil:
|
|
||||||
kvPair.Value.Null = &trueVal
|
|
||||||
case int:
|
|
||||||
kvPair.Value.Int = &val
|
|
||||||
case float64:
|
|
||||||
kvPair.Value.Float = &val
|
|
||||||
case string:
|
|
||||||
kvPair.Value.String = &val
|
|
||||||
case bool:
|
|
||||||
kvPair.Value.Boolean = &val
|
|
||||||
case interface{}:
|
|
||||||
if obj, ok := value.(map[string]interface{}); ok {
|
|
||||||
if _, ok := obj["/"]; ok && len(obj) == 1 {
|
|
||||||
if _, ok := obj["/"].(string); ok {
|
|
||||||
kvPair.Value.Reference = &Reference{
|
|
||||||
ID: obj["/"].(string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bytes, err := json.Marshal(obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonStr := string(bytes)
|
|
||||||
kvPair.Value.JSON = &jsonStr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if kvPair.Value.Null == nil {
|
|
||||||
kvPair.Value.Null = &falseVal
|
|
||||||
}
|
|
||||||
|
|
||||||
valueType := reflect.ValueOf(value)
|
|
||||||
if valueType.Kind() == reflect.Slice {
|
|
||||||
bytes, err := json.Marshal(value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonStr := string(bytes)
|
|
||||||
kvPair.Value.JSON = &jsonStr
|
|
||||||
}
|
|
||||||
|
|
||||||
kvPairs = append(kvPairs, kvPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
return kvPairs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseRequestAttributes(attrs []*KeyValueInput) []*registrytypes.QueryListRecordsRequest_KeyValueInput {
|
|
||||||
kvPairs := []*registrytypes.QueryListRecordsRequest_KeyValueInput{}
|
kvPairs := []*registrytypes.QueryListRecordsRequest_KeyValueInput{}
|
||||||
|
|
||||||
for _, value := range attrs {
|
for _, value := range attrs {
|
||||||
|
parsedValue := toRPCValue(value.Value)
|
||||||
kvPair := ®istrytypes.QueryListRecordsRequest_KeyValueInput{
|
kvPair := ®istrytypes.QueryListRecordsRequest_KeyValueInput{
|
||||||
Key: value.Key,
|
Key: value.Key,
|
||||||
Value: ®istrytypes.QueryListRecordsRequest_ValueInput{},
|
Value: parsedValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
if value.Value.String != nil {
|
|
||||||
kvPair.Value.String_ = *value.Value.String
|
|
||||||
kvPair.Value.Type = "string"
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.Value.Int != nil {
|
|
||||||
kvPair.Value.Int = int64(*value.Value.Int)
|
|
||||||
kvPair.Value.Type = "int"
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.Value.Float != nil {
|
|
||||||
kvPair.Value.Float = *value.Value.Float
|
|
||||||
kvPair.Value.Type = "float"
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.Value.Boolean != nil {
|
|
||||||
kvPair.Value.Boolean = *value.Value.Boolean
|
|
||||||
kvPair.Value.Type = "boolean"
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.Value.Reference != nil {
|
|
||||||
reference := ®istrytypes.QueryListRecordsRequest_ReferenceInput{
|
|
||||||
Id: value.Value.Reference.ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
kvPair.Value.Reference = reference
|
|
||||||
kvPair.Value.Type = "reference"
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Handle arrays.
|
|
||||||
|
|
||||||
kvPairs = append(kvPairs, kvPair)
|
kvPairs = append(kvPairs, kvPair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@ package indexer
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
errorsmod "cosmossdk.io/errors"
|
||||||
rpctypes "github.com/cerc-io/laconicd/rpc/types"
|
rpctypes "github.com/cerc-io/laconicd/rpc/types"
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
||||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
@ -110,12 +110,12 @@ func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.Response
|
|||||||
ethTxIndex++
|
ethTxIndex++
|
||||||
|
|
||||||
if err := saveTxResult(kv.clientCtx.Codec, batch, txHash, &txResult); err != nil {
|
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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@ -134,14 +134,14 @@ func (kv *KVIndexer) FirstIndexedBlock() (int64, error) {
|
|||||||
func (kv *KVIndexer) GetByTxHash(hash common.Hash) (*ethermint.TxResult, error) {
|
func (kv *KVIndexer) GetByTxHash(hash common.Hash) (*ethermint.TxResult, error) {
|
||||||
bz, err := kv.db.Get(TxHashKey(hash))
|
bz, err := kv.db.Get(TxHashKey(hash))
|
||||||
if err != nil {
|
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 {
|
if len(bz) == 0 {
|
||||||
return nil, fmt.Errorf("tx not found, hash: %s", hash.Hex())
|
return nil, fmt.Errorf("tx not found, hash: %s", hash.Hex())
|
||||||
}
|
}
|
||||||
var txKey ethermint.TxResult
|
var txKey ethermint.TxResult
|
||||||
if err := kv.clientCtx.Codec.Unmarshal(bz, &txKey); err != nil {
|
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
|
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) {
|
func (kv *KVIndexer) GetByBlockAndIndex(blockNumber int64, txIndex int32) (*ethermint.TxResult, error) {
|
||||||
bz, err := kv.db.Get(TxIndexKey(blockNumber, txIndex))
|
bz, err := kv.db.Get(TxIndexKey(blockNumber, txIndex))
|
||||||
if err != nil {
|
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 {
|
if len(bz) == 0 {
|
||||||
return nil, fmt.Errorf("tx not found, block: %d, eth-index: %d", blockNumber, txIndex)
|
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) {
|
func LoadLastBlock(db dbm.DB) (int64, error) {
|
||||||
it, err := db.ReverseIterator([]byte{KeyPrefixTxIndex}, []byte{KeyPrefixTxIndex + 1})
|
it, err := db.ReverseIterator([]byte{KeyPrefixTxIndex}, []byte{KeyPrefixTxIndex + 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, sdkerrors.Wrap(err, "LoadLastBlock")
|
return 0, errorsmod.Wrap(err, "LoadLastBlock")
|
||||||
}
|
}
|
||||||
defer it.Close()
|
defer it.Close()
|
||||||
if !it.Valid() {
|
if !it.Valid() {
|
||||||
@ -187,7 +187,7 @@ func LoadLastBlock(db dbm.DB) (int64, error) {
|
|||||||
func LoadFirstBlock(db dbm.DB) (int64, error) {
|
func LoadFirstBlock(db dbm.DB) (int64, error) {
|
||||||
it, err := db.Iterator([]byte{KeyPrefixTxIndex}, []byte{KeyPrefixTxIndex + 1})
|
it, err := db.Iterator([]byte{KeyPrefixTxIndex}, []byte{KeyPrefixTxIndex + 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, sdkerrors.Wrap(err, "LoadFirstBlock")
|
return 0, errorsmod.Wrap(err, "LoadFirstBlock")
|
||||||
}
|
}
|
||||||
defer it.Close()
|
defer it.Close()
|
||||||
if !it.Valid() {
|
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 {
|
func saveTxResult(codec codec.Codec, batch dbm.Batch, txHash common.Hash, txResult *ethermint.TxResult) error {
|
||||||
bz := codec.MustMarshal(txResult)
|
bz := codec.MustMarshal(txResult)
|
||||||
if err := batch.Set(TxHashKey(txHash), bz); err != nil {
|
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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
2
init.bat
2
init.bat
@ -9,7 +9,7 @@ rem 3. add path C:\msys64\mingw64\bin
|
|||||||
rem C:\msys64\usr\bin
|
rem C:\msys64\usr\bin
|
||||||
|
|
||||||
set KEY="mykey"
|
set KEY="mykey"
|
||||||
set CHAINID="ethermint_9000-1"
|
set CHAINID="laconic_9000-1"
|
||||||
set MONIKER="localtestnet"
|
set MONIKER="localtestnet"
|
||||||
set KEYRING="test"
|
set KEYRING="test"
|
||||||
set KEYALGO="eth_secp256k1"
|
set KEYALGO="eth_secp256k1"
|
||||||
|
119
init.sh
119
init.sh
@ -1,22 +1,29 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
KEY="mykey"
|
KEY="mykey"
|
||||||
CHAINID="ethermint_9000-1"
|
CHAINID="laconic_9000-1"
|
||||||
MONIKER="localtestnet"
|
MONIKER="localtestnet"
|
||||||
KEYRING="test"
|
KEYRING="test"
|
||||||
KEYALGO="eth_secp256k1"
|
KEYALGO="eth_secp256k1"
|
||||||
LOGLEVEL="info"
|
LOGLEVEL="${LOGLEVEL:-info}"
|
||||||
# to trace evm
|
# trace evm
|
||||||
TRACE="--trace"
|
TRACE="--trace"
|
||||||
# TRACE=""
|
# TRACE=""
|
||||||
|
|
||||||
|
if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
|
||||||
# validate dependencies are installed
|
# validate dependencies are installed
|
||||||
command -v jq > /dev/null 2>&1 || { echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"; exit 1; }
|
command -v jq > /dev/null 2>&1 || {
|
||||||
|
echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# remove existing daemon and client
|
# remove existing daemon and client
|
||||||
rm -rf ~/.laconic*
|
rm -rf $HOME/.laconicd/*
|
||||||
|
rm -rf $HOME/.laconic/*
|
||||||
|
|
||||||
|
if [ -n "`which make`" ]; then
|
||||||
make install
|
make install
|
||||||
|
fi
|
||||||
|
|
||||||
laconicd config keyring-backend $KEYRING
|
laconicd config keyring-backend $KEYRING
|
||||||
laconicd config chain-id $CHAINID
|
laconicd config chain-id $CHAINID
|
||||||
@ -27,41 +34,46 @@ laconicd keys add $KEY --keyring-backend $KEYRING --algo $KEYALGO
|
|||||||
# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
|
# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
|
||||||
laconicd init $MONIKER --chain-id $CHAINID
|
laconicd init $MONIKER --chain-id $CHAINID
|
||||||
|
|
||||||
|
update_genesis() {
|
||||||
|
jq "$1" $HOME/.laconicd/config/genesis.json > $HOME/.laconicd/config/tmp_genesis.json &&
|
||||||
|
mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||||
|
}
|
||||||
|
|
||||||
# Change parameter token denominations to aphoton
|
# Change parameter token denominations to aphoton
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["staking"]["params"]["bond_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["staking"]["params"]["bond_denom"]="aphoton"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["crisis"]["constant_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["crisis"]["constant_fee"]["denom"]="aphoton"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["mint"]["params"]["mint_denom"]="aphoton"'
|
||||||
# Custom modules
|
# Custom modules
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["record_rent"]["denom"]="aphoton"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_rent"]["denom"]="aphoton"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"'
|
||||||
|
|
||||||
if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then
|
if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then
|
||||||
echo "Setting timers for expiry tests."
|
echo "Setting timers for expiry tests."
|
||||||
|
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["record_rent_duration"]="60s"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_grace_period"]="60s"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_rent_duration"]="60s"'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then
|
if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then
|
||||||
echo "Enabling auction and setting timers."
|
echo "Enabling auction and setting timers."
|
||||||
|
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_enabled"]=true' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_auction_enabled"]=true'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_rent_duration"]="60s"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="300s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_grace_period"]="300s"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commits_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_auction_commits_duration"]="60s"'
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveals_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.app_state["registry"]["params"]["authority_auction_reveals_duration"]="60s"'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# increase block time (?)
|
# increase block time (?)
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["time_iota_ms"]="1000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.consensus_params["block"]["time_iota_ms"]="1000"'
|
||||||
|
|
||||||
# Set gas limit in genesis
|
# Set gas limit in genesis
|
||||||
cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="10000000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
update_genesis '.consensus_params["block"]["max_gas"]="10000000"'
|
||||||
|
|
||||||
# disable produce empty block
|
# disable produce empty block
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
@ -70,28 +82,33 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
|
|||||||
sed -i 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
|
sed -i 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $1 == "pending" ]]; then
|
if [[ "$1" == "pending" ]]; then
|
||||||
|
alias sed-i="sed -i"
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
sed -i '' 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml
|
alias sed-i="sed -i ''"
|
||||||
sed -i '' 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i '' 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i '' 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i '' 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i '' 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i '' 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i '' 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i '' 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
else
|
|
||||||
sed -i 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
sed -i 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
|
||||||
fi
|
fi
|
||||||
|
sed-i \
|
||||||
|
-e 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' \
|
||||||
|
-e 's/timeout_propose = "3s"/timeout_propose = "30s"/g' \
|
||||||
|
-e 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' \
|
||||||
|
-e 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' \
|
||||||
|
-e 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' \
|
||||||
|
-e 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' \
|
||||||
|
-e 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' \
|
||||||
|
-e 's/timeout_commit = "5s"/timeout_commit = "150s"/g' \
|
||||||
|
-e 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' \
|
||||||
|
$HOME/.laconicd/config/config.toml
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable telemetry (prometheus metrics: http://localhost:1317/metrics?format=prometheus)
|
||||||
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
sed -i '' 's/enabled = false/enabled = true/g' $HOME/.laconicd/config/app.toml
|
||||||
|
sed -i '' 's/prometheus-retention-time = 0/prometheus-retention-time = 60/g' $HOME/.laconicd/config/app.toml
|
||||||
|
sed -i '' 's/prometheus = false/prometheus = true/g' $HOME/.laconicd/config/config.toml
|
||||||
|
else
|
||||||
|
sed -i 's/enabled = false/enabled = true/g' $HOME/.laconicd/config/app.toml
|
||||||
|
sed -i 's/prometheus-retention-time = 0/prometheus-retention-time = 60/g' $HOME/.laconicd/config/app.toml
|
||||||
|
sed -i 's/prometheus = false/prometheus = true/g' $HOME/.laconicd/config/config.toml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Allocate genesis accounts (cosmos formatted addresses)
|
# Allocate genesis accounts (cosmos formatted addresses)
|
||||||
@ -106,9 +123,19 @@ laconicd collect-gentxs
|
|||||||
# Run this to ensure everything worked and that the genesis file is setup correctly
|
# Run this to ensure everything worked and that the genesis file is setup correctly
|
||||||
laconicd validate-genesis
|
laconicd validate-genesis
|
||||||
|
|
||||||
if [[ $1 == "pending" ]]; then
|
if [[ "$1" == "pending" ]]; then
|
||||||
echo "pending mode is on, please wait for the first block committed."
|
echo "pending mode is on, please wait for the first block committed."
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
echo "Using existing database at $HOME/.laconicd. To replace, run '`basename $0` clean'"
|
||||||
|
fi
|
||||||
|
|
||||||
# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
|
# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
|
||||||
laconicd start --pruning=nothing --evm.tracer=json $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton --json-rpc.api eth,txpool,personal,net,debug,web3,miner --api.enable --gql-server --gql-playground
|
laconicd start \
|
||||||
|
--pruning=nothing \
|
||||||
|
--evm.tracer=json $TRACE \
|
||||||
|
--log_level $LOGLEVEL \
|
||||||
|
--minimum-gas-prices=0.0001aphoton \
|
||||||
|
--json-rpc.api eth,txpool,personal,net,debug,web3,miner \
|
||||||
|
--api.enable \
|
||||||
|
--gql-server --gql-playground
|
||||||
|
5
mlc_config.json
Normal file
5
mlc_config.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"retryOn429": true,
|
||||||
|
"retryCount": 3,
|
||||||
|
"fallbackRetryDelay": "20s"
|
||||||
|
}
|
@ -15,7 +15,7 @@ COPY . .
|
|||||||
RUN make build-linux
|
RUN make build-linux
|
||||||
|
|
||||||
# Final image
|
# Final image
|
||||||
FROM golang:1.18 as final
|
FROM golang:1.19 as final
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import sources.nixpkgs {
|
|||||||
dotenv = builtins.path { name = "dotenv"; path = ../scripts/.env; };
|
dotenv = builtins.path { name = "dotenv"; path = ../scripts/.env; };
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
(_: pkgs: { test-env = import ./testenv.nix { inherit pkgs; }; })
|
(_: pkgs: { test-env = pkgs.callPackage ./testenv.nix { }; })
|
||||||
(_: pkgs: {
|
(_: pkgs: {
|
||||||
cosmovisor = pkgs.buildGo118Module rec {
|
cosmovisor = pkgs.buildGo118Module rec {
|
||||||
name = "cosmovisor";
|
name = "cosmovisor";
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user