Compare commits

...

174 Commits

Author SHA1 Message Date
Julian Strobl
1dce252617
chore(sims): copy makefiles from cosmos-sdk (#495)
sources:
* https://github.com/cosmos/cosmos-sdk/blob/v0.47.14/Makefile
* https://github.com/cosmos/cosmos-sdk/blob/v0.47.14/contrib/devtools/Makefile

closes #483

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-12-16 09:15:49 +01:00
Jürgen Eckel
9ea03441d8
added testcase for distribution after req and resp (#493)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-11-29 15:55:55 +01:00
Jürgen Eckel
f6c9af77c0
fixed varialbe assignment addr vs tx id (#492)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-11-29 15:07:12 +01:00
Jürgen Eckel
41b5bf545f
Eckelj/distributions query (#491)
* added distributions query
* added test cases

---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
Co-authored-by: Julian Strobl <jmastr@mailbox.org>
2024-11-28 17:15:16 +01:00
Julian Strobl
75cb64de68
chore(deps): update cosmos-sdk to v0.47.14 (#489)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-27 12:03:02 +01:00
Jürgen Eckel
aec55171f9
every node needs a key pair (#488)
* added panic if there is no key pair that can be used for the node (keystore or trustwallet)
* renamed GetValidatorAddress to GetNodeAddress
* fixed lib/test/e2e failing test case. The issue is an internal race condition of the unit test network in case of 1 node. Moving to two nodes solves the issue with the test case. In case of 1 validator, the first chain interaction happens before the address environment variables are set

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-11-26 15:31:39 +01:00
Lorenz Herzberger
90381166e6
docs: update README.md with structure, testing and contributing sections (#482)
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-11-26 08:20:20 +01:00
Julian Strobl
de1546ebe3
refactor(lib): use planetmint-go v0.11.1 (#487)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-25 17:55:04 +01:00
Julian Strobl
8e87cd77db
refactor clients (#486)
* refactor(clients): into sub-packages
* refactor(clients): improve readability
  - add some error cases
* refactor(client): align naming with rddl claim client
  - rddl claim client is `RCClient`

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-21 10:13:42 +01:00
Jürgen Eckel
3cf3c67e08
Identify issues during DistributionResult calls (#484)
* added test case to cover and identifiy cases Distribution result caused creashes.
  e.g. "" is resolved as an address during DistributionResult this case is now covered.
  Hopefully, the test case will detect issues in the future
* added old initiator format to the test cases

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-11-20 13:54:13 +01:00
Julian Strobl
7538de159f
feat(log): force to log error object (#481)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-20 11:58:18 +01:00
Julian Strobl
94706c8f99
fix(dao): challenger and challengee can be empty (#480)
* put validator rewards into else case to protect the claim object against bogus values

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-11-20 10:45:21 +01:00
Julian Strobl
190f24a10b
refactor configs (#479)
* refactor(config): improve readability/maintainability
* refactor(lib): make config more readable

- export variables from struct
- lock/defer lock

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-19 09:44:53 +01:00
Lorenz Herzberger
de63f1dddc
remove client implementation to correct client after upgrade (#478)
* refactor: replace claim client with exported version
* refactor: replace shamir coordinator client with exported version
* chore: update rddl-claim-service/client dependency
* chore: update shamir-coordinator-service client

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-18 15:14:14 +01:00
Julian Strobl
186cab3356
refactor(mqtt): defer unlock where applicable (#477)
also directly return values instead of assigning them first.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-18 10:44:52 +01:00
Jürgen Eckel
ae086b9b37
using the defined function (#476)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-11-18 10:26:19 +01:00
Julian Strobl
b48432f541
refactor: reduce cognitive complexity (#475)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-18 10:14:11 +01:00
Julian Strobl
c507a3490e
chore(sonar): add util.go to exclusion
it was copied over from cosmos-sdk.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-15 16:10:12 +01:00
Julian Strobl
d6570c3e54
chore(sonar): add network.go to exclusion
it was copied over from cosmos-sdk.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-15 16:00:26 +01:00
Julian Strobl
fc91345ab9
chore(sonar): define a constant instead of duplicating literal (#474)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-15 13:01:43 +01:00
Jürgen Eckel
702b9d6f7e
* clear unresolved claims for the initiators as well (#473)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-11-15 12:15:23 +01:00
Julian Strobl
61adbc0a5d
feat(mqtt): start monitor after api server (#472)
* refactor(mqtt): load end of app.new
* feat(mqtt): switch to proper logging instance
* refactor(mqtt): dry
* refactor(mqtt): do not start log message with uppercase

closes #435

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-15 11:27:17 +01:00
Julian Strobl
6ddc07356e
fix(query): unknown flag: --page (#471)
some query commands use pagination when delivering results:
```
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
    return err
}
```
to be able to use this feature, we need to add pagination related flags
to the `cmd`.

* chore(lint): exclude query files from `dupl`

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-14 09:52:06 +01:00
Lorenz Herzberger
67453107d1
461 validator earn rewards for sending pop init successfully (#464)
* change: intitiator rewards are minted on InitPoP
* fix: split initiator, challenger and challengee reward amounts into different maps
* fix: expand error in logging
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-11-13 11:00:08 +01:00
Julian Strobl
0b0b1206ed
chore(deps): update go-utils and elements-rpc (#469)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-13 08:47:58 +01:00
Julian Strobl
bead62bd04
refactor(query): align with cosmos-sdk style (#466)
- use one `cmd.AddCommand(...)`
- sort commands
- use `GetCmd...` function name style

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-12 15:59:52 +01:00
Julian Strobl
8db682d994
feat(lint): replace deprecated exportloopref (#467)
with `copyloopvar`, which needs Go 1.22.

* chore(ci): bump go version to v1.22
* fix(ci): pin release pipeline to go v1.22

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-12 15:59:09 +01:00
Julian Strobl
72e36c11eb
fix(lint): remove inactivated execinquery (#468)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-12 11:27:04 +01:00
Lorenz Herzberger
0bd6964d3e
feat: add unresolved claim cleanup (#460)
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-11-07 09:51:06 +01:00
Lorenz Herzberger
764d1158dc
refactor: IsValidatorBlockProposer no longer accepts proposerAddress … (#458)
* refactor: IsValidatorBlockProposer no longer accepts proposerAddress because already given in ctx
* refactor: make use of ctx.BlockHeader().ProposerAddress to ensure correct Proposer
* fix: linter error because no longer in use* feat: add call logging to MQTT mock

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-11-05 07:59:34 +01:00
Lorenz Herzberger
0b17e93e9c
fix: remove error from valid check (#456) 2024-10-15 12:56:00 +02:00
Lorenz Herzberger
2a5b7c49c8
447 add validatoraddress getter to config (#449)
* feat: add GetValidatorAddress() to config
* feat: add GetDefaultValidatorRecord() to libConfig
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-10-02 13:52:26 +02:00
Lorenz Herzberger
72df3de139
fix: pop initiator is now validator address instead of blockProposer in order to not mixup rewards (#450)
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-10-02 10:36:08 +02:00
Lorenz Herzberger
dacd261df4
446 add command to initialize tw (#448)
* fix: use correct array index on OSCresponse.data
* feat: add trust-wallet initialize cmd
* feat: add trust-wallet keys subcommand
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-09-24 15:10:26 +02:00
Lorenz Herzberger
e404fef08b
Add occ signing to lib (#441)
* feat: add trustwallet signing to lib
* feat: add osc message sender to lib
* docs: update README
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-09-19 16:20:24 +02:00
Lorenz Herzberger
a7bb114301
chore: changed module param defaults to be more visible (#445)
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-09-19 15:41:44 +02:00
Lorenz Herzberger
975a1005b0
test: add additonal validatorPopReward reallocation test (#436)
* test: add additonal validatorPopReward reallocation test
* fix: linter & staticcheck errors
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-09-10 09:13:20 +02:00
Lorenz Herzberger
5d84ae6806
fix: ConsensusVersion on machine module (#432)
* fix: ConsensusVersion on machine module
* fix: use correct key to store activated ta counter on migration
---------
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-07-25 10:31:15 +02:00
Lorenz Herzberger
c2ef2b5924
feat: add QueryActiveTrustAnchorCount (#431)
* feat: add QueryActiveTrustAnchorCount
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-07-24 09:44:07 +02:00
Lorenz Herzberger
4c8427c3b1
426 add registered machine counter to machine module (#430)
* feat: add counter for activated TAs
* feat: add QueryActivatedTrustAnchorCount
* feat: add migration for activated ta counter
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-07-24 09:24:13 +02:00
Lorenz Herzberger
e06fc55630
427 add more details to machine not found error message (#429)
* fix: add more details to machine not found error
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-07-19 11:03:56 +02:00
Lorenz Herzberger
605b6c73d6
415 add validator pop reward amount to chain params (#420)
* feat: add validator pop reward as chain param
* feat: add store for challenge initiator reward amount indexed by height
* feat: add validator PoP reward calculation between distributions
* fix: remove paralleltest lint rule due to data race
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-07-18 10:34:50 +02:00
Julian Strobl
197ebe1279
chore: remove obsolete rpc config (#423)
this is handled by shamir coordinator now.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-07-03 10:39:05 +02:00
Lorenz Herzberger
3ffd9f96ef
chore: replace elementsd-connector with shamir-coordinator-client (#422)
* chore: replace elementsd-connector with shamir-coordinator-client
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-07-03 09:54:42 +02:00
Julian Strobl
d2def2b453
chore: remove obsolete config param (#417)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-06-27 15:16:52 +02:00
Lorenz Herzberger
a4c8c821d0
feat: add certs path and mtls setup for shamir coordinator client (#414)
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-06-27 10:09:34 +02:00
Lorenz Herzberger
7d87d662ea
feat: add shamir-coordinator-client for issuer wallet protection (#413)
* feat: add shamir-coordinator-client for issuer wallet protection
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-06-26 14:02:28 +02:00
dependabot[bot]
bd16b0a151
chore(deps): Bump github.com/cosmos/ibc-go/v7 in /lib (#360)
Bumps [github.com/cosmos/ibc-go/v7](https://github.com/cosmos/ibc-go) from 7.1.0 to 7.4.0.
- [Release notes](https://github.com/cosmos/ibc-go/releases)
- [Changelog](https://github.com/cosmos/ibc-go/blob/v7.4.0/CHANGELOG.md)
- [Commits](https://github.com/cosmos/ibc-go/compare/v7.1.0...v7.4.0)

---
updated-dependencies:
- dependency-name: github.com/cosmos/ibc-go/v7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-26 11:24:00 +02:00
dependabot[bot]
90d19cea1d
chore(deps): Bump github.com/cosmos/ibc-go/v7 from 7.1.0 to 7.4.0 (#361)
Bumps [github.com/cosmos/ibc-go/v7](https://github.com/cosmos/ibc-go) from 7.1.0 to 7.4.0.
- [Release notes](https://github.com/cosmos/ibc-go/releases)
- [Changelog](https://github.com/cosmos/ibc-go/blob/v7.4.0/CHANGELOG.md)
- [Commits](https://github.com/cosmos/ibc-go/compare/v7.1.0...v7.4.0)

---
updated-dependencies:
- dependency-name: github.com/cosmos/ibc-go/v7
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-26 11:07:41 +02:00
dependabot[bot]
640b34ceab
chore(deps): Bump google.golang.org/protobuf from 1.31.0 to 1.33.0 in /lib (#349)
* chore(deps): Bump google.golang.org/protobuf in /lib

Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* fixed dep isue

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-26 00:16:56 +02:00
dependabot[bot]
7e1bbc9eb4
chore(deps): Bump google.golang.org/protobuf from 1.31.0 to 1.33.0 (#348)
* chore(deps): Bump google.golang.org/protobuf from 1.31.0 to 1.33.0

Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* fixe dependencies

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-25 23:51:19 +02:00
dependabot[bot]
95036475b4
chore(deps): Bump github.com/hashicorp/go-getter in /lib (#411)
Bumps [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) from 1.7.1 to 1.7.5.
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.7.1...v1.7.5)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-getter
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-25 23:50:44 +02:00
dependabot[bot]
48ef258ed6
chore(deps): Bump github.com/hashicorp/go-getter in /lib (#386)
Bumps [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) from 1.7.1 to 1.7.4.
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.7.1...v1.7.4)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-getter
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-25 23:38:44 +02:00
dependabot[bot]
2d73110836
chore(deps): Bump golang.org/x/net from 0.17.0 to 0.23.0 in /lib (#374)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.17.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-25 23:38:16 +02:00
dependabot[bot]
a8109e8273
chore(deps): Bump github.com/hashicorp/go-getter from 1.7.1 to 1.7.5 (#412)
Bumps [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) from 1.7.1 to 1.7.5.
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.7.1...v1.7.5)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-getter
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <eckelj@users.noreply.github.com>
2024-06-25 23:28:57 +02:00
dependabot[bot]
b2c526941a
chore(deps): Bump github.com/btcsuite/btcd from 0.23.2 to 0.24.0 in /lib (#394)
Bumps [github.com/btcsuite/btcd](https://github.com/btcsuite/btcd) from 0.23.2 to 0.24.0.
- [Release notes](https://github.com/btcsuite/btcd/releases)
- [Changelog](https://github.com/btcsuite/btcd/blob/master/CHANGES)
- [Commits](https://github.com/btcsuite/btcd/compare/v0.23.2...v0.24.0)

---
updated-dependencies:
- dependency-name: github.com/btcsuite/btcd
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-25 23:13:43 +02:00
dependabot[bot]
d055d7f63c
chore(deps): Bump golang.org/x/net from 0.17.0 to 0.23.0 (#373)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.17.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-25 22:59:11 +02:00
dependabot[bot]
8c66ce9ba4
chore(deps): Bump github.com/hashicorp/go-getter from 1.7.1 to 1.7.4 (#385)
Bumps [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) from 1.7.1 to 1.7.4.
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.7.1...v1.7.4)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-getter
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-25 22:58:43 +02:00
dependabot[bot]
700cfdcd0b
chore(deps): Bump github.com/btcsuite/btcd from 0.23.2 to 0.24.0 (#393)
Bumps [github.com/btcsuite/btcd](https://github.com/btcsuite/btcd) from 0.23.2 to 0.24.0.
- [Release notes](https://github.com/btcsuite/btcd/releases)
- [Changelog](https://github.com/btcsuite/btcd/blob/master/CHANGES)
- [Commits](https://github.com/btcsuite/btcd/compare/v0.23.2...v0.24.0)

---
updated-dependencies:
- dependency-name: github.com/btcsuite/btcd
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-25 22:58:18 +02:00
Lorenz Herzberger
468fbb5305
402 bug asset query does not repsect lookupperiodinmin value (#405)
* chore: remove unused asset.proto and asset.pb.go files
* feat: add AssetByAddress store functionality
* fix: asset query now returns numElements passed in req
* chore: add migration for new store mechanics
* chore: set upgradehandler for assetmodule migration
* chore: removed obsolete GetCIDsByAddress function
* chore: adjust cmd usage
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-06-06 14:39:05 +02:00
Jürgen Eckel
1462b6ee88
add only legit machine addresses to the PoPSelection process (#404)
add only legit machine addresses to the PoPSelection process

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-06-06 14:37:09 +02:00
Jürgen Eckel
dd2621afde
hot fix for the tasmota PoP issues (#403)
* hot fix for the RDDL-Tasmota PoP issues
* adjusted test case

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-05-28 14:54:31 +02:00
Jürgen Eckel
e99b614e4a
added connection loss handler, extended logging, mqtt msg updates (#400)
* added a bit of logging
* added update messages to mqtt (every second with a timestamp)
* added isConnectionOpen to the interface and analysis this during execution
* added connection loss handler and status check
* put some global objects into an objects to avoid inter service testing issues
* TestingLocker Mutex to RWMutex (increase performance)
* termintationMutex became a sync.RWMutex
* added logging to the mqtt mock client
* made monitor Mutex a RWMutex
* added Mutex protection to the numberOfElements varialbe
* added another Waiting block to the machine attestation methods (CI tests)
* had to adjust the test cases to the impact of that change.

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-05-16 17:06:19 +02:00
Jürgen Eckel
0c05081604
unlock mutex before return (#399)
* unlock mutex before return
* added termination clause for the scheduler



Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-05-15 17:05:26 +02:00
Jürgen Eckel
1f2b1702ea
Eckelj/mqtt monitoring fix (#398)
* set keepalive ping
* made mutex more granular
* avoid using app.Logger to have a consistent log from the beginning
* made lazyLoading local to the module
* fixed ticker bug so that the tasks are executed in an endless loop
* fixed timezone bug of Add Participant. only validator local time is used not the timestamp from the mqtt messages as these might come from a different time zone (resulted in delayed deletion from the activeActors DB)
* improved connection management for the monitor
* added a watchdog task to restart the monitor in case of connection loss (every 2 min)
* removed obsolete SetContext function/interface
* removed obsolete time conversion method

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-05-15 13:23:06 +02:00
Jürgen Eckel
ccf491d658
added uncompressed trust anchor pub key processing (#396)
* added uncompressed trust anchor pub key processing
* added a nother waiting block to pass CI test cases - these are a bit slower

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-05-14 10:32:52 +02:00
Jürgen Eckel
af1483a8ec
added secp256r1 machine ID Sig verification (#395)
* added secp256r1 machineIDSignature verification
* to go-utils v0.1.1
---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-05-10 10:57:55 +02:00
Lorenz Herzberger
066c1a7667
Fix rddl claim client load (#388)
* fix: lazyLoad on rddl-claim-service-client
* fix: sane default value for claim-host
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-04-29 11:49:45 +02:00
Lorenz Herzberger
b0f8516cd6
379 create redeem claim does not call service (#383)
* feat: add rddl-claim-service/client
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
Co-authored-by: Julian Strobl <jmastr@mailbox.org>
2024-04-25 14:38:58 +02:00
Julian Strobl
937104b3cd
fix: mqtt default config (#382)
* fix: mqtt-tls in default config template

- panic: json: cannot unmarshal string into Go struct field
  Config.mqtt-tls of type bool

* fix: default mqtt port

- since MqttTLS is set to true by default we need to use the mqtts port
  as well.

  panic: network Error : EOF

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-04-25 13:50:22 +02:00
Jürgen Eckel
b45c381b3b
TLS support for planetmint (#381)
* added TSL support for mqtt
* added configuration value mqtt-tls (bool) to support tls and non-tls connections (testing)


Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-04-24 14:59:17 +02:00
Jürgen Eckel
43d152fcf6
Donate tokens to attested machines so that these are able to run after their attestation (#375)
* added donation of tokens/denom to the just attestet machine
* extended the machine module to have two additional parameters: amount of tokens to be distributed and their denominator

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-04-23 12:00:31 +02:00
Lorenz Herzberger
5e2b307a70
368 make attestmachine msgtx with fee=zero (#372)
* no fee deduction in case of machineattestation messages
* no gas price for machineattestations in lib/tx
* test: add balance check to machine attestation e2e test

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-04-22 13:07:40 +02:00
Jürgen Eckel
1983890fb8
Adjusting to newest version of elements-rpc (#353)
* added tests (for the sake of on-demand local tests)
* added wrapping the first parameters of the calls into `"`
* using newest elements RPC from now on (>=1.0.0)
* removed print outputs
* removed parallel testing from util/elementsd_connector_test.go

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-04-09 13:49:51 +02:00
Jürgen Eckel
0fd12a563c
added to wait for another block to ensure the tx went through (#365)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-04-08 14:42:54 +02:00
Jürgen Eckel
779b1edd48
Eckelj/mqtt monitoring (#359)
* added a MqttMonitor module with levelDB and periodic cleanup
* initialized in the app
* passed to dao keeper
* added conversion methods (string2unixtime, byte ToJSON)
* removed obsolete keeper code
* maded  RDDLToken.Factor public
* added explicit mqtt client to the monitor module
* restart mqtt connection in mqttmonitor on connection loss
* adjusted mqttmock structure to be compatible
* added some linter exclusions to let the monitor tool pass
* created a MockMqttMonitor interface and mock object
* used this to pass tests
* made the MockMqttMonitor a global object so that it can be easily mocked
* removed MockMqttMonitor from the app/keeper initialization
* adjusted test cases to register "active machines" to the mqttmonitor
* added mutex in mocks to protect against data races
* defined mocks for the dao tests
* clear separation between interface and mqtt-Monitor

* added another waiting block to ensure the tx went through (multi-threading issue, race condition) during tests this failed sometimes
* added memstorage to test instead of a file based DB


Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-04-08 10:49:00 +02:00
Julian Strobl
0ec6fba4ec
test: run action dynamically for each module in a repository (#351)
// https://stackoverflow.com/a/68746128

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-03-20 09:48:18 +01:00
Lorenz Herzberger
7d4ec9d56c
change: CreateRedeemClaim consumes entire claim for reduced complexity (#352)
* change: CreateRedeemClaim consumes entire claim for reduced complexity

---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-03-19 14:29:29 +01:00
Jürgen Eckel
588a21f76e
stageing network takedown to avoid leveldb panics (#347)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-03-11 15:30:39 +01:00
Julian Strobl
06e60809ca
chore: bump lib version to v0.5.0 (#346)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-03-11 11:24:36 +01:00
Jürgen Eckel
1e1e19bb19
added more sync objects to avoid accidential data races (#345)
* Added more sync objects to avoid accidental data races
* made lib.config.Config variables are private, so they cannot be tampered with (multithreading).
Please introduce Get-methods to retrieve the varialbes outside of the package if you need it.
This way, the race conditions and unexpected change of the global object state can be protected
* added reverse takedown of the validators to avoid the following error
 [app] PoP broadcast tx failed: node0.info: key not found
* moved util.TerminationWaitGroup.Wait()
to the central network cleanup method
* removed mappings for private variables


Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-03-11 11:11:56 +01:00
Jürgen Eckel
d5d86997f3
added wait for another block to have more reliable tests (#344)
* added wait for another block to have more reliable tests
* Added one network reload in case the address/port was still bound during the last try
test related

* separated Dao test suites (faster output on the CI)
* added 2 seconds wait time to avoid errors of still blocked ports/bindings (network)
* removed parallel flag from test/e2e/asset
* renamed a bunch of things to please the linters
* moved the reset of the libConfing clientctx back to the validator context before waiting for some blocks.
This should prevent the

panic: Log in goroutine after TestE2EMachineTestSuite has completed: [app] PoP broadcast tx failed: node0.info: key not found

on the CI.


Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-03-08 15:14:36 +01:00
Jürgen Eckel
e6f6e43754
fixed crashes when two machines are attested at the same time (#343)
* * added creation of random machines to prepare a test case
* setting all the consensus timeout values at once (if changed)
* mutex protection of the elements tx crafting methods (sequential processing)
* Extending the TestMachineNFTIssuance test case to parallel threads and threading issues
* moving all elements-rpc usage to the elementd-connector.go file
* removed call to fatal
* added WaitForNextBlock to be out of sync with PoP to avoid the following error
                PoP broadcast tx failed: node0.info: key not found
  after the test
---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-03-08 10:54:52 +01:00
Julian Strobl
8a5e7b5da6
fix: deprecated github actions (#342)
Warning:
```
Node.js 16 actions are deprecated. Please update the following actions
to use Node.js 20: actions/checkout@v3, actions/setup-go@v4.
```

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-03-07 10:02:32 +01:00
Jürgen Eckel
73e27b6145
tidy up ci logs (#339)
* moved initialization code to network initialization so that failures during the 1st 5 blocks disappear

---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-03-06 15:04:38 +01:00
Julian Strobl
26457a7a6f
refactor: goify function (#337)
* chore: log in case of error

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-03-06 14:51:27 +01:00
Julian Strobl
f6f10b54b6
refactor: generate contract from struct in test (#338)
- also use default params

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-03-06 13:28:00 +01:00
Jürgen Eckel
31b304f232
added TermintionWaitGroup (#336)
* added TermintionWaitGroup
* added mutex to lib/tx
* removed machine attestation thread (to comply with testing-race conditions becoming apparent on the CI)
* renamed test suites to have a clear naming structure
* removed parallel-testing from e2e machine test suite
* improved test suite logging
* removed parallel tests of machine_nft_tests - this caused data races due to the mock overwrites
* reduced error check to "out of gas" due to multi-threading and locking  delays that result in different gas consumptions
* Added waiting blocks to pass the CI

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-03-06 10:52:22 +01:00
Jürgen Eckel
f13c54f582
fixed mqtt URI bug (#334)
* adjusted to refactored path

* removed go routine from attest machine msg server

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-03-05 15:29:24 +01:00
Lorenz Herzberger
caa795e5f7
relocate redeem claim and reissuance proposal ante decorator to respe… (#331)
* relocate redeem claim and reissuance proposal ante decorator to respective msg servers

---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-03-05 15:03:27 +01:00
Jürgen Eckel
4f5b1e5777
Multi validator setup in test cases (#333)
* Initializing rootDir of dao and machine keeper with the home path of the validator key material
* added Block height logging of context decorator
* removed SetRoot usage
* fixed data races of the attest machine go-routine
* reproduction of the issue
* fixed testing URL issue
* refactored the machine-nft functions/mock
* fixed keeper.param read-bug that increased the gas prices in an inconsistent way
* increased the validator number to 3 for all e2e tests
* added go routine to attest machine workflow

---------

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
Co-authored-by: Julian Strobl <jmastr@mailbox.org>
Co-authored-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-03-05 11:37:01 +01:00
Julian Strobl
838c887a91
Revert "Revert "Revert unnecessary config patch (#323)" (#324)" (#332)
This reverts commit b205c5ff29df25bad6b923bae327b88bdad89518.

This needs to be removed so that the parameters are read from chain.
2024-03-01 12:42:44 +01:00
Jürgen Eckel
55b7065744
Eckelj/remove the smell (#326)
* removed some more code smell/error message aggregation
* removed obsolete/duplicate tests/code
* excluded TODOs (simulation) from being processed by sonarqube
* removed TODO code

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-02-26 18:06:43 +01:00
Jürgen Eckel
75ed13b357
Eckelj/reducing code smell (#325)
* aggregating error messages
* removed duplicate err msgs
* removed obsolete test (two times equal behaviour )
* added global error msg module
* refactored test utils to have sample types and sample objects by keepers separated
* excluded auto-generated code from sonarcube analysis


Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-02-26 16:44:00 +01:00
Julian Strobl
b205c5ff29
Revert "Revert unnecessary config patch (#323)" (#324)
This reverts commit b1c4d11ccf3e98bd46a13d7fb54b6b5c0aefbf29.
2024-02-26 13:04:41 +01:00
Julian Strobl
b1c4d11ccf
Revert unnecessary config patch (#323)
* Revert "feat: bring back config parameters"

This reverts commit 4ab279033cae5e351cd13c348a21e4717705f341.

Unnecessary because cosmos sdk handles chain upgrades properly: it holds
the chain and waits for a new binary version.

* refactor: use testnet parameters as default in x/dao
---------

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-02-26 12:25:12 +01:00
Jürgen Eckel
ec697840de
Eckelj/machine update params (#322)
* added signing authority (dao) to the keeper to enable dao signing checks
* added UpdateParam message for the machine module

---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-02-26 12:00:37 +01:00
Julian Strobl
412e15449b feat: add migration to v0.8.0
Take x/dao and x/machine default parameters and store them into the
respective module state.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-02-26 08:30:10 +01:00
Julian Strobl
4ab279033c feat: bring back config parameters
Needed for migration as interim solution.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-02-26 08:30:10 +01:00
Lorenz Herzberger
373b2aeab6
docs: shorten readme to development parts only (#314)
* docs: shorten readme to development parts only

* docs: add discord link to readme

* docs: add link REPs
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-02-15 16:09:43 +01:00
Jürgen Eckel
951d854891
311 review test case ssendpopresultoutbytes true todo bug (#313)
* added PoP report validation to the ReportPoPResult msg server
* removed two obsolete pop report deliveries
* added challenger is the PoPreport msg creator (new restriction)
* extended msg server test cases

---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-02-15 14:41:05 +01:00
Jürgen Eckel
04e45a7fb2
275 refactor feedenom on e2e test suite (#312)
* extended AttestMachine FundAccount to support a given fee denominator
* renamed testutil/network/network.go to testutil/network/loader.go
* renamed new to Load
* integrated cosmos/testutil/network to planetmint-go/testutil/network
* changed to plmnt token tests only!
* removed obsolete variables
* fixed newest linter issues

---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-02-14 12:15:40 +01:00
Jürgen Eckel
f6a7a56704
* added default params for x/machine/params (#310)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-02-01 15:24:41 +01:00
Jürgen Eckel
373614e1b2
269 set a chain wide upper gas limit for transactions (#309)
* set global tx gas limit
* extend lib/tx to process multiple messages
* extend lib/tx to configure tx gas limit
* added global gas limit tests
* increased account funding to support needs of testcases

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-02-01 10:23:38 +01:00
Lorenz Herzberger
a38fe781ba
187 implement rddl claim (#298)
* ignite scaffold map redeem-claim amount issued:bool --module dao --index beneficiary,liquid-tx-hash

* revert: remove autogenerated delete redeem claim logic

* fix: replace deprecated autogenerated sdkerrors with errorsmod

* refactor: rename issued to confirmed on redeem claim

* feat: add claim address param

* test: add test for restricted msg UpdateRedeemClaim

* refactor: update redeem claim key creation and messages

* feat: add SendUpdateRedeemCLaim to util

* feat: add RedeemClaimDecorator for ante package

* ignite scaffold message confirm-redeem-claim id:uint beneficiary:string --module dao

* feat: add handleConfirmRedeemClaim to ante handler

* feat: add handleUpdateRedeemClaim to ante handler

* feat: implement ConfirmRedeemClaim msg handler

* test: add redeem claim test and adjust e2e test suite

* fix: make use of uint to rddl string util in CreateRedeemClaim

* fix: linter and staticcheck errors

* ignite scaffold query redeem-claim-by-liquid-tx-hash liquid-tx-hash --response redeem-claim:RedeemClaim --module dao

* feat: add RedeemClaimByLiquidTXHash store capabilities

* test: add QueryRedeemClaimByLiquidTxHash to e2e test suite

* feat: add RedeemClaimDecorator to ante handler chain

* fix: remove redundant planetmint-go from service path

* fix: linter and staticcheck errors

* fix: go vet errors

* fix: remove unused autogenerated simulation

* fix: broken simulation

* fix: openapi.yml

* revert: remove autogenerated redundant test file that causes data race on pipeline

* feat: burn claim on CreateRedeemClaim

* fix: linter error

* test: fix mock bankkeeper for msg server test

* fix: reissuance test if statement

* chore: removed TODO comment

* fix: typo in redeem claim error msg

* revert: remove autogenerated genesis state

* fix: dao module simulation

* revert: remove unused function

* fix: linter errors

* fix: linter error

---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-02-01 09:57:58 +01:00
Jürgen Eckel
a29f394bc4
192 migrate config params to on chain module params (#307)
* initial refactoring commit
* added config passing to network creation for some test suits
* fixed refactoring issues
* adjusted params

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-01-30 16:12:04 +01:00
Julian Strobl
df264421b4
chore: bump lib version to v0.4.1
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-30 12:15:58 +01:00
Julian Strobl
23648927c3
feat: put sequence files into sub-directory (#308)
- aligns the folder structure in `planetmint-go/`
- makes sequence number clean up via systemd possible

// see https://github.com/rddl-network/issues/issues/61

* refactor: open sequence file into function
* refactor: get sequence number into utils

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-30 12:13:05 +01:00
Jürgen Eckel
bfbe9584a1
296 change distribution (#306)
* updated planetmint-go dependency in lib/tx
* added two additional distribution addresses. splitted up the previous investor pool of 31% into three pools:
* early investors 19%
* investors 10%
* strategic 2%

* adjusted distribution request message
* adjusted distribution result
* adjusted distribution order
* refactored reissuance and distribution msg methods to be more readable

* fixed token distribution test case

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-01-29 14:33:40 +01:00
Jürgen Eckel
f6509cfa64
removed StakeDenom and it's related code (#299)
* removed StakeDenom and it's related code
* fixed PoP, reissuance & distribution tests

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-01-25 15:10:07 +01:00
Jürgen Eckel
2a9d3d4b47
lazy loading of config.GetConfig calls (#293)
* the execution of Config code is not determinitic within init methods. That's why we apply lazy loading.

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-01-22 11:03:11 +01:00
Jürgen Eckel
7aa0c7f6cc
fixed decision-making bug within SendMqttPopInitMessagesToServer from last releaes (#292)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-01-19 11:17:47 +01:00
Jürgen Eckel
8ba6b20357
removed 2nd init() method that caused behaviour during testing and real execution (#291)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-01-19 10:26:57 +01:00
Julian Strobl
0e0637a04b
fix: refactor forgotten asset endpoints (#290)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-18 14:36:21 +01:00
Lorenz Herzberger
8d0e189593
fix: challangee rewards stay in dao module if challenge is not sucessful (#286)
* fix: challangee rewards stay in dao module if challenge is not sucessful

* refactor: split up coin conversion functions

* fix: add dao module coin conversion

* test: adjust test case for updated behavior

* chore: fix typo

* fix: do not mint claims for dao

* refactor: remove redundant statement

* fix: error handling on claim converstion fail

* fix: linter error

* chore: add comment to test case
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-01-18 13:56:16 +01:00
Julian Strobl
cb230f1615
refactor: cli queries (#288)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-18 12:06:21 +01:00
Jürgen Eckel
5d3cd51ba3
281 implement pop corner cases (#282)
* ensure PoP is always initialized even without a defined challenger and challengee
* send the MQTT PoPInit if challenger and challengee are defined
* store the challenge in any case without regarding the minting of the rewards
* structured the added test and their staging
* fixed SelectPopParticipants bug
* restore the previous pop epoch after running dao/suite.go
* avoid popInit during machine attestations (within test cases)
---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2024-01-17 15:37:38 +01:00
Julian Strobl
ee4089f847
Remove planetmint-go from API endpoints (#287)
* feat: let the ci check if there are malformed api endpoints

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-16 10:39:32 +01:00
Julian Strobl
525d6a8da6
Improve get-distribution CLI output and error handling (#279)
* refactor: rename variable

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-16 09:11:44 +01:00
Lorenz Herzberger
6d7a5f1acb
test: fix crddl assertion on pop result e2e test (#285)
* test: fix crddl assertion on pop result e2e test

* test: replace contains with equal assertion
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-01-15 12:11:11 +01:00
Julian Strobl
d0e269a478
lib: bump version to v0.4.0
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-12 10:03:24 +01:00
Jürgen Eckel
3ca10dfff1
Verifying the availability of PoP participants (#274)
* feat: verify the availability of PoP participants

* simplified and improved logging
* added MQTT-based availability check for PoP participants
* extended MQTT mocking
* Only the block proposer will send out the MQTT messages to the pop participants
* Added a configuration value for the MQTT response timeout
* removed parallel execution of one test case
* added r/w locking to the MQTT response processing
* set MQTT timeout unit to ms

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-12 10:02:09 +01:00
Julian Strobl
986685d8db
test: add e2e test for asset distribution (#276)
Closes #164

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-11 16:56:35 +01:00
Lorenz Herzberger
461891cde8
refactor: remove duplicate test scenarios (#278)
* refactor: remove duplicate test scenarios

* chore: remove deprecated rest testutil
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-01-11 15:59:53 +01:00
Lorenz Herzberger
2534828fc6
feature: add ante handler to block non validators from sending restri… (#273)
* feature: add ante handler to block non validators from sending restricted txs

* fix: add missing msg types and linter errors

* fix: staticcheck error

* refactor: use fallthrough on ante handle switch

* fix: set val address on machine attest test
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-01-11 14:33:20 +01:00
Julian Strobl
001a472ef9
Refactoring and fixes (#272)
* refactor: switch log level for PoP messages

Needs to be the other way around, otherwise we receive up to 720
messages on info level.

* refactor: align spelling in comments and log messages

* fix: config key

Commit fc9e795bd0678746993806ac21c92a675ed7006f changed the reissuance
variable. The config key was forgotten to change.

* refactor: return early to reduce indentation

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-11 10:39:25 +01:00
Julian Strobl
7e3c0b719b
fix: distribution relative to the reissuance epoch (#270)
- reissuance   = 1 day
- distribution = 1 day + 30 min

expectation:
- reissuance:   1 day, 2 day, 3 day, ...
- distribution: 1 day + 30 min, 2 day + 30 min, 3 day + 30 min, ...

without patch:
- reissuance:   1 day, 2 day, 3 day, ...
- distribution: 1 day + 30 min, 2 day + 60 min, 3 day + 90 min, ...

Closes #260

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-11 10:27:57 +01:00
Lorenz Herzberger
4042968dff
Add gaskv ante decorator (#268)
* feature: add gaskv ante handler

* test: add test case for gaskv consumption

* chore: fix typo

* test: split up consumption test cases

* test: replace contains with equal

* fix: linter error
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-01-10 16:49:48 +01:00
Julian Strobl
fc9e795bd0
refactor: fix casing for reissuance variable (#267)
Reissue and reissuance are standalone words and should not contain an
uppercase `I` in the variable name. This should only happen to connect
different word like: file name gets `fileName` resp. `FileName`.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-10 10:47:38 +01:00
Julian Strobl
2cf9bd4c43
refactor: replace raw tx by command in reissuance (#266)
In the beginning we wanted to send the raw transaction to elements, but
what we ended up doing is to send the command like:
```
"reissueasset assetID amount"
```
to elements-cli/elements-rpc.

Closes #226

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-10 10:30:58 +01:00
Julian Strobl
094f547e7a
fix: app logger formatting (#265)
From this:
```
ERR [app] reissue: failed. valid result: %v proposer: %s validator
identity: %s module=server
```
to this:
```
ERR [app] reissue: failed. valid result: true proposer:
9d3b2072f96f9481de983700605fbcd9158d5b63 validator identity:
31615187759d4bdb1c43ea7e7b9be91066042fbf module=server
```

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-09 16:55:33 +01:00
Julian Strobl
25649be550
fix: remove check from machine attestation request (#264)
`k.isNFTCreationRequest(msg.Machine)` was removed as it became obsolete
and we are not issuing generic tokens from within the machine
attestation process.

Closes #242

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-09 10:25:50 +01:00
Julian Strobl
6d05f85cbd
Use lib in rest e2e machine test (#263)
* refactor: align variable name with rest of the code

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-09 10:14:54 +01:00
Julian Strobl
ae161f11e5
refactor: let lib set client context's address and name (#261)
* fix: make a real copy of bytes.Buffer

* refactor: rename `address` for maximum clarity in lib

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-08 16:04:42 +01:00
Julian Strobl
3e23260a9c
test: refactor broadcast tx into function (#259)
Force test cases to check tx response for errors.

* refactor: improve broadcast error logging

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-05 13:43:52 +01:00
Julian Strobl
fa05ec7fff
Fix test pop result (#258)
* chore: update elements-rpc to v0.5.2

* fix: logging output in dao keeper

* refactor: properly check broadcast tx output

* fix: use correct proposer address in test

Otherwise we get an error like:
```
[app] reissue: failed. valid result: true proposer: plmnt1gyg6lxcre5f8t4ef0uxcqen9jczwalzjvc25k8
  validator identity: fb7ecaf9584dfdc67265f599155571651c149207
```

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-05 09:49:40 +01:00
Julian Strobl
4599bc2c78
refactor: improve logging (#257)
* refactor: improve logging

- Introduce logger tags
- Log variable contents
- Fix testing logger to support string formatting

* refactor: set logging context

And move logging into function.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-04 12:50:34 +01:00
Lorenz Herzberger
6bff8e835d
Split up e2e test suites to run separately (#256)
* refactor: Split up machine e2e test suites

* refactor: move CreateAccount and FundAccount to testutil/e2e

* refactor: add AttestMachine to testutil/e2e

* refactor: split up asset e2e test suites

* refactor: make use of testutil in e2e dao suite

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2024-01-04 07:43:01 +01:00
Julian Strobl
99031fb857
lib: add initial e2e tests (#255)
* fix: only increase counter if broadcast was successful

Otherwise we will get account and sequence numbers mismatches.

* test: add initial e2e tests for `lib/`

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-03 13:08:13 +01:00
Julian Strobl
f957f540a1
Refactor lib (#254)
* refactor: remove unwanted function in `lib`

The `lib` shall always be used with file lock.

* refactor: log `txResponse` in `buildSignBroadcastTx`

- Move `GetTxResponseFromOut` from `testutil` to `lib`

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-03 10:41:09 +01:00
dependabot[bot]
3ca729c15b
Bump github.com/dvsekhvalnov/jose2go from 1.5.0 to 1.6.0 in /lib (#252)
Bumps [github.com/dvsekhvalnov/jose2go](https://github.com/dvsekhvalnov/jose2go) from 1.5.0 to 1.6.0.
- [Commits](https://github.com/dvsekhvalnov/jose2go/compare/v1.5...v1.6.0)

---
updated-dependencies:
- dependency-name: github.com/dvsekhvalnov/jose2go
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-03 10:36:49 +01:00
dependabot[bot]
e4a57914cd
Bump github.com/dvsekhvalnov/jose2go from 1.5.0 to 1.6.0 (#253)
Bumps [github.com/dvsekhvalnov/jose2go](https://github.com/dvsekhvalnov/jose2go) from 1.5.0 to 1.6.0.
- [Commits](https://github.com/dvsekhvalnov/jose2go/compare/v1.5...v1.6.0)

---
updated-dependencies:
- dependency-name: github.com/dvsekhvalnov/jose2go
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-03 10:32:04 +01:00
Julian Strobl
48b3145aaa
refactor: github audit workflow (#251)
Execute jobs in parallel to speed up the workflow.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-03 09:24:17 +01:00
Julian Strobl
f812a8c543
fix: do not try to notarize liquid asset here (#250)
Actually error in case of error.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-01-02 14:59:22 +01:00
Julian Strobl
a1d6923ca3
Support releasing from different branch (#249)
* ci: support releasing from different branch
* fix: git tags are not fetched

This preveted to detect if a `LIB_TAG` is already there.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-22 11:25:32 +01:00
Julian Strobl
926fc76659
* fixed the cause for different results by different keepers during the processing of the distribution rewards. (#248)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-12-22 10:07:53 +01:00
Julian Strobl
1d41d050fe
feat: add mqtt mock client (#245)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-21 13:03:10 +01:00
Lorenz Herzberger
0cab7d5878
217 pop participant election (#244)
* implemented SelectPopParticipants
* added check if enough participants to initiate PoP
* make use of lib for broadcasting tx

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2023-12-21 12:29:11 +01:00
Jürgen Eckel
c09aab8b38
Initializing the PoP process on the tasmota nodes (#243)
* added MQTT lib
* added MQTT config params: domain, port user, password
* sending PoPInit commands to devices par of the pop (after delivery of the PoPInit message)
* Added test case to verify the working of the MQTT connection (test is skipped and designed for manual tests (lack of credentials))
---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-12-20 10:01:28 +01:00
Julian Strobl
fd58362a42
Fix typo and align log messages (#241)
* Fix typo and align log messages
* Align some variable names with rest of the program
* [log] Fix log formatting and change log level
* Fix comment

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-19 14:28:15 +01:00
Julian Strobl
00aba3115f
[lib] Bump version to v0.3.0
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-19 09:11:52 +01:00
Jürgen Eckel
379cc761b2
adjusted re-issuance values and the corresponding test cases. (#238)
* adjusted re-issuance values and the corresponding test cases.
* [test] Fix `TestPoPResult`
* [test] Revert `TestReissuance`

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
Co-authored-by: Julian Strobl <jmastr@mailbox.org>
2023-12-19 09:02:35 +01:00
dependabot[bot]
618f8835be
Bump golang.org/x/crypto from 0.14.0 to 0.17.0 in /lib (#240)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 08:27:52 +01:00
dependabot[bot]
94ecb64034
Bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#239)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 08:18:49 +01:00
Julian Strobl
7ac0f31de0
[config] Default config shall point to testnet (#237)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-18 16:14:34 +01:00
Julian Strobl
036ce7cbc1
Enable sequence file locking in tests (#236)
* [lib] Add `FeeGranter` to tx factory
* [lib] Align return value with test cases
* [test] Return error on tx response
* [test] Switch to sequence file locking via libRPC
* [test] Reintegrate `TestPoPResult`

Closes #234


Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-18 15:47:44 +01:00
Julian Strobl
487dc3b93c
[test] Check TxResponse on every ExecTestCLICmd() (#235)
Just a small improvement to not forget to check the error code of the
transaction and not only from the command itself.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-15 11:32:29 +01:00
Lorenz Herzberger
0d74b81ac9
210 make distribution dependent reissuance (#216)
* distribution now requires re-issuance
* change claim conversion to use fixed uint amounts
* change initialization of util variable
* move rpc conf init to app config init


Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-12-15 09:39:02 +01:00
Julian Strobl
ff2f2eb386
[test] Use elements RPC mock server (#232)
Fix `reissueasset` in tests.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-13 15:42:09 +01:00
Lorenz Herzberger
bb8e055e44
add challenges query (#231)
* add challenges query

* implement query reissuances paginated

* fix linter errors

---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2023-12-13 11:47:32 +01:00
Julian Strobl
804a8e5be6
Add AppLogger to test runs (#230)
* [log] Do not create a new object of `GetAppLogger()` every time

* [tests] Enable AppLogger during testing

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-12 13:39:37 +01:00
Jürgen Eckel
3c1a2fa776
fixed precsion issue within the distribution order (#229)
* fixed precision issue within the distribution order
* adjusted test cases: migrated from uint64 to float64
---------

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-12-12 13:15:14 +01:00
Julian Strobl
7b381f3313
Use elements RPC library (#225)
* Use elements RPC library

// Closes #218

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-12 12:14:19 +01:00
Jürgen Eckel
2b19b8194b
Fix distribution bugs (#228)
* fixed missing-proposer bug for asset distribution

* improved logging

reduced type conversions and potential errors

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-12-12 11:09:33 +01:00
Jürgen Eckel
73b0d1b4c8
Add GetDistribution query (#227)
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-12-12 10:13:27 +01:00
Julian Strobl
ede70b073b
Replace call to external python program (#215)
* Split asset registry endpoint

Into scheme, domain and path. We need the domain in the liquid contract.

* Switch to pure Go implementation

This is a reimplementation of the `issue2liquid.py`.

See https://github.com/rddl-network/issuer_service

// Closes #196

* Move elements RPC URL into config

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-11 15:53:58 +01:00
Julian Strobl
363d82d344
[ci] Improve staticcheck setup (#221)
* [staticcheck] Fix comments on exported functions and structs

* [ci] Improve staticcheck setup

- Add global staticcheck.conf file
- Ignore: at least one file in a package should have a package comment (ST1000)
- Ignore deprecation warnings. They are reported by golangci-lint and
  there we have a proper way to exclude generated files.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-11 11:41:45 +01:00
Julian Strobl
df8ece2a30
Fix TestReissuance() E2E test (#214)
* [lib] Add fee denominator parameter

* [lib] Add client context parameter

e.g. the test cases create their own client context.

* [lib] Reset client context's output

Otherwise if the client context does not change, output gets appended
and gets un-parsable.

* [test] Set missing validator client context values

Necessary for sending transactions.

* [test] Configure RPC library

* [test] Fix `TestReissuance()`

// Closes #195

* Partially revert "[lib] Provide default encoding config (#209)"

This reverts commit 8a8a3aaaf2648f87c4052575bc1a60b23056463b.

Fix README example.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-07 09:57:33 +01:00
Jürgen Eckel
ff6aab33df
Fix error throwing bug that lead to block creation inconsistencies (#212)
* removed error throwing within the AttestMachine method
* add more extensive logging around that call

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-12-06 11:20:37 +01:00
Julian Strobl
0455176123
[ci] Pin ignite version to v0.27.1 (#213)
Version v28.0.0 was released and breaks the pipeline.

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-06 11:13:04 +01:00
Lorenz Herzberger
94830df5fc
184 implement staged claim (#190)
* adjust issuePoPRewards to mint stagedCRDDL
* add GetChallengeRange
* add resolveStagedClaims on ReissueRDDLResult msg
* move claim resolve to distribution result
* add StagedDenom and ClaimDenom to config
* added the prepare4linting.sh script
* renamed PoPEpochs to PopEpochs
* renamed DistributionAddressPoP to DistributionAddressPop
* added config value ReIssuanceEpochs
* detached the re-issuance from the distribution process and schedule them independently
* changed logging messages
* added an explicit util/kv_serialize.go file to have all KV serialization done
* switched to Bigendian serialization of int64 to have the ordered list on the kvstore
* added ComputeReIssuanceValue to enable re-issuances once a day or defined by ReIssuanceEpoch
* integrated a ReIssuanceValue computation test case
* adjusted the challenges test cases to be epoch-dependent
* added ReIssuances per ReIssuanceEpoch
* extended the Reissue message
* checking ReIssuanceProposal in the ante handler
* added precision setter for the UINT to RDDL token converter (and test cases)
* add e2e test case for pop rewards


Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-12-05 10:51:06 +01:00
Julian Strobl
8a8a3aaaf2
[lib] Provide default encoding config (#209)
Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2023-12-05 10:35:52 +01:00
Jürgen Eckel
cefd22f448
Add the PoPCycle concept (#208)
* added reissuance details, the concept of popepochs and popcycles

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-11-29 14:14:29 +01:00
Jürgen Eckel
6a60b78b62
Added PoP Initialization and a Challenge Query (#207)
* added InitPoP message
* added getChallenge query to inspect challenges
* adjusted towards a unique block height identification unit: int64, not uint64
* added challenge param finished to identify challenges that weren't completed but will be part of re-issuance.

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
2023-11-29 13:33:25 +01:00
286 changed files with 24190 additions and 3786 deletions

View File

@ -4,62 +4,214 @@ name: Audit
on: [push]
jobs:
audit:
build:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [ '1.20', '1.21' ]
directory: [".", "lib"]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v4
- name: Checkout dependency
uses: actions/checkout@v4
with:
go-version: ${{ matrix.go-version }}
repository: rddl-network/bc-slip39-go
path: bc-slip39-go
- name: Build dependency
run: |
pushd bc-slip39-go
./deps.sh
popd
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Verify dependencies
run: go mod verify
- name: Build
run: go build -v ./...
run: |
pushd ${{ matrix.directory }}
go build -v ./...
proto:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check proto files
run: |
if [ "$(find . -name 'query.proto' -exec grep 'option (google.api.http).* = ./planetmint/planetmint-go/' {} \; | wc -l)" -gt 0 ]; then exit 1; fi
ignite:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check generated files
run: |
curl https://get.ignite.com/cli | bash
curl https://get.ignite.com/cli@v0.27.1 | bash
./ignite chain init --clear-cache --yes
rm ignite
if [ "$(git diff --stat | wc -l)" -gt 0 ]; then exit 1; fi
gofmt:
runs-on: ubuntu-latest
strategy:
matrix:
directory: [".", "lib"]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Run gofmt
run: if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then exit 1; fi
run: |
pushd ${{ matrix.directory }}
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then exit 1; fi
govet:
runs-on: ubuntu-latest
strategy:
matrix:
directory: [".", "lib"]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout dependency
uses: actions/checkout@v4
with:
repository: rddl-network/bc-slip39-go
path: bc-slip39-go
- name: Build dependency
run: |
pushd bc-slip39-go
./deps.sh
popd
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Run go vet
run: go vet ./...
run: |
pushd ${{ matrix.directory }}
go vet ./...
staticcheck:
runs-on: ubuntu-latest
strategy:
matrix:
directory: [".", "lib"]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout dependency
uses: actions/checkout@v4
with:
repository: rddl-network/bc-slip39-go
path: bc-slip39-go
- name: Build dependency
run: |
pushd bc-slip39-go
./deps.sh
popd
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@latest
- name: Run staticcheck
env:
LINT: "//lint:file-ignore SA1019 Ignore all deprecation errors, it's generated"
run: |
# Add lint-ignore comment to beginning of files
sed -i "1i${LINT}" ./x/asset/types/query.pb.gw.go
sed -i "1i${LINT}" ./x/machine/types/query.pb.gw.go
sed -i "1i${LINT}" ./x/dao/types/query.pb.gw.go
pushd ${{ matrix.directory }}
staticcheck ./...
golangci-lint:
strategy:
matrix:
directory: [".", "lib"]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Install golangci-lint
run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- name: Run golangci-lint
run: (golangci-lint run && cd lib && golangci-lint run)
run: |
pushd ${{ matrix.directory }}
golangci-lint run
gotest:
strategy:
matrix:
directory: [".", "lib"]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout dependency
uses: actions/checkout@v4
with:
repository: rddl-network/bc-slip39-go
path: bc-slip39-go
- name: Build dependency
run: |
pushd bc-slip39-go
./deps.sh
popd
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Run tests
run: |
pushd ${{ matrix.directory }}
# Exclude generated .pb.go and .pb.gw.go files from test and coverage
go test -coverprofile cover.out -race -vet=off -v $(go list ./... | grep -v types)
# Print coverage by function

View File

@ -24,7 +24,15 @@ jobs:
PRERELEASE: ${{ github.event.inputs.prerelease }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: ${{ github.ref_name }}
- name: Fetch tags
run: |
# Cannot use `fetch-tags: true` due to:
# https://github.com/actions/checkout/issues/1471
git fetch --prune --unshallow --tags
- name: Tag
run: |
@ -42,7 +50,9 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Build
run: |

View File

@ -11,7 +11,7 @@ jobs:
name: Sonar Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
# Shallow clones should be disabled for a better relevancy of analysis
fetch-depth: 0

View File

@ -9,6 +9,7 @@ linters:
- bodyclose
- containedctx
- contextcheck
- copyloopvar
- decorder
- dogsled
- dupl
@ -18,9 +19,7 @@ linters:
- errchkjson
- errname
- errorlint
- execinquery
- exhaustive
- exportloopref
- forbidigo
- forcetypeassert
- ginkgolinter
@ -53,7 +52,6 @@ linters:
- noctx
- nolintlint
- nosprintfhostport
- paralleltest
- perfsprint
- prealloc
- predeclared
@ -93,12 +91,55 @@ issues:
- path: x/.*/types/message.*\.go
linters:
- dupl
- path: x/dao/client/cli/query_.*\.go
linters:
- dupl
- path: x/dao/client/cli/tx_reissue_rddl.*\.go
linters:
- dupl
- path: x/dao/client/cli/*\.go
linters:
- revive
- path: testutil/nullify/nullify\.go
linters:
- exhaustive
- path: x/.*/keeper/query.*\.go
linters:
- dupl
- paralleltest
- path: tests/.*/*\.go
linters:
- paralleltest
- path: util/machine_nft_test\.go
linters:
- paralleltest
- path: testutil/network/network.go
linters:
- gocognit
- gocyclo
- wastedassign
- nestif
- path: x/.*/simulation/.*\.go
linters:
- revive
- path: x/.*/module_simulation\.go
linters:
- revive
- path: x/.*/client/cli/query_params\.go
linters:
- revive
- path: x/.*/.*/cli/query_.*\.go
linters:
- revive
- path: docs/docs\.go
linters:
- revive
- path: util/elementsd_connector_test\.go
linters:
- paralleltest
- path: monitor/mqtt_monitor_test\.go
linters:
- paralleltest
- path: monitor/.*\.go
linters:
- durationcheck

501
Makefile Normal file
View File

@ -0,0 +1,501 @@
#!/usr/bin/make -f
PACKAGES_NOSIMULATION=$(shell go list ./... | grep -v '/simulation')
PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation')
export VERSION := $(shell echo $(shell git describe --always --match "v*") | sed 's/^v//')
export TMVERSION := $(shell go list -m github.com/cometbft/cometbft | sed 's:.* ::')
export COMMIT := $(shell git log -1 --format='%H')
LEDGER_ENABLED ?= true
BINDIR ?= $(GOPATH)/bin
BUILDDIR ?= $(CURDIR)/build
MOCKS_DIR = $(CURDIR)/tests/mocks
HTTPS_GIT := https://github.com/cosmos/cosmos-sdk.git
DOCKER := $(shell which docker)
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
DOCS_DOMAIN=docs.cosmos.network
# process build tags
build_tags = netgo
ifeq ($(LEDGER_ENABLED),true)
ifeq ($(OS),Windows_NT)
GCCEXE = $(shell where gcc.exe 2> NUL)
ifeq ($(GCCEXE),)
$(error gcc.exe not installed for ledger support, please install or set LEDGER_ENABLED=false)
else
build_tags += ledger
endif
else
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S),OpenBSD)
$(warning OpenBSD detected, disabling ledger support (https://github.com/cosmos/cosmos-sdk/issues/1988))
else
GCC = $(shell command -v gcc 2> /dev/null)
ifeq ($(GCC),)
$(error gcc not installed for ledger support, please install or set LEDGER_ENABLED=false)
else
build_tags += ledger
endif
endif
endif
endif
ifeq (secp,$(findstring secp,$(COSMOS_BUILD_OPTIONS)))
build_tags += libsecp256k1_sdk
endif
ifeq (legacy,$(findstring legacy,$(COSMOS_BUILD_OPTIONS)))
build_tags += app_v1
endif
whitespace :=
whitespace += $(whitespace)
comma := ,
build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags))
# process linker flags
ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=sim \
-X github.com/cosmos/cosmos-sdk/version.AppName=simd \
-X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
-X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)" \
-X github.com/cometbft/cometbft/version.TMCoreSemVer=$(TMVERSION)
# DB backend selection
ifeq (cleveldb,$(findstring cleveldb,$(COSMOS_BUILD_OPTIONS)))
build_tags += gcc
endif
ifeq (badgerdb,$(findstring badgerdb,$(COSMOS_BUILD_OPTIONS)))
build_tags += badgerdb
endif
# handle rocksdb
ifeq (rocksdb,$(findstring rocksdb,$(COSMOS_BUILD_OPTIONS)))
CGO_ENABLED=1
build_tags += rocksdb
endif
# handle boltdb
ifeq (boltdb,$(findstring boltdb,$(COSMOS_BUILD_OPTIONS)))
build_tags += boltdb
endif
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
ldflags += -w -s
endif
ldflags += $(LDFLAGS)
ldflags := $(strip $(ldflags))
build_tags += $(BUILD_TAGS)
build_tags := $(strip $(build_tags))
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
# check for nostrip option
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
BUILD_FLAGS += -trimpath
endif
# Check for debug option
ifeq (debug,$(findstring debug,$(COSMOS_BUILD_OPTIONS)))
BUILD_FLAGS += -gcflags "all=-N -l"
endif
all: tools build lint test vulncheck
# The below include contains the tools and runsim targets.
include contrib/devtools/Makefile
###############################################################################
### Build ###
###############################################################################
BUILD_TARGETS := build install
build: BUILD_ARGS=-o $(BUILDDIR)/
build-linux-amd64:
GOOS=linux GOARCH=amd64 LEDGER_ENABLED=false $(MAKE) build
build-linux-arm64:
GOOS=linux GOARCH=arm64 LEDGER_ENABLED=false $(MAKE) build
$(BUILD_TARGETS): go.sum $(BUILDDIR)/
cd ${CURRENT_DIR}/app && go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./...
$(BUILDDIR)/:
mkdir -p $(BUILDDIR)/
cosmovisor:
$(MAKE) -C tools/cosmovisor cosmovisor
.PHONY: build build-linux-amd64 build-linux-arm64 cosmovisor
mocks: $(MOCKS_DIR)
@go install github.com/golang/mock/mockgen@v1.6.0
sh ./scripts/mockgen.sh
.PHONY: mocks
vulncheck: $(BUILDDIR)/
GOBIN=$(BUILDDIR) go install golang.org/x/vuln/cmd/govulncheck@latest
$(BUILDDIR)/govulncheck ./...
$(MOCKS_DIR):
mkdir -p $(MOCKS_DIR)
distclean: clean tools-clean
clean:
rm -rf \
$(BUILDDIR)/ \
artifacts/ \
tmp-swagger-gen/ \
.testnets
.PHONY: distclean clean
###############################################################################
### Tools & Dependencies ###
###############################################################################
go.sum: go.mod
echo "Ensure dependencies have not been modified ..." >&2
go mod verify
go mod tidy
###############################################################################
### Documentation ###
###############################################################################
update-swagger-docs: statik
$(BINDIR)/statik -src=client/docs/swagger-ui -dest=client/docs -f -m
@if [ -n "$(git status --porcelain)" ]; then \
echo "\033[91mSwagger docs are out of sync!!!\033[0m";\
exit 1;\
else \
echo "\033[92mSwagger docs are in sync\033[0m";\
fi
.PHONY: update-swagger-docs
godocs:
@echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cosmos/cosmos-sdk/types"
godoc -http=:6060
# This builds the docs.cosmos.network docs using docusaurus.
# Old documentation, which have not been migrated to docusaurus are generated with vuepress.
build-docs:
@echo "building docusaurus docs"
@cd docs && npm ci && npm run build
mv docs/build ~/output
@echo "building old docs"
@cd docs && \
while read -r branch path_prefix; do \
echo "building vuepress $${branch} docs" ; \
(git clean -fdx && git reset --hard && git checkout $${branch} && npm install && VUEPRESS_BASE="/$${path_prefix}/" npm run build) ; \
mkdir -p ~/output/$${path_prefix} ; \
cp -r .vuepress/dist/* ~/output/$${path_prefix}/ ; \
done < vuepress_versions ;
@echo "setup domain"
@echo $(DOCS_DOMAIN) > ~/output/CNAME
.PHONY: build-docs
###############################################################################
### Tests & Simulation ###
###############################################################################
test: test-unit
test-e2e:
$(MAKE) -C tests test-e2e
test-e2e-cov:
$(MAKE) -C tests test-e2e-cov
test-integration:
$(MAKE) -C tests test-integration
test-integration-cov:
$(MAKE) -C tests test-integration-cov
test-all: test-unit test-e2e test-integration test-ledger-mock test-race
TEST_PACKAGES=./...
TEST_TARGETS := test-unit test-unit-amino test-unit-proto test-ledger-mock test-race test-ledger test-race
# Test runs-specific rules. To add a new test target, just add
# a new rule, customise ARGS or TEST_PACKAGES ad libitum, and
# append the new rule to the TEST_TARGETS list.
test-unit: test_tags += cgo ledger test_ledger_mock norace
test-unit-amino: test_tags += ledger test_ledger_mock test_amino norace
test-ledger: test_tags += cgo ledger norace
test-ledger-mock: test_tags += ledger test_ledger_mock norace
test-race: test_tags += cgo ledger test_ledger_mock
test-race: ARGS=-race
test-race: TEST_PACKAGES=$(PACKAGES_NOSIMULATION)
$(TEST_TARGETS): run-tests
# check-* compiles and collects tests without running them
# note: go test -c doesn't support multiple packages yet (https://github.com/golang/go/issues/15513)
CHECK_TEST_TARGETS := check-test-unit check-test-unit-amino
check-test-unit: test_tags += cgo ledger test_ledger_mock norace
check-test-unit-amino: test_tags += ledger test_ledger_mock test_amino norace
$(CHECK_TEST_TARGETS): EXTRA_ARGS=-run=none
$(CHECK_TEST_TARGETS): run-tests
ARGS += -tags "$(test_tags)"
SUB_MODULES = $(shell find . -type f -name 'go.mod' -print0 | xargs -0 -n1 dirname | sort)
CURRENT_DIR = $(shell pwd)
run-tests:
ifneq (,$(shell which tparse 2>/dev/null))
@echo "Starting unit tests"; \
finalec=0; \
for module in $(SUB_MODULES); do \
cd ${CURRENT_DIR}/$$module; \
echo "Running unit tests for module $$module"; \
go test -mod=readonly -json $(ARGS) $(TEST_PACKAGES) ./... | tparse; \
ec=$$?; \
if [ "$$ec" -ne '0' ]; then finalec=$$ec; fi; \
done; \
exit $$finalec
else
@echo "Starting unit tests"; \
finalec=0; \
for module in $(SUB_MODULES); do \
cd ${CURRENT_DIR}/$$module; \
echo "Running unit tests for module $$module"; \
go test -mod=readonly $(ARGS) $(TEST_PACKAGES) ./... ; \
ec=$$?; \
if [ "$$ec" -ne '0' ]; then finalec=$$ec; fi; \
done; \
exit $$finalec
endif
.PHONY: run-tests test test-all $(TEST_TARGETS)
test-sim-nondeterminism:
@echo "Running non-determinism test..."
@cd ${CURRENT_DIR}/app && go test -mod=readonly -run TestAppStateDeterminism -Enabled=true \
-NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h
test-sim-custom-genesis-fast:
@echo "Running custom genesis simulation..."
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
@cd ${CURRENT_DIR}/app && go test -mod=readonly -run TestFullAppSimulation -Genesis=${HOME}/.gaiad/config/genesis.json \
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h
test-sim-import-export: runsim
@echo "Running application import/export simulation. This may take several minutes..."
@cd ${CURRENT_DIR}/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 5 TestAppImportExport
test-sim-after-import: runsim
@echo "Running application simulation-after-import. This may take several minutes..."
@cd ${CURRENT_DIR}/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 5 TestAppSimulationAfterImport
test-sim-custom-genesis-multi-seed: runsim
@echo "Running multi-seed custom genesis simulation..."
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
@cd ${CURRENT_DIR}/app && $(BINDIR)/runsim -Genesis=${HOME}/.gaiad/config/genesis.json -SimAppPkg=. -ExitOnFail 400 5 TestFullAppSimulation
test-sim-multi-seed-long: runsim
@echo "Running long multi-seed application simulation. This may take awhile!"
@cd ${CURRENT_DIR}/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 500 50 TestFullAppSimulation
test-sim-multi-seed-short: runsim
@echo "Running short multi-seed application simulation. This may take awhile!"
@cd ${CURRENT_DIR}/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 10 TestFullAppSimulation
test-sim-benchmark-invariants:
@echo "Running simulation invariant benchmarks..."
cd ${CURRENT_DIR}/app && @go test -mod=readonly -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
SIM_NUM_BLOCKS ?= 500
SIM_BLOCK_SIZE ?= 200
SIM_COMMIT ?= true
test-sim-benchmark:
@echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@cd ${CURRENT_DIR}/app && go test -mod=readonly -benchmem -run=^$$ $(.) -bench ^BenchmarkFullAppSimulation$$ \
-Enabled=true -NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h
test-sim-profile:
@echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@cd ${CURRENT_DIR}/app && go test -mod=readonly -benchmem -run=^$$ $(.) -bench ^BenchmarkFullAppSimulation$$ \
-Enabled=true -NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out
.PHONY: test-sim-profile test-sim-benchmark
test-rosetta:
docker build -t rosetta-ci:latest -f contrib/rosetta/rosetta-ci/Dockerfile .
docker-compose -f contrib/rosetta/docker-compose.yaml up --abort-on-container-exit --exit-code-from test_rosetta --build
.PHONY: test-rosetta
benchmark:
@go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION)
.PHONY: benchmark
###############################################################################
### Linting ###
###############################################################################
golangci_lint_cmd=golangci-lint
golangci_version=v1.50.1
lint:
@echo "--> Running linter"
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version)
@$(golangci_lint_cmd) run --timeout=10m
lint-fix:
@echo "--> Running linter"
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version)
@$(golangci_lint_cmd) run --fix --out-format=tab --issues-exit-code=0
.PHONY: lint lint-fix
format:
@go install mvdan.cc/gofumpt@latest
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version)
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/docs/statik/statik.go" -not -path "./tests/mocks/*" -not -name "*.pb.go" -not -name "*.pb.gw.go" -not -name "*.pulsar.go" -not -path "./crypto/keys/secp256k1/*" | xargs gofumpt -w -l
$(golangci_lint_cmd) run --fix
.PHONY: format
###############################################################################
### Devdoc ###
###############################################################################
DEVDOC_SAVE = docker commit `docker ps -a -n 1 -q` devdoc:local
devdoc-init:
$(DOCKER) run -it -v "$(CURDIR):/go/src/github.com/cosmos/cosmos-sdk" -w "/go/src/github.com/cosmos/cosmos-sdk" tendermint/devdoc echo
# TODO make this safer
$(call DEVDOC_SAVE)
devdoc:
$(DOCKER) run -it -v "$(CURDIR):/go/src/github.com/cosmos/cosmos-sdk" -w "/go/src/github.com/cosmos/cosmos-sdk" devdoc:local bash
devdoc-save:
# TODO make this safer
$(call DEVDOC_SAVE)
devdoc-clean:
docker rmi -f $$(docker images -f "dangling=true" -q)
devdoc-update:
docker pull tendermint/devdoc
.PHONY: devdoc devdoc-clean devdoc-init devdoc-save devdoc-update
###############################################################################
### Protobuf ###
###############################################################################
protoVer=0.13.0
protoImageName=ghcr.io/cosmos/proto-builder:$(protoVer)
protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName)
proto-all: proto-format proto-lint proto-gen
proto-gen:
@echo "Generating Protobuf files"
@$(protoImage) sh ./scripts/protocgen.sh
proto-swagger-gen:
@echo "Generating Protobuf Swagger"
@$(protoImage) sh ./scripts/protoc-swagger-gen.sh
$(MAKE) update-swagger-docs
proto-format:
@$(protoImage) find ./ -name "*.proto" -exec clang-format -i {} \;
proto-lint:
@$(protoImage) buf lint --error-format=json
proto-check-breaking:
@$(protoImage) buf breaking --against $(HTTPS_GIT)#branch=main
CMT_URL = https://raw.githubusercontent.com/cometbft/cometbft/v0.37.0/proto/tendermint
TM_CRYPTO_TYPES = proto/tendermint/crypto
TM_ABCI_TYPES = proto/tendermint/abci
TM_TYPES = proto/tendermint/types
TM_VERSION = proto/tendermint/version
TM_LIBS = proto/tendermint/libs/bits
TM_P2P = proto/tendermint/p2p
proto-update-deps:
@echo "Updating Protobuf dependencies"
@mkdir -p $(TM_ABCI_TYPES)
@curl -sSL $(TM_URL)/abci/types.proto > $(TM_ABCI_TYPES)/types.proto
@mkdir -p $(TM_VERSION)
@curl -sSL $(TM_URL)/version/types.proto > $(TM_VERSION)/types.proto
@mkdir -p $(TM_TYPES)
@curl -sSL $(TM_URL)/types/types.proto > $(TM_TYPES)/types.proto
@curl -sSL $(TM_URL)/types/evidence.proto > $(TM_TYPES)/evidence.proto
@curl -sSL $(TM_URL)/types/params.proto > $(TM_TYPES)/params.proto
@curl -sSL $(TM_URL)/types/validator.proto > $(TM_TYPES)/validator.proto
@curl -sSL $(TM_URL)/types/block.proto > $(TM_TYPES)/block.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
@mkdir -p $(TM_LIBS)
@curl -sSL $(TM_URL)/libs/bits/types.proto > $(TM_LIBS)/types.proto
@mkdir -p $(TM_P2P)
@curl -sSL $(TM_URL)/p2p/types.proto > $(TM_P2P)/types.proto
$(DOCKER) run --rm -v $(CURDIR)/proto:/workspace --workdir /workspace $(protoImageName) buf mod update
.PHONY: proto-all proto-gen proto-swagger-gen proto-format proto-lint proto-check-breaking proto-update-deps
###############################################################################
### Localnet ###
###############################################################################
localnet-build-env:
$(MAKE) -C contrib/images simd-env
localnet-build-dlv:
$(MAKE) -C contrib/images simd-dlv
localnet-build-nodes:
$(DOCKER) run --rm -v $(CURDIR)/.testnets:/data cosmossdk/simd \
testnet init-files --v 4 -o /data --starting-ip-address 192.168.10.2 --keyring-backend=test
docker-compose up -d
localnet-stop:
docker-compose down
# localnet-start will run a 4-node testnet locally. The nodes are
# based off the docker images in: ./contrib/images/simd-env
localnet-start: localnet-stop localnet-build-env localnet-build-nodes
# localnet-debug will run a 4-node testnet locally in debug mode
# you can read more about the debug mode here: ./contrib/images/simd-dlv/README.md
localnet-debug: localnet-stop localnet-build-dlv localnet-build-nodes
.PHONY: localnet-start localnet-stop localnet-debug localnet-build-env localnet-build-dlv localnet-build-nodes
###############################################################################
### rosetta ###
###############################################################################
# builds rosetta test data dir
rosetta-data:
-docker container rm data_dir_build
docker build -t rosetta-ci:latest -f contrib/rosetta/rosetta-ci/Dockerfile .
docker run --name data_dir_build -t rosetta-ci:latest sh /rosetta/data.sh
docker cp data_dir_build:/tmp/data.tar.gz "$(CURDIR)/contrib/rosetta/rosetta-ci/data.tar.gz"
docker container rm data_dir_build
.PHONY: rosetta-data

View File

@ -21,6 +21,7 @@ type HandlerOptions struct {
TxFeeChecker TxFeeChecker
MachineKeeper MachineKeeper
DaoKeeper DaoKeeper
StakingKeeper StakingKeeper
}
// NewAnteHandler returns an AnteHandler that checks and increments sequence
@ -45,16 +46,20 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
if options.DaoKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "dao keeper is required for ante builder")
}
if options.StakingKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "staking keeper is required for ante builder")
}
anteDecorators := []sdk.AnteDecorator{
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
NewSetUpContextDecorator(options.DaoKeeper), // outermost AnteDecorator. SetUpContext must be called first
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
NewGasKVCostDecorator(options.StakingKeeper),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
NewCheckValidatorDecorator(options.StakingKeeper),
NewCheckMachineDecorator(options.MachineKeeper),
NewCheckMintAddressDecorator(options.DaoKeeper),
NewCheckReissuanceDecorator(),
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators

View File

@ -51,21 +51,21 @@ func (cm CheckMachineDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
func (cm CheckMachineDecorator) handleNotarizeAsset(ctx sdk.Context, notarizeMsg *assettypes.MsgNotarizeAsset) (sdk.Context, error) {
_, found := cm.mk.GetMachineIndexByAddress(ctx, notarizeMsg.GetCreator())
if !found {
return ctx, errorsmod.Wrapf(machinetypes.ErrMachineNotFound, "error during CheckTx or ReCheckTx")
return ctx, errorsmod.Wrap(machinetypes.ErrMachineNotFound, ErrorAnteContext)
}
return ctx, nil
}
func (cm CheckMachineDecorator) handleAttestMachine(ctx sdk.Context, attestMsg *machinetypes.MsgAttestMachine) (sdk.Context, error) {
if attestMsg.GetCreator() != attestMsg.Machine.GetAddress() {
return ctx, errorsmod.Wrapf(machinetypes.ErrMachineIsNotCreator, "error during CheckTx or ReCheckTx")
return ctx, errorsmod.Wrap(machinetypes.ErrMachineIsNotCreator, ErrorAnteContext)
}
_, activated, found := cm.mk.GetTrustAnchor(ctx, attestMsg.Machine.MachineId)
if !found {
return ctx, errorsmod.Wrapf(machinetypes.ErrTrustAnchorNotFound, "error during CheckTx or ReCheckTx")
return ctx, errorsmod.Wrap(machinetypes.ErrTrustAnchorNotFound, ErrorAnteContext)
}
if activated {
return ctx, errorsmod.Wrapf(machinetypes.ErrTrustAnchorAlreadyInUse, "error during CheckTx or ReCheckTx")
return ctx, errorsmod.Wrap(machinetypes.ErrTrustAnchorAlreadyInUse, ErrorAnteContext)
}
return ctx, nil
}
@ -73,7 +73,7 @@ func (cm CheckMachineDecorator) handleAttestMachine(ctx sdk.Context, attestMsg *
func (cm CheckMachineDecorator) handlePopResult(ctx sdk.Context, popMsg *daotypes.MsgReportPopResult) (sdk.Context, error) {
_, found := cm.mk.GetMachineIndexByAddress(ctx, popMsg.GetCreator())
if !found {
return ctx, errorsmod.Wrapf(machinetypes.ErrMachineNotFound, "error during CheckTx or ReCheckTx")
return ctx, errorsmod.Wrap(machinetypes.ErrMachineNotFound, ErrorAnteContext)
}
return ctx, nil
}

View File

@ -1,35 +0,0 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/util"
"github.com/planetmint/planetmint-go/x/dao/keeper"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
)
type CheckReissuanceDecorator struct{}
func NewCheckReissuanceDecorator() CheckReissuanceDecorator {
return CheckReissuanceDecorator{}
}
func (cmad CheckReissuanceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
for _, msg := range tx.GetMsgs() {
if sdk.MsgTypeURL(msg) == "/planetmintgo.dao.MsgReissueRDDLProposal" {
MsgProposal, ok := msg.(*daotypes.MsgReissueRDDLProposal)
if ok {
util.GetAppLogger().Debug(ctx, "REISSUE: receive Proposal")
conf := config.GetConfig()
isValid := keeper.IsValidReissuanceCommand(MsgProposal.GetTx(), conf.ReissuanceAsset, MsgProposal.GetBlockHeight())
if !isValid {
util.GetAppLogger().Info(ctx, "REISSUE: error during CheckTx or ReCheckTx")
return ctx, errorsmod.Wrapf(daotypes.ErrReissuanceProposal, "error during CheckTx or ReCheckTx")
}
}
}
}
return next(ctx, tx, simulate)
}

View File

@ -0,0 +1,59 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/x/dao/types"
)
type CheckValidatorDecorator struct {
sk StakingKeeper
}
func NewCheckValidatorDecorator(sk StakingKeeper) CheckValidatorDecorator {
return CheckValidatorDecorator{sk: sk}
}
func (cv CheckValidatorDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (_ sdk.Context, err error) {
if simulate || ctx.BlockHeight() == 0 {
return next(ctx, tx, simulate)
}
for _, msg := range tx.GetMsgs() {
switch sdk.MsgTypeURL(msg) {
case "/planetmintgo.dao.MsgInitPop":
fallthrough
case "/planetmintgo.dao.MsgDistributionRequest":
fallthrough
case "/planetmintgo.dao.MsgDistributionResult":
fallthrough
case "/planetmintgo.dao.MsgReissueRDDLProposal":
fallthrough
case "/planetmintgo.dao.MsgReissueRDDLResult":
fallthrough
case "/planetmintgo.dao.MsgUpdateRedeemClaim":
fallthrough
case "/planetmintgo.machine.MsgNotarizeLiquidAsset":
fallthrough
case "/planetmintgo.machine.MsgRegisterTrustAnchor":
ctx, err = cv.handleMsg(ctx, msg)
default:
continue
}
}
if err != nil {
return ctx, err
}
return next(ctx, tx, simulate)
}
func (cv CheckValidatorDecorator) handleMsg(ctx sdk.Context, msg sdk.Msg) (_ sdk.Context, err error) {
signer := msg.GetSigners()[0]
_, found := cv.sk.GetValidator(ctx, sdk.ValAddress(signer))
if !found {
return ctx, errorsmod.Wrap(types.ErrRestrictedMsg, ErrorAnteContext)
}
return ctx, nil
}

View File

@ -40,7 +40,7 @@ func NewDeductFeeDecorator(ak AccountKeeper, bk authtypes.BankKeeper, fk Feegran
func checkTxFee(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, ErrorTxFeeTx)
}
feeCoins := feeTx.GetFee()
@ -74,7 +74,7 @@ func checkTxFee(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, error) {
func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, ErrorTxFeeTx)
}
if !simulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 {
@ -84,6 +84,10 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
var (
err error
)
msgs := tx.GetMsgs()
if len(msgs) == 1 && sdk.MsgTypeURL(msgs[0]) == "/planetmintgo.machine.MsgAttestMachine" {
return next(ctx, tx, simulate)
}
fee := feeTx.GetFee()
if !simulate {
@ -102,7 +106,7 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error {
feeTx, ok := sdkTx.(sdk.FeeTx)
if !ok {
return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
return errorsmod.Wrap(sdkerrors.ErrTxDecode, ErrorTxFeeTx)
}
if addr := dfd.accountKeeper.GetModuleAddress(authtypes.FeeCollectorName); addr == nil {
@ -162,7 +166,7 @@ func (dfd DeductFeeDecorator) deductFees(bankKeeper authtypes.BankKeeper, ctx sd
err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authtypes.FeeCollectorName, fees)
if err != nil {
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
return errorsmod.Wrap(sdkerrors.ErrInsufficientFunds, err.Error())
}
return nil

6
app/ante/error.go Normal file
View File

@ -0,0 +1,6 @@
package ante
var (
ErrorAnteContext = "error during CheckTx or ReCheckTx"
ErrorTxFeeTx = "Tx must be a FeeTx"
)

View File

@ -5,6 +5,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
)
@ -32,9 +33,19 @@ type BankKeeper interface {
IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error
SendCoins(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
}
type DaoKeeper interface {
GetMintRequestByHash(ctx sdk.Context, hash string) (val daotypes.MintRequest, found bool)
GetMintAddress(ctx sdk.Context) (mintAddress string)
GetTxGasLimit(ctx sdk.Context) (txGasLimit uint64)
GetClaimAddress(ctx sdk.Context) (claimAddress string)
IsValidReissuanceProposal(ctx sdk.Context, msg *daotypes.MsgReissueRDDLProposal) (isValid bool)
GetRedeemClaim(ctx sdk.Context, benficiary string, id uint64) (val daotypes.RedeemClaim, found bool)
GetParams(ctx sdk.Context) (params daotypes.Params)
}
type StakingKeeper interface {
GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool)
}

View File

@ -0,0 +1,42 @@
package ante
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
type GasKVCostDecorator struct {
sk StakingKeeper
}
func NewGasKVCostDecorator(sk StakingKeeper) GasKVCostDecorator {
return GasKVCostDecorator{sk: sk}
}
func (gc GasKVCostDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (_ sdk.Context, err error) {
if simulate || ctx.BlockHeight() == 0 {
return next(ctx, tx, simulate)
}
msgs := tx.GetMsgs()
signers := msgs[0].GetSigners()
signer := signers[0]
valAddr := sdk.ValAddress(signer)
_, found := gc.sk.GetValidator(ctx, valAddr)
if !found {
return next(ctx, tx, simulate)
}
ctx = ctx.WithKVGasConfig(sdk.GasConfig{
HasCost: 0,
DeleteCost: 0,
ReadCostFlat: 0,
ReadCostPerByte: 0,
WriteCostFlat: 0,
WriteCostPerByte: 0,
IterNextCostFlat: 0,
})
return next(ctx, tx, simulate)
}

View File

@ -0,0 +1,92 @@
package ante
import (
"fmt"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
)
var _ GasTx = (*legacytx.StdTx)(nil) // assert StdTx implements GasTx
// GasTx defines a Tx with a GetGas() method which is needed to use SetUpContextDecorator
type GasTx interface {
sdk.Tx
GetGas() uint64
}
// SetUpContextDecorator sets the GasMeter in the Context and wraps the next AnteHandler with a defer clause
// to recover from any downstream OutOfGas panics in the AnteHandler chain to return an error with information
// on gas provided and gas used.
// CONTRACT: Must be first decorator in the chain
// CONTRACT: Tx must implement GasTx interface
type SetUpContextDecorator struct {
dk DaoKeeper
}
func NewSetUpContextDecorator(dk DaoKeeper) SetUpContextDecorator {
return SetUpContextDecorator{
dk: dk,
}
}
func (sud SetUpContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// all transactions must implement GasTx
gasTx, ok := tx.(GasTx)
if !ok {
// Set a gas meter with limit 0 as to prevent an infinite gas meter attack
// during runTx.
newCtx = SetGasMeter(simulate, ctx, 0)
return newCtx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
gasLimit := sud.dk.GetTxGasLimit(ctx)
if gasLimit == 0 {
gasLimit = gasTx.GetGas()
}
newCtx = SetGasMeter(simulate, ctx, gasLimit)
if cp := ctx.ConsensusParams(); cp != nil && cp.Block != nil {
// If there exists a maximum block gas limit, we must ensure that the tx
// does not exceed it.
if cp.Block.MaxGas > 0 && gasTx.GetGas() > uint64(cp.Block.MaxGas) {
return newCtx, errorsmod.Wrapf(sdkerrors.ErrInvalidGasLimit, "tx gas limit %d exceeds block max gas %d", gasTx.GetGas(), cp.Block.MaxGas)
}
}
// Decorator will catch an OutOfGasPanic caused in the next antehandler
// AnteHandlers must have their own defer/recover in order for the BaseApp
// to know how much gas was used! This is because the GasMeter is created in
// the AnteHandler, but if it panics the context won't be set properly in
// runTx's recover call.
defer func() {
if r := recover(); r != nil {
switch rType := r.(type) {
case sdk.ErrorOutOfGas:
log := fmt.Sprintf(
"out of gas in location: %v; gasWanted: %d, gasUsed: %d",
rType.Descriptor, gasTx.GetGas(), newCtx.GasMeter().GasConsumed())
err = errorsmod.Wrap(sdkerrors.ErrOutOfGas, log)
default:
panic(r)
}
}
}()
return next(newCtx, tx, simulate)
}
// SetGasMeter returns a new context with a gas meter set from a given context.
func SetGasMeter(simulate bool, ctx sdk.Context, gasLimit uint64) sdk.Context {
// In various cases such as simulation and during the genesis block, we do not
// meter any gas utilization.
if simulate || ctx.BlockHeight() == 0 {
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
}
return ctx.WithGasMeter(sdk.NewGasMeter(gasLimit))
}

View File

@ -109,6 +109,7 @@ import (
ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint"
"github.com/spf13/cast"
"github.com/planetmint/planetmint-go/monitor"
machinemodule "github.com/planetmint/planetmint-go/x/machine"
machinemodulekeeper "github.com/planetmint/planetmint-go/x/machine/keeper"
machinemoduletypes "github.com/planetmint/planetmint-go/x/machine/types"
@ -548,6 +549,8 @@ func New(
keys[machinemoduletypes.AddressIndexKey],
keys[machinemoduletypes.MemStoreKey],
app.GetSubspace(machinemoduletypes.ModuleName),
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
homePath,
)
machineModule := machinemodule.NewAppModule(appCodec, app.MachineKeeper, app.AccountKeeper, app.BankKeeper)
@ -568,11 +571,14 @@ func New(
keys[daomoduletypes.ChallengeKey],
keys[daomoduletypes.MintRequestHashKey],
keys[daomoduletypes.MintRequestAddressKey],
keys[authtypes.StoreKey],
app.GetSubspace(daomoduletypes.ModuleName),
app.BankKeeper,
app.AccountKeeper,
app.MachineKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
homePath,
)
daoModule := daomodule.NewAppModule(appCodec, app.DaoKeeper, app.AccountKeeper, app.BankKeeper)
@ -777,6 +783,7 @@ func New(
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
MachineKeeper: app.MachineKeeper,
DaoKeeper: app.DaoKeeper,
StakingKeeper: app.StakingKeeper,
},
)
if err != nil {
@ -788,6 +795,8 @@ func New(
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.setupUpgradeHandlers()
if loadLatest {
if err := app.LoadLatestVersion(); err != nil {
tmos.Exit(err.Error())
@ -798,6 +807,8 @@ func New(
app.ScopedTransferKeeper = scopedTransferKeeper
// this line is used by starport scaffolding # stargate/app/beforeInitReturn
monitor.LazyMqttMonitorLoader(logger, homePath)
return app
}
@ -944,6 +955,12 @@ func (app *App) RegisterTendermintService(clientCtx client.Context) {
// RegisterNodeService implements the Application.RegisterNodeService method.
func (app *App) RegisterNodeService(clientCtx client.Context) {
nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter())
// HACK: start mqtt monitor as late as possible (hint: look in vendor directory for startup order)
mqttMonitorInstance := monitor.GetMqttMonitorInstance()
err := mqttMonitorInstance.Start()
if err != nil {
panic(err)
}
}
// initParamsKeeper init params keeper and its subspaces
@ -979,3 +996,22 @@ func (app *App) SimulationManager() *module.SimulationManager {
func (app *App) ModuleManager() *module.Manager {
return app.mm
}
func (app *App) setupUpgradeHandlers() {
app.UpgradeKeeper.SetUpgradeHandler("v0.8.0", func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// Set versions to the latest ConsensusVersion in the VersionMap.
// This will skip running InitGenesis on Dao
fromVM[daomoduletypes.ModuleName] = daomodule.AppModule{}.ConsensusVersion()
fromVM[machinemoduletypes.ModuleName] = machinemodule.AppModule{}.ConsensusVersion()
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
})
app.UpgradeKeeper.SetUpgradeHandler("v0.10.0", func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
})
app.UpgradeKeeper.SetUpgradeHandler("v0.10.5", func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
})
app.UpgradeKeeper.SetUpgradeHandler("v0.11.0", func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
})
}

View File

@ -6,8 +6,8 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
)
// The genesis state of the blockchain is represented here as a map of raw json
// messages key'd by a identifier string.
// GenesisState The genesis state of the blockchain is represented here as a
// map of raw json messages key'd by a identifier string.
// The identifier is used to determine which module genesis information belongs
// to so it may be appropriately routed during init chain.
// Within this application default genesis information is retrieved from

48
clients/claim/client.go Normal file
View File

@ -0,0 +1,48 @@
package claim
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/planetmint/planetmint-go/config"
"github.com/rddl-network/rddl-claim-service/client"
"github.com/rddl-network/rddl-claim-service/types"
)
var (
RCClient client.IRCClient
)
func lazyLoad() client.IRCClient {
if RCClient != nil {
return RCClient
}
cfg := config.GetConfig()
RCClient = client.NewRCClient(cfg.ClaimHost, &http.Client{})
return RCClient
}
func PostClaim(ctx context.Context, beneficiary string, amount uint64, id uint64) (txID string, err error) {
if beneficiary == "" {
return txID, errors.New("beneficiary cannot be empty")
}
if amount == 0 {
return txID, errors.New("amount must be greater than 0")
}
req := types.PostClaimRequest{
Beneficiary: beneficiary,
Amount: amount,
ClaimID: int(id),
}
client := lazyLoad()
resp, err := client.PostClaim(ctx, req)
if err != nil {
return txID, fmt.Errorf("failed to post claim: %w", err)
}
return resp.TxID, nil
}

View File

@ -0,0 +1,55 @@
package coordinator
import (
"context"
"errors"
"github.com/planetmint/planetmint-go/config"
"github.com/rddl-network/go-utils/tls"
"github.com/rddl-network/shamir-coordinator-service/client"
)
var (
SCClient client.ISCClient
)
func lazyLoad() client.ISCClient {
if SCClient != nil {
return SCClient
}
cfg := config.GetConfig()
httpsClient, err := tls.Get2WayTLSClient(cfg.CertsPath)
if err != nil {
err := errors.New("fatal error setting up mutual tls client for shamir coordinator")
panic(err)
}
SCClient = client.NewSCClient(cfg.IssuerHost, httpsClient)
return SCClient
}
func SendTokens(ctx context.Context, recipient string, amount string, asset string) (txID string, err error) {
client := lazyLoad()
resp, err := client.SendTokens(ctx, recipient, amount, asset)
if err != nil {
return
}
return resp.TxID, nil
}
func ReIssueAsset(ctx context.Context, asset string, amount string) (txID string, err error) {
client := lazyLoad()
resp, err := client.ReIssueAsset(ctx, asset, amount)
if err != nil {
return
}
return resp.TxID, nil
}
func IssueNFTAsset(ctx context.Context, name string, machineAddress string, domain string) (assetID string, contract string, hexTx string, err error) {
client := lazyLoad()
resp, err := client.IssueMachineNFT(ctx, name, machineAddress, domain)
if err != nil {
return
}
return resp.Asset, resp.Contract, resp.HexTX, nil
}

View File

@ -2,25 +2,57 @@ package cmd
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/app"
)
func initSDKConfig() *sdk.Config {
// Set prefixes
accountPubKeyPrefix := app.AccountAddressPrefix + "pub"
validatorAddressPrefix := app.AccountAddressPrefix + "valoper"
validatorPubKeyPrefix := app.AccountAddressPrefix + "valoperpub"
consNodeAddressPrefix := app.AccountAddressPrefix + "valcons"
consNodePubKeyPrefix := app.AccountAddressPrefix + "valconspub"
const (
// Address prefix suffixes
pubKeySuffix = "pub"
valOperSuffix = "valoper"
valOperPubSuffix = "valoperpub"
valConsSuffix = "valcons"
valConsPubSuffix = "valconspub"
// Set and seal config
// PLMNT coin type as defined in SLIP44
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
plmntCoinType = 8680
)
// initSDKConfig initializes and returns the SDK configuration with proper Bech32 prefixes
// and coin type settings for the Planetmint network.
func initSDKConfig() *sdk.Config {
config := sdk.GetConfig()
config.SetBech32PrefixForAccount(app.AccountAddressPrefix, accountPubKeyPrefix)
config.SetBech32PrefixForValidator(validatorAddressPrefix, validatorPubKeyPrefix)
config.SetBech32PrefixForConsensusNode(consNodeAddressPrefix, consNodePubKeyPrefix)
// Set to PLMNT coin type as defined in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
config.SetCoinType(8680)
// Configure address prefixes
configureBech32Prefixes(config)
// Set coin type for PLMNT
config.SetCoinType(plmntCoinType)
// Seal the configuration to prevent further modifications
config.Seal()
return config
}
// configureBech32Prefixes sets up all the Bech32 prefixes for different address types
// using the base account address prefix defined in the app package.
func configureBech32Prefixes(config *sdk.Config) {
// Account addresses
config.SetBech32PrefixForAccount(
app.AccountAddressPrefix,
app.AccountAddressPrefix+pubKeySuffix,
)
// Validator addresses
config.SetBech32PrefixForValidator(
app.AccountAddressPrefix+valOperSuffix,
app.AccountAddressPrefix+valOperPubSuffix,
)
// Consensus node addresses
config.SetBech32PrefixForConsensusNode(
app.AccountAddressPrefix+valConsSuffix,
app.AccountAddressPrefix+valConsPubSuffix,
)
}

View File

@ -129,6 +129,7 @@ func initRootCmd(
),
genutilcli.ValidateGenesisCmd(app.ModuleBasics),
AddGenesisAccountCmd(app.DefaultNodeHome),
TrustWalletCmd(),
tmcli.NewCompletionCmd(rootCmd, true),
debug.Cmd(),
config.Cmd(),
@ -359,6 +360,7 @@ func initAppConfig(clientCtx client.Context) (string, interface{}) {
type CustomAppConfig struct {
serverconfig.Config
PlmntConfig planetmintconfig.Config
LibConfig lib.Config
}
// Optionally allow the chain developer to overwrite the SDK's default
@ -378,12 +380,14 @@ func initAppConfig(clientCtx client.Context) (string, interface{}) {
// In simapp, we set the min gas prices to 0.
srvCfg.MinGasPrices = "0stake"
plmntCfg := planetmintconfig.GetConfig()
plmntCfg.SetRoot(clientCtx.HomeDir)
plmntConfig := planetmintconfig.GetConfig()
libConfig := lib.GetConfig()
libConfig.SetChainID(clientCtx.ChainID)
customAppConfig := CustomAppConfig{
Config: *srvCfg,
PlmntConfig: *plmntCfg,
PlmntConfig: *plmntConfig,
LibConfig: *libConfig,
}
customAppTemplate := serverconfig.DefaultConfigTemplate + planetmintconfig.DefaultConfigTemplate

View File

@ -0,0 +1,142 @@
package cmd
import (
"errors"
"strconv"
"strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/go-bip39"
"github.com/planetmint/planetmint-go/lib/trustwallet"
"github.com/spf13/cobra"
)
const (
flagSerialPort = "serial-port"
SerialPort = "/dev/ttyACM0"
)
func TrustWalletCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "trust-wallet [command]",
Short: "Trust Wallet subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
cmd.AddCommand(
initializeCmd(),
keysCmd(),
)
return cmd
}
func initializeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "initialize \"[mnemonic]\"",
Short: "Initialize a Trust Wallet",
Long: `Initialize a Trust Wallet with a mnemonic phrase (optional). If no mnemonic is provided then one is created for you.
Provided mnemonics must be 12 or 24 words long and adhere to bip39.`,
RunE: initializeCmdFunc,
Args: cobra.RangeArgs(0, 1),
}
cmd.Flags().String(flagSerialPort, SerialPort, "The serial port your Trust Wallet is connected to")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
func initializeCmdFunc(cmd *cobra.Command, args []string) error {
serialPort, err := cmd.Flags().GetString(flagSerialPort)
if err != nil {
return err
}
connector, err := trustwallet.NewTrustWalletConnector(serialPort)
if err != nil {
return err
}
// create mnemonic if non is given
if len(args) == 0 {
cmd.Println("Initializing Trust Wallet. This may take a few seconds...")
mnemonic, err := connector.CreateMnemonic()
if err != nil {
return err
}
cmd.Println("Created mnemonic:")
cmd.Println(mnemonic + "\n")
cmd.Println("IMPORTANT: Store your mnemonic securely in an offline location, such as a hardware wallet, encrypted USB, or paper stored in a safe, never online or on cloud storage!")
return nil
}
// recover from given mnemonic
cmd.Println("Recovering Trust Wallet from mnemonic...")
words := strings.Split(args[0], " ")
if len(words) != 12 && len(words) != 24 {
return errors.New("expected length of mnemonic is 12 or 24, got: " + strconv.Itoa(len(words)))
}
mnemonic := strings.Join(words, " ")
if !bip39.IsMnemonicValid(mnemonic) {
return errors.New("invalid mnemonic, please check provided words")
}
response, err := connector.RecoverFromMnemonic(mnemonic)
if err != nil {
return err
}
cmd.Println(response)
return nil
}
func keysCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "keys",
Short: "Retrieve keys from Trust Wallet",
Long: `Retrieve keys from Trust Wallet. Includes:
planetmint address,
extended planetmint public key,
extended liquid public key,
raw planetmint key (hex encoded)`,
RunE: keysCmdFunc,
Args: cobra.ExactArgs(0),
}
cmd.Flags().String(flagSerialPort, SerialPort, "The serial port your Trust Wallet is connected to")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
func keysCmdFunc(cmd *cobra.Command, _ []string) error {
serialPort, err := cmd.Flags().GetString(flagSerialPort)
if err != nil {
return err
}
connector, err := trustwallet.NewTrustWalletConnector(serialPort)
if err != nil {
return err
}
cmd.Println("Retrieving keys from Trust Wallet. This may take a few seconds...")
cmd.Println()
keys, err := connector.GetPlanetmintKeys()
if err != nil {
return err
}
cmd.Println("- address: " + keys.PlanetmintAddress)
cmd.Printf(" pubkey: [{\"@type\":\"PlanetmintExtended\",\"key\":\"%s\"},{\"@type\":\"PlanetmintHex\",\"key\":\"%s\"},{\"@type\":\"LiquidExtended\",\"key\":\"%s\"}]\n", keys.ExtendedPlanetmintPubkey, keys.RawPlanetmintPubkey, keys.ExtendedLiquidPubkey)
cmd.Println(" type: hardware")
return nil
}

View File

@ -2,7 +2,13 @@ package config
import (
"encoding/json"
"errors"
"os"
"sync"
"github.com/planetmint/planetmint-go/lib"
"github.com/planetmint/planetmint-go/lib/trustwallet"
"github.com/rddl-network/go-utils/logger"
)
const DefaultConfigTemplate = `
@ -11,45 +17,40 @@ const DefaultConfigTemplate = `
###############################################################################
[planetmint]
asset-registry-endpoint = "{{ .PlmntConfig.AssetRegistryEndpoint }}"
token-denom = "{{ .PlmntConfig.TokenDenom }}"
stake-denom = "{{ .PlmntConfig.StakeDenom }}"
fee-denom = "{{ .PlmntConfig.FeeDenom }}"
pop-epochs = {{ .PlmntConfig.PoPEpochs }}
rpc-host = "{{ .PlmntConfig.RPCHost }}"
rpc-port = {{ .PlmntConfig.RPCPort }}
rpc-user = "{{ .PlmntConfig.RPCUser }}"
rpc-password = "{{ .PlmntConfig.RPCPassword }}"
issuance-service-dir = "{{ .PlmntConfig.IssuanceServiceDir }}"
reissuance-asset = "{{ .PlmntConfig.ReissuanceAsset }}"
validator-address = "{{ .PlmntConfig.ValidatorAddress }}"
distribution-address-inv = "{{ .PlmntConfig.DistributionAddrInv }}"
distribution-address-dao = "{{ .PlmntConfig.DistributionAddrDAO }}"
distribution-address-pop = "{{ .PlmntConfig.DistributionAddrPoP }}"
distribution-epochs = {{ .PlmntConfig.DistributionEpochs }}
certs-path = "{{ .PlmntConfig.CertsPath }}"
claim-host = "{{ .PlmntConfig.ClaimHost }}"
issuer-host = "{{ .PlmntConfig.IssuerHost }}"
mqtt-domain = "{{ .PlmntConfig.MqttDomain }}"
mqtt-password = "{{ .PlmntConfig.MqttPassword }}"
mqtt-port = {{ .PlmntConfig.MqttPort }}
mqtt-tls = {{ .PlmntConfig.MqttTLS }}
mqtt-user = "{{ .PlmntConfig.MqttUser }}"
`
// ValAddr to be reomved see: https://github.com/planetmint/planetmint-go/issues/454
const ValAddr = "VALIDATOR_ADDRESS"
const (
defaultCertsPath = "./certs/"
defaultClaimHost = "https://testnet-p2r.rddl.io"
defaultIssuerHost = "https://testnet-issuer.rddl.io"
defaultMqttDomain = "testnet-mqtt.rddl.io"
defaultMqttPassword = "password"
defaultMqttPort = 1886
defaultMqttTLS = true
defaultMqttUser = "user"
)
// Config defines Planetmint's top level configuration
type Config struct {
AssetRegistryEndpoint string `json:"asset-registry-endpoint" mapstructure:"asset-registry-endpoint"`
TokenDenom string `json:"token-denom" mapstructure:"token-denom"`
StakeDenom string `json:"stake-denom" mapstructure:"stake-denom"`
FeeDenom string `json:"fee-denom" mapstructure:"fee-denom"`
ConfigRootDir string `json:"config-root-dir" mapstructure:"config-root-dir"`
PoPEpochs int `json:"pop-epochs" mapstructure:"pop-epochs"` //nolint: tagliatelle // json(kebab): got 'pop-epochs' want 'po-p-epochs'
RPCHost string `json:"rpc-host" mapstructure:"rpc-host"`
RPCPort int `json:"rpc-port" mapstructure:"rpc-port"`
RPCUser string `json:"rpc-user" mapstructure:"rpc-user"`
RPCPassword string `json:"rpc-password" mapstructure:"rpc-password"`
IssuanceServiceDir string `json:"issuance-service-dir" mapstructure:"issuance-service-dir"`
ReissuanceAsset string `json:"reissuance-asset" mapstructure:"reissuance-asset"`
ValidatorAddress string `json:"validator-address" mapstructure:"validator-address"`
DistributionAddrInv string `json:"distribution-addr-inv" mapstructure:"distribution-addr-inv"`
DistributionAddrDAO string `json:"distribution-addr-dao" mapstructure:"distribution-addr-dao"`
DistributionAddrPoP string `json:"distribution-addr-pop" mapstructure:"distribution-addr-pop"` //nolint: tagliatelle // json(kebab): got 'distribution-addr-pop' want 'distribution-addr-po-p'
DistributionEpochs int `json:"distribution-epochs" mapstructure:"distribution-epochs"`
CertsPath string `json:"certs-path" mapstructure:"certs-path"`
ClaimHost string `json:"claim-host" mapstructure:"claim-host"`
IssuerHost string `json:"issuer-host" mapstructure:"issuer-host"`
MqttDomain string `json:"mqtt-domain" mapstructure:"mqtt-domain"`
MqttPassword string `json:"mqtt-password" mapstructure:"mqtt-password"`
MqttPort int `json:"mqtt-port" mapstructure:"mqtt-port"`
MqttTLS bool `json:"mqtt-tls" mapstructure:"mqtt-tls"`
MqttUser string `json:"mqtt-user" mapstructure:"mqtt-user"`
}
// cosmos-sdk wide global singleton
@ -61,23 +62,14 @@ var (
// DefaultConfig returns planetmint's default configuration.
func DefaultConfig() *Config {
return &Config{
AssetRegistryEndpoint: "https://assets.rddl.io/register_asset",
TokenDenom: "plmnt",
StakeDenom: "plmntstake",
FeeDenom: "plmnt",
ConfigRootDir: "",
PoPEpochs: 24, // 24 CometBFT epochs of 5s equate 120s
RPCHost: "localhost",
RPCPort: 18884,
RPCUser: "user",
RPCPassword: "password",
IssuanceServiceDir: "/opt/issuer_service",
ReissuanceAsset: "7add40beb27df701e02ee85089c5bc0021bc813823fedb5f1dcb5debda7f3da9",
ValidatorAddress: "plmnt1w5dww335zhh98pzv783hqre355ck3u4w4hjxcx",
DistributionAddrInv: "vjTyRN2G42Yq3T5TJBecHj1dF1xdhKF89hKV4HJN3uXxUbaVGVR76hAfVRQqQCovWaEpar7G5qBBprFG",
DistributionAddrDAO: "vjU8eMzU3JbUWZEpVANt2ePJuPWSPixgjiSj2jDMvkVVQQi2DDnZuBRVX4Ygt5YGBf5zvTWCr1ntdqYH",
DistributionAddrPoP: "vjTvXCFSReRsZ7grdsAreRR12KuKpDw8idueQJK9Yh1BYS7ggAqgvCxCgwh13KGK6M52y37HUmvr4GdD",
DistributionEpochs: 17280, // CometBFT epochs of 5s equate 1 day (12*60*24)
CertsPath: defaultCertsPath,
ClaimHost: defaultClaimHost,
IssuerHost: defaultIssuerHost,
MqttDomain: defaultMqttDomain,
MqttPassword: defaultMqttPassword,
MqttPort: defaultMqttPort,
MqttTLS: defaultMqttTLS,
MqttUser: defaultMqttUser,
}
}
@ -89,19 +81,72 @@ func GetConfig() *Config {
return plmntConfig
}
func (config *Config) SetRoot(root string) *Config {
config.ConfigRootDir = root
return config
}
// SetWatchmenConfig sets Planetmint's configuration
// SetPlanetmintConfig sets Planetmint's configuration
func (config *Config) SetPlanetmintConfig(planetmintconfig interface{}) {
jsonConfig, err := json.Marshal(planetmintconfig)
if err != nil {
panic(err)
}
err = json.Unmarshal(jsonConfig, &config)
if err != nil {
if err := json.Unmarshal(jsonConfig, config); err != nil {
panic(err)
}
}
// GetNodeAddress retrieves the validator address through multiple methods
func (config *Config) GetNodeAddress() (address string) {
var err error
// Check environment variable first <- this is used for test cases only
if address = os.Getenv(ValAddr); address != "" {
return
}
libConfig := lib.GetConfig()
// Handle no Trust Wallet connected scenario
if libConfig.GetSerialPort() == "" {
address, err = getKeyringAddress(libConfig)
} else { // Handle Trust Wallet connected scenario
address, err = getTrustWalletAddress(libConfig)
}
if err != nil {
msg := "Cannot get node address. Please configure a Trust Wallet or define at least one key pair in the utilized keyring."
newError := errors.New(msg + ": " + err.Error())
panic(newError)
}
return address
}
// getKeyringAddress retrieves the default validator address
func getKeyringAddress(libConfig *lib.Config) (address string, err error) {
defaultRecord, err := libConfig.GetDefaultValidatorRecord()
if err != nil {
logger.GetLogger(logger.ERROR).Error("msg", err.Error())
return
}
addr, err := defaultRecord.GetAddress()
if err != nil {
logger.GetLogger(logger.ERROR).Error("msg", err.Error())
return
}
address = addr.String()
return
}
// getTrustWalletAddress retrieves validator address from Trust Wallet
func getTrustWalletAddress(libConfig *lib.Config) (address string, err error) {
connector, err := trustwallet.NewTrustWalletConnector(libConfig.GetSerialPort())
if err != nil {
logger.GetLogger(logger.ERROR).Error("msg", err.Error())
return
}
keys, err := connector.GetPlanetmintKeys()
if err != nil {
logger.GetLogger(logger.ERROR).Error("msg", err.Error())
return
}
address = keys.PlanetmintAddress
return
}

View File

@ -5,7 +5,12 @@ import (
)
// LiquidNetParams defines the network parameters for the Liquid network.
var LiquidNetParams chaincfg.Params
var LiquidNetParams = func() chaincfg.Params {
params := chaincfg.MainNetParams
params.Name = "liquidv1"
params.HDCoinType = 1776
return params
}()
// PlmntNetParams defines the network parameters for the Planetmint network.
var PlmntNetParams = chaincfg.Params{
@ -21,17 +26,9 @@ var PlmntNetParams = chaincfg.Params{
}
func init() {
// Not allowed to register LiquidNetParams, because it's just another
// Bitcoin network with different coin type.
// See https://github.com/satoshilabs/slips/blob/master/slip-0044.md
LiquidNetParams = chaincfg.MainNetParams
LiquidNetParams.Name = "liquidv1"
LiquidNetParams.HDCoinType = 1776
// Need to register PlmntNetParams, otherwise we get an "unknown hd
// private extended key bytes" error.
err := chaincfg.Register(&PlmntNetParams)
if err != nil {
if err := chaincfg.Register(&PlmntNetParams); err != nil {
panic(err)
}
}

76
contrib/devtools/Makefile Normal file
View File

@ -0,0 +1,76 @@
###
# Find OS and Go environment
# GO contains the Go binary
# FS contains the OS file separator
###
ifeq ($(OS),Windows_NT)
GO := $(shell where go.exe 2> NUL)
FS := "\\"
else
GO := $(shell command -v go 2> /dev/null)
FS := "/"
endif
ifeq ($(GO),)
$(error could not find go. Is it in PATH? $(GO))
endif
###############################################################################
### Functions ###
###############################################################################
go_get = $(if $(findstring Windows_NT,$(OS)),\
IF NOT EXIST $(GITHUBDIR)$(FS)$(1)$(FS) ( mkdir $(GITHUBDIR)$(FS)$(1) ) else (cd .) &\
IF NOT EXIST $(GITHUBDIR)$(FS)$(1)$(FS)$(2)$(FS) ( cd $(GITHUBDIR)$(FS)$(1) && git clone https://github.com/$(1)/$(2) ) else (cd .) &\
,\
mkdir -p $(GITHUBDIR)$(FS)$(1) &&\
(test ! -d $(GITHUBDIR)$(FS)$(1)$(FS)$(2) && cd $(GITHUBDIR)$(FS)$(1) && git clone https://github.com/$(1)/$(2)) || true &&\
)\
cd $(GITHUBDIR)$(FS)$(1)$(FS)$(2) && git fetch origin && git checkout -q $(3)
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
mkfile_dir := $(shell cd $(shell dirname $(mkfile_path)); pwd)
###############################################################################
### Tools ###
###############################################################################
PREFIX ?= /usr/local
BIN ?= $(PREFIX)/bin
UNAME_S ?= $(shell uname -s)
UNAME_M ?= $(shell uname -m)
GOPATH ?= $(shell $(GO) env GOPATH)
GITHUBDIR := $(GOPATH)$(FS)src$(FS)github.com
BUF_VERSION ?= 0.11.0
TOOLS_DESTDIR ?= $(GOPATH)/bin
STATIK = $(TOOLS_DESTDIR)/statik
RUNSIM = $(TOOLS_DESTDIR)/runsim
tools: tools-stamp
tools-stamp: statik runsim
# Create dummy file to satisfy dependency and avoid
# rebuilding when this Makefile target is hit twice
# in a row.
touch $@
# Install the runsim binary
statik: $(STATIK)
$(STATIK):
@echo "Installing statik..."
@go install github.com/rakyll/statik@v0.1.6
# Install the runsim binary
runsim: $(RUNSIM)
$(RUNSIM):
@echo "Installing runsim..."
@go install github.com/cosmos/tools/cmd/runsim@v1.0.0
tools-clean:
rm -f $(STATIK) $(GOLANGCI_LINT) $(RUNSIM)
rm -f tools-stamp
.PHONY: tools-clean statik runsim

1639
docs/static/openapi.yml vendored

File diff suppressed because it is too large Load Diff

7
errormsg/error.go Normal file
View File

@ -0,0 +1,7 @@
package errormsg
var (
CouldNotGetValidatorIdentity = "could not get validator identity"
ErrorInvalidCreator = "invalid creator address (%s)"
InvalidRequest = "invalid request"
)

156
go.mod
View File

@ -1,58 +1,67 @@
module github.com/planetmint/planetmint-go
go 1.19
go 1.22
require (
cosmossdk.io/api v0.3.1
cosmossdk.io/errors v1.0.0
cosmossdk.io/math v1.1.2
github.com/btcsuite/btcd v0.23.2
github.com/btcsuite/btcd/btcutil v1.1.2
github.com/cometbft/cometbft v0.37.2
github.com/cometbft/cometbft-db v0.7.0
github.com/cosmos/cosmos-proto v1.0.0-beta.2
github.com/cosmos/cosmos-sdk v0.47.5
cosmossdk.io/depinject v1.0.0-alpha.4
cosmossdk.io/errors v1.0.1
cosmossdk.io/math v1.4.0
cosmossdk.io/simapp v0.0.0-20230323161446-0af178d721ff
github.com/btcsuite/btcd v0.24.0
github.com/btcsuite/btcd/btcutil v1.1.5
github.com/cometbft/cometbft v0.37.5
github.com/cometbft/cometbft-db v0.8.0
github.com/cosmos/cosmos-proto v1.0.0-beta.5
github.com/cosmos/cosmos-sdk v0.47.14
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/gogoproto v1.4.10
github.com/cosmos/ibc-go/v7 v7.1.0
github.com/cosmos/gogoproto v1.7.0
github.com/cosmos/ibc-go/v7 v7.4.0
github.com/eclipse/paho.mqtt.golang v1.4.3
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3
github.com/golang/protobuf v1.5.4
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2
github.com/planetmint/planetmint-go/lib v0.2.1
github.com/spf13/cast v1.5.0
github.com/spf13/cobra v1.6.1
github.com/planetmint/planetmint-go/lib v0.6.0
github.com/rddl-network/elements-rpc v1.2.1
github.com/rddl-network/go-utils v0.2.3
github.com/rddl-network/rddl-claim-service v0.3.2
github.com/rddl-network/rddl-claim-service/client v0.0.6
github.com/rddl-network/shamir-coordinator-service v0.7.7
github.com/rddl-network/shamir-coordinator-service/client v0.1.0
github.com/spf13/cast v1.6.0
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529
google.golang.org/grpc v1.56.3
github.com/stretchr/testify v1.9.0
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80
google.golang.org/grpc v1.62.1
gopkg.in/yaml.v2 v2.4.0
gotest.tools v2.2.0+incompatible
sigs.k8s.io/yaml v1.3.0
sigs.k8s.io/yaml v1.4.0
)
require (
cloud.google.com/go v0.110.4 // indirect
cloud.google.com/go/compute v1.20.1 // indirect
cloud.google.com/go v0.112.0 // indirect
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.0 // indirect
cloud.google.com/go/storage v1.30.1 // indirect
cloud.google.com/go/iam v1.1.5 // indirect
cloud.google.com/go/storage v1.36.0 // indirect
cosmossdk.io/core v0.5.1 // indirect
cosmossdk.io/depinject v1.0.0-alpha.4 // indirect
cosmossdk.io/log v1.2.1 // indirect
cosmossdk.io/log v1.4.1 // indirect
cosmossdk.io/tools/rosetta v0.2.1 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // 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 v1.0.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go v1.44.203 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // 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.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
@ -65,40 +74,43 @@ require (
github.com/confio/ics23/go v0.9.0 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/iavl v0.20.0 // indirect
github.com/cosmos/iavl v0.20.1 // indirect
github.com/cosmos/ics23/go v0.10.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.4 // indirect
github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect
github.com/creachadair/taskgroup v0.4.2 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/getsentry/sentry-go v0.23.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.1.0 // indirect
github.com/golang/glog v1.2.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.11.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
@ -106,7 +118,7 @@ require (
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.1 // indirect
github.com/hashicorp/go-getter v1.7.5 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
@ -118,15 +130,16 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.16.3 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/linxGnu/grocksdb v1.7.16 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
@ -134,10 +147,10 @@ require (
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
@ -146,38 +159,47 @@ require (
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rs/cors v1.8.3 // indirect
github.com/rs/zerolog v1.30.0 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/viper v1.15.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tidwall/btree v1.6.0 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.1 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v0.14.3 // indirect
go.bug.st/serial v1.6.2 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.126.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/protobuf v1.31.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
go.opentelemetry.io/otel v1.21.0 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/api v0.155.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
pgregory.net/rapid v0.5.5 // indirect
pgregory.net/rapid v1.1.0 // indirect
)
replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7

399
go.sum
View File

@ -3,7 +3,6 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
@ -16,7 +15,6 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
@ -32,8 +30,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk=
cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM=
cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4=
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
@ -70,8 +68,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg=
cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
@ -111,8 +109,8 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97
cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94=
cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk=
cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
@ -170,12 +168,11 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8=
cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
@ -193,12 +190,14 @@ cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI=
cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE=
cosmossdk.io/depinject v1.0.0-alpha.4 h1:PLNp8ZYAMPTUKyG9IK2hsbciDWqna2z1Wsl98okJopc=
cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vMaOmslGFM3yU=
cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04=
cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0=
cosmossdk.io/log v1.2.1 h1:Xc1GgTCicniwmMiKwDxUjO4eLhPxoVdI9vtMW8Ti/uk=
cosmossdk.io/log v1.2.1/go.mod h1:GNSCc/6+DhFIj1aLn/j7Id7PaO8DzNylUZoOYBL9+I4=
cosmossdk.io/math v1.1.2 h1:ORZetZCTyWkI5GlZ6CZS28fMHi83ZYf+A2vVnHNzZBM=
cosmossdk.io/math v1.1.2/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=
cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U=
cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM=
cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU=
cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ=
cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk=
cosmossdk.io/simapp v0.0.0-20230323161446-0af178d721ff h1:P1ialzTepD1oxdNPYc5N8Eggq3RdejZq3cJs8YYMs9Y=
cosmossdk.io/simapp v0.0.0-20230323161446-0af178d721ff/go.mod h1:AKzx6Mb544LjJ9RHmGFHjY9rEOLiUAi8I0F727TR0dY=
cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw=
cosmossdk.io/tools/rosetta v0.2.1/go.mod h1:Pqdc1FdvkNV3LcNIkYWt2RQY6IP1ge6YWZk8MhhO9Hw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
@ -209,14 +208,17 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN
github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o=
github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg=
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4=
github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM=
github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
@ -224,6 +226,7 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I=
github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -258,20 +261,21 @@ github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
github.com/btcsuite/btcd v0.23.2 h1:/YOgUp25sdCnP5ho6Hl3s0E438zlX+Kak7E6TgBgoT0=
github.com/btcsuite/btcd v0.23.2/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=
github.com/btcsuite/btcd v0.24.0 h1:gL3uHE/IaFj6fcZSu03SvqPMSx7s/dPzfpG/atRwWdo=
github.com/btcsuite/btcd v0.24.0/go.mod h1:K4IDc1593s8jKXIF7yS7yCTSxrknB9z0STzc2j6XgE4=
github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ=
github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0=
github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8=
github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
@ -282,6 +286,9 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@ -295,6 +302,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
@ -317,6 +326,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E=
github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
@ -329,13 +340,14 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA=
github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c=
github.com/cometbft/cometbft v0.37.2 h1:XB0yyHGT0lwmJlFmM4+rsRnczPlHoAKFX6K8Zgc2/Jc=
github.com/cometbft/cometbft v0.37.2/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs=
github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo=
github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0=
github.com/cometbft/cometbft v0.37.5 h1:/U/TlgMh4NdnXNo+YU9T2NMCWyhXNDF34Mx582jlvq0=
github.com/cometbft/cometbft v0.37.5/go.mod h1:QC+mU0lBhKn8r9qvmnq53Dmf3DWBt4VtkcKw2C81wxY=
github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AKVZpjo=
github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0=
github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4=
github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@ -344,41 +356,44 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk=
github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis=
github.com/cosmos/cosmos-proto v1.0.0-beta.2 h1:X3OKvWgK9Gsejo0F1qs5l8Qn6xJV/AzgIWR2wZ8Nua8=
github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0=
github.com/cosmos/cosmos-sdk v0.47.5 h1:n1+WjP/VM/gAEOx3TqU2/Ny734rj/MX1kpUnn7zVJP8=
github.com/cosmos/cosmos-sdk v0.47.5/go.mod h1:EHwCeN9IXonsjKcjpS12MqeStdZvIdxt3VYXhus3G3c=
github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA=
github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec=
github.com/cosmos/cosmos-sdk v0.47.14 h1:vD9JyIdlbVaXMOE/BLamViQvylfUq0E0FpqdPVv/fWw=
github.com/cosmos/cosmos-sdk v0.47.14/go.mod h1:GrDj/zd9Tiuy8ZpG9PbUbhghCVU7lwyH0GS7CpxHpyM=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=
github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI=
github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU=
github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI=
github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek=
github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38=
github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A=
github.com/cosmos/ibc-go/v7 v7.1.0 h1:SCLgs7tqVnzdIDO5MRLgovAnc696vTTKl+8qsTu8IMM=
github.com/cosmos/ibc-go/v7 v7.1.0/go.mod h1:7MptlWeIyqmDiuJeRAFqBvXKY8Hybd+rF8vMSmGd2zg=
github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro=
github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0=
github.com/cosmos/iavl v0.20.1 h1:rM1kqeG3/HBT85vsZdoSNsehciqUQPWrR4BYmqE2+zg=
github.com/cosmos/iavl v0.20.1/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A=
github.com/cosmos/ibc-go/v7 v7.4.0 h1:8FqYMptvksgMvlbN4UW9jFxTXzsPyfAzEZurujXac8M=
github.com/cosmos/ibc-go/v7 v7.4.0/go.mod h1:L/KaEhzV5TGUCTfGysVgMBQtl5Dm7hHitfpk+GIeoAo=
github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM=
github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0=
github.com/cosmos/ledger-cosmos-go v0.12.1 h1:sMBxza5p/rNK/06nBSNmsI/WDqI0pVJFVNihy1Y984w=
github.com/cosmos/ledger-cosmos-go v0.12.1/go.mod h1:dhO6kj+Y+AHIOgAe4L9HL/6NDdyyth4q238I9yFpD2g=
github.com/cosmos/ledger-cosmos-go v0.12.4 h1:drvWt+GJP7Aiw550yeb3ON/zsrgW0jgh5saFCr7pDnw=
github.com/cosmos/ledger-cosmos-go v0.12.4/go.mod h1:fjfVWRf++Xkygt9wzCsjEBdjcf7wiiY35fv3ctT+k4M=
github.com/cosmos/rosetta-sdk-go v0.10.0 h1:E5RhTruuoA7KTIXUcMicL76cffyeoyvNybzUGSKFTcM=
github.com/cosmos/rosetta-sdk-go v0.10.0/go.mod h1:SImAZkb96YbwvoRkzSMQB6noNJXFgWl/ENIznEoYQI4=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8=
github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
@ -397,16 +412,20 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM=
github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY=
github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -419,21 +438,24 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE=
github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@ -441,8 +463,10 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -458,13 +482,21 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
@ -473,7 +505,8 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@ -488,8 +521,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -524,8 +557,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
@ -548,17 +581,20 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us=
github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -570,24 +606,24 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
@ -597,10 +633,9 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4=
github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
@ -637,8 +672,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY=
github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4=
github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
@ -680,13 +715,13 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ=
github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
@ -703,6 +738,7 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
@ -717,11 +753,12 @@ github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -731,13 +768,16 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8=
github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
@ -745,16 +785,15 @@ github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3v
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@ -785,6 +824,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@ -801,6 +841,7 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
@ -809,15 +850,20 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q=
github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
@ -827,14 +873,15 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA=
github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU=
@ -842,15 +889,16 @@ github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7c
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
@ -889,6 +937,18 @@ github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Ung
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rddl-network/elements-rpc v1.2.1 h1:clE3daxNPJJ1EDiAkTSlXUM2+gakmLHxWOazZ4t2W48=
github.com/rddl-network/elements-rpc v1.2.1/go.mod h1:9a71Z7xja4rFMXa+ssUMLAF9VIZVPz2jZRB1hTS9Ey4=
github.com/rddl-network/go-utils v0.2.3 h1:STiiyZVkFjovjMAyKK1IsqvVED14mRHoXFIDVbwxlFQ=
github.com/rddl-network/go-utils v0.2.3/go.mod h1:jLOkVBK/xjfVyY0d4gs1pkafTXF3mYA7ZIE68QXau5o=
github.com/rddl-network/rddl-claim-service v0.3.2 h1:Cp8FV40y9mwTbjVNlFrZ02QT+HZWD1pSsWaE5MLYAmc=
github.com/rddl-network/rddl-claim-service v0.3.2/go.mod h1:RLg6AcNL790WuAl3AYoxFGkuuwKP3t3IiBfhOYOcwdo=
github.com/rddl-network/rddl-claim-service/client v0.0.6 h1:GLqj8RMozFPVUvPQGRLBH2yGV+VHRuUCXTWaf+4wxFo=
github.com/rddl-network/rddl-claim-service/client v0.0.6/go.mod h1:CFAfupB5XogWqVsb6ndsLU97feGs4oUqlGI4WRff3zU=
github.com/rddl-network/shamir-coordinator-service v0.7.7 h1:hszDZZnqBdeiOEBWlnSK2lKIJEbWclX6cchYDazpvIU=
github.com/rddl-network/shamir-coordinator-service v0.7.7/go.mod h1:g3JnQlzKQWtnp4ZA7VtD/4N0GKpFWrW0ANHqged7M/g=
github.com/rddl-network/shamir-coordinator-service/client v0.1.0 h1:o8oZzvGSAyTto5hSkNRr2KvilhwWiqGbL70HRg4aKhA=
github.com/rddl-network/shamir-coordinator-service/client v0.1.0/go.mod h1:dhxYyhmU71iv32WqS6S+6Pm/Lsb5/d0KVn2MVTq5Jfk=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@ -899,12 +959,16 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo=
github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c=
github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
@ -915,41 +979,43 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -959,25 +1025,27 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok=
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg=
github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
@ -991,10 +1059,12 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo=
github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
github.com/zondax/ledger-go v0.14.1 h1:Pip65OOl4iJ84WTpA4BKChvOufMhhbxED3BaihoZN4c=
github.com/zondax/ledger-go v0.14.1/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320=
github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U=
github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw=
github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI=
go.bug.st/serial v1.6.2 h1:kn9LRX3sdm+WxWKufMlIRndwGfPWsH1/9lCWXQCasq8=
go.bug.st/serial v1.6.2/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
@ -1010,15 +1080,33 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -1031,12 +1119,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -1048,8 +1133,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us=
golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -1076,7 +1161,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1119,14 +1205,12 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@ -1139,8 +1223,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1166,8 +1250,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1182,7 +1266,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1239,13 +1324,11 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1257,7 +1340,6 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1277,17 +1359,17 @@ golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1299,12 +1381,14 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -1359,7 +1443,6 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@ -1367,7 +1450,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1426,8 +1510,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ
google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o=
google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw=
google.golang.org/api v0.155.0 h1:vBmGhCYs0djJttDNynWo44zosHlPvHmA0XiN2zP2DtA=
google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1435,8 +1519,9 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -1475,10 +1560,8 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@ -1545,12 +1628,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw
google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8=
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y=
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 h1:s5YSX+ZH5b5vS9rnpGymvIyMpLRJizowqDlOuyjXnTk=
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU=
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -1592,8 +1675,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -1610,14 +1693,15 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@ -1645,7 +1729,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@ -1656,12 +1741,12 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA=
pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View File

@ -9,6 +9,10 @@ After that we construct three messages to send `10plmnt` each to three addresses
We then build and sign the transaction and eventually send this transaction via RPC.
For debugging purposes we print the transaction that we send as JSON.
## Support for Trust Wallet over serial connection
The config has a setting for a `serialPort`. If it is set then `BroadcastTxWithFileLock()` will sign transactions with the TrustWallet. Be aware that the public key must be available on the keyring in order to construct transactions signing data.
```
package main
@ -45,7 +49,7 @@ func main() {
}
fmt.Println(txJSON)
_, err = lib.BroadcastTx(addr0, msg1, msg2, msg3)
_, err = lib.BroadcastTxWithFileLock(addr0, msg1, msg2, msg3)
if err != nil {
log.Fatal(err)
}

View File

@ -1,73 +1,190 @@
package lib
import (
"errors"
"os"
"sync"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/lib/params"
)
// Config defines library top level configuration.
type Config struct {
ChainID string `json:"chain-id" mapstructure:"chain-id"`
EncodingConfig params.EncodingConfig `json:"encoding-config" mapstructure:"encoding-config"`
RootDir string `json:"root-dir" mapstructure:"root-dir"`
RPCEndpoint string `json:"rpc-endpoint" mapstructure:"rpc-endpoint"`
}
// lib wide global singleton
var (
libConfig *Config
sdkConfig *sdk.Config
initConfig sync.Once
// ErrInvalidConfig is returned when configuration validation fails
ErrInvalidConfig = errors.New("invalid configuration")
// Global singleton instances
instance *Config
mu sync.RWMutex
once sync.Once
sdkConfig *sdk.Config
)
// DefaultConfig returns library default configuration.
func DefaultConfig() *Config {
// Config defines the top-level configuration for the Planetmint library.
// All fields are exported to allow external access while maintaining
// thread-safe modifications through methods.
type Config struct {
ChainID string
ClientCtx client.Context
EncodingConfig params.EncodingConfig
FeeDenom string
RPCEndpoint string
RootDir string
SerialPort string
TxGas uint64
}
// NewConfig creates a new Config instance with default values.
func NewConfig() *Config {
return &Config{
ChainID: "planetmint-testnet-1",
ClientCtx: client.Context{},
EncodingConfig: params.EncodingConfig{},
RootDir: "~/.planetmint-go/",
FeeDenom: "plmnt",
RPCEndpoint: "http://127.0.0.1:26657",
RootDir: "~/.planetmint-go/",
TxGas: 200000,
}
}
// GetConfig returns the config instance for the SDK.
// GetConfig returns the singleton Config instance, initializing it if necessary.
func GetConfig() *Config {
initConfig.Do(func() {
libConfig = DefaultConfig()
once.Do(func() {
instance = NewConfig()
sdkConfig = sdk.GetConfig()
libConfig.SetBech32PrefixForAccount("plmnt")
// Initialize default configuration
instance.SetBech32PrefixForAccount("plmnt")
encodingConfig := MakeEncodingConfig()
instance.SetEncodingConfig(encodingConfig)
})
return libConfig
return instance
}
// SetBech32PrefixForAccount sets the bech32 account prefix.
func (config *Config) SetBech32PrefixForAccount(bech32Prefix string) *Config {
sdkConfig.SetBech32PrefixForAccount(bech32Prefix, "pub")
return config
// Validate checks if the configuration is valid.
func (c *Config) Validate() error {
mu.RLock()
defer mu.RUnlock()
if c.ChainID == "" {
return errors.New("chain ID cannot be empty")
}
if c.RPCEndpoint == "" {
return errors.New("RPC endpoint cannot be empty")
}
if c.TxGas == 0 {
return errors.New("transaction gas cannot be zero")
}
return nil
}
// SetEncodingConfig sets the encoding config and must not be nil.
func (config *Config) SetEncodingConfig(encodingConfig params.EncodingConfig) *Config {
config.EncodingConfig = encodingConfig
return config
// Builder methods
func (c *Config) SetBech32PrefixForAccount(prefix string) *Config {
mu.Lock()
defer mu.Unlock()
sdkConfig.SetBech32PrefixForAccount(prefix, "pub")
return c
}
// SetChainID sets the chain ID parameter.
func (config *Config) SetChainID(chainID string) *Config {
config.ChainID = chainID
return config
func (c *Config) SetEncodingConfig(config params.EncodingConfig) *Config {
mu.Lock()
defer mu.Unlock()
c.EncodingConfig = config
return c
}
// SetRoot sets the root directory where to find the keyring.
func (config *Config) SetRoot(root string) *Config {
config.RootDir = root
return config
func (c *Config) SetChainID(chainID string) *Config {
mu.Lock()
defer mu.Unlock()
c.ChainID = chainID
return c
}
// SetRPCEndpoint sets the RPC endpoint to send requests to.
func (config *Config) SetRPCEndpoint(rpcEndpoint string) *Config {
config.RPCEndpoint = rpcEndpoint
return config
func (c *Config) SetClientCtx(ctx client.Context) *Config {
mu.Lock()
defer mu.Unlock()
c.ClientCtx = ctx
return c
}
func (c *Config) SetFeeDenom(denom string) *Config {
mu.Lock()
defer mu.Unlock()
c.FeeDenom = denom
return c
}
func (c *Config) SetRoot(root string) *Config {
mu.Lock()
defer mu.Unlock()
c.RootDir = root
return c
}
func (c *Config) SetRPCEndpoint(endpoint string) *Config {
mu.Lock()
defer mu.Unlock()
c.RPCEndpoint = endpoint
return c
}
func (c *Config) SetTxGas(gas uint64) *Config {
mu.Lock()
defer mu.Unlock()
c.TxGas = gas
return c
}
func (c *Config) SetSerialPort(port string) *Config {
mu.Lock()
defer mu.Unlock()
c.SerialPort = port
return c
}
// Getter methods
func (c *Config) GetSerialPort() string {
mu.RLock()
defer mu.RUnlock()
return c.SerialPort
}
// Keyring operations
// GetLibKeyring returns a new keyring instance configured with the current settings.
func (c *Config) GetLibKeyring() (keyring.Keyring, error) {
mu.RLock()
defer mu.RUnlock()
return keyring.New(
"lib",
keyring.BackendTest,
c.RootDir,
os.Stdin,
c.EncodingConfig.Marshaler,
[]keyring.Option{}...,
)
}
// GetDefaultValidatorRecord returns the first validator record from the keyring.
func (c *Config) GetDefaultValidatorRecord() (*keyring.Record, error) {
keyring, err := c.GetLibKeyring()
if err != nil {
return nil, err
}
records, err := keyring.List()
if err != nil {
return nil, err
}
if len(records) == 0 {
return nil, errors.New("no keyring records found")
}
return records[0], nil
}

32
lib/encoding.go Normal file
View File

@ -0,0 +1,32 @@
package lib
import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/std"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/planetmint/planetmint-go/lib/params"
)
// makeEncodingConfig creates an EncodingConfig for an amino based test configuration.
func makeEncodingConfig() params.EncodingConfig {
amino := codec.NewLegacyAmino()
interfaceRegistry := types.NewInterfaceRegistry()
marshaler := codec.NewProtoCodec(interfaceRegistry)
txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes)
return params.EncodingConfig{
InterfaceRegistry: interfaceRegistry,
Marshaler: marshaler,
TxConfig: txCfg,
Amino: amino,
}
}
// MakeEncodingConfig creates an EncodingConfig for testing
func MakeEncodingConfig() params.EncodingConfig {
encodingConfig := makeEncodingConfig()
std.RegisterLegacyAminoCodec(encodingConfig.Amino)
std.RegisterInterfaces(encodingConfig.InterfaceRegistry)
return encodingConfig
}

View File

@ -1,125 +1,202 @@
module github.com/planetmint/planetmint-go/lib
go 1.20
go 1.22
require (
github.com/cometbft/cometbft v0.37.2
github.com/cosmos/cosmos-sdk v0.47.5
github.com/cometbft/cometbft v0.37.5
github.com/cosmos/cosmos-sdk v0.47.14
github.com/planetmint/planetmint-go v0.12.8
github.com/stretchr/testify v1.9.0
go.bug.st/serial v1.6.2
sigs.k8s.io/yaml v1.4.0
)
require (
cloud.google.com/go v0.112.0 // indirect
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.5 // indirect
cloud.google.com/go/storage v1.36.0 // indirect
cosmossdk.io/api v0.3.1 // indirect
cosmossdk.io/core v0.5.1 // indirect
cosmossdk.io/depinject v1.0.0-alpha.4 // indirect
cosmossdk.io/errors v1.0.0 // indirect
cosmossdk.io/math v1.1.2 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/log v1.4.1 // indirect
cosmossdk.io/math v1.4.0 // indirect
cosmossdk.io/simapp v0.0.0-20230323161446-0af178d721ff // indirect
cosmossdk.io/tools/rosetta v0.2.1 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // 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 v1.0.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go v1.44.203 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
github.com/btcsuite/btcd v0.24.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/btcsuite/btcd/btcutil v1.1.5 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
github.com/cockroachdb/errors v1.10.0 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cometbft/cometbft-db v0.7.0 // indirect
github.com/coinbase/rosetta-sdk-go/types v1.0.0 // indirect
github.com/cometbft/cometbft-db v0.8.0 // indirect
github.com/confio/ics23/go v0.9.0 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogoproto v1.4.10 // indirect
github.com/cosmos/iavl v0.20.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/gogoproto v1.7.0 // indirect
github.com/cosmos/iavl v0.20.1 // indirect
github.com/cosmos/ibc-go/v7 v7.4.0 // indirect
github.com/cosmos/ics23/go v0.10.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.4 // indirect
github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect
github.com/creachadair/taskgroup v0.4.2 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
github.com/eclipse/paho.mqtt.golang v1.4.3 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/getsentry/sentry-go v0.23.0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.1.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/glog v1.2.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.5 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-uuid v1.0.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
github.com/huandu/skiplist v1.2.0 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.16.3 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/linxGnu/grocksdb v1.7.16 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/rakyll/statik v0.1.7 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rddl-network/elements-rpc v1.2.1 // indirect
github.com/rddl-network/go-utils v0.2.3 // indirect
github.com/rddl-network/rddl-claim-service v0.3.2 // indirect
github.com/rddl-network/rddl-claim-service/client v0.0.6 // indirect
github.com/rddl-network/shamir-coordinator-service v0.7.7 // indirect
github.com/rddl-network/shamir-coordinator-service/client v0.1.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rs/cors v1.8.3 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.6.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.15.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tidwall/btree v1.6.0 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.1 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v0.14.3 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/grpc v1.56.3 // indirect
google.golang.org/protobuf v1.31.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
go.opentelemetry.io/otel v1.21.0 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/api v0.155.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/grpc v1.62.1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
pgregory.net/rapid v0.5.5 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
nhooyr.io/websocket v1.8.6 // indirect
pgregory.net/rapid v1.1.0 // indirect
)
replace github.com/planetmint/planetmint-go => ../

1094
lib/go.sum

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
package dao
package machine
import (
"testing"
@ -8,8 +8,9 @@ import (
"github.com/stretchr/testify/suite"
)
func TestE2ETestSuite(t *testing.T) {
func TestE2ELibTestSuite(t *testing.T) {
t.Parallel()
cfg := network.DefaultConfig()
cfg := network.LoaderDefaultConfig()
cfg.NumValidators = 2
suite.Run(t, NewE2ETestSuite(cfg))
}

146
lib/tests/e2e/suite.go Normal file
View File

@ -0,0 +1,146 @@
package machine
import (
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/planetmint/planetmint-go/lib"
"github.com/planetmint/planetmint-go/lib/trustwallet"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
const (
SerialPort = "/dev/ttyACM0"
)
// E2ETestSuite struct definition of machine suite
type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
}
// NewE2ETestSuite returns configured machine E2ETestSuite
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
return &E2ETestSuite{cfg: cfg}
}
// SetupSuite initializes machine E2ETestSuite
func (s *E2ETestSuite) SetupSuite() {
s.T().Log("setting up e2e lib test suite")
s.network = network.Load(s.T(), s.cfg)
}
// TearDownSuite clean up after testing
func (s *E2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e lib test suite")
}
func (s *E2ETestSuite) TestBankSendBroadcastTxWithFileLock() {
val := s.network.Validators[0]
kb := val.ClientCtx.Keyring
account, err := kb.NewAccount(sample.Name, sample.Mnemonic, keyring.DefaultBIP39Passphrase, sample.DefaultDerivationPath, hd.Secp256k1)
s.Require().NoError(err)
addr, err := account.GetAddress()
s.Require().NoError(err)
libConfig := lib.GetConfig()
libConfig.SetFeeDenom("stake")
// incorrect denom
coin := sdk.NewCoins(sdk.NewInt64Coin("foobar", 1000))
msg := banktypes.NewMsgSend(val.Address, addr, coin)
out, err := lib.BroadcastTxWithFileLock(val.Address, msg)
s.Require().NoError(err)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
assert.Equal(s.T(), "received wrong fee denom; got: stake required: plmnt: invalid coins", txResponse.RawLog)
libConfig.SetFeeDenom(sample.FeeDenom)
// incorrect coin
out, err = lib.BroadcastTxWithFileLock(val.Address, msg)
s.Require().NoError(err)
txResponse, err = lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
assert.Equal(s.T(), "[]", txResponse.RawLog)
s.Require().NoError(s.network.WaitForNextBlock())
_, err = clitestutil.GetRawLogFromTxOut(val, out)
assert.Equal(s.T(), "failed to execute message; message index: 0: spendable balance is smaller than 1000foobar: insufficient funds", err.Error())
// valid transaction
coin = sdk.NewCoins(sdk.NewInt64Coin("stake", 1000))
msg = banktypes.NewMsgSend(val.Address, addr, coin)
out, err = lib.BroadcastTxWithFileLock(val.Address, msg)
s.Require().NoError(err)
txResponse, err = lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
assert.Equal(s.T(), "[]", txResponse.RawLog)
}
func (s *E2ETestSuite) TestLoadKeys() {
s.T().SkipNow()
_, err := setKeys()
if err == nil {
_, err = loadKeys()
s.Require().NoError(err)
}
s.Require().NoError(s.network.WaitForNextBlock())
}
func (s *E2ETestSuite) TestOccSigning() {
s.T().SkipNow()
val := s.network.Validators[0]
keys, err := loadKeys()
s.Require().NoError(err)
addr := sdk.MustAccAddressFromBech32(keys.PlanetmintAddress)
coin := sdk.NewCoins(sdk.NewInt64Coin("stake", 10))
msg := banktypes.NewMsgSend(addr, val.Address, coin)
libConfig := lib.GetConfig()
libConfig.SetSerialPort(SerialPort)
out, err := lib.BroadcastTxWithFileLock(addr, msg)
s.Require().NoError(err)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal("[]", txResponse.RawLog)
s.Require().Equal(uint32(0), txResponse.Code)
}
// set sample mnemonic on trust wallet
func setKeys() (string, error) {
connector, err := trustwallet.NewTrustWalletConnector(SerialPort)
if err != nil {
return "", err
}
return connector.RecoverFromMnemonic(sample.Mnemonic)
}
func loadKeys() (*trustwallet.PlanetMintKeys, error) {
connector, err := trustwallet.NewTrustWalletConnector(SerialPort)
if err != nil {
return nil, err
}
return connector.GetPlanetmintKeys()
}

139
lib/trustwallet/occ.go Normal file
View File

@ -0,0 +1,139 @@
package trustwallet
import (
"errors"
"fmt"
"io"
"time"
"go.bug.st/serial"
)
const (
SlipEnd = 0xC0
SlipEsc = 0xDB
SlipEscEnd = 0xDC
SlipEscEsc = 0xDD
nsPerUs = 1000
nsPerMs = 8000 * nsPerUs
)
// occDo performs the operations to send and receive data over serial port.
func occDo(data []byte, bufferDelayMs int, portName string, outBuffer []byte) (int, error) {
// Initialize unencoded and encoded payloads
payloadUnencoded := make([]byte, 0, len(data))
payloadSlipEncoded := make([]byte, 0, len(data)*2)
// Copy data to payloadUnencoded
payloadUnencoded = append(payloadUnencoded, data...)
// Open serial port
mode := &serial.Mode{BaudRate: 115200}
s, err := serial.Open(portName, mode)
if err != nil {
return 0, fmt.Errorf("unable to open serial port: %w", err)
}
defer s.Close()
// Encode payload using SLIP
encodeSLIP(payloadUnencoded, &payloadSlipEncoded)
// Send encoded payload over serial
if _, err := s.Write(payloadSlipEncoded); err != nil {
return 0, fmt.Errorf("unable to write to serial port: %w", err)
}
time.Sleep(time.Duration(bufferDelayMs) * time.Millisecond)
// Read response from serial
readBuffer := make([]byte, 1)
encodedResponse := make([]byte, 0)
slipMsgFramer := 0
for {
n, err := s.Read(readBuffer)
if err != nil && !errors.Is(err, io.EOF) {
time.Sleep(10 * time.Millisecond)
continue
}
if n == 0 {
break
}
encodedResponse = append(encodedResponse, readBuffer[0])
if readBuffer[0] == SlipEnd {
if slipMsgFramer == 1 {
break
}
slipMsgFramer++
}
time.Sleep(1 * time.Millisecond)
}
// Decode SLIP response
decodedResponse, err := decodeSLIP(encodedResponse)
if err != nil {
return 0, fmt.Errorf("unable to decode SLIP: %w", err)
}
// Copy decoded response to outBuffer
copyLength := min(len(decodedResponse), len(outBuffer))
copy(outBuffer, decodedResponse[:copyLength])
return copyLength, nil
}
// encodeSLIP encodes data using SLIP protocol.
func encodeSLIP(data []byte, encoded *[]byte) {
*encoded = append(*encoded, SlipEnd)
for _, b := range data {
switch b {
case SlipEnd:
*encoded = append(*encoded, SlipEsc, SlipEscEnd)
case SlipEsc:
*encoded = append(*encoded, SlipEsc, SlipEscEsc)
default:
*encoded = append(*encoded, b)
}
}
*encoded = append(*encoded, SlipEnd)
}
// decodeSLIP decodes SLIP-encoded data.
func decodeSLIP(encoded []byte) ([]byte, error) {
// Check for empty input
if len(encoded) == 0 {
return nil, errors.New("encoded data is empty")
}
// Remove first and last SLIP_END bytes
if encoded[0] == SlipEnd {
encoded = encoded[1:]
}
if encoded[len(encoded)-1] == SlipEnd {
encoded = encoded[:len(encoded)-1]
}
decoded := make([]byte, 0, len(encoded))
esc := false
for _, b := range encoded {
switch {
case b == SlipEsc && !esc:
esc = true
case b == SlipEscEnd && esc:
decoded = append(decoded, SlipEnd)
esc = false
case b == SlipEscEsc && esc:
decoded = append(decoded, SlipEsc)
esc = false
default:
decoded = append(decoded, b)
esc = false
}
}
return decoded, nil
}

View File

@ -0,0 +1,88 @@
package trustwallet
import (
"bytes"
"errors"
"fmt"
"strings"
)
const (
PrefixIhw = "/IHW"
BufferSize = 1024
BufferDelayMs = 200
)
type OSCResponse struct {
Command string
Data []string
}
type OSCMessageSender struct {
portName []byte
bufferSize int
bufferDelayMs int
}
func NewOSCMessageSender(portName string) (*OSCMessageSender, error) {
return &OSCMessageSender{
portName: []byte(portName),
bufferSize: BufferSize,
bufferDelayMs: BufferDelayMs,
}, nil
}
func (s *OSCMessageSender) SendMessage(message []byte) (OSCResponse, error) {
outputBuffer := make([]byte, s.bufferSize)
// Call occDo function
outputLength, err := occDo(
message,
s.bufferDelayMs,
string(s.portName),
outputBuffer,
)
if err != nil {
return OSCResponse{}, fmt.Errorf("failed to send message: %w", err)
}
if outputLength == 0 {
return OSCResponse{}, errors.New("no response received")
}
// Extract the information from the output buffer
return extractInformation(outputBuffer[:outputLength])
}
func extractInformation(responseBytes []byte) (OSCResponse, error) {
decodedString := string(bytes.Trim(responseBytes, "\x00"))
parts := strings.Split(decodedString, "\x00")
var response OSCResponse
if len(parts) > 0 {
commandPart := parts[0]
dataParts := parts[1:]
if strings.Contains(commandPart, ",") {
splitCmd := strings.SplitN(commandPart, ",", 2)
response.Command = strings.TrimSpace(splitCmd[0])
dataParts = append([]string{splitCmd[1]}, dataParts...)
} else {
response.Command = strings.TrimSpace(commandPart)
}
response.Data = make([]string, 0, len(dataParts))
for _, part := range dataParts {
if trimmed := strings.TrimSpace(part); trimmed != "" {
response.Data = append(response.Data, trimmed)
}
}
}
if len(response.Data) == 0 {
response.Data = []string{"No valid data found."}
}
return response, nil
}

View File

@ -0,0 +1,290 @@
package trustwallet
import (
"bytes"
"encoding/binary"
"errors"
"strconv"
"sync"
)
const (
NoDataReturned = "no data returned"
NoPublicKeyReturned = "no public key returned"
NoSignatureReturned = "no signature returned"
)
var (
keys *PlanetMintKeys
)
type Connector struct {
oscSender *OSCMessageSender
mu sync.Mutex
}
func NewTrustWalletConnector(portName string) (*Connector, error) {
sender, err := NewOSCMessageSender(portName)
if err != nil {
return nil, err
}
return &Connector{
oscSender: sender,
}, nil
}
func (t *Connector) sendOSCMessage(address string, args ...interface{}) (OSCResponse, error) {
t.mu.Lock()
defer t.mu.Unlock()
message, err := encodeOSCMessage(address, args...)
if err != nil {
return OSCResponse{}, err
}
return t.oscSender.SendMessage(message)
}
func (t *Connector) ValiseGet() (string, error) {
response, err := t.sendOSCMessage(PrefixIhw + "/getSeed")
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoDataReturned)
}
func (t *Connector) CreateMnemonic() (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/mnemonicToSeed", int32(1))
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoDataReturned)
}
func (t *Connector) InjectPlanetminkeyToSE050(slot int) (bool, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/se050InjectSECPKeys", int32(slot))
if err != nil {
return false, err
}
if len(response.Data) > 1 {
return response.Data[1] == "0", nil
}
return false, errors.New(NoDataReturned)
}
func (t *Connector) RecoverFromMnemonic(mnemonic string) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/mnemonicToSeed", int32(1), mnemonic)
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoDataReturned)
}
func (t *Connector) GetPlanetmintKeys() (*PlanetMintKeys, error) {
if keys == nil {
response, err := t.sendOSCMessage(PrefixIhw + "/getPlntmntKeys")
if err != nil {
return nil, err
}
if len(response.Data) < 4 {
return nil, errors.New("trust wallet not initialized. Please initialize the wallet")
}
keys = &PlanetMintKeys{
PlanetmintAddress: response.Data[1],
ExtendedLiquidPubkey: response.Data[2],
ExtendedPlanetmintPubkey: response.Data[3],
RawPlanetmintPubkey: response.Data[4],
}
}
return keys, nil
}
func (t *Connector) GetSeedSE050() (string, error) {
response, err := t.sendOSCMessage(PrefixIhw + "/se050GetSeed")
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoDataReturned)
}
func (t *Connector) SignHashWithPlanetmint(dataToSign string) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/ecdsaSignPlmnt", dataToSign)
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoSignatureReturned)
}
func (t *Connector) SignHashWithRDDL(dataToSign string) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/ecdsaSignRddl", dataToSign)
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoSignatureReturned)
}
func (t *Connector) CreateOptegaKeypair(ctx int) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/optigaTrustXCreateSecret", int32(ctx), "")
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoPublicKeyReturned)
}
func (t *Connector) SignWithOptega(ctx int, dataToSign, pubkey string) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/optigaTrustXSignMessage", int32(ctx), dataToSign, pubkey, "")
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoSignatureReturned)
}
func (t *Connector) UnwrapPublicKey(publicKey string) (bool, string) {
length := len(publicKey)
if length == 136 || length == 130 {
return true, publicKey[len(publicKey)-128:]
} else if length == 128 {
return true, publicKey
}
return false, publicKey
}
func (t *Connector) CalculateHash(dataToSign string) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/se050CalculateHash", dataToSign)
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New("no hash returned")
}
func (t *Connector) CreateSE050KeypairNIST(ctx int) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/se050CreateKeyPair", int32(ctx), int32(1))
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoPublicKeyReturned)
}
func (t *Connector) GetPublicKeyFromSE050(ctx int) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/se050GetPublicKey", int32(ctx))
if err != nil {
return "", err
}
if len(response.Data) > 1 {
valid, pubKey := t.UnwrapPublicKey(response.Data[1])
if !valid {
return "", errors.New("inject PlanetMintKey failed: No key found")
}
return pubKey, nil
}
return "", errors.New(NoPublicKeyReturned)
}
func (t *Connector) SignWithSE050(dataToSign string, ctx int) (string, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/se050SignData", dataToSign, int32(ctx))
if err != nil {
return "", err
}
if len(response.Data) > 1 {
return response.Data[1], nil
}
return "", errors.New(NoSignatureReturned)
}
func (t *Connector) VerifySE050Signature(dataToSign, signature string, ctx int) (bool, error) {
response, err := t.sendOSCMessage(PrefixIhw+"/se050VerifySignature", dataToSign, signature, int32(ctx))
if err != nil {
return false, err
}
if len(response.Data) > 1 {
return strconv.ParseBool(response.Data[1])
}
return false, errors.New("no verification result returned")
}
func encodeOSCMessage(address string, args ...interface{}) (returnBytes []byte, err error) {
var buffer bytes.Buffer
// Write address
buffer.WriteString(address)
buffer.WriteByte(0)
alignBuffer(&buffer)
// Write type tags
buffer.WriteByte(',')
for _, arg := range args {
switch arg.(type) {
case int32:
err = buffer.WriteByte('i')
case float32:
err = buffer.WriteByte('f')
case string:
err = buffer.WriteByte('s')
}
if err != nil {
return buffer.Bytes(), err
}
}
buffer.WriteByte(0)
alignBuffer(&buffer)
// Write arguments
for _, arg := range args {
switch v := arg.(type) {
case int32:
err = binary.Write(&buffer, binary.BigEndian, v)
case float32:
err = binary.Write(&buffer, binary.BigEndian, v)
case string:
_, err = buffer.WriteString(v)
if err != nil {
return buffer.Bytes(), err
}
err = buffer.WriteByte(0)
alignBuffer(&buffer)
}
if err != nil {
return buffer.Bytes(), err
}
}
return buffer.Bytes(), nil
}
func alignBuffer(buffer *bytes.Buffer) {
for buffer.Len()%4 != 0 {
buffer.WriteByte(0)
}
}

8
lib/trustwallet/types.go Normal file
View File

@ -0,0 +1,8 @@
package trustwallet
type PlanetMintKeys struct {
PlanetmintAddress string
ExtendedLiquidPubkey string
ExtendedPlanetmintPubkey string
RawPlanetmintPubkey string
}

319
lib/tx.go
View File

@ -1,28 +1,34 @@
package lib
import (
"bufio"
"bytes"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"github.com/cometbft/cometbft/crypto"
comethttp "github.com/cometbft/cometbft/rpc/client/http"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/planetmint/planetmint-go/lib/trustwallet"
)
var ErrTypeAssertionFailed = errors.New("type assertion failed")
var (
ErrTypeAssertionFailed = errors.New("type assertion failed")
LibSyncAccess sync.Mutex
)
func init() {
GetConfig()
@ -38,31 +44,51 @@ func getAccountNumberAndSequence(clientCtx client.Context) (accountNumber, seque
return
}
func getClientContextAndTxFactory(address sdk.AccAddress) (clientCtx client.Context, txf tx.Factory, err error) {
clientCtx, err = getClientContext(address)
func getClientContextAndTxFactory(fromAddress sdk.AccAddress, withoutFee bool) (clientCtx client.Context, txf tx.Factory, err error) {
clientCtx = GetConfig().ClientCtx
// at least we need an account retriever
// it would be better to check for an empty client context, but that does not work at the moment
if clientCtx.AccountRetriever == nil {
clientCtx, err = getClientContext(fromAddress)
if err != nil {
return
}
}
record, err := clientCtx.Keyring.KeyByAddress(fromAddress)
if err != nil {
return
}
// name and address of private key with which to sign
clientCtx = clientCtx.
WithFromAddress(fromAddress).
WithFromName(record.Name)
accountNumber, sequence, err := getAccountNumberAndSequence(clientCtx)
if err != nil {
return
}
txf = getTxFactoryWithAccountNumberAndSequence(clientCtx, accountNumber, sequence)
gasPrice := "0.000005"
if withoutFee {
gasPrice = "0.0"
}
txf = getTxFactoryWithAccountNumberAndSequence(clientCtx, accountNumber, sequence, gasPrice)
return
}
func getTxFactoryWithAccountNumberAndSequence(clientCtx client.Context, accountNumber, sequence uint64) (txf tx.Factory) {
func getTxFactoryWithAccountNumberAndSequence(clientCtx client.Context, accountNumber, sequence uint64, gasPrice string) (txf tx.Factory) {
return tx.Factory{}.
WithAccountNumber(accountNumber).
WithAccountRetriever(clientCtx.AccountRetriever).
WithChainID(clientCtx.ChainID).
WithGas(200000).
WithGasPrices("0.000005plmnt").
WithFeeGranter(clientCtx.FeeGranter).
WithGas(GetConfig().TxGas).
WithGasPrices(gasPrice + GetConfig().FeeDenom).
WithKeybase(clientCtx.Keyring).
WithSequence(sequence).
WithTxConfig(clientCtx.TxConfig)
}
func getClientContext(address sdk.AccAddress) (clientCtx client.Context, err error) {
func getClientContext(fromAddress sdk.AccAddress) (clientCtx client.Context, err error) {
encodingConfig := GetConfig().EncodingConfig
rootDir := GetConfig().RootDir
@ -70,12 +96,12 @@ func getClientContext(address sdk.AccAddress) (clientCtx client.Context, err err
codec := encodingConfig.Marshaler
keyringOptions := []keyring.Option{}
keyring, err := keyring.New("lib", keyring.BackendTest, rootDir, input, codec, keyringOptions...)
keyring, err := GetConfig().GetLibKeyring()
if err != nil {
return
}
record, err := keyring.KeyByAddress(address)
record, err := keyring.KeyByAddress(fromAddress)
if err != nil {
return
}
@ -94,8 +120,8 @@ func getClientContext(address sdk.AccAddress) (clientCtx client.Context, err err
ChainID: GetConfig().ChainID,
Client: wsClient,
Codec: codec,
From: address.String(),
FromAddress: address,
From: fromAddress.String(),
FromAddress: fromAddress,
FromName: record.Name,
HomeDir: rootDir,
Input: input,
@ -113,10 +139,21 @@ func getClientContext(address sdk.AccAddress) (clientCtx client.Context, err err
return
}
func isMachineAttestationMsg(msgs ...sdk.Msg) (isMachineAttestation bool) {
if len(msgs) != 1 {
return
}
if sdk.MsgTypeURL(msgs[0]) == "/planetmintgo.machine.MsgAttestMachine" {
isMachineAttestation = true
}
return
}
// BuildUnsignedTx builds a transaction to be signed given a set of messages.
// Once created, the fee, memo, and messages are set.
func BuildUnsignedTx(address sdk.AccAddress, msgs ...sdk.Msg) (txJSON string, err error) {
clientCtx, txf, err := getClientContextAndTxFactory(address)
func BuildUnsignedTx(fromAddress sdk.AccAddress, msgs ...sdk.Msg) (txJSON string, err error) {
withoutFee := isMachineAttestationMsg(msgs...)
clientCtx, txf, err := getClientContextAndTxFactory(fromAddress, withoutFee)
if err != nil {
return
}
@ -133,101 +170,20 @@ func BuildUnsignedTx(address sdk.AccAddress, msgs ...sdk.Msg) (txJSON string, er
return
}
// BroadcastTx broadcasts a transaction via RPC.
func BroadcastTx(address sdk.AccAddress, msgs ...sdk.Msg) (broadcastTxResponseJSON string, err error) {
clientCtx, txf, err := getClientContextAndTxFactory(address)
if err != nil {
return
}
broadcastTxResponseJSON, err = broadcastTx(clientCtx, txf, msgs...)
return
}
func broadcastTx(clientCtx client.Context, txf tx.Factory, msgs ...sdk.Msg) (broadcastTxResponseJSON string, err error) {
func broadcastTx(clientCtx client.Context, txf tx.Factory, msgs ...sdk.Msg) (out *bytes.Buffer, err error) {
err = tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msgs...)
if err != nil {
return
}
output, ok := clientCtx.Output.(*bytes.Buffer)
if !ok {
err = ErrTypeAssertionFailed
return
}
result := make(map[string]interface{})
err = json.Unmarshal(output.Bytes(), &result)
if err != nil {
return
}
code, ok := result["code"].(float64)
if !ok {
err = ErrTypeAssertionFailed
return
}
if code != 0 {
err = errors.New(output.String())
return
}
broadcastTxResponseJSON = output.String()
return
}
func getSequenceFromFile(seqFile *os.File, filename string) (sequence uint64, err error) {
var sequenceString string
lineCount := int64(0)
scanner := bufio.NewScanner(seqFile)
for scanner.Scan() {
sequenceString = scanner.Text()
lineCount++
}
err = scanner.Err()
if err != nil {
return
}
if lineCount == 0 {
err = errors.New("Sequence file empty " + filename + ": no lines")
return
} else if lineCount != 1 {
err = errors.New("Malformed " + filename + ": wrong number of lines")
return
}
sequence, err = strconv.ParseUint(sequenceString, 10, 64)
if err != nil {
return
}
return
}
func getSequenceFromChain(clientCtx client.Context) (sequence uint64, err error) {
// Get sequence number from chain.
account, err := clientCtx.AccountRetriever.GetAccount(clientCtx, clientCtx.FromAddress)
if err != nil {
return
}
sequence = account.GetSequence()
return
return writeClientCtxOutputToBuffer(clientCtx)
}
// BroadcastTxWithFileLock broadcasts a transaction via gRPC and synchronises requests via a file lock.
func BroadcastTxWithFileLock(address sdk.AccAddress, msgs ...sdk.Msg) (broadcastTxResponseJSON string, err error) {
func BroadcastTxWithFileLock(fromAddress sdk.AccAddress, msgs ...sdk.Msg) (out *bytes.Buffer, err error) {
LibSyncAccess.Lock()
defer LibSyncAccess.Unlock()
// open and lock file, if it exists
usr, err := user.Current()
if err != nil {
return
}
homeDir := usr.HomeDir
addrHex := hex.EncodeToString(address)
filename := filepath.Join(GetConfig().RootDir, addrHex+".sequence")
// Expand tilde to user's home directory.
if filename == "~" {
filename = homeDir
} else if strings.HasPrefix(filename, "~/") {
filename = filepath.Join(homeDir, filename[2:])
}
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0644)
file, err := openSequenceFile(fromAddress)
if err != nil {
return
}
@ -245,12 +201,13 @@ func BroadcastTxWithFileLock(address sdk.AccAddress, msgs ...sdk.Msg) (broadcast
}()
// get basic chain information
clientCtx, txf, err := getClientContextAndTxFactory(address)
withoutFee := isMachineAttestationMsg(msgs...)
clientCtx, txf, err := getClientContextAndTxFactory(fromAddress, withoutFee)
if err != nil {
return
}
sequenceFromFile, errFile := getSequenceFromFile(file, filename)
sequenceFromFile, errFile := getSequenceFromFile(file)
sequenceFromChain, errChain := getSequenceFromChain(clientCtx)
var sequence uint64
@ -265,11 +222,25 @@ func BroadcastTxWithFileLock(address sdk.AccAddress, msgs ...sdk.Msg) (broadcast
// Set new sequence number
txf = txf.WithSequence(sequence)
broadcastTxResponseJSON, err = broadcastTx(clientCtx, txf, msgs...)
if GetConfig().SerialPort != "" {
out, err = broadcastTxWithTrustWalletSignature(clientCtx, txf, msgs...)
} else {
out, err = broadcastTx(clientCtx, txf, msgs...)
}
if err != nil {
return
}
txResponse, err := GetTxResponseFromOut(out)
if err != nil {
return
}
// Only increase counter if broadcast was successful
if txResponse.Code != 0 {
return
}
// Increase counter for next round.
sequence++
@ -282,3 +253,135 @@ func BroadcastTxWithFileLock(address sdk.AccAddress, msgs ...sdk.Msg) (broadcast
return
}
func broadcastTxWithTrustWalletSignature(clientCtx client.Context, txf tx.Factory, msgs ...sdk.Msg) (out *bytes.Buffer, err error) {
txBuilder, err := txf.BuildUnsignedTx(msgs...)
if err != nil {
return
}
if err = signWithTrustWallet(txf, clientCtx, txBuilder); err != nil {
return
}
txBytes, err := clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
if err != nil {
return
}
res, err := clientCtx.BroadcastTx(txBytes)
if err != nil {
return
}
if err = clientCtx.PrintProto(res); err != nil {
return
}
return writeClientCtxOutputToBuffer(clientCtx)
}
func writeClientCtxOutputToBuffer(clientCtx client.Context) (out *bytes.Buffer, err error) {
output, ok := clientCtx.Output.(*bytes.Buffer)
if !ok {
err = ErrTypeAssertionFailed
return
}
defer output.Reset()
result := make(map[string]interface{})
err = json.Unmarshal(output.Bytes(), &result)
if err != nil {
return
}
// Make a copy because we `defer output.Reset()`
out = &bytes.Buffer{}
// This is still copying references: *out = *output
// Make a real copy: https://stackoverflow.com/a/69758157
out.Write(output.Bytes())
return
}
func signWithTrustWallet(txf tx.Factory, clientCtx client.Context, txBuilder client.TxBuilder) error {
connector, err := trustwallet.NewTrustWalletConnector(GetConfig().SerialPort)
if err != nil {
return err
}
keys, err := connector.GetPlanetmintKeys()
if err != nil {
return err
}
pubkeyBytes, err := hex.DecodeString(keys.RawPlanetmintPubkey)
if err != nil {
return err
}
pk := secp256k1.PubKey{Key: pubkeyBytes}
signMode := txf.SignMode()
if signMode == signing.SignMode_SIGN_MODE_UNSPECIFIED {
// use the SignModeHandler's default mode if unspecified
signMode = clientCtx.TxConfig.SignModeHandler().DefaultMode()
}
signerData := authsigning.SignerData{
ChainID: txf.ChainID(),
AccountNumber: txf.AccountNumber(),
Sequence: txf.Sequence(),
PubKey: &pk,
Address: sdk.AccAddress(pk.Address()).String(),
}
sigData := signing.SingleSignatureData{
SignMode: signMode,
Signature: nil,
}
sig := signing.SignatureV2{
PubKey: &pk,
Data: &sigData,
Sequence: txf.Sequence(),
}
if err := txBuilder.SetSignatures(sig); err != nil {
return err
}
bytesToSign, err := clientCtx.TxConfig.SignModeHandler().GetSignBytes(signMode, signerData, txBuilder.GetTx())
if err != nil {
return err
}
hashBytesToSign := crypto.Sha256(bytesToSign)
hexHash := hex.EncodeToString(hashBytesToSign)
hexSig, err := connector.SignHashWithPlanetmint(hexHash)
if err != nil {
return err
}
signature, err := hex.DecodeString(hexSig)
if err != nil {
return err
}
sigData = signing.SingleSignatureData{
SignMode: signMode,
Signature: signature,
}
sig = signing.SignatureV2{
PubKey: &pk,
Data: &sigData,
Sequence: txf.Sequence(),
}
if err = txBuilder.SetSignatures(sig); err != nil {
return fmt.Errorf("unable to set signatures on payload: %w", err)
}
// Run optional preprocessing if specified. By default, this is unset
// and will return nil.
return txf.PreprocessTx(clientCtx.FromName, txBuilder)
}

107
lib/utils.go Normal file
View File

@ -0,0 +1,107 @@
package lib
import (
"bufio"
"bytes"
"encoding/hex"
"encoding/json"
"errors"
"os"
"os/user"
"path/filepath"
"regexp"
"strconv"
"strings"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
"sigs.k8s.io/yaml"
)
func getSequenceFromFile(seqFile *os.File) (sequence uint64, err error) {
var sequenceString string
lineCount := int64(0)
scanner := bufio.NewScanner(seqFile)
for scanner.Scan() {
sequenceString = scanner.Text()
lineCount++
}
err = scanner.Err()
if err != nil {
return
}
if lineCount == 0 {
err = errors.New("Sequence file empty " + seqFile.Name() + ": no lines")
return
} else if lineCount != 1 {
err = errors.New("Malformed " + seqFile.Name() + ": wrong number of lines")
return
}
sequence, err = strconv.ParseUint(sequenceString, 10, 64)
if err != nil {
return
}
return
}
func getSequenceFromChain(clientCtx client.Context) (sequence uint64, err error) {
// get sequence number from chain
account, err := clientCtx.AccountRetriever.GetAccount(clientCtx, clientCtx.FromAddress)
if err != nil {
return
}
sequence = account.GetSequence()
return
}
func createSequenceDirectory() (path string, err error) {
usr, err := user.Current()
if err != nil {
return
}
homeDir := usr.HomeDir
path = filepath.Join(GetConfig().RootDir, "sequence")
// expand tilde to user's home directory
if strings.HasPrefix(path, "~/") {
path = filepath.Join(homeDir, path[2:])
}
_, err = os.Stat(path)
// directory already exists
if !os.IsNotExist(err) {
return
}
err = os.Mkdir(path, os.ModePerm)
return
}
func openSequenceFile(fromAddress sdk.AccAddress) (file *os.File, err error) {
path, err := createSequenceDirectory()
if err != nil {
return
}
addrHex := hex.EncodeToString(fromAddress)
filename := filepath.Join(path, addrHex)
file, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
return
}
return
}
// GetTxResponseFromOut converts strings to numbers and unmarshalles out into TxResponse struct
func GetTxResponseFromOut(out *bytes.Buffer) (txResponse sdk.TxResponse, err error) {
m := regexp.MustCompile(`"([0-9]+?)"`)
str := m.ReplaceAllString(out.String(), "${1}")
// We might have YAML here, so we need to convert to JSON first, because TxResponse struct lacks `yaml:"height,omitempty"`, etc.
// Since JSON is a subset of YAML, passing JSON through YAMLToJSON is a no-op and the result is the byte array of the JSON again.
j, err := yaml.YAMLToJSON([]byte(str))
if err != nil {
return
}
err = json.Unmarshal(j, &txResponse)
return
}

109
monitor/backend.go Normal file
View File

@ -0,0 +1,109 @@
package monitor
import (
"encoding/json"
"strconv"
"time"
"github.com/syndtr/goleveldb/leveldb/iterator"
)
type LastSeenEvent struct {
Address string `binding:"required" json:"address"`
Timestamp int64 `binding:"required" json:"timestamp"`
}
func (mms *MqttMonitor) AddParticipant(address string, lastSeenTS int64) (err error) {
// store receive address - planetmint address pair
var lastSeen LastSeenEvent
lastSeen.Address = address
lastSeen.Timestamp = lastSeenTS
lastSeenBytes, err := json.Marshal(lastSeen)
if err != nil {
Log("error serializing ConversionRequest: " + err.Error())
return
}
// returns an error if the entry does not exist (we have to increase the counter in this case)
_, err = mms.db.Get([]byte(address), nil)
if err != nil {
mms.setNumDBElements(mms.getNumDBElements() + 1)
}
mms.dbMutex.Lock()
defer mms.dbMutex.Unlock()
err = mms.db.Put([]byte(address), lastSeenBytes, nil)
if err != nil {
Log("error storing addresses in DB: " + err.Error())
} else {
Log("stored address in DB: " + address)
}
return
}
func (mms *MqttMonitor) deleteEntry(key []byte) (err error) {
mms.setNumDBElements(mms.getNumDBElements() - 1)
mms.dbMutex.Lock()
defer mms.dbMutex.Unlock()
return mms.db.Delete(key, nil)
}
func (mms *MqttMonitor) getAmountOfElements() (amount int64, err error) {
iter := mms.db.NewIterator(nil, nil)
defer iter.Release()
for iter.Next() {
amount++
}
// Check for any errors encountered during iteration
if err := iter.Error(); err != nil {
Log("" + err.Error())
} else {
Log("elements: " + strconv.FormatInt(amount, 10))
}
return
}
func (mms *MqttMonitor) getDataFromIter(iter iterator.Iterator) (lastSeen LastSeenEvent, err error) {
key := iter.Key()
value := iter.Value()
err = json.Unmarshal(value, &lastSeen)
if err != nil {
Log("failed to unmarshal entry: " + string(key) + " - " + err.Error())
}
return
}
func (mms *MqttMonitor) CleanupDB() {
// Create an iterator for the database
Log("starting clean-up process")
iter := mms.db.NewIterator(nil, nil)
defer iter.Release() // Make sure to release the iterator at the end
// Iterate over all elements in the database
for iter.Next() && !mms.IsTerminated() {
// Use iter.Key() and iter.Value() to access the key and value
lastSeen, err := mms.getDataFromIter(iter)
if err != nil {
Log("failed to unmarshal entry: " + string(iter.Key()) + " - " + err.Error())
continue
}
timeThreshold := time.Now().Add(-1 * mms.CleanupPeriodicityInMinutes * time.Minute).Unix()
if lastSeen.Timestamp <= timeThreshold {
// If the entry is older than 12 hours, delete it
err := mms.deleteEntry(iter.Key())
if err != nil {
Log("failed to delete entry: " + err.Error())
} else {
Log("delete entry: " + string(iter.Key()))
}
}
}
// Check for any errors encountered during iteration
if err := iter.Error(); err != nil {
Log("error during cleanup : " + err.Error())
}
}

83
monitor/interface.go Normal file
View File

@ -0,0 +1,83 @@
package monitor
import (
"sync"
"github.com/cometbft/cometbft/libs/log"
"github.com/planetmint/planetmint-go/config"
"github.com/syndtr/goleveldb/leveldb"
)
type MQTTMonitorClientI interface {
AddParticipant(address string, lastSeenTS int64) (err error)
SelectPoPParticipantsOutOfActiveActors() (challenger string, challengee string, err error)
GetActiveActorCount() (count uint64)
Start() (err error)
}
var monitorMutex sync.RWMutex
var mqttLogger log.Logger
var mqttMonitorInstance MQTTMonitorClientI
func SetMqttMonitorInstance(monitorInstance MQTTMonitorClientI) {
monitorMutex.Lock()
defer monitorMutex.Unlock()
mqttMonitorInstance = monitorInstance
}
func GetMqttMonitorInstance() (monitorInstance MQTTMonitorClientI) {
monitorMutex.Lock()
defer monitorMutex.Unlock()
return mqttMonitorInstance
}
func LazyMqttMonitorLoader(logger log.Logger, homeDir string) {
monitorMutex.RLock()
tmpInstance := mqttMonitorInstance
monitorMutex.RUnlock()
if tmpInstance != nil {
return
}
if logger != nil {
mqttLogger = logger
}
if homeDir == "" {
homeDir = "./"
}
aciveActorsDB, err := leveldb.OpenFile(homeDir+"activeActors.db", nil)
if err != nil {
panic(err)
}
SetMqttMonitorInstance(NewMqttMonitorService(aciveActorsDB, *config.GetConfig()))
}
func SelectPoPParticipantsOutOfActiveActors() (challenger string, challengee string, err error) {
monitorMutex.RLock()
defer monitorMutex.RUnlock()
return mqttMonitorInstance.SelectPoPParticipantsOutOfActiveActors()
}
func Start() (err error) {
err = mqttMonitorInstance.Start()
return
}
func AddParticipant(address string, lastSeenTS int64) (err error) {
monitorMutex.RLock()
defer monitorMutex.RUnlock()
return mqttMonitorInstance.AddParticipant(address, lastSeenTS)
}
func GetActiveActorCount() (count uint64) {
monitorMutex.RLock()
defer monitorMutex.RUnlock()
return mqttMonitorInstance.GetActiveActorCount()
}
func Log(msg string) {
if mqttLogger == nil {
return
}
mqttLogger.Info("[app] [monitor] " + msg)
}

View File

@ -0,0 +1,37 @@
package mocks
import "log"
// MockMQTTMonitorClientI is a mock of MQTTMonitorClientI interface.
type MockMQTTMonitorClientI struct {
myStringList []string
}
// AddParticipant mocks base method.
func (m *MockMQTTMonitorClientI) AddParticipant(address string, _ int64) error {
log.Println("[app] [Monitor] [Mock] added participant: " + address)
m.myStringList = append(m.myStringList, address)
return nil
}
// SelectPoPParticipantsOutOfActiveActors mocks base method.
func (m *MockMQTTMonitorClientI) SelectPoPParticipantsOutOfActiveActors() (string, string, error) {
var challenger, challengee string
amount := len(m.myStringList)
if amount >= 2 {
challenger = m.myStringList[amount-2]
challengee = m.myStringList[amount-1]
}
log.Println("[app] [Monitor] [Mock] participants: " + challenger + ", " + challengee)
return challenger, challengee, nil
}
func (m *MockMQTTMonitorClientI) GetActiveActorCount() (count uint64) {
return uint64(len(m.myStringList))
}
// Start mocks base method.
func (m *MockMQTTMonitorClientI) Start() error {
return nil
}

410
monitor/mqtt_monitor.go Normal file
View File

@ -0,0 +1,410 @@
package monitor
import (
"context"
"crypto/tls"
"encoding/json"
"errors"
"io"
"math/rand"
"net"
"net/http"
"strconv"
"strings"
"sync"
"time"
mqtt "github.com/eclipse/paho.mqtt.golang"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/util"
"github.com/syndtr/goleveldb/leveldb"
)
var MonitorMQTTClient util.MQTTClientI
type MqttMonitor struct {
db *leveldb.DB
dbMutex sync.Mutex // Mutex to synchronize write operations
CleanupPeriodicityInMinutes time.Duration
config config.Config
numberOfElementsMutex sync.RWMutex
numberOfElements int64
isTerminated bool
terminationMutex sync.RWMutex
maxRetries time.Duration
lostConnection bool
lostConnectionMutex sync.Mutex
clientMutex sync.Mutex
localMqttClient util.MQTTClientI
}
func (mms *MqttMonitor) Terminate() {
mms.terminationMutex.Lock()
defer mms.terminationMutex.Unlock()
mms.isTerminated = true
}
func (mms *MqttMonitor) IsTerminated() (isTerminated bool) {
mms.terminationMutex.RLock()
defer mms.terminationMutex.RUnlock()
return mms.isTerminated
}
func (mms *MqttMonitor) getNumDBElements() int64 {
mms.numberOfElementsMutex.RLock()
defer mms.numberOfElementsMutex.RUnlock()
return mms.numberOfElements
}
func (mms *MqttMonitor) setNumDBElements(numElements int64) {
mms.numberOfElementsMutex.Lock()
defer mms.numberOfElementsMutex.Unlock()
mms.numberOfElements = numElements
}
func getClientID() string {
conf := config.GetConfig()
return "monitor-" + conf.GetNodeAddress()
}
func (mms *MqttMonitor) lazyLoadMonitorMQTTClient() util.MQTTClientI {
if MonitorMQTTClient != nil {
return MonitorMQTTClient
}
conf := config.GetConfig()
hostPort := net.JoinHostPort(conf.MqttDomain, strconv.FormatInt(int64(conf.MqttPort), 10))
uri := "tcp://" + hostPort
if conf.MqttTLS {
uri = "ssl://" + hostPort
}
opts := mqtt.NewClientOptions().AddBroker(uri).SetKeepAlive(time.Second * 60).SetCleanSession(true)
opts.SetClientID(getClientID())
opts.SetUsername(conf.MqttUser)
opts.SetPassword(conf.MqttPassword)
opts.SetConnectionLostHandler(mms.onConnectionLost)
if conf.MqttTLS {
tlsConfig := &tls.Config{}
opts.SetTLSConfig(tlsConfig)
}
Log("create new client")
client := mqtt.NewClient(opts)
return client
}
func NewMqttMonitorService(db *leveldb.DB, config config.Config) *MqttMonitor {
service := &MqttMonitor{db: db, config: config, numberOfElements: 0, CleanupPeriodicityInMinutes: 10}
return service
}
func (mms *MqttMonitor) runPeriodicTasks() {
tickerRestablishConnection := time.NewTicker(2 * time.Minute)
tickerCleanup := time.NewTicker(5 * time.Minute)
defer tickerRestablishConnection.Stop()
defer tickerCleanup.Stop()
for !mms.IsTerminated() {
select {
case <-tickerRestablishConnection.C:
go mms.MonitorActiveParticipants()
case <-tickerCleanup.C:
go mms.CleanupDB()
}
}
}
func (mms *MqttMonitor) Start() (err error) {
amount, err := mms.getAmountOfElements()
if err != nil {
return
}
mms.setNumDBElements(amount)
go mms.runPeriodicTasks()
go mms.MonitorActiveParticipants()
go mms.CleanupDB()
return
}
func (mms *MqttMonitor) getRandomNumbers() (challenger int, challengee int) {
for challenger == challengee {
// Generate random numbers
numElements := int(mms.getNumDBElements())
challenger = rand.Intn(numElements)
challengee = rand.Intn(numElements)
}
return
}
func (mms *MqttMonitor) SelectPoPParticipantsOutOfActiveActors() (challenger string, challengee string, err error) {
numElements := int(mms.getNumDBElements())
if numElements < 2 {
return
}
randomChallenger, randomChallengee := mms.getRandomNumbers()
Log("number of elements: " + strconv.Itoa(numElements))
Log("selected IDs: " + strconv.Itoa(randomChallenger) + " " + strconv.Itoa(randomChallengee))
iter := mms.db.NewIterator(nil, nil)
defer iter.Release()
count := 0
found := 0
var lastSeen LastSeenEvent
for iter.Next() {
if count == randomChallenger {
lastSeen, err = mms.getDataFromIter(iter)
if err != nil {
Log("could not get Data from ID" + strconv.Itoa(randomChallenger))
return
}
challenger = lastSeen.Address
found++
} else if count == randomChallengee {
lastSeen, err = mms.getDataFromIter(iter)
if err != nil {
Log("could not get Data from ID" + strconv.Itoa(randomChallengee))
return
}
challengee = lastSeen.Address
found++
}
count++
if found == 2 {
break
}
}
Log("challenger, challengee: " + challenger + " " + challengee)
return
}
func (mms *MqttMonitor) GetActiveActorCount() (count uint64) {
count = uint64(mms.getNumDBElements())
return
}
func (mms *MqttMonitor) MqttMsgHandler(_ mqtt.Client, msg mqtt.Message) {
if mms.IsTerminated() {
return
}
topicParts := strings.Split(msg.Topic(), "/")
if len(topicParts) != 3 {
return
}
if topicParts[0] != "tele" {
return
}
if topicParts[2] != "STATE" {
return
}
address := topicParts[1]
valid, err := util.IsValidAddress(address)
if err != nil || !valid {
return
}
active, err := IsLegitMachineAddress(address)
if err != nil || !active {
return
}
unixTime := time.Now().Unix()
err = mms.AddParticipant(address, unixTime)
if err != nil {
Log("error adding active actor to DB: " + address + " " + err.Error())
} else {
Log("added active actor to DB: " + address)
}
}
func IsLegitMachineAddress(address string) (active bool, err error) {
url := "http://localhost:1317/planetmint/machine/address/" + address
// Create a new HTTP client
client := &http.Client{}
// Create a new request
ctx := context.Background()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
Log("cannot send machine query request " + err.Error())
return
}
// Set the header
req.Header.Set("Accept", "application/json")
// Send the request
resp, err := client.Do(req)
if err != nil {
Log("cannot connect to server: " + err.Error())
return
}
// Close the response body
defer resp.Body.Close()
// Read the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
Log("cannot read response: " + err.Error())
return
}
// Check the status code
if resp.StatusCode != http.StatusOK {
Log("unexpected status code: " + string(body))
return
}
// Unmarshal the response body into a map
var data map[string]interface{}
err = json.Unmarshal(body, &data)
if err != nil {
Log("cannot unmarshal response " + err.Error())
return
}
// Check if the "info" key exists
machineValue, ok := data["machine"]
if !ok {
Log("response does not contain the required machine")
return
}
machineMap, ok := machineValue.(map[string]interface{})
if !ok {
Log("cannot convert machine map")
return
}
addressMap, ok := machineMap["address"]
if !ok {
Log("response does not contain the required name")
return
}
value, ok := addressMap.(string)
if !ok || value != address {
Log("return machine is not the required one")
return
}
err = nil
active = true
return
}
func (mms *MqttMonitor) onConnectionLost(_ mqtt.Client, err error) {
Log("connection lost: " + err.Error())
// Handle connection loss here (e.g., reconnect attempts, logging)
if !mms.IsTerminated() {
mms.setConnectionStatus(true)
}
}
func (mms *MqttMonitor) MonitorActiveParticipants() {
mqttClient, err := mms.initializeClient()
if err != nil {
Log(err.Error())
return
}
// Maximum reconnection attempts (adjust as needed)
mms.SetMaxRetries()
for !mms.IsTerminated() && mms.maxRetries > 0 {
if !mms.connectClient(mqttClient) {
continue
}
if !mms.subscribeToTopic(mqttClient) {
continue
}
mms.monitorConnection(mqttClient)
}
mms.handleConnectionTermination()
}
func (mms *MqttMonitor) initializeClient() (mqttClient util.MQTTClientI, err error) {
mms.clientMutex.Lock()
defer mms.clientMutex.Unlock()
if mms.localMqttClient != nil {
return nil, errors.New("client is still working")
}
mms.localMqttClient = mms.lazyLoadMonitorMQTTClient()
return mms.localMqttClient, nil
}
func (mms *MqttMonitor) connectClient(mqttClient util.MQTTClientI) bool {
if token := mqttClient.Connect(); token.Wait() && token.Error() != nil {
Log("error connecting to mqtt: " + token.Error().Error())
mms.maxRetries--
time.Sleep(time.Second * 5)
return false
}
mms.setConnectionStatus(false)
Log("established connection")
return true
}
func (mms *MqttMonitor) subscribeToTopic(mqttClient util.MQTTClientI) bool {
messageHandler := mqtt.MessageHandler(mms.MqttMsgHandler)
subscriptionTopic := "tele/#"
if token := mqttClient.Subscribe(subscriptionTopic, 0, messageHandler); token.Wait() && token.Error() != nil {
Log("error registering the mqtt subscription: " + token.Error().Error())
return false
}
Log("subscribed to tele/# channels")
return true
}
func (mms *MqttMonitor) monitorConnection(mqttClient util.MQTTClientI) {
for !mms.IsTerminated() {
if mms.isConnectionLost(mqttClient) {
Log("retry establishing a connection")
break
}
SendUpdateMessage(mqttClient)
mms.SetMaxRetries()
time.Sleep(60 * time.Second)
}
}
func (mms *MqttMonitor) isConnectionLost(mqttClient util.MQTTClientI) bool {
mms.lostConnectionMutex.Lock()
defer mms.lostConnectionMutex.Unlock()
return !mqttClient.IsConnected() || !mqttClient.IsConnectionOpen() || mms.lostConnection
}
func (mms *MqttMonitor) setConnectionStatus(lost bool) {
mms.lostConnectionMutex.Lock()
defer mms.lostConnectionMutex.Unlock()
mms.lostConnection = lost
}
func (mms *MqttMonitor) handleConnectionTermination() {
if mms.maxRetries == 0 {
Log("reached maximum reconnection attempts. Exiting. New client will be activated soon.")
}
mms.clientMutex.Lock()
defer mms.clientMutex.Unlock()
mms.localMqttClient = nil
}
func SendUpdateMessage(mqttClient util.MQTTClientI) {
// Publish message
now := time.Now().Format("2006-01-02 15:04:05") // Adjust format as needed
token := mqttClient.Publish("tele/"+getClientID(), 1, false, now)
token.Wait()
}
func (mms *MqttMonitor) SetMaxRetries() {
mms.maxRetries = 5
}

View File

@ -0,0 +1,132 @@
package monitor_test
import (
"os"
"testing"
"time"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/monitor"
"github.com/planetmint/planetmint-go/util/mocks"
"github.com/stretchr/testify/assert"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/storage"
)
func init() {
// Use MQTT mock client
monitor.MonitorMQTTClient = &mocks.MockMQTTClient{}
os.Setenv(config.ValAddr, "plmnt10mq5nj8jhh27z7ejnz2ql3nh0qhzjnfvy50877")
}
const (
challengerInput = "plmnt1fx3x6u8k5q8kjl7pamsuwjtut8nkks8dk92dek"
challengeeInput = "plmnt1fsaljz3xqf6vchkjxfzfrd30cdp3j4vqh298pr"
)
func TestGMonitorActiveParticipants(t *testing.T) {
cfg := config.GetConfig()
db, err := leveldb.Open(storage.NewMemStorage(), nil)
assert.NoError(t, err)
defer db.Close()
mqttMonitor := monitor.NewMqttMonitorService(db, *cfg)
err = mqttMonitor.Start()
assert.NoError(t, err)
currentTime := time.Now()
unixTime := currentTime.Unix()
err = mqttMonitor.AddParticipant(challengerInput, unixTime)
assert.NoError(t, err)
err = mqttMonitor.AddParticipant(challengeeInput, unixTime)
assert.NoError(t, err)
mqttMonitor.CleanupDB()
challenger, challengee, err := mqttMonitor.SelectPoPParticipantsOutOfActiveActors()
assert.NoError(t, err)
assert.Contains(t, challenger, "plmnt")
assert.Contains(t, challengee, "plmnt")
mqttMonitor.Terminate()
}
func TestCleanupRemoval(t *testing.T) {
cfg := config.GetConfig()
db, err := leveldb.Open(storage.NewMemStorage(), nil)
assert.NoError(t, err)
defer db.Close()
mqttMonitor := monitor.NewMqttMonitorService(db, *cfg)
err = mqttMonitor.Start()
assert.NoError(t, err)
currentTime := time.Now()
CleanupPeriodicityAgo := currentTime.Add(-1 * mqttMonitor.CleanupPeriodicityInMinutes * time.Minute)
unixTimeNow := currentTime.Unix()
err = mqttMonitor.AddParticipant(challengerInput, unixTimeNow)
assert.NoError(t, err)
err = mqttMonitor.AddParticipant(challengeeInput, CleanupPeriodicityAgo.Unix()-1)
assert.NoError(t, err)
mqttMonitor.CleanupDB()
challenger, challengee, err := mqttMonitor.SelectPoPParticipantsOutOfActiveActors()
assert.NoError(t, err)
assert.Equal(t, "", challenger)
assert.Contains(t, "", challengee)
mqttMonitor.Terminate()
}
func TestCleanupPrecisionTest(t *testing.T) {
cfg := config.GetConfig()
db, err := leveldb.Open(storage.NewMemStorage(), nil)
assert.NoError(t, err)
defer db.Close()
mqttMonitor := monitor.NewMqttMonitorService(db, *cfg)
err = mqttMonitor.Start()
assert.NoError(t, err)
currentTime := time.Now()
CleanupThresholdAgo := currentTime.Add(-1 * mqttMonitor.CleanupPeriodicityInMinutes * time.Minute)
aboveThreshold := CleanupThresholdAgo.Unix() + 10
unixTimeNow := currentTime.Unix()
err = mqttMonitor.AddParticipant(challengerInput, unixTimeNow)
assert.NoError(t, err)
err = mqttMonitor.AddParticipant(challengeeInput, aboveThreshold)
assert.NoError(t, err)
mqttMonitor.CleanupDB()
challenger, challengee, err := mqttMonitor.SelectPoPParticipantsOutOfActiveActors()
assert.NoError(t, err)
assert.Contains(t, challenger, "plmnt")
assert.Contains(t, challengee, "plmnt")
mqttMonitor.Terminate()
}
func TestIsLegitMachineAddress(t *testing.T) {
t.SkipNow()
active, err := monitor.IsLegitMachineAddress("plmnt1z6xmwqfnn9mvean9gsd57segawgjykpxw8hq5t")
assert.NoError(t, err)
assert.Equal(t, active, true)
}
func TestGetActiveActorCount(t *testing.T) {
cfg := config.GetConfig()
db, err := leveldb.Open(storage.NewMemStorage(), nil)
assert.NoError(t, err)
defer db.Close()
mqttMonitor := monitor.NewMqttMonitorService(db, *cfg)
err = mqttMonitor.Start()
assert.NoError(t, err)
currentTime := time.Now()
unixTime := currentTime.Unix()
err = mqttMonitor.AddParticipant(challengerInput, unixTime)
assert.NoError(t, err)
err = mqttMonitor.AddParticipant(challengeeInput, unixTime)
assert.NoError(t, err)
mqttMonitor.CleanupDB()
count := mqttMonitor.GetActiveActorCount()
assert.Equal(t, uint64(2), count)
}

View File

@ -1,8 +0,0 @@
syntax = "proto3";
package planetmintgo.asset;
option go_package = "github.com/planetmint/planetmint-go/x/asset/types";
message Asset {
string cid = 1;
}

View File

@ -20,13 +20,13 @@ service Query {
// Queries a list of GetCIDsByAddress items.
rpc GetCIDsByAddress (QueryGetCIDsByAddressRequest) returns (QueryGetCIDsByAddressResponse) {
option (google.api.http).get = "/planetmint/asset/get_cids_by_address/{address}/{lookupPeriodInMin}";
option (google.api.http).get = "/planetmint/asset/address/{address}/{numElements}";
}
// Queries a list of GetNotarizedAsset items.
rpc GetNotarizedAsset (QueryGetNotarizedAssetRequest) returns (QueryGetNotarizedAssetResponse) {
option (google.api.http).get = "/planetmint/asset/get_notarized_asset/{cid}";
option (google.api.http).get = "/planetmint/asset/cid/{cid}";
}
}
@ -42,7 +42,7 @@ message QueryParamsResponse {
message QueryGetCIDsByAddressRequest {
string address = 1;
uint64 lookupPeriodInMin = 2;
uint64 numElements = 2;
cosmos.base.query.v1beta1.PageRequest pagination = 3;
}

View File

@ -8,7 +8,7 @@ message Challenge {
string initiator = 1;
string challenger = 2;
string challengee = 3;
uint64 height = 4;
int64 height = 4;
bool success = 5;
string description = 6;
bool finished = 6;
}

View File

@ -4,8 +4,6 @@ package planetmintgo.dao;
option go_package = "github.com/planetmint/planetmint-go/x/dao/types";
message DistributionOrder {
string daoAddr = 1;
string daoAmount = 2;
string daoTxID = 3;
@ -18,4 +16,10 @@ message DistributionOrder {
int64 firstPop = 10;
int64 lastPop = 11;
string proposer = 12;
string earlyInvAddr = 13;
string earlyInvAmount = 14;
string earlyInvTxID = 15;
string strategicAddr = 16;
string strategicAmount = 17;
string strategicTxID = 18;
}

View File

@ -1,12 +1,15 @@
syntax = "proto3";
package planetmintgo.dao;
import "gogoproto/gogo.proto";
import "planetmintgo/dao/params.proto";
import "planetmintgo/dao/redeem_claim.proto";
option go_package = "github.com/planetmint/planetmint-go/x/dao/types";
// GenesisState defines the dao module's genesis state.
message GenesisState {
Params params = 1 [(gogoproto.nullable) = false];
Params params = 1 [(gogoproto.nullable) = false];
}

View File

@ -10,4 +10,20 @@ message Params {
option (gogoproto.goproto_stringer) = false;
string mint_address = 1;
string token_denom = 2;
string staged_denom = 3;
string claim_denom = 4;
string reissuance_asset = 5;
int64 reissuance_epochs = 6;
int64 pop_epochs = 7;
int64 distribution_offset = 8;
string distribution_address_early_inv = 9;
string distribution_address_investor = 10;
string distribution_address_strategic = 11;
string distribution_address_dao = 12;
string distribution_address_pop = 13;
int64 mqtt_response_timeout = 14;
string claim_address = 15;
uint64 tx_gas_limit = 16;
uint64 validator_pop_reward = 17;
}

View File

@ -9,6 +9,10 @@ import "planetmintgo/dao/params.proto";
import "planetmintgo/dao/mint_request.proto";
import "planetmintgo/dao/mint_requests.proto";
import "planetmintgo/dao/reissuance.proto";
import "planetmintgo/dao/challenge.proto";
import "amino/amino.proto";
import "planetmintgo/dao/distribution_order.proto";
import "planetmintgo/dao/redeem_claim.proto";
option go_package = "github.com/planetmint/planetmint-go/x/dao/types";
@ -23,25 +27,65 @@ service Query {
// Queries a list of GetMintRequestsByHash items.
rpc GetMintRequestsByHash (QueryGetMintRequestsByHashRequest) returns (QueryGetMintRequestsByHashResponse) {
option (google.api.http).get = "/planetmint/dao/get_mint_requests_by_hash/{hash}";
option (google.api.http).get = "/planetmint/dao/mint_requests/hash/{hash}";
}
// Queries a list of MintRequestsByAddress items.
rpc MintRequestsByAddress (QueryMintRequestsByAddressRequest) returns (QueryMintRequestsByAddressResponse) {
option (google.api.http).get = "/planetmint/dao/mint_requests_by_address/{address}";
option (google.api.http).get = "/planetmint/dao/mint_requests/address/{address}";
}
// Queries a list of GetReissuance items.
rpc GetReissuance (QueryGetReissuanceRequest) returns (QueryGetReissuanceResponse) {
option (google.api.http).get = "/planetmint/dao/get_reissuance/{blockHeight}";
option (google.api.http).get = "/planetmint/dao/reissuance/{blockHeight}";
}
// Queries a list of GetReissuances items.
rpc GetReissuances (QueryGetReissuancesRequest) returns (QueryGetReissuancesResponse) {
option (google.api.http).get = "/planetmint/dao/get_reissuances";
// Queries a list of Reissuances items.
rpc Reissuances (QueryReissuancesRequest) returns (QueryReissuancesResponse) {
option (google.api.http).get = "/planetmint/dao/reissuances";
}
// Queries a list of GetChallenge items.
rpc GetChallenge (QueryGetChallengeRequest) returns (QueryGetChallengeResponse) {
option (google.api.http).get = "/planetmint/dao/challenge/{height}";
}
// Queries a list of Challenges items.
rpc Challenges (QueryChallengesRequest) returns (QueryChallengesResponse) {
option (google.api.http).get = "/planetmint/dao/challenges";
}
// Queries a list of GetDistribution items.
rpc GetDistribution (QueryGetDistributionRequest) returns (QueryGetDistributionResponse) {
option (google.api.http).get = "/planetmint/dao/distribution/{height}";
}
// Queries a list of RedeemClaim items.
rpc RedeemClaim (QueryGetRedeemClaimRequest) returns (QueryGetRedeemClaimResponse) {
option (google.api.http).get = "/planetmint/dao/redeem_claim/{beneficiary}/{id}";
}
rpc RedeemClaimAll (QueryAllRedeemClaimRequest) returns (QueryAllRedeemClaimResponse) {
option (google.api.http).get = "/planetmint/dao/redeem_claim";
}
// Queries a list of RedeemClaimByLiquidTxHash items.
rpc RedeemClaimByLiquidTxHash (QueryRedeemClaimByLiquidTxHashRequest) returns (QueryRedeemClaimByLiquidTxHashResponse) {
option (google.api.http).get = "/planetmint/dao/redeem_claim_by_liquid_tx_hash/{liquidTxHash}";
}
// Queries a list of Distributions items.
rpc Distributions (QueryDistributionsRequest) returns (QueryDistributionsResponse) {
option (google.api.http).get = "/planetmint/dao/distributions";
}
}
@ -79,12 +123,72 @@ message QueryGetReissuanceResponse {
Reissuance reissuance = 1;
}
message QueryGetReissuancesRequest {
message QueryReissuancesRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
message QueryGetReissuancesResponse {
Reissuance reissuance = 1;
cosmos.base.query.v1beta1.PageResponse pagination = 2;
message QueryReissuancesResponse {
repeated Reissuance reissuances = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
message QueryGetChallengeRequest {
int64 height = 1;
}
message QueryGetChallengeResponse {
Challenge challenge = 1;
}
message QueryChallengesRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
message QueryChallengesResponse {
repeated Challenge challenges = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
message QueryGetDistributionRequest {
int64 height = 1;
}
message QueryGetDistributionResponse {
DistributionOrder distribution = 1;
}
message QueryGetRedeemClaimRequest {
string beneficiary = 1;
uint64 id = 2;
}
message QueryGetRedeemClaimResponse {
RedeemClaim redeemClaim = 1 [(gogoproto.nullable) = false];
}
message QueryAllRedeemClaimRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
message QueryAllRedeemClaimResponse {
repeated RedeemClaim redeemClaim = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
message QueryRedeemClaimByLiquidTxHashRequest {
string liquidTxHash = 1;
}
message QueryRedeemClaimByLiquidTxHashResponse {
RedeemClaim redeemClaim = 1;
}
message QueryDistributionsRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
message QueryDistributionsResponse {
repeated DistributionOrder distributions = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

View File

@ -0,0 +1,14 @@
syntax = "proto3";
package planetmintgo.dao;
option go_package = "github.com/planetmint/planetmint-go/x/dao/types";
message RedeemClaim {
uint64 id = 1;
string beneficiary = 2;
string liquidTxHash = 3;
uint64 amount = 4;
bool confirmed = 5;
string creator = 6;
}

View File

@ -6,7 +6,9 @@ option go_package = "github.com/planetmint/planetmint-go/x/dao/types";
message Reissuance {
string proposer = 1;
string rawtx = 2;
string command = 2;
string txID = 3;
int64 blockHeight = 4;
int64 firstIncludedPop = 5;
int64 lastIncludedPop = 6;
}

View File

@ -10,18 +10,23 @@ import "amino/amino.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/msg/v1/msg.proto";
import "planetmintgo/dao/redeem_claim.proto";
option go_package = "github.com/planetmint/planetmint-go/x/dao/types";
// Msg defines the Msg service.
service Msg {
rpc ReissueRDDLProposal (MsgReissueRDDLProposal ) returns (MsgReissueRDDLProposalResponse );
rpc MintToken (MsgMintToken ) returns (MsgMintTokenResponse );
rpc ReissueRDDLResult (MsgReissueRDDLResult ) returns (MsgReissueRDDLResultResponse );
rpc DistributionResult (MsgDistributionResult ) returns (MsgDistributionResultResponse );
rpc DistributionRequest (MsgDistributionRequest) returns (MsgDistributionRequestResponse);
rpc UpdateParams (MsgUpdateParams ) returns (MsgUpdateParamsResponse );
rpc ReportPopResult (MsgReportPopResult) returns (MsgReportPopResultResponse);
rpc ReissueRDDLProposal (MsgReissueRDDLProposal) returns (MsgReissueRDDLProposalResponse);
rpc MintToken (MsgMintToken ) returns (MsgMintTokenResponse );
rpc ReissueRDDLResult (MsgReissueRDDLResult ) returns (MsgReissueRDDLResultResponse );
rpc DistributionResult (MsgDistributionResult ) returns (MsgDistributionResultResponse );
rpc DistributionRequest (MsgDistributionRequest) returns (MsgDistributionRequestResponse);
rpc UpdateParams (MsgUpdateParams ) returns (MsgUpdateParamsResponse );
rpc ReportPopResult (MsgReportPopResult ) returns (MsgReportPopResultResponse );
rpc InitPop (MsgInitPop ) returns (MsgInitPopResponse );
rpc CreateRedeemClaim (MsgCreateRedeemClaim ) returns (MsgCreateRedeemClaimResponse );
rpc UpdateRedeemClaim (MsgUpdateRedeemClaim ) returns (MsgUpdateRedeemClaimResponse );
rpc ConfirmRedeemClaim (MsgConfirmRedeemClaim ) returns (MsgConfirmRedeemClaimResponse );
}
message MsgReportPopResult {
string creator = 1;
@ -31,10 +36,12 @@ message MsgReportPopResult {
message MsgReportPopResultResponse {}
message MsgReissueRDDLProposal {
string creator = 1;
string proposer = 2;
string tx = 3;
int64 blockHeight = 4;
string creator = 1;
string proposer = 2;
string command = 3;
int64 blockHeight = 4;
int64 firstIncludedPop = 5;
int64 lastIncludedPop = 6;
}
message MsgReissueRDDLProposalResponse {}
@ -54,12 +61,15 @@ message MsgReissueRDDLResult {
}
message MsgReissueRDDLResultResponse {}
message MsgDistributionResult {
string creator = 1;
int64 lastPop = 2;
string daoTxID = 3;
string investorTxID = 4;
string popTxID = 5;
string creator = 1;
int64 lastPop = 2;
string daoTxID = 3;
string investorTxID = 4;
string popTxID = 5;
string earlyInvestorTxID = 6;
string strategicTxID = 7;
}
message MsgDistributionResultResponse {}
@ -73,14 +83,49 @@ message MsgDistributionRequestResponse {}
message MsgUpdateParams {
option (cosmos.msg.v1.signer) = "authority";
// authority is the address that controls the module (defaults to x/gov unless overwritten).
string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// params defines the x/dao parameters to update.
//
// NOTE: All parameters must be supplied.
Params params = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}
message MsgUpdateParamsResponse {}
message MsgInitPop {
string creator = 1;
string initiator = 2;
string challenger = 3;
string challengee = 4;
int64 height = 5;
}
message MsgInitPopResponse {}
message MsgCreateRedeemClaim {
string creator = 1;
string beneficiary = 2;
}
message MsgCreateRedeemClaimResponse {}
message MsgUpdateRedeemClaim {
string creator = 1;
uint64 id = 2;
string beneficiary = 3;
string liquidTxHash = 4;
}
message MsgUpdateRedeemClaimResponse {}
message MsgConfirmRedeemClaim {
string creator = 1;
uint64 id = 2;
string beneficiary = 3;
}
message MsgConfirmRedeemClaimResponse {}

View File

@ -8,5 +8,9 @@ option go_package = "github.com/planetmint/planetmint-go/x/machine/types";
// Params defines the parameters for the module.
message Params {
option (gogoproto.goproto_stringer) = false;
string asset_registry_scheme =1;
string asset_registry_domain =2;
string asset_registry_path =3;
uint64 dao_machine_funding_amount = 4;
string dao_machine_funding_denom = 5;
}

View File

@ -22,25 +22,36 @@ service Query {
// Queries a list of GetMachineByPublicKey items.
rpc GetMachineByPublicKey (QueryGetMachineByPublicKeyRequest) returns (QueryGetMachineByPublicKeyResponse) {
option (google.api.http).get = "/planetmint/machine/get_machine_by_public_key/{publicKey}";
option (google.api.http).get = "/planetmint/machine/public_key/{publicKey}";
}
// Queries a list of GetTrustAnchorStatus items.
rpc GetTrustAnchorStatus (QueryGetTrustAnchorStatusRequest) returns (QueryGetTrustAnchorStatusResponse) {
option (google.api.http).get = "/planetmint/machine/get_trust_anchor_status/{machineid}";
option (google.api.http).get = "/planetmint/machine/trust_anchor/status/{machineid}";
}
// Queries a list of GetMachineByAddress items.
rpc GetMachineByAddress (QueryGetMachineByAddressRequest) returns (QueryGetMachineByAddressResponse) {
option (google.api.http).get = "/planetmint/machine/get_machine_by_address/{address}";
option (google.api.http).get = "/planetmint/machine/address/{address}";
}
// Queries a list of GetLiquidAssetsByMachineid items.
rpc GetLiquidAssetsByMachineid (QueryGetLiquidAssetsByMachineidRequest) returns (QueryGetLiquidAssetsByMachineidResponse) {
option (google.api.http).get = "/planetmint/planetmint-go/machine/get_liquid_assets_by_machineid/{machineID}";
option (google.api.http).get = "/planetmint/machine/liquid_assets/{machineID}";
}
// Queries a list of ActiveTrustAnchorCount items.
rpc ActiveTrustAnchorCount (QueryActiveTrustAnchorCountRequest) returns (QueryActiveTrustAnchorCountResponse) {
option (google.api.http).get = "/planetmint/machine/active_trust_anchor_count";
}
// Queries a list of ActivatedTrustAnchorCount items.
rpc ActivatedTrustAnchorCount (QueryActivatedTrustAnchorCountRequest) returns (QueryActivatedTrustAnchorCountResponse) {
option (google.api.http).get = "/planetmint/machine/activated_trust_anchor_count";
}
}
@ -87,3 +98,15 @@ message QueryGetLiquidAssetsByMachineidResponse {
LiquidAsset liquidAssetEntry = 1;
}
message QueryActiveTrustAnchorCountRequest {}
message QueryActiveTrustAnchorCountResponse {
uint64 count = 1;
}
message QueryActivatedTrustAnchorCountRequest {}
message QueryActivatedTrustAnchorCountResponse {
uint64 count = 1;
}

View File

@ -5,6 +5,11 @@ package planetmintgo.machine;
import "planetmintgo/machine/machine.proto";
import "planetmintgo/machine/trust_anchor.proto";
import "planetmintgo/machine/liquid_asset.proto";
import "planetmintgo/machine/params.proto";
import "amino/amino.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/msg/v1/msg.proto";
option go_package = "github.com/planetmint/planetmint-go/x/machine/types";
@ -13,6 +18,7 @@ service Msg {
rpc AttestMachine (MsgAttestMachine ) returns (MsgAttestMachineResponse );
rpc RegisterTrustAnchor (MsgRegisterTrustAnchor) returns (MsgRegisterTrustAnchorResponse);
rpc NotarizeLiquidAsset (MsgNotarizeLiquidAsset) returns (MsgNotarizeLiquidAssetResponse);
rpc UpdateParams (MsgUpdateParams ) returns (MsgUpdateParamsResponse );
}
message MsgAttestMachine {
string creator = 1;
@ -35,3 +41,17 @@ message MsgNotarizeLiquidAsset {
message MsgNotarizeLiquidAssetResponse {}
message MsgUpdateParams {
option (cosmos.msg.v1.signer) = "authority";
// authority is the address that controls the module (defaults to x/gov unless overwritten).
string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// params defines the x/dao parameters to update.
// NOTE: All parameters must be supplied.
Params params = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}
message MsgUpdateParamsResponse {}

View File

@ -1,52 +1,65 @@
# planetmintgo
**planetmintgo** is a blockchain built using Cosmos SDK and Tendermint and created with [Ignite CLI](https://ignite.com/cli).
# planetmint-go
**planetmint** is a blockchain built using Cosmos SDK and CometBFT written in Go and created with [Ignite CLI](https://ignite.com/cli).
## Get started
```
ignite chain serve
```
`serve` command installs dependencies, builds, initializes, and starts your blockchain in development.
### Configure
Your blockchain in development can be configured with `config.yml`. To learn more, see the [Ignite CLI docs](https://docs.ignite.com).
### Web Frontend
Ignite CLI has scaffolded a Vue.js-based web app in the `vue` directory. Run the following commands to install dependencies and start the app:
```
cd vue
npm install
npm run serve
```
The frontend app is built using the `@starport/vue` and `@starport/vuex` packages. For details, see the [monorepo for Ignite front-end development](https://github.com/ignite/web).
## Release
To release a new version of your blockchain, create and push a new tag with `v` prefix. A new draft release with the configured targets will be created.
```
git tag v0.1
git push origin v0.1
```
After a draft release is created, make your final changes from the release page and publish it.
### Install
To install the latest version of your blockchain node's binary, execute the following command on your machine:
To install the latest version of this blockchain node's binary, execute the following command on your machine:
```
git clone https://github.com/planetmint/planetmint-go.git
ignite chain build
```
## Structure
```
curl https://get.ignite.com/username/planetmint-go@latest! | sudo bash
- .github/ ... github workflows
- app/ ... app wiring and tx ante handlers
- clients/ ... clients for interactions with external services
- cmd/ ... entry point, sdk config and top level commands
- config/ ... custom planetmint config
- docs/ ... openapi docs
- errormsg/ ... custom error messages
- lib/ ... tools for interacting with planetmint and trust wallet
- monitor/ ... MQTT monitor
- proto/ ... message and type definitions
- tests/ ... e2e test suites
- testutil/
- tools/ ... sdk tools
- util/
- x/ ... custom planetmint modules
```
`username/planetmint-go` should match the `username` and `repo_name` of the Github repository to which the source code was pushed. Learn more about [the install process](https://github.com/allinbits/starport-installer).
## Testing
Follow this [guide](https://docs.cosmos.network/v0.47/build/building-modules/testing) for general testing guidelines.
The E2E-tests found in the `tests/` folder setup a test network of n-Nodes and running transactions on said network. Tools to mock interactions with external services for these tests can be found in `testutil/network/`.
For Tests that involve multiple keepers mocks can be found in `x/<module>/testutil/expected_keepers_mocks.go`. These are manipulated in `testutil/keepers/`.
## Contributing
For contributions refer to the RDDL enhancement proposals repository [here](https://github.com/rddl-network/REPs)
### Adding Module Capabilities
Use the `ignite scaffold` [command](https://docs.ignite.com/references/cli#ignite-scaffold) to easily add modules and messages to the existing project. A more manual approach is to add to the `proto/` folder to setup messages and the corresponding message servers and running the `ignite generate proto-go` command.
### Migrations
Module migrations must be registered in each respective module in the `AppModule.RegisterServices(cfg module.Configurator)` function. For each module that is to be upgraded in a migration the ConsensusVersion must be updated. In addition an `UpgradeHandler` needs to be added to the `App.setupUpgradeHandlers()`. Upgrade handlers have a name that needs to be added to an upgrade proposal which needs to be voted on by participating validators.
For more info see [here](https://docs.cosmos.network/v0.47/learn/advanced/upgrade).
## Learn more
- [Ignite CLI](https://ignite.com/cli)
- [Tutorials](https://docs.ignite.com/guide)
- [Planetmint docs](https://docs.rddl.io)
- [Ignite CLI docs](https://docs.ignite.com)
- [Cosmos SDK docs](https://docs.cosmos.network)
- [Developer Chat](https://discord.gg/ignite)
- [Developer Chat](https://discord.gg/uy4CA2Xw54)
- [RDDL enhancement Proposals](https://github.com/rddl-network/REPs)

View File

@ -1,2 +1,2 @@
sonar.projectKey=planetmint_planetmint-go_AYjnSLNdwwdSy162QoXI
sonar.exclusions=docs/static/openapi.yml,x/**/*.pb.go,x/**/*.pb.gw.go,x/**/module.go,x/**/types/genesis_test.go,x/**/types/params.go,x/**/client/cli/query_params.go,tests/e2e/**/suite.go,app/simulation_test.go
sonar.exclusions=docs/static/openapi.yml,x/**/*.pb.go,x/**/*.pb.gw.go,x/**/module.go,x/**/types/genesis_test.go,x/**/types/params.go,x/**/client/cli/query_params.go,tests/e2e/**/suite.go,app/simulation_test.go,x/**/client/cli/tx_update_params.go,x/**/types/message_update_params_test.go,x/**/keeper/message_server_update_params.go,x/**/types/message*test.go,x/**/module_simulation.go,x/**/simulation/*.go,testutil/network/network.go,testutil/network/util.go

1
staticcheck.conf Normal file
View File

@ -0,0 +1 @@
checks = ["all", "-SA1019", "-ST1000"]

View File

@ -2,15 +2,16 @@ package asset
import (
"testing"
"time"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/stretchr/testify/suite"
)
func TestE2ETestSuite(t *testing.T) {
t.Parallel()
cfg := network.DefaultConfig()
cfg.NumValidators = 1
func TestE2EAssetTestSuite(t *testing.T) {
time.Sleep(2 * time.Second)
cfg := network.LoaderDefaultConfig()
cfg.NumValidators = 3
suite.Run(t, NewE2ETestSuite(cfg))
}

View File

@ -1,83 +0,0 @@
package asset
import (
"fmt"
"github.com/planetmint/planetmint-go/testutil"
"github.com/planetmint/planetmint-go/testutil/sample"
assettypes "github.com/planetmint/planetmint-go/x/asset/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
)
// TestNotarizeAssetREST notarizes asset over REST endpoint
func (s *E2ETestSuite) TestNotarizeAssetREST() {
val := s.network.Validators[0]
// Create Msg
k, err := val.ClientCtx.Keyring.Key(sample.Name)
s.Require().NoError(err)
addr, err := k.GetAddress()
s.Require().NoError(err)
cid := sample.Asset()
testCases := []struct {
name string
msg assettypes.MsgNotarizeAsset
rawLog string
expectCheckTxErr bool
}{
{
"invalid address",
assettypes.MsgNotarizeAsset{
Creator: "invalid creator address",
Cid: cid,
},
"invalid address",
true,
},
{
"machine not found",
assettypes.MsgNotarizeAsset{
Creator: "plmnt1v5394e8vmfrp4qzdav7xkze0f567w3tsgxf09j",
Cid: cid,
},
"machine not found",
true,
},
{
"valid notarization",
assettypes.MsgNotarizeAsset{
Creator: addr.String(),
Cid: cid,
},
"[]",
true,
},
}
for _, tc := range testCases {
// Prepare Tx
txBytes, err := testutil.PrepareTx(val, &tc.msg, sample.Name)
s.Require().NoError(err)
// Broadcast Tx
broadcastTxResponse, err := testutil.BroadcastTx(val, txBytes)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
tx, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", val.APIAddress, broadcastTxResponse.TxResponse.TxHash))
s.Require().NoError(err)
if !tc.expectCheckTxErr {
var txRes txtypes.GetTxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(tx, &txRes)
s.Require().NoError(err)
s.Require().Contains(txRes.TxResponse.RawLog, tc.rawLog)
} else {
s.Require().Contains(broadcastTxResponse.TxResponse.RawLog, tc.rawLog)
}
}
}

View File

@ -1,29 +1,19 @@
package asset
import (
"encoding/json"
"fmt"
"github.com/planetmint/planetmint-go/lib"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
e2etestutil "github.com/planetmint/planetmint-go/testutil/e2e"
assetcli "github.com/planetmint/planetmint-go/x/asset/client/cli"
machinecli "github.com/planetmint/planetmint-go/x/machine/client/cli"
assettypes "github.com/planetmint/planetmint-go/x/asset/types"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
var (
pubKey string
prvKey string
)
// E2ETestSuite struct definition of asset suite
type E2ETestSuite struct {
suite.Suite
@ -39,84 +29,16 @@ func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
// SetupSuite initializes asset E2ETestSuite
func (s *E2ETestSuite) SetupSuite() {
s.T().Log("setting up e2e test suite")
s.T().Log("setting up e2e asset test suite")
s.network = network.New(s.T())
val := s.network.Validators[0]
kb := val.ClientCtx.Keyring
account, err := kb.NewAccount(sample.Name, sample.Mnemonic, keyring.DefaultBIP39Passphrase, sample.DefaultDerivationPath, hd.Secp256k1)
s.network = network.Load(s.T(), s.cfg)
err := e2etestutil.AttestMachine(s.network, sample.Name, sample.Mnemonic, 0, sample.FeeDenom)
s.Require().NoError(err)
addr, _ := account.GetAddress()
// sending funds to machine to initialize account on chain
args := []string{
val.Moniker,
addr.String(),
sample.Amount,
"--yes",
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.NewSendTxCmd(), args)
s.Require().NoError(err)
txResponse, err := clitestutil.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err := clitestutil.GetRawLogFromTxResponse(val, txResponse)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, "cosmos.bank.v1beta1.MsgSend")
s.Require().NoError(s.network.WaitForNextBlock())
prvKey, pubKey = sample.KeyPair()
ta := sample.TrustAnchor(pubKey)
taJSON, err := json.Marshal(&ta)
s.Require().NoError(err)
args = []string{
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
fmt.Sprintf("--%s=%s", flags.FlagFrom, addr.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
string(taJSON),
}
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdRegisterTrustAnchor(), args)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
machine := sample.Machine(sample.Name, pubKey, prvKey, addr.String())
machineJSON, err := json.Marshal(&machine)
s.Require().NoError(err)
args = []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, sample.Name),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
string(machineJSON),
}
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdAttestMachine(), args)
s.Require().NoError(err)
txResponse, err = clitestutil.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err = clitestutil.GetRawLogFromTxResponse(val, txResponse)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, "planetmintgo.machine.MsgAttestMachine")
}
// TearDownSuite clean up after testing
func (s *E2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e test suite")
s.T().Log("tearing down e2e asset test suite")
}
// TestNotarizeAsset notarizes asset over cli
@ -126,40 +48,46 @@ func (s *E2ETestSuite) TestNotarizeAsset() {
s.Require().NoError(err)
addr, _ := k.GetAddress()
cid := sample.Asset()
testCases := []struct {
name string
args []string
msg *assettypes.MsgNotarizeAsset
rawLog string
expectCheckTxErr bool
}{
{
"valid notarization",
[]string{
cid,
fmt.Sprintf("--%s=%s", flags.FlagFrom, addr.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
},
assettypes.NewMsgNotarizeAsset(addr.String(), sample.Asset()),
"[]",
false,
},
{
"machine not found",
assettypes.NewMsgNotarizeAsset("plmnt1v5394e8vmfrp4qzdav7xkze0f567w3tsgxf09j", sample.Asset()),
"error during CheckTx or ReCheckTx: machine not found",
true,
},
}
for _, tc := range testCases {
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, assetcli.CmdNotarizeAsset(), tc.args)
s.Require().NoError(err)
out, err := e2etestutil.BuildSignBroadcastTx(s.T(), addr, tc.msg)
if tc.expectCheckTxErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
}
txResponse, err := clitestutil.GetTxResponseFromOut(out)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err := clitestutil.GetRawLogFromTxResponse(val, txResponse)
if !tc.expectCheckTxErr {
assert.Equal(s.T(), int(0), int(txResponse.Code))
args := []string{sample.Asset()}
asset, err := clitestutil.ExecTestCLICmd(val.ClientCtx, assetcli.GetCmdByCID(), args)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, tc.rawLog)
assert.Contains(s.T(), asset.String(), sample.Asset())
} else {
assert.Contains(s.T(), txResponse.RawLog, tc.rawLog)
}

View File

@ -0,0 +1,17 @@
package basic
import (
"testing"
"time"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/stretchr/testify/suite"
)
func TestE2EDaoTestSuite(t *testing.T) {
time.Sleep(2 * time.Second)
cfg := network.LoaderDefaultConfig()
cfg.NumValidators = 3
suite.Run(t, NewE2ETestSuite(cfg))
}

View File

@ -0,0 +1,212 @@
package basic
import (
"bufio"
"bytes"
"os"
"strconv"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
"github.com/planetmint/planetmint-go/lib"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
e2etestutil "github.com/planetmint/planetmint-go/testutil/e2e"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
daocli "github.com/planetmint/planetmint-go/x/dao/client/cli"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/planetmint/planetmint-go/testutil/moduleobject"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
)
// E2ETestSuite struct definition of dao suite
type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
reissuanceEpochs int64
distributionOffset int64
bobAddr sdk.AccAddress
aliceAddr sdk.AccAddress
}
// NewE2ETestSuite returns configured dao E2ETestSuite
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
return &E2ETestSuite{cfg: cfg}
}
// SetupSuite initializes dao E2ETestSuite
func (s *E2ETestSuite) SetupSuite() {
// set epochs: make sure to start after initial height of 7
s.reissuanceEpochs = 25
s.distributionOffset = 5
s.T().Log("setting up e2e dao test suite")
// Setup MintAddress parameter in genesis state
// use sample.Mnemonic to make mint address deterministic for test
s.cfg.Mnemonics = []string{sample.Mnemonic}
valAddr, err := s.createValAccount(s.cfg)
s.Require().NoError(err)
// set accounts for alice and bob in genesis state
var authGenState authtypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[authtypes.ModuleName], &authGenState)
s.bobAddr = sample.Secp256k1AccAddress()
s.aliceAddr = sample.Secp256k1AccAddress()
bob := authtypes.NewBaseAccount(s.bobAddr, nil, 0, 0)
alice := authtypes.NewBaseAccount(s.aliceAddr, nil, 0, 0)
accounts, err := authtypes.PackAccounts(authtypes.GenesisAccounts{bob, alice})
s.Require().NoError(err)
authGenState.Accounts = append(authGenState.Accounts, accounts...)
s.cfg.GenesisState[authtypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&authGenState)
var daoGenState daotypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[daotypes.ModuleName], &daoGenState)
daoGenState.Params.DistributionOffset = s.distributionOffset
daoGenState.Params.ReissuanceEpochs = s.reissuanceEpochs
daoGenState.Params.MintAddress = valAddr.String()
daoGenState.Params.ClaimAddress = valAddr.String()
s.cfg.GenesisState[daotypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&daoGenState)
bbalances := sdk.NewCoins(
sdk.NewCoin(daoGenState.Params.TokenDenom, math.NewInt(10000)),
)
abalances := sdk.NewCoins(
sdk.NewCoin(daoGenState.Params.TokenDenom, math.NewInt(10000)),
)
accountBalances := []banktypes.Balance{
{Address: s.bobAddr.String(), Coins: bbalances.Sort()},
{Address: s.aliceAddr.String(), Coins: abalances.Sort()},
}
// set the balances in genesis state
var bankGenState banktypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[banktypes.ModuleName], &bankGenState)
bankGenState.Balances = append(bankGenState.Balances, accountBalances...)
s.cfg.GenesisState[banktypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&bankGenState)
s.network = network.Load(s.T(), s.cfg)
// create account for redeem claim test case
account, err := e2etestutil.CreateAccount(s.network, sample.Name, sample.Mnemonic)
s.Require().NoError(err)
err = e2etestutil.FundAccount(s.network, account, sample.FeeDenom)
s.Require().NoError(err)
}
// TearDownSuite clean up after testing
func (s *E2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e dao test suite")
}
func (s *E2ETestSuite) TestMintToken() {
val := s.network.Validators[0]
mintRequest := moduleobject.MintRequest(s.aliceAddr.String(), 1000, "hash")
msg1 := daotypes.NewMsgMintToken(val.Address.String(), &mintRequest)
out, err := e2etestutil.BuildSignBroadcastTx(s.T(), val.Address, msg1)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err := clitestutil.GetRawLogFromTxOut(val, out)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, "planetmintgo.dao.MsgMintToken")
// assert that alice has actually received the minted tokens 10000 (initial supply) + 1000 (minted) = 11000 (total)
output, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
s.aliceAddr.String(),
})
out, ok := output.(*bytes.Buffer)
if !ok {
err = lib.ErrTypeAssertionFailed
s.Require().NoError(err)
}
assert.Contains(s.T(), out.String(), "plmnt")
assert.Contains(s.T(), out.String(), "11000")
s.Require().NoError(err)
// send mint token request from non mint address
k, err := val.ClientCtx.Keyring.Key(sample.Name)
s.Require().NoError(err)
addr, _ := k.GetAddress()
msg1 = daotypes.NewMsgMintToken(addr.String(), &mintRequest)
out, err = lib.BroadcastTxWithFileLock(addr, msg1)
s.Require().NoError(err)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(2), int(txResponse.Code))
}
func (s *E2ETestSuite) createValAccount(cfg network.Config) (address sdk.AccAddress, err error) {
buf := bufio.NewReader(os.Stdin)
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, s.T().TempDir(), buf, cfg.Codec, cfg.KeyringOptions...)
if err != nil {
return nil, err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos)
if err != nil {
return nil, err
}
mnemonic := cfg.Mnemonics[0]
record, err := kb.NewAccount("node0", mnemonic, keyring.DefaultBIP39Passphrase, sdk.GetConfig().GetFullBIP44Path(), algo)
if err != nil {
return nil, err
}
addr, err := record.GetAddress()
if err != nil {
return nil, err
}
return addr, nil
}
func (s *E2ETestSuite) TestReissuance() {
val := s.network.Validators[0]
var err error
latestHeight, err := s.network.LatestHeight()
s.Require().NoError(err)
var wait int64
for {
latestHeight, err = s.network.WaitForHeight(latestHeight + 1)
s.Require().NoError(err)
// wait + for sending the reissuance result, i.e.:
// 0: block 25: initializing RDDL reissuance broadcast tx succeeded
// 1: block 26: sending the reissuance result broadcast tx succeeded
// 2: block 27: confirmation
wait = 2
if latestHeight%s.reissuanceEpochs == wait {
break
}
}
// - because we waited on the reissuance result, see above
intValue := strconv.FormatInt(latestHeight-wait, 10)
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.GetCmdReissuance(), []string{intValue})
s.Require().NoError(err)
}

View File

@ -0,0 +1,103 @@
package distribution
import (
"math"
"strconv"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
"github.com/planetmint/planetmint-go/testutil/network"
daocli "github.com/planetmint/planetmint-go/x/dao/client/cli"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
"github.com/stretchr/testify/suite"
)
type AssetDistributionE2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
reissaunceEpochs int64
distributionOffset int64
}
func NewAssetDistributionE2ETestSuite(cfg network.Config) *AssetDistributionE2ETestSuite {
return &AssetDistributionE2ETestSuite{cfg: cfg}
}
func (s *AssetDistributionE2ETestSuite) SetupSuite() {
s.T().Log("setting up e2e dao distribution test suite")
// set epochs: make sure to start after initial height of 7
s.distributionOffset = 5
s.reissaunceEpochs = 10
var daoGenState daotypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[daotypes.ModuleName], &daoGenState)
daoGenState.Params.DistributionOffset = s.distributionOffset
daoGenState.Params.ReissuanceEpochs = s.reissaunceEpochs
s.cfg.GenesisState[daotypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&daoGenState)
s.network = network.Load(s.T(), s.cfg)
}
func (s *AssetDistributionE2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e dao distribution test suites")
}
func (s *AssetDistributionE2ETestSuite) TestAssetDistribution() {
val := s.network.Validators[0]
latestHeight, err := s.network.LatestHeight()
s.Require().NoError(err)
// wait so that we see exactly on reissuance/distribution round, e.g.
// wait = ceil((10 - 5) / 2) = ceil(2.5) = 3
wait := int64(math.Ceil((float64(s.reissaunceEpochs - s.distributionOffset)) / 2.0))
height := s.reissaunceEpochs + s.distributionOffset + wait
for {
latestHeight, err = s.network.WaitForHeight(latestHeight + 1)
s.Require().NoError(err)
if latestHeight == height {
break
}
}
errmsg := "rpc error: code = NotFound desc = distribution not found: key not found"
testCases := []struct {
name string
requestHeight int64
expectedErr string
}{
{
"request height too low",
s.distributionOffset,
errmsg,
},
{
"wrong request height",
height,
errmsg,
},
{
"request height too high",
2*s.reissaunceEpochs + s.distributionOffset,
errmsg,
},
{
"valid distribution request",
s.reissaunceEpochs + s.distributionOffset,
"",
},
}
for _, tc := range testCases {
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.GetCmdDistribution(), []string{
strconv.FormatInt(tc.requestHeight, 10),
})
if tc.expectedErr == "" {
s.Require().NoError(err)
} else {
s.Require().Error(err)
}
}
}

View File

@ -0,0 +1,17 @@
package distribution
import (
"testing"
"time"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/stretchr/testify/suite"
)
func TestAssetDistributionE2EDaoTestSuite(t *testing.T) {
time.Sleep(2 * time.Second)
cfg := network.LoaderDefaultConfig()
cfg.NumValidators = 3
suite.Run(t, NewAssetDistributionE2ETestSuite(cfg))
}

View File

@ -0,0 +1,17 @@
package gas
import (
"testing"
"time"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/stretchr/testify/suite"
)
func TestConsumptionE2EDaoTestSuite(t *testing.T) {
time.Sleep(2 * time.Second)
cfg := network.LoaderDefaultConfig()
cfg.NumValidators = 3
suite.Run(t, NewConsumptionE2ETestSuite(cfg))
}

View File

@ -0,0 +1,172 @@
package gas
import (
"bufio"
"os"
"strconv"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/planetmint/planetmint-go/lib"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
e2etestutil "github.com/planetmint/planetmint-go/testutil/e2e"
"github.com/planetmint/planetmint-go/testutil/moduleobject"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type ConsumptionE2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
minterAddr sdk.AccAddress
feeDenom string
}
func NewConsumptionE2ETestSuite(cfg network.Config) *ConsumptionE2ETestSuite {
return &ConsumptionE2ETestSuite{cfg: cfg}
}
func (s *ConsumptionE2ETestSuite) createValAccount(cfg network.Config) (address sdk.AccAddress, err error) {
buf := bufio.NewReader(os.Stdin)
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, s.T().TempDir(), buf, cfg.Codec, cfg.KeyringOptions...)
if err != nil {
return nil, err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos)
if err != nil {
return nil, err
}
mnemonic := cfg.Mnemonics[0]
record, err := kb.NewAccount("node0", mnemonic, keyring.DefaultBIP39Passphrase, sdk.GetConfig().GetFullBIP44Path(), algo)
if err != nil {
return nil, err
}
addr, err := record.GetAddress()
if err != nil {
return nil, err
}
return addr, nil
}
func (s *ConsumptionE2ETestSuite) SetupSuite() {
s.T().Log("setting up e2e dao gas consumption test suite")
s.feeDenom = sample.FeeDenom
s.cfg.Mnemonics = []string{sample.Mnemonic}
addr, err := s.createValAccount(s.cfg)
s.Require().NoError(err)
// set accounts for alice and bob in genesis state
var authGenState authtypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[authtypes.ModuleName], &authGenState)
s.minterAddr = addr
minter := authtypes.NewBaseAccount(s.minterAddr, nil, 0, 0)
accounts, err := authtypes.PackAccounts(authtypes.GenesisAccounts{minter})
s.Require().NoError(err)
authGenState.Accounts = append(authGenState.Accounts, accounts...)
s.cfg.GenesisState[authtypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&authGenState)
var daoGenState daotypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[daotypes.ModuleName], &daoGenState)
daoGenState.Params.MintAddress = s.minterAddr.String()
s.cfg.GenesisState[daotypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&daoGenState)
s.network = network.Load(s.T(), s.cfg)
account, err := e2etestutil.CreateAccount(s.network, sample.Name, sample.Mnemonic)
s.Require().NoError(err)
err = e2etestutil.FundAccount(s.network, account, s.feeDenom)
s.Require().NoError(err)
}
func (s *ConsumptionE2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e dao gas consumption test suites")
}
func (s *ConsumptionE2ETestSuite) TestValidatorConsumption() {
val := s.network.Validators[0]
k, err := val.ClientCtx.Keyring.Key(sample.Name)
s.Require().NoError(err)
addr, _ := k.GetAddress()
// send huge tx but as val and with no gas kv costs
msgs := s.createMsgs(val.Address, addr, 10)
out, err := lib.BroadcastTxWithFileLock(val.Address, msgs...)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
_, err = clitestutil.GetRawLogFromTxOut(val, out)
s.Require().NoError(err)
}
func (s *ConsumptionE2ETestSuite) TestNonValidatorConsumptionOverflow() {
val := s.network.Validators[0]
k, err := val.ClientCtx.Keyring.Key(sample.Name)
s.Require().NoError(err)
err = e2etestutil.FundAccount(s.network, k, s.feeDenom)
s.Require().NoError(err)
addr, _ := k.GetAddress()
// exceed gas limit with too many msgs as non validator
msgs := s.createMsgs(addr, val.Address, 10)
out, err := lib.BroadcastTxWithFileLock(addr, msgs...)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
_, err = clitestutil.GetRawLogFromTxOut(val, out)
s.Require().Error(err)
assert.Contains(s.T(), err.Error(), "out of gas")
}
func (s *ConsumptionE2ETestSuite) createMsgs(from sdk.AccAddress, to sdk.AccAddress, n int) (msgs []sdk.Msg) {
coins := sdk.NewCoins(sdk.NewInt64Coin(s.feeDenom, 10))
for i := 0; i < n; i++ {
msg := banktypes.NewMsgSend(from, to, coins)
msgs = append(msgs, msg)
}
return
}
func (s *ConsumptionE2ETestSuite) TestNetworkBasedTxGasLimit() {
var gasAmountAboveGlobalGasLimit uint64 = 200000000
libConfig := lib.GetConfig()
libConfig.SetTxGas(gasAmountAboveGlobalGasLimit)
var msgs []sdk.Msg
for i := 0; i < 1000; i++ {
mintRequest := moduleobject.MintRequest(s.minterAddr.String(), 1, "hash"+strconv.Itoa(i))
msg := daotypes.NewMsgMintToken(s.minterAddr.String(), &mintRequest)
msgs = append(msgs, msg)
}
_, err := e2etestutil.BuildSignBroadcastTx(s.T(), s.minterAddr, msgs...)
s.Require().Error(err)
s.Assert().Contains(err.Error(), "out of gas in location: txSize; gasWanted: "+strconv.FormatUint(gasAmountAboveGlobalGasLimit, 10)+", gasUsed:")
s.Assert().Contains(err.Error(), " out of gas")
s.Require().NoError(s.network.WaitForNextBlock())
}

View File

@ -0,0 +1,17 @@
package msgs
import (
"testing"
"time"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/stretchr/testify/suite"
)
func TestRestrictedMsgsE2EDaoTestSuite(t *testing.T) {
time.Sleep(2 * time.Second)
cfg := network.LoaderDefaultConfig()
cfg.NumValidators = 3
suite.Run(t, NewRestrictedMsgsE2ESuite(cfg))
}

View File

@ -0,0 +1,125 @@
package msgs
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/lib"
e2etestutil "github.com/planetmint/planetmint-go/testutil/e2e"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
machinetypes "github.com/planetmint/planetmint-go/x/machine/types"
"github.com/stretchr/testify/suite"
)
var msgs = []sdk.Msg{
&daotypes.MsgInitPop{},
&daotypes.MsgDistributionRequest{},
&daotypes.MsgDistributionResult{},
&daotypes.MsgReissueRDDLProposal{},
&daotypes.MsgReissueRDDLResult{},
&daotypes.MsgUpdateRedeemClaim{},
&machinetypes.MsgRegisterTrustAnchor{},
&machinetypes.MsgNotarizeLiquidAsset{},
}
type RestrictedMsgsE2ESuite struct {
suite.Suite
cfg network.Config
network *network.Network
}
func NewRestrictedMsgsE2ESuite(cfg network.Config) *RestrictedMsgsE2ESuite {
return &RestrictedMsgsE2ESuite{cfg: cfg}
}
func (s *RestrictedMsgsE2ESuite) SetupSuite() {
s.T().Log("setting up e2e dao restricted msg test suite")
s.network = network.Load(s.T(), s.cfg)
account, err := e2etestutil.CreateAccount(s.network, sample.Name, sample.Mnemonic)
s.Require().NoError(err)
err = e2etestutil.FundAccount(s.network, account, sample.FeeDenom)
s.Require().NoError(err)
}
func (s *RestrictedMsgsE2ESuite) TearDownSuite() {
s.T().Log("tearing down e2e dao restricted msg test suite")
}
func (s *RestrictedMsgsE2ESuite) TestRestrictedMsgsValidator() {
val := s.network.Validators[0]
msg := daotypes.NewMsgInitPop(val.Address.String(), val.Address.String(), val.Address.String(), val.Address.String(), 0)
out, err := lib.BroadcastTxWithFileLock(val.Address, msg)
s.Require().NoError(err)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(0), int(txResponse.Code))
}
func (s *RestrictedMsgsE2ESuite) TestRestrictedMsgsNonValidator() {
val := s.network.Validators[0]
k, err := val.ClientCtx.Keyring.Key(sample.Name)
s.Require().NoError(err)
addr, _ := k.GetAddress()
for _, msg := range msgs {
msg = setCreator(msg, addr.String())
out, err := lib.BroadcastTxWithFileLock(addr, msg)
s.Require().NoError(err)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(18), int(txResponse.Code))
s.Require().NoError(s.network.WaitForNextBlock())
}
}
func setCreator(msg sdk.Msg, creator string) sdk.Msg {
switch sdk.MsgTypeURL(msg) {
case "/planetmintgo.dao.MsgInitPop":
msg, ok := msg.(*daotypes.MsgInitPop)
if ok {
msg.Creator = creator
}
case "/planetmintgo.dao.MsgDistributionRequest":
msg, ok := msg.(*daotypes.MsgDistributionRequest)
if ok {
msg.Creator = creator
}
case "/planetmintgo.dao.MsgDistributionResult":
msg, ok := msg.(*daotypes.MsgDistributionResult)
if ok {
msg.Creator = creator
}
case "/planetmintgo.dao.MsgReissueRDDLProposal":
msg, ok := msg.(*daotypes.MsgReissueRDDLProposal)
if ok {
msg.Creator = creator
}
case "/planetmintgo.dao.MsgReissueRDDLResult":
msg, ok := msg.(*daotypes.MsgReissueRDDLResult)
if ok {
msg.Creator = creator
}
case "/planetmintgo.dao.MsgUpdateRedeemClaim":
msg, ok := msg.(*daotypes.MsgUpdateRedeemClaim)
if ok {
msg.Creator = creator
}
case "/planetmintgo.machine.MsgNotarizeLiquidAsset":
msg, ok := msg.(*machinetypes.MsgNotarizeLiquidAsset)
if ok {
msg.Creator = creator
}
case "/planetmintgo.machine.MsgRegisterTrustAnchor":
msg, ok := msg.(*machinetypes.MsgRegisterTrustAnchor)
if ok {
msg.Creator = creator
}
}
return msg
}

View File

@ -0,0 +1,17 @@
package pop
import (
"testing"
"time"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/stretchr/testify/suite"
)
func TestPopE2EDaoTestSuite(t *testing.T) {
time.Sleep(2 * time.Second)
cfg := network.LoaderDefaultConfig()
cfg.NumValidators = 3
suite.Run(t, NewSelectionE2ETestSuite(cfg))
}

View File

@ -0,0 +1,404 @@
package pop
import (
"bufio"
"fmt"
"log"
"math"
"os"
"regexp"
"strconv"
"time"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/planetmint/planetmint-go/lib"
"github.com/planetmint/planetmint-go/monitor"
"github.com/planetmint/planetmint-go/testutil"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
e2etestutil "github.com/planetmint/planetmint-go/testutil/e2e"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
"github.com/planetmint/planetmint-go/util/mocks"
daocli "github.com/planetmint/planetmint-go/x/dao/client/cli"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"gopkg.in/yaml.v2"
)
var machines = []struct {
name string
mnemonic string
address string
}{
{
name: "R2D2",
mnemonic: "number judge garbage lock village slush business upset suspect green wrestle puzzle foil tragic drum stereo ticket teach upper bone inject monkey deny portion",
address: "plmnt1kp93kns6hs2066d8qw0uz84fw3vlthewt2ck6p",
},
{
name: "C3PO",
mnemonic: "letter plate husband impulse grid lake panel seminar try powder virtual run spice siege mutual enhance ripple country two boring have convince symptom fuel",
address: "plmnt15wrx9eqegjtlvvx80huau7rkn3f44rdj969xrx",
},
}
type SelectionE2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
popEpochs int64
reissuanceEpochs int64
distributionOffset int64
claimDenom string
feeDenom string
errormsg string
}
func NewSelectionE2ETestSuite(cfg network.Config) *SelectionE2ETestSuite {
testsuite := &SelectionE2ETestSuite{cfg: cfg}
testsuite.errormsg = "--%s=%s"
return testsuite
}
func (s *SelectionE2ETestSuite) SetupSuite() {
s.T().Log("setting up e2e dao pop selection test suite")
s.popEpochs = 10
s.reissuanceEpochs = 60
s.distributionOffset = 2
s.claimDenom = "crddl"
s.feeDenom = sample.FeeDenom
s.cfg.Mnemonics = []string{sample.Mnemonic}
valAddr, err := s.createValAccount(s.cfg)
s.Require().NoError(err)
var daoGenState daotypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[daotypes.ModuleName], &daoGenState)
daoGenState.Params.PopEpochs = s.popEpochs
daoGenState.Params.ReissuanceEpochs = s.reissuanceEpochs
daoGenState.Params.DistributionOffset = s.distributionOffset
daoGenState.Params.MqttResponseTimeout = 200
daoGenState.Params.ClaimAddress = valAddr.String()
s.cfg.GenesisState[daotypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&daoGenState)
// setting up stagedClaims that are not part of PoP issuance (i.e.: past unresolved claims)
machineBalances := []banktypes.Balance{
{Address: machines[0].address, Coins: sdk.NewCoins(sdk.NewCoin(daoGenState.Params.StagedDenom, sdkmath.NewInt(10000)))},
{Address: machines[1].address, Coins: sdk.NewCoins(sdk.NewCoin(daoGenState.Params.StagedDenom, sdkmath.NewInt(10000)))},
}
var bankGenState banktypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[banktypes.ModuleName], &bankGenState)
bankGenState.Balances = append(bankGenState.Balances, machineBalances...)
s.cfg.GenesisState[banktypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&bankGenState)
s.network = network.Load(s.T(), s.cfg)
}
// TearDownSuite clean up after testing
func (s *SelectionE2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e dao pop selection test suite")
}
func (s *SelectionE2ETestSuite) perpareLocalTest() testutil.BufferWriter {
val := s.network.Validators[0]
latestHeight, err := s.network.LatestHeight()
s.Require().NoError(err)
wait := int64(math.Ceil(float64(s.popEpochs) / 2.0))
for {
latestHeight, err = s.network.WaitForHeight(latestHeight + 1)
s.Require().NoError(err)
if latestHeight%s.popEpochs == wait {
break
}
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.GetCmdChallenge(), []string{
strconv.FormatInt(latestHeight-wait, 10),
})
s.Require().NoError(err)
return out
}
type yamlChallenge struct {
Initiator string `yaml:"initiator"`
Challenger string `yaml:"challenger"`
Challengee string `yaml:"challengee"`
Height string `yaml:"height"`
Success bool `yaml:"success"`
Finished bool `yaml:"finished"`
}
func (s *SelectionE2ETestSuite) sendPoPResult(storedChallenge []byte, success bool) {
val := s.network.Validators[0]
var wrapper struct {
Challenge yamlChallenge `yaml:"challenge"`
}
err := yaml.Unmarshal(storedChallenge, &wrapper)
if err != nil {
log.Fatalf("error: %v", err)
}
tmpChallenge := wrapper.Challenge
var challenge daotypes.Challenge
challenge.Challengee = tmpChallenge.Challengee
challenge.Challenger = tmpChallenge.Challenger
challenge.Initiator = tmpChallenge.Initiator
challenge.Height, err = strconv.ParseInt(tmpChallenge.Height, 10, 64)
s.Require().NoError(err)
challenge.Finished = true
challenge.Success = success
machineName := machines[0].name
if challenge.Challenger != machines[0].address {
machineName = machines[1].name
}
k, err := val.ClientCtx.Keyring.Key(machineName)
s.Require().NoError(err)
challengerAccAddress, _ := k.GetAddress()
msg := daotypes.NewMsgReportPopResult(challengerAccAddress.String(), &challenge)
_, err = e2etestutil.BuildSignBroadcastTx(s.T(), challengerAccAddress, msg)
s.Require().NoError(err)
}
func (s *SelectionE2ETestSuite) TestPopSelectionNoActors() {
out := s.perpareLocalTest()
assert.NotContains(s.T(), out.String(), machines[0].address)
assert.NotContains(s.T(), out.String(), machines[1].address)
}
func (s *SelectionE2ETestSuite) TestPopSelectionOneActors() {
err := monitor.AddParticipant(machines[0].address, time.Now().Unix())
s.Require().NoError(err)
err = e2etestutil.AttestMachine(s.network, machines[0].name, machines[0].mnemonic, 0, s.feeDenom)
s.Require().NoError(err)
out := s.perpareLocalTest()
assert.NotContains(s.T(), out.String(), machines[0].address)
assert.NotContains(s.T(), out.String(), machines[1].address)
}
func (s *SelectionE2ETestSuite) TestPopSelectionTwoActors() {
err := monitor.AddParticipant(machines[1].address, time.Now().Unix())
s.Require().NoError(err)
err = e2etestutil.AttestMachine(s.network, machines[1].name, machines[1].mnemonic, 1, s.feeDenom)
s.Require().NoError(err)
out := s.perpareLocalTest()
assert.Contains(s.T(), out.String(), machines[0].address)
assert.Contains(s.T(), out.String(), machines[1].address)
s.sendPoPResult(out.Bytes(), true)
}
func (s *SelectionE2ETestSuite) VerifyTokens(token string) {
val := s.network.Validators[0]
// check balance for crddl
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetCmdQueryTotalSupply(), []string{
fmt.Sprintf(s.errormsg, bank.FlagDenom, token),
})
s.Require().NoError(err)
assert.Contains(s.T(), out.String(), token)
// Account for 1 additional unfinished PoP when checking balances after distribution
if token == s.claimDenom {
assert.Equal(s.T(), "amount: \"18579472050\"\ndenom: "+token+"\n", out.String()) // Total supply 2 * 7990867578 (total supply) + 1 * 1997716894 (challenger) + 6 * 100000000 (validator) + 2 * 10000 (past unresolved claims) = 18579472050
} else {
assert.Equal(s.T(), "amount: \"18479472050\"\ndenom: "+token+"\n", out.String()) // Total supply 2 * 7990867578 (total supply) + 1 * 1997716894 (challenger) + 5 * 100000000 (validator) + 2 * 10000 (past unresolved claims) = 18479472050
}
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
machines[0].address,
fmt.Sprintf(s.errormsg, bank.FlagDenom, token),
})
s.Require().NoError(err)
assert.Contains(s.T(), out.String(), token)
assert.Equal(s.T(), "amount: \"5993160682\"\ndenom: "+token+"\n", out.String()) // 3 * 1997716894 + 1 * 10000 = 5993160682
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
machines[1].address,
fmt.Sprintf(s.errormsg, bank.FlagDenom, token),
})
s.Require().NoError(err)
assert.Contains(s.T(), out.String(), token)
assert.Equal(s.T(), "amount: \"11986311368\"\ndenom: "+token+"\n", out.String()) // 2 * 5993150684 + 1 * 10000 = 11986311368
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
val.Address.String(),
fmt.Sprintf(s.errormsg, bank.FlagDenom, token),
})
s.Require().NoError(err)
assert.Contains(s.T(), out.String(), token)
// Account for 1 additional unfinished PoP when checking balances after distribution
if token == s.claimDenom {
assert.Equal(s.T(), "amount: \"600000000\"\ndenom: "+token+"\n", out.String()) // 6 * 100000000
} else {
assert.Equal(s.T(), "amount: \"500000000\"\ndenom: "+token+"\n", out.String()) // 5 * 100000000
}
}
func (s *SelectionE2ETestSuite) TestTokenDistribution1() {
out := s.perpareLocalTest()
assert.Contains(s.T(), out.String(), machines[0].address)
assert.Contains(s.T(), out.String(), machines[1].address)
s.sendPoPResult(out.Bytes(), false)
out = s.perpareLocalTest()
assert.Contains(s.T(), out.String(), machines[0].address)
assert.Contains(s.T(), out.String(), machines[1].address)
s.sendPoPResult(out.Bytes(), true)
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
var daoGenState daotypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[daotypes.ModuleName], &daoGenState)
s.VerifyTokens(daoGenState.Params.StagedDenom)
// send Reissuance and DistributionResult implicitly
latestHeight, err := s.network.LatestHeight()
s.Require().NoError(err)
for {
latestHeight, err := s.network.WaitForHeight(latestHeight + 1)
s.Require().NoError(err)
// s.Require().NoError(s.network.WaitForNextBlock())
if latestHeight%s.reissuanceEpochs == s.distributionOffset {
break
}
}
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
s.VerifyTokens(daoGenState.Params.ClaimDenom)
}
func (s *SelectionE2ETestSuite) TestTokenRedeemClaim() {
val := s.network.Validators[0]
k, err := val.ClientCtx.Keyring.Key(machines[0].name)
s.Require().NoError(err)
addr, _ := k.GetAddress()
// Addr sends CreateRedeemClaim => accepted query redeem claim
createClaimMsg := daotypes.NewMsgCreateRedeemClaim(addr.String(), "liquidAddress")
out, err := lib.BroadcastTxWithFileLock(addr, createClaimMsg)
s.Require().NoError(err)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(0), int(txResponse.Code))
// WaitForBlock => Validator should implicitly send UpdateRedeemClaim
s.Require().NoError(s.network.WaitForNextBlock())
// Claim burned on CreateRedeemClaim
balanceOut, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
addr.String(),
fmt.Sprintf(s.errormsg, bank.FlagDenom, s.claimDenom),
})
s.Require().NoError(err)
assert.Equal(s.T(), "amount: \"0\"\ndenom: crddl\n", balanceOut.String()) // consumes all claims
// Addr sends ConfirmRedeemClaim => rejected not claim address
confirmMsg := daotypes.NewMsgConfirmRedeemClaim(addr.String(), 0, "liquidAddress")
out, err = lib.BroadcastTxWithFileLock(addr, confirmMsg)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock()) // added another waiting block to pass CI test cases (they are a bit slower)
_, err = clitestutil.GetRawLogFromTxOut(val, out)
s.Require().ErrorContains(err, "failed to execute message; message index: 0: expected: plmnt19cl05ztgt8ey6v86hjjjn3thfmpu6q2xtveehc; got: plmnt1kp93kns6hs2066d8qw0uz84fw3vlthewt2ck6p: invalid claim address")
// Validator with Claim Address sends ConfirmRedeemClaim => accepted
valConfirmMsg := daotypes.NewMsgConfirmRedeemClaim(val.Address.String(), 0, "liquidAddress")
out, err = lib.BroadcastTxWithFileLock(val.Address, valConfirmMsg)
s.Require().NoError(err)
txResponse, err = lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(0), int(txResponse.Code))
// WaitForBlock before query (2 blocks since 3 validators)
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
// QueryRedeemClaim
qOut, err := clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.GetCmdShowRedeemClaim(), []string{"liquidAddress", "0"})
s.Require().NoError(err)
assert.Equal(s.T(), "redeemClaim:\n amount: \"5993160682\"\n beneficiary: liquidAddress\n confirmed: true\n creator: plmnt1kp93kns6hs2066d8qw0uz84fw3vlthewt2ck6p\n id: \"0\"\n liquidTxHash: \"0000000000000000000000000000000000000000000000000000000000000000\"\n", qOut.String())
qOut, err = clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.GetCmdRedeemClaimByLiquidTxHash(), []string{"0000000000000000000000000000000000000000000000000000000000000000"})
s.Require().NoError(err)
assert.Equal(s.T(), "redeemClaim:\n amount: \"5993160682\"\n beneficiary: liquidAddress\n confirmed: true\n creator: plmnt1kp93kns6hs2066d8qw0uz84fw3vlthewt2ck6p\n id: \"0\"\n liquidTxHash: \"0000000000000000000000000000000000000000000000000000000000000000\"\n", qOut.String())
// Make sure "Publish" has been called with PoPInit cmnd
calls := mocks.GetCallLog()
var popInitCalls []mocks.Call
regex := regexp.MustCompile(`cmnd\/[a-zA-Z0-9]{15,50}\/PoPInit`)
for _, call := range calls {
if call.FuncName != "Publish" {
continue
}
cmnd, ok := call.Params[0].(string)
if !ok {
assert.True(s.T(), ok) // fails test case if !ok
continue
}
if regex.MatchString(cmnd) {
popInitCalls = append(popInitCalls, call)
}
}
assert.Greater(s.T(), len(popInitCalls), 0)
}
func (s *SelectionE2ETestSuite) createValAccount(cfg network.Config) (address sdk.AccAddress, err error) {
buf := bufio.NewReader(os.Stdin)
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, s.T().TempDir(), buf, cfg.Codec, cfg.KeyringOptions...)
if err != nil {
return nil, err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos)
if err != nil {
return nil, err
}
mnemonic := cfg.Mnemonics[0]
record, err := kb.NewAccount("node0", mnemonic, keyring.DefaultBIP39Passphrase, sdk.GetConfig().GetFullBIP44Path(), algo)
if err != nil {
return nil, err
}
addr, err := record.GetAddress()
if err != nil {
return nil, err
}
return addr, nil
}

View File

@ -1,273 +0,0 @@
package dao
import (
"bufio"
"encoding/json"
"fmt"
"os"
"strconv"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
"github.com/planetmint/planetmint-go/config"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
daocli "github.com/planetmint/planetmint-go/x/dao/client/cli"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
)
var (
bobAddr sdk.AccAddress
aliceAddr sdk.AccAddress
)
// E2ETestSuite struct definition of dao suite
type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
}
// NewE2ETestSuite returns configured dao E2ETestSuite
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
return &E2ETestSuite{cfg: cfg}
}
// SetupSuite initializes dao E2ETestSuite
func (s *E2ETestSuite) SetupSuite() {
// set FeeDenom to node0token because the sending account is initialized with no plmnt tokens
conf := config.GetConfig()
conf.FeeDenom = "node0token"
conf.SetPlanetmintConfig(conf)
s.T().Log("setting up e2e test suite")
// set accounts for alice and bob in genesis state
var authGenState authtypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[authtypes.ModuleName], &authGenState)
bobAddr = sample.Secp256k1AccAddress()
aliceAddr = sample.Secp256k1AccAddress()
bob := authtypes.NewBaseAccount(bobAddr, nil, 0, 0)
alice := authtypes.NewBaseAccount(aliceAddr, nil, 0, 0)
accounts, err := authtypes.PackAccounts(authtypes.GenesisAccounts{bob, alice})
s.Require().NoError(err)
authGenState.Accounts = append(authGenState.Accounts, accounts...)
s.cfg.GenesisState[authtypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&authGenState)
// set the balances in genesis state
var bankGenState banktypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[banktypes.ModuleName], &bankGenState)
bbalances := sdk.NewCoins(
sdk.NewCoin(conf.TokenDenom, math.NewInt(10000)),
sdk.NewCoin(conf.StakeDenom, math.NewInt(10000)),
)
abalances := sdk.NewCoins(
sdk.NewCoin(conf.TokenDenom, math.NewInt(10000)),
sdk.NewCoin(conf.StakeDenom, math.NewInt(5000)),
)
accountBalances := []banktypes.Balance{
{Address: bobAddr.String(), Coins: bbalances.Sort()},
{Address: aliceAddr.String(), Coins: abalances.Sort()},
}
bankGenState.Balances = append(bankGenState.Balances, accountBalances...)
s.cfg.GenesisState[banktypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&bankGenState)
// Setup MintAddress parameter in genesis state
// use sample.Mnemonic to make mint address deterministic for test
s.cfg.Mnemonics = []string{sample.Mnemonic}
// set MintAddress in GenesisState
var daoGenState daotypes.GenesisState
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[daotypes.ModuleName], &daoGenState)
valAddr, err := s.createValAccount(s.cfg)
s.Require().NoError(err)
daoGenState.Params.MintAddress = valAddr.String()
s.cfg.GenesisState[daotypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&daoGenState)
s.cfg.MinGasPrices = fmt.Sprintf("0.000006%s", conf.FeeDenom)
s.network = network.New(s.T(), s.cfg)
}
// TearDownSuite clean up after testing
func (s *E2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e test suite")
}
func (s *E2ETestSuite) TestDistributeCollectedFees() {
conf := config.GetConfig()
val := s.network.Validators[0]
// sending funds to alice and pay some fees to be distributed
args := []string{
val.Moniker,
aliceAddr.String(),
"1000stake",
"--yes",
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("10%s", conf.FeeDenom)),
}
_, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.NewSendTxCmd(), args)
s.Require().NoError(err)
err = s.network.WaitForNextBlock()
s.Require().NoError(err)
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.NewSendTxCmd(), args)
s.Require().NoError(err)
err = s.network.WaitForNextBlock()
s.Require().NoError(err)
err = s.network.WaitForNextBlock()
s.Require().NoError(err)
// assert that alice has 6 of 20 paid fee tokens based on 5000 stake of 15000 total stake
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
aliceAddr.String(),
})
assert.Contains(s.T(), out.String(), "node0token")
assert.Contains(s.T(), out.String(), "6")
s.Require().NoError(err)
// assert that bob has 13 of 20 paid fee tokens based on 10000 stake of 15000 total stake
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
bobAddr.String(),
})
assert.Contains(s.T(), out.String(), "node0token")
assert.Contains(s.T(), out.String(), "13")
s.Require().NoError(err)
}
func (s *E2ETestSuite) TestMintToken() {
conf := config.GetConfig()
val := s.network.Validators[0]
mintRequest := sample.MintRequest(aliceAddr.String(), 1000, "hash")
mrJSON, err := json.Marshal(&mintRequest)
s.Require().NoError(err)
// send mint token request from mint address
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Moniker),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("10%s", conf.FeeDenom)),
"--yes",
string(mrJSON),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.CmdMintToken(), args)
s.Require().NoError(err)
txResponse, err := clitestutil.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(0), int(txResponse.Code))
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err := clitestutil.GetRawLogFromTxResponse(val, txResponse)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, "planetmintgo.dao.MsgMintToken")
// assert that alice has actually received the minted tokens 10000 (initial supply) + 1000 (minted) = 11000 (total)
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
aliceAddr.String(),
})
assert.Contains(s.T(), out.String(), "plmnt")
assert.Contains(s.T(), out.String(), "11000")
s.Require().NoError(err)
// send mint token request from non mint address
kb := val.ClientCtx.Keyring
account, err := kb.NewAccount(sample.Name, sample.Mnemonic, keyring.DefaultBIP39Passphrase, sample.DefaultDerivationPath, hd.Secp256k1)
s.Require().NoError(err)
addr, _ := account.GetAddress()
// sending funds to account to initialize on chain
args = []string{
val.Moniker,
addr.String(),
sample.Amount,
"--yes",
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("10%s", conf.FeeDenom)),
}
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.NewSendTxCmd(), args)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
args = []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, addr.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("10%s", conf.FeeDenom)),
"--yes",
string(mrJSON),
}
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.CmdMintToken(), args)
s.Require().NoError(err)
txResponse, err = clitestutil.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(2), int(txResponse.Code))
}
func (s *E2ETestSuite) createValAccount(cfg network.Config) (address sdk.AccAddress, err error) {
buf := bufio.NewReader(os.Stdin)
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, s.T().TempDir(), buf, cfg.Codec, cfg.KeyringOptions...)
if err != nil {
return nil, err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos)
if err != nil {
return nil, err
}
mnemonic := cfg.Mnemonics[0]
record, err := kb.NewAccount("node0", mnemonic, keyring.DefaultBIP39Passphrase, sdk.GetConfig().GetFullBIP44Path(), algo)
if err != nil {
return nil, err
}
addr, err := record.GetAddress()
if err != nil {
return nil, err
}
return addr, nil
}
func (s *E2ETestSuite) TestReissuance() {
conf := config.GetConfig()
val := s.network.Validators[0]
var err error
for i := 0; i < conf.PoPEpochs+10; i++ {
err = s.network.WaitForNextBlock()
s.Require().NoError(err)
}
var height int64
height, _ = s.network.LatestHeight()
intValue := strconv.FormatInt(height, 10)
_, _ = clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.CmdGetReissuance(), []string{intValue})
}

View File

@ -2,15 +2,16 @@ package machine
import (
"testing"
"time"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/stretchr/testify/suite"
)
func TestE2ETestSuite(t *testing.T) {
t.Parallel()
cfg := network.DefaultConfig()
cfg.NumValidators = 1
func TestE2EMachineTestSuite(t *testing.T) {
time.Sleep(2 * time.Second)
cfg := network.LoaderDefaultConfig()
cfg.NumValidators = 3
suite.Run(t, NewE2ETestSuite(cfg))
}

View File

@ -1,70 +0,0 @@
package machine
import (
"fmt"
"github.com/planetmint/planetmint-go/testutil"
"github.com/planetmint/planetmint-go/testutil/sample"
machinetypes "github.com/planetmint/planetmint-go/x/machine/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
)
func (s *E2ETestSuite) TestAttestMachineREST() {
val := s.network.Validators[0]
baseURL := val.APIAddress
// Query Sequence Number
k, err := val.ClientCtx.Keyring.Key(sample.Name)
s.Require().NoError(err)
addr, err := k.GetAddress()
s.Require().NoError(err)
prvKey, pubKey := sample.KeyPair(1)
// Register TA
ta := sample.TrustAnchor(pubKey)
taMsg := machinetypes.MsgRegisterTrustAnchor{
Creator: addr.String(),
TrustAnchor: &ta,
}
txBytes, err := testutil.PrepareTx(val, &taMsg, sample.Name)
s.Require().NoError(err)
_, err = testutil.BroadcastTx(val, txBytes)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
// Create Attest Machine TX
machine := sample.Machine(sample.Name, pubKey, prvKey, addr.String())
msg := machinetypes.MsgAttestMachine{
Creator: addr.String(),
Machine: &machine,
}
txBytes, err = testutil.PrepareTx(val, &msg, sample.Name)
s.Require().NoError(err)
broadcastTxResponse, err := testutil.BroadcastTx(val, txBytes)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
tx, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", val.APIAddress, broadcastTxResponse.TxResponse.TxHash))
s.Require().NoError(err)
var txRes txtypes.GetTxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(tx, &txRes)
s.Require().NoError(err)
s.Require().Equal(uint32(0), txRes.TxResponse.Code)
queryMachineURL := fmt.Sprintf("%s/planetmint/machine/get_machine_by_public_key/%s", baseURL, pubKey)
queryMachineRes, err := testutil.GetRequest(queryMachineURL)
s.Require().NoError(err)
var qmRes machinetypes.QueryGetMachineByPublicKeyResponse
err = val.ClientCtx.Codec.UnmarshalJSON(queryMachineRes, &qmRes)
s.Require().NoError(err)
s.Require().Equal(&machine, qmRes.Machine)
}

View File

@ -1,29 +1,35 @@
package machine
import (
"encoding/json"
"fmt"
"bytes"
"github.com/planetmint/planetmint-go/lib"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
machinecli "github.com/planetmint/planetmint-go/x/machine/client/cli"
machinetypes "github.com/planetmint/planetmint-go/x/machine/types"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
txcli "github.com/cosmos/cosmos-sdk/x/auth/tx"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
feegrant "github.com/cosmos/cosmos-sdk/x/feegrant/client/cli"
"github.com/cosmos/cosmos-sdk/x/feegrant"
e2etestutil "github.com/planetmint/planetmint-go/testutil/e2e"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/planetmint/planetmint-go/testutil/moduleobject"
)
// E2ETestSuite struct definition of machine suite
type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
cfg network.Config
network *network.Network
feeDenom string
}
// NewE2ETestSuite returns configured machine E2ETestSuite
@ -33,41 +39,21 @@ func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
// SetupSuite initializes machine E2ETestSuite
func (s *E2ETestSuite) SetupSuite() {
s.T().Log("setting up e2e test suite")
s.T().Log("setting up e2e machine test suite")
s.network = network.New(s.T())
val := s.network.Validators[0]
s.feeDenom = sample.FeeDenom
s.network = network.Load(s.T(), s.cfg)
kb := val.ClientCtx.Keyring
account, err := kb.NewAccount(sample.Name, sample.Mnemonic, keyring.DefaultBIP39Passphrase, sample.DefaultDerivationPath, hd.Secp256k1)
// create machine account for attestation
account, err := e2etestutil.CreateAccount(s.network, sample.Name, sample.Mnemonic)
s.Require().NoError(err)
addr, _ := account.GetAddress()
// sending funds to machine to initialize account on chain
args := []string{
val.Moniker,
addr.String(),
sample.Amount,
"--yes",
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.NewSendTxCmd(), args)
err = e2etestutil.FundAccount(s.network, account, s.feeDenom)
s.Require().NoError(err)
txResponse, err := clitestutil.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err := clitestutil.GetRawLogFromTxResponse(val, txResponse)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, "cosmos.bank.v1beta1.MsgSend")
}
// TearDownSuite clean up after testing
func (s *E2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e test suite")
s.T().Log("tearing down e2e machine test suite")
}
// TestAttestMachine attests machine and query attested machine from chain
@ -77,24 +63,14 @@ func (s *E2ETestSuite) TestAttestMachine() {
// register Ta
prvKey, pubKey := sample.KeyPair()
ta := sample.TrustAnchor(pubKey)
taJSON, err := json.Marshal(&ta)
s.Require().NoError(err)
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
fmt.Sprintf("--%s=%s", flags.FlagFrom, sample.Name),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
string(taJSON),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdRegisterTrustAnchor(), args)
s.Require().NoError(err)
txResponse, err := clitestutil.GetTxResponseFromOut(out)
ta := moduleobject.TrustAnchor(pubKey)
msg1 := machinetypes.NewMsgRegisterTrustAnchor(val.Address.String(), &ta)
out, err := e2etestutil.BuildSignBroadcastTx(s.T(), val.Address, msg1)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err := clitestutil.GetRawLogFromTxResponse(val, txResponse)
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err := clitestutil.GetRawLogFromTxOut(val, out)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, "planetmintgo.machine.MsgRegisterTrustAnchor")
@ -103,84 +79,88 @@ func (s *E2ETestSuite) TestAttestMachine() {
s.Require().NoError(err)
addr, _ := k.GetAddress()
machine := sample.Machine(sample.Name, pubKey, prvKey, addr.String())
machineJSON, err := json.Marshal(&machine)
// Check preAttestationBalance in order to verify that it doesn't change after machine attestation
preAttestationBalanceOutput, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
addr.String(),
})
s.Require().NoError(err)
args = []string{
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
fmt.Sprintf("--%s=%s", flags.FlagFrom, sample.Name),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
string(machineJSON),
preAttestationBalance, ok := preAttestationBalanceOutput.(*bytes.Buffer)
if !ok {
err = lib.ErrTypeAssertionFailed
s.Require().NoError(err)
}
assert.Contains(s.T(), preAttestationBalance.String(), "10000")
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdAttestMachine(), args)
s.Require().NoError(err)
txResponse, err = clitestutil.GetTxResponseFromOut(out)
machine := moduleobject.Machine(sample.Name, pubKey, prvKey, addr.String())
msg2 := machinetypes.NewMsgAttestMachine(addr.String(), &machine)
out, err = e2etestutil.BuildSignBroadcastTx(s.T(), addr, msg2)
s.Require().NoError(err)
// give machine attestation some time to issue the liquid asset
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err = clitestutil.GetRawLogFromTxResponse(val, txResponse)
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err = clitestutil.GetRawLogFromTxOut(val, out)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, "planetmintgo.machine.MsgAttestMachine")
args = []string{
args := []string{
pubKey,
}
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdGetMachineByPublicKey(), args)
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.GetCmdMachineByPublicKey(), args)
s.Require().NoError(err)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
txResp, err := txcli.QueryTx(val.ClientCtx, txResponse.TxHash)
s.Require().NoError(err)
assert.Contains(s.T(), txResp.TxHash, txResponse.TxHash)
s.Require().NoError(err)
// Check postAttestationBalance it should be the preAttestationBalance + th 8800 tokens being donated to the machine (no fees are taken)
postAttestationBalanceOutput, err := clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
addr.String(),
})
s.Require().NoError(err)
postAttestationBalance, ok := postAttestationBalanceOutput.(*bytes.Buffer)
if !ok {
err = lib.ErrTypeAssertionFailed
s.Require().NoError(err)
}
assert.Contains(s.T(), postAttestationBalance.String(), "18800")
}
func (s *E2ETestSuite) TestInvalidAttestMachine() {
val := s.network.Validators[0]
// already used in REST test case
prvKey, pubKey := sample.KeyPair(1)
// already used in previous test case
prvKey, pubKey := sample.KeyPair()
k, err := val.ClientCtx.Keyring.Key(sample.Name)
s.Require().NoError(err)
addr, _ := k.GetAddress()
machine := sample.Machine(sample.Name, pubKey, prvKey, addr.String())
machineJSON, err := json.Marshal(&machine)
machine := moduleobject.Machine(sample.Name, pubKey, prvKey, addr.String())
s.Require().NoError(err)
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
fmt.Sprintf("--%s=%s", flags.FlagFrom, sample.Name),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
string(machineJSON),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdAttestMachine(), args)
s.Require().NoError(err)
txResponse, err := clitestutil.GetTxResponseFromOut(out)
msg := machinetypes.NewMsgAttestMachine(addr.String(), &machine)
out, _ := lib.BroadcastTxWithFileLock(addr, msg)
txResponse, err := lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(txResponse.Code), int(4))
unregisteredPubKey, unregisteredPrivKey := sample.KeyPair(2)
machine = sample.Machine(sample.Name, unregisteredPubKey, unregisteredPrivKey, addr.String())
machineJSON, err = json.Marshal(&machine)
machine = moduleobject.Machine(sample.Name, unregisteredPubKey, unregisteredPrivKey, addr.String())
s.Require().NoError(err)
args = []string{
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
fmt.Sprintf("--%s=%s", flags.FlagFrom, sample.Name),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
string(machineJSON),
}
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdAttestMachine(), args)
s.Require().NoError(err)
txResponse, err = clitestutil.GetTxResponseFromOut(out)
msg = machinetypes.NewMsgAttestMachine(addr.String(), &machine)
out, _ = lib.BroadcastTxWithFileLock(addr, msg)
txResponse, err = lib.GetTxResponseFromOut(out)
s.Require().NoError(err)
s.Require().Equal(int(txResponse.Code), int(3))
}
@ -199,59 +179,57 @@ func (s *E2ETestSuite) TestMachineAllowanceAttestation() {
// register TA
prvKey, pubKey := sample.KeyPair(3)
ta := sample.TrustAnchor(pubKey)
taJSON, err := json.Marshal(&ta)
ta := moduleobject.TrustAnchor(pubKey)
msg1 := machinetypes.NewMsgRegisterTrustAnchor(val.Address.String(), &ta)
_, err = e2etestutil.BuildSignBroadcastTx(s.T(), val.Address, msg1)
s.Require().NoError(err)
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Moniker),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
string(taJSON),
}
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdRegisterTrustAnchor(), args)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
// create allowance for machine
args = []string{
val.Moniker, // granter
addr.String(), // grantee
fmt.Sprintf("--%s=%s", feegrant.FlagAllowedMsgs, "/planetmintgo.machine.MsgAttestMachine"),
fmt.Sprintf("--%s=%s", feegrant.FlagSpendLimit, "2stake"),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
"--yes",
allowedMsgs := []string{"/planetmintgo.machine.MsgAttestMachine"}
limit := sdk.NewCoins(sdk.NewInt64Coin(s.feeDenom, 2))
basic := feegrant.BasicAllowance{
SpendLimit: limit,
}
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, feegrant.NewCmdFeeGrant(), args)
var grant feegrant.FeeAllowanceI
grant = &basic
grant, err = feegrant.NewAllowedMsgAllowance(grant, allowedMsgs)
s.Require().NoError(err)
msg2, err := feegrant.NewMsgGrantAllowance(grant, val.Address, addr)
s.Require().NoError(err)
_, err = e2etestutil.BuildSignBroadcastTx(s.T(), val.Address, msg2)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
// attest machine with fee granter without funding the machine account first
machine := sample.Machine(sample.Name, pubKey, prvKey, addr.String())
machineJSON, err := json.Marshal(&machine)
machine := moduleobject.Machine(sample.Name, pubKey, prvKey, addr.String())
s.Require().NoError(err)
args = []string{
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
fmt.Sprintf("--%s=%s", flags.FlagFrom, addr.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sample.Fees),
fmt.Sprintf("--%s=%s", flags.FlagFeeGranter, val.Address.String()),
"--yes",
string(machineJSON),
}
// name and address of private key with which to sign
clientCtx := val.ClientCtx.
WithFeeGranterAddress(val.Address)
libConfig := lib.GetConfig()
libConfig.SetClientCtx(clientCtx)
msg3 := machinetypes.NewMsgAttestMachine(addr.String(), &machine)
_, err = e2etestutil.BuildSignBroadcastTx(s.T(), addr, msg3)
// reset clientCtx to validator ctx
libConfig.SetClientCtx(val.ClientCtx)
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdAttestMachine(), args)
s.Require().NoError(err)
// give machine attestation some time to issue the liquid asset
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
s.Require().NoError(s.network.WaitForNextBlock())
args = []string{
args := []string{
pubKey,
}
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.CmdGetMachineByPublicKey(), args)
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, machinecli.GetCmdMachineByPublicKey(), args)
s.Require().NoError(err)
}

View File

@ -1,74 +1,81 @@
package cli
import (
"bytes"
"context"
"encoding/json"
"github.com/planetmint/planetmint-go/testutil"
"regexp"
"errors"
"github.com/planetmint/planetmint-go/lib"
"github.com/planetmint/planetmint-go/testutil"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
)
// ExecTestCLICmd builds the client context, mocks the output and executes the command.
func ExecTestCLICmd(clientCtx client.Context, cmd *cobra.Command, extraArgs []string) (testutil.BufferWriter, error) {
func ExecTestCLICmd(clientCtx client.Context, cmd *cobra.Command, extraArgs []string) (out testutil.BufferWriter, err error) {
cmd.SetArgs(extraArgs)
_, out := testutil.ApplyMockIO(cmd)
_, out = testutil.ApplyMockIO(cmd)
clientCtx = clientCtx.WithOutput(out)
ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
if err := cmd.ExecuteContext(ctx); err != nil {
return out, err
if err = cmd.ExecuteContext(ctx); err != nil {
return
}
return out, nil
output, ok := out.(*bytes.Buffer)
if !ok {
err = lib.ErrTypeAssertionFailed
return
}
txResponse, err := lib.GetTxResponseFromOut(output)
if err != nil {
return
}
if txResponse.Code != 0 {
err = errors.New(txResponse.RawLog)
return
}
return
}
// GetTxResponseFromOut converts strings to numbers and unmarshalles out into TxResponse struct
func GetTxResponseFromOut(out testutil.BufferWriter) (sdk.TxResponse, error) {
var txResponse sdk.TxResponse
m := regexp.MustCompile(`"([0-9]+?)"`)
str := m.ReplaceAllString(out.String(), "${1}")
// We might have YAML here, so we need to convert to JSON first, because TxResponse struct lacks `yaml:"height,omitempty"`, etc.
// Since JSON is a subset of YAML, passing JSON through YAMLToJSON is a no-op and the result is the byte array of the JSON again.
j, err := yaml.YAMLToJSON([]byte(str))
// GetRawLogFromTxOut queries the TxHash of out from the chain and returns the RawLog from the answer.
func GetRawLogFromTxOut(val *network.Validator, out *bytes.Buffer) (rawLog string, err error) {
txResponse, err := lib.GetTxResponseFromOut(out)
if err != nil {
return txResponse, err
return
}
err = json.Unmarshal(j, &txResponse)
if err != nil {
return txResponse, err
if txResponse.Code != 0 {
err = errors.New(txResponse.RawLog)
return
}
return txResponse, nil
}
// GetRawLogFromTxResponse queries the TxHash of txResponse from the chain and returns the RawLog from the answer.
func GetRawLogFromTxResponse(val *network.Validator, txResponse sdk.TxResponse) (string, error) {
args := []string{
txResponse.TxHash,
}
out, err := ExecTestCLICmd(val.ClientCtx, authcmd.QueryTxCmd(), args)
output, err := ExecTestCLICmd(val.ClientCtx, authcmd.QueryTxCmd(), args)
if err != nil {
return "", err
return
}
txRes, err := GetTxResponseFromOut(out)
if err != nil {
return "", err
out, ok := output.(*bytes.Buffer)
if !ok {
err = lib.ErrTypeAssertionFailed
return
}
return txRes.RawLog, nil
txRes, err := lib.GetTxResponseFromOut(out)
if err != nil {
return
}
rawLog = txRes.RawLog
return
}

116
testutil/e2e/e2e.go Normal file
View File

@ -0,0 +1,116 @@
package e2e
import (
"errors"
"strings"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/planetmint/planetmint-go/lib"
clitestutil "github.com/planetmint/planetmint-go/testutil/cli"
"github.com/planetmint/planetmint-go/testutil/moduleobject"
"github.com/planetmint/planetmint-go/testutil/network"
"github.com/planetmint/planetmint-go/testutil/sample"
machinetypes "github.com/planetmint/planetmint-go/x/machine/types"
)
func CreateAccount(network *network.Network, name string, mnemonic string) (account *keyring.Record, err error) {
val := network.Validators[0]
kb := val.ClientCtx.Keyring
account, err = kb.NewAccount(name, mnemonic, keyring.DefaultBIP39Passphrase, sample.DefaultDerivationPath, hd.Secp256k1)
if err != nil {
return nil, err
}
return account, nil
}
func FundAccount(network *network.Network, account *keyring.Record, tokenDenom string) (err error) {
val := network.Validators[0]
addr, err := account.GetAddress()
if err != nil {
return err
}
// sending funds to account to initialize account on chain
coin := sdk.NewCoins(sdk.NewInt64Coin(tokenDenom, 10000))
msg := banktypes.NewMsgSend(val.Address, addr, coin)
out, err := lib.BroadcastTxWithFileLock(val.Address, msg)
if err != nil {
return err
}
err = network.WaitForNextBlock()
if err != nil {
return err
}
err = network.WaitForNextBlock()
if err != nil {
return err
}
rawLog, err := clitestutil.GetRawLogFromTxOut(val, out)
if err != nil {
return err
}
if !strings.Contains(rawLog, "cosmos.bank.v1beta1.MsgSend") {
err = errors.New("failed to fund account")
}
return
}
func AttestMachine(network *network.Network, name string, mnemonic string, num int, tokenDenom string) (err error) {
val := network.Validators[0]
account, err := CreateAccount(network, name, mnemonic)
if err != nil {
return err
}
err = FundAccount(network, account, tokenDenom)
if err != nil {
return err
}
// register Ta
prvKey, pubKey := sample.KeyPair(num)
ta := moduleobject.TrustAnchor(pubKey)
registerMsg := machinetypes.NewMsgRegisterTrustAnchor(val.Address.String(), &ta)
_, err = lib.BroadcastTxWithFileLock(val.Address, registerMsg)
if err != nil {
return err
}
err = network.WaitForNextBlock()
if err != nil {
return err
}
addr, err := account.GetAddress()
if err != nil {
return err
}
machine := moduleobject.Machine(name, pubKey, prvKey, addr.String())
attestMsg := machinetypes.NewMsgAttestMachine(addr.String(), &machine)
_, err = lib.BroadcastTxWithFileLock(addr, attestMsg)
if err != nil {
return err
}
err = network.WaitForNextBlock()
if err != nil {
return err
}
err = network.WaitForNextBlock()
if err != nil {
return err
}
return
}

29
testutil/e2e/tx.go Normal file
View File

@ -0,0 +1,29 @@
package e2e
import (
"bytes"
"errors"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/lib"
)
// BuildSignBroadcastTx builds, signs and broadcasts transaction to the network.
func BuildSignBroadcastTx(t *testing.T, addr sdk.AccAddress, msgs ...sdk.Msg) (out *bytes.Buffer, err error) {
out, err = lib.BroadcastTxWithFileLock(addr, msgs...)
if err != nil {
t.Log("broadcast tx failed: " + err.Error())
return
}
txResponse, err := lib.GetTxResponseFromOut(out)
if err != nil {
t.Log("getting tx response from out failed: " + err.Error())
return
}
if txResponse.Code != 0 {
err = errors.New(txResponse.RawLog)
return
}
return
}

View File

@ -0,0 +1,5 @@
package errormsg
var (
ErrorInvalidAddress = "invalid_address"
)

View File

@ -4,6 +4,7 @@ import (
"testing"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/testutil/moduleobject"
"github.com/planetmint/planetmint-go/testutil/sample"
"github.com/planetmint/planetmint-go/x/asset/keeper"
"github.com/planetmint/planetmint-go/x/asset/types"
@ -49,15 +50,15 @@ func AssetKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
ctrl := gomock.NewController(t)
mk := assettestutils.NewMockMachineKeeper(ctrl)
sk, pk := sample.KeyPair()
_, ppk := sample.ExtendedKeyPair(config.PlmntNetParams)
_, lpk := sample.ExtendedKeyPair(config.LiquidNetParams)
_, ppk := moduleobject.ExtendedKeyPair(config.PlmntNetParams)
_, lpk := moduleobject.ExtendedKeyPair(config.LiquidNetParams)
id := sample.MachineIndex(pk, ppk, lpk)
id := moduleobject.MachineIndex(pk, ppk, lpk)
mk.EXPECT().GetMachineIndexByPubKey(ctx, pk).Return(id, true).AnyTimes()
mk.EXPECT().GetMachineIndexByPubKey(ctx, ppk).Return(id, true).AnyTimes()
mk.EXPECT().GetMachineIndexByPubKey(ctx, sk).Return(id, false).AnyTimes()
mk.EXPECT().GetMachine(ctx, id).Return(sample.Machine(pk, pk, sk, ""), true).AnyTimes()
mk.EXPECT().GetMachine(ctx, sk).Return(sample.Machine(pk, pk, sk, ""), false).AnyTimes()
mk.EXPECT().GetMachine(ctx, id).Return(moduleobject.Machine(pk, pk, sk, ""), true).AnyTimes()
mk.EXPECT().GetMachine(ctx, sk).Return(moduleobject.Machine(pk, pk, sk, ""), false).AnyTimes()
k := keeper.NewKeeper(
cdc,

View File

@ -15,18 +15,16 @@ import (
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
typesparams "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/golang/mock/gomock"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/testutil/sample"
"github.com/planetmint/planetmint-go/monitor"
monitormocks "github.com/planetmint/planetmint-go/monitor/mocks"
"github.com/planetmint/planetmint-go/x/dao/keeper"
daotestutil "github.com/planetmint/planetmint-go/x/dao/testutil"
"github.com/planetmint/planetmint-go/x/dao/types"
"github.com/stretchr/testify/require"
daotestutil "github.com/planetmint/planetmint-go/x/dao/testutil"
)
func DaoKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
cfg := config.GetConfig()
monitor.SetMqttMonitorInstance(&monitormocks.MockMQTTMonitorClientI{})
storeKey := sdk.NewKVStoreKey(types.StoreKey)
memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey)
challengeStoreKey := storetypes.NewMemoryStoreKey(types.ChallengeKey)
@ -58,11 +56,11 @@ func DaoKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
ctrl := gomock.NewController(t)
bk := daotestutil.NewMockBankKeeper(ctrl)
amt := sdk.NewCoins(sdk.NewCoin(cfg.TokenDenom, sdk.NewIntFromUint64(1000)))
beneficiaryAddr, _ := sdk.AccAddressFromBech32(sample.ConstBech32Addr)
bk.EXPECT().MintCoins(ctx, types.ModuleName, amt).Return(nil).AnyTimes()
bk.EXPECT().SendCoinsFromModuleToAccount(ctx, types.ModuleName, beneficiaryAddr, amt).Return(nil).AnyTimes()
bk.EXPECT().MintCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
bk.EXPECT().BurnCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
bk.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
bk.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
bk.EXPECT().GetBalance(gomock.Any(), gomock.Any(), gomock.Any()).Return(sdk.NewCoin("crddl", sdk.NewInt(10000))).AnyTimes()
k := keeper.NewKeeper(
cdc,
@ -71,10 +69,13 @@ func DaoKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
challengeStoreKey,
mintRequestHashStoreKey,
mintRequestAddressStoreKey,
nil, // TODO: mount and add store/key
paramsSubspace,
bk,
nil,
nil,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
"",
)
// Initialize params

View File

@ -14,6 +14,8 @@ import (
"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"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
typesparams "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/stretchr/testify/require"
)
@ -58,12 +60,14 @@ func MachineKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
addressStoreKey,
memStoreKey,
paramsSubspace,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
"",
)
ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger())
// Initialize params
k.SetParams(ctx, types.DefaultParams())
_ = k.SetParams(ctx, types.DefaultParams())
return k, ctx
}

View File

@ -0,0 +1,66 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./clients/claim_client.go
// Package mocks is a generated GoMock package.
package mocks
import (
context "context"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
"github.com/rddl-network/rddl-claim-service/types"
)
// MockIRCClient is a mock of IRCClient interface.
type MockIRCClient struct {
ctrl *gomock.Controller
recorder *MockIRCClientMockRecorder
}
// MockIRCClientMockRecorder is the mock recorder for MockIRCClient.
type MockIRCClientMockRecorder struct {
mock *MockIRCClient
}
// NewMockIRCClient creates a new mock instance.
func NewMockIRCClient(ctrl *gomock.Controller) *MockIRCClient {
mock := &MockIRCClient{ctrl: ctrl}
mock.recorder = &MockIRCClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockIRCClient) EXPECT() *MockIRCClientMockRecorder {
return m.recorder
}
// GetClaim mocks base method.
func (m *MockIRCClient) GetClaim(ctx context.Context, id int) (types.GetClaimResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetClaim", ctx, id)
ret0, _ := ret[0].(types.GetClaimResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetClaim indicates an expected call of GetClaim.
func (mr *MockIRCClientMockRecorder) GetClaim(ctx, id interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClaim", reflect.TypeOf((*MockIRCClient)(nil).GetClaim), ctx, id)
}
// PostClaim mocks base method.
func (m *MockIRCClient) PostClaim(ctx context.Context, req types.PostClaimRequest) (types.PostClaimResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PostClaim", ctx, req)
ret0, _ := ret[0].(types.PostClaimResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PostClaim indicates an expected call of PostClaim.
func (mr *MockIRCClientMockRecorder) PostClaim(ctx, req interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostClaim", reflect.TypeOf((*MockIRCClient)(nil).PostClaim), ctx, req)
}

View File

@ -0,0 +1,110 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./clients/shamir_coordinator_client.go
// Package mocks is a generated GoMock package.
package mocks
import (
context "context"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
"github.com/rddl-network/shamir-coordinator-service/types"
)
// MockISCClient is a mock of ISCClient interface.
type MockISCClient struct {
ctrl *gomock.Controller
recorder *MockISCClientMockRecorder
}
// MockISCClientMockRecorder is the mock recorder for MockISCClient.
type MockISCClientMockRecorder struct {
mock *MockISCClient
}
// NewMockISCClient creates a new mock instance.
func NewMockISCClient(ctrl *gomock.Controller) *MockISCClient {
mock := &MockISCClient{ctrl: ctrl}
mock.recorder = &MockISCClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockISCClient) EXPECT() *MockISCClientMockRecorder {
return m.recorder
}
// GetMnemonics mocks base method.
func (m *MockISCClient) GetMnemonics(ctx context.Context) (types.MnemonicsResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetMnemonics", ctx)
ret0, _ := ret[0].(types.MnemonicsResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetMnemonics indicates an expected call of GetMnemonics.
func (mr *MockISCClientMockRecorder) GetMnemonics(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMnemonics", reflect.TypeOf((*MockISCClient)(nil).GetMnemonics), ctx)
}
// IssueMachineNFT mocks base method.
func (m *MockISCClient) IssueMachineNFT(ctx context.Context, name, machineAddress, domain string) (types.IssueMachineNFTResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IssueMachineNFT", ctx, name, machineAddress, domain)
ret0, _ := ret[0].(types.IssueMachineNFTResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// IssueMachineNFT indicates an expected call of IssueMachineNFT.
func (mr *MockISCClientMockRecorder) IssueMachineNFT(ctx, name, machineAddress, domain interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IssueMachineNFT", reflect.TypeOf((*MockISCClient)(nil).IssueMachineNFT), ctx, name, machineAddress, domain)
}
// PostMnemonics mocks base method.
func (m *MockISCClient) PostMnemonics(ctx context.Context, secret string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PostMnemonics", ctx, secret)
ret0, _ := ret[0].(error)
return ret0
}
// PostMnemonics indicates an expected call of PostMnemonics.
func (mr *MockISCClientMockRecorder) PostMnemonics(ctx, secret interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostMnemonics", reflect.TypeOf((*MockISCClient)(nil).PostMnemonics), ctx, secret)
}
// ReIssueAsset mocks base method.
func (m *MockISCClient) ReIssueAsset(ctx context.Context, asset, amount string) (types.ReIssueResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ReIssueAsset", ctx, asset, amount)
ret0, _ := ret[0].(types.ReIssueResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ReIssueAsset indicates an expected call of ReIssueAsset.
func (mr *MockISCClientMockRecorder) ReIssueAsset(ctx, asset, amount interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReIssueAsset", reflect.TypeOf((*MockISCClient)(nil).ReIssueAsset), ctx, asset, amount)
}
// SendTokens mocks base method.
func (m *MockISCClient) SendTokens(ctx context.Context, recipient, amount, asset string) (types.SendTokensResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendTokens", ctx, recipient, amount, asset)
ret0, _ := ret[0].(types.SendTokensResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SendTokens indicates an expected call of SendTokens.
func (mr *MockISCClientMockRecorder) SendTokens(ctx, recipient, amount, asset interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTokens", reflect.TypeOf((*MockISCClient)(nil).SendTokens), ctx, recipient, amount, asset)
}

View File

@ -0,0 +1,132 @@
package moduleobject
import (
"encoding/hex"
"strconv"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/testutil/sample"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
machinetypes "github.com/planetmint/planetmint-go/x/machine/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/go-bip39"
)
func ExtendedKeyPair(cfg chaincfg.Params) (string, string) {
seed, err := bip39.NewSeedWithErrorChecking(sample.Mnemonic, keyring.DefaultBIP39Passphrase)
if err != nil {
panic(err)
}
xprivKey, err := hdkeychain.NewMaster(seed, &cfg)
if err != nil {
panic(err)
}
xpubKey, err := xprivKey.Neuter()
if err != nil {
panic(err)
}
return xprivKey.String(), xpubKey.String()
}
// Machine creates a new machine object
// TODO: make address deterministic for test cases
func Machine(name, pubKey string, prvKey string, address string) machinetypes.Machine {
metadata := Metadata()
_, liquidPubKey := ExtendedKeyPair(config.LiquidNetParams)
_, planetmintPubKey := ExtendedKeyPair(config.PlmntNetParams)
prvKeyBytes, _ := hex.DecodeString(prvKey)
sk := &secp256k1.PrivKey{Key: prvKeyBytes}
pubKeyBytes, _ := hex.DecodeString(pubKey)
sign, _ := sk.Sign(pubKeyBytes)
signatureHex := hex.EncodeToString(sign)
if address == "" {
address = sample.Secp256k1AccAddress().String()
}
m := machinetypes.Machine{
Name: name,
Ticker: name + "_ticker",
Domain: "testnet-assets.rddl.iok",
Reissue: true,
Amount: 1000,
Precision: 8,
IssuerPlanetmint: planetmintPubKey,
IssuerLiquid: liquidPubKey,
MachineId: pubKey,
Metadata: &metadata,
Type: 1,
MachineIdSignature: signatureHex,
Address: address,
}
return m
}
func MachineRandom(name, pubKey string, prvKey string, address string, random int) machinetypes.Machine {
metadata := Metadata()
_, liquidPubKey := ExtendedKeyPair(config.LiquidNetParams)
_, planetmintPubKey := ExtendedKeyPair(config.PlmntNetParams)
prvKeyBytes, _ := hex.DecodeString(prvKey)
sk := &secp256k1.PrivKey{Key: prvKeyBytes}
pubKeyBytes, _ := hex.DecodeString(pubKey)
sign, _ := sk.Sign(pubKeyBytes)
signatureHex := hex.EncodeToString(sign)
if address == "" {
address = sample.Secp256k1AccAddress().String()
}
m := machinetypes.Machine{
Name: name + strconv.Itoa(random),
Ticker: name + strconv.Itoa(random) + "_ticker",
Domain: "testnet-assets.rddl.io",
Reissue: true,
Amount: 1000,
Precision: 8,
IssuerPlanetmint: planetmintPubKey,
IssuerLiquid: liquidPubKey,
MachineId: pubKey,
Metadata: &metadata,
Type: 1,
MachineIdSignature: signatureHex,
Address: address,
}
return m
}
func MachineIndex(pubKey string, planetmintPubKey string, liquidPubKey string) machinetypes.MachineIndex {
return machinetypes.MachineIndex{
MachineId: pubKey,
IssuerPlanetmint: planetmintPubKey,
IssuerLiquid: liquidPubKey,
}
}
func Metadata() machinetypes.Metadata {
return machinetypes.Metadata{
Gps: "{\"Latitude\":\"-48.876667\",\"Longitude\":\"-123.393333\"}",
Device: "{\"Manufacturer\": \"RDDL\",\"Serial\":\"AdnT2uyt\"}",
AssetDefinition: "{\"Version\": \"0.1\"}",
AdditionalDataCID: "CID",
}
}
func TrustAnchor(pubkey string) machinetypes.TrustAnchor {
return machinetypes.TrustAnchor{
Pubkey: pubkey,
}
}
func MintRequest(beneficiaryAddr string, amount uint64, txhash string) daotypes.MintRequest {
return daotypes.MintRequest{
Beneficiary: beneficiaryAddr,
Amount: amount,
LiquidTxHash: txhash,
}
}

137
testutil/network/loader.go Normal file
View File

@ -0,0 +1,137 @@
package network
import (
"strings"
"testing"
"time"
tmdb "github.com/cometbft/cometbft-db"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
pruningtypes "github.com/cosmos/cosmos-sdk/store/pruning/types"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/golang/mock/gomock"
"github.com/planetmint/planetmint-go/app"
"github.com/planetmint/planetmint-go/clients/claim"
"github.com/planetmint/planetmint-go/clients/shamir/coordinator"
"github.com/planetmint/planetmint-go/monitor"
monitormocks "github.com/planetmint/planetmint-go/monitor/mocks"
clientmocks "github.com/planetmint/planetmint-go/testutil/mocks"
"github.com/planetmint/planetmint-go/testutil/sample"
"github.com/planetmint/planetmint-go/util"
"github.com/planetmint/planetmint-go/util/mocks"
elements "github.com/rddl-network/elements-rpc"
elementsmocks "github.com/rddl-network/elements-rpc/utils/mocks"
rcctypes "github.com/rddl-network/rddl-claim-service/types"
scctypes "github.com/rddl-network/shamir-coordinator-service/types"
"github.com/stretchr/testify/require"
)
// Load creates instance with fully configured cosmos network.
// Accepts optional config, that will be used in place of the DefaultConfig() if provided.
func Load(t *testing.T, configs ...Config) *Network {
if len(configs) > 1 {
panic("at most one config should be provided")
}
var cfg Config
if len(configs) == 0 {
cfg = LoaderDefaultConfig()
} else {
cfg = configs[0]
}
validatorTmpDir := t.TempDir()
// use mock client for testing
util.MQTTClient = &mocks.MockMQTTClient{}
monitor.MonitorMQTTClient = &mocks.MockMQTTClient{}
monitor.SetMqttMonitorInstance(&monitormocks.MockMQTTMonitorClientI{})
elements.Client = &elementsmocks.MockClient{}
util.RegisterAssetServiceHTTPClient = &mocks.MockClient{}
ctrl := gomock.NewController(t)
claimMock := clientmocks.NewMockIRCClient(ctrl)
claimMock.EXPECT().PostClaim(gomock.Any(), gomock.Any()).AnyTimes().Return(rcctypes.PostClaimResponse{
TxID: "0000000000000000000000000000000000000000000000000000000000000000",
}, nil)
claim.RCClient = claimMock
shamirMock := clientmocks.NewMockISCClient(ctrl)
shamirMock.EXPECT().SendTokens(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(scctypes.SendTokensResponse{
TxID: "7add40beb27df701e02ee85089c5bc0021bc813823fedb5f1dcb5debda7f3da9",
}, nil)
shamirMock.EXPECT().ReIssueAsset(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(scctypes.ReIssueResponse{
TxID: "7add40beb27df701e02ee85089c5bc0021bc813823fedb5f1dcb5debda7f3da9",
}, nil)
shamirMock.EXPECT().IssueMachineNFT(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(scctypes.IssueMachineNFTResponse{
HexTX: "0000000000000000000000000000000000000000000000000000000000000000",
Contract: `{"entity":{"domain":"testnet-assets.rddl.io"}, "issuer_pubkey":"02", "machine_addr":"addr","name":"machine","precicion":8,"version":1}`,
Asset: "0000000000000000000000000000000000000000000000000000000000000000",
}, nil)
coordinator.SCClient = shamirMock
// enable application logger in tests
appLogger := util.GetAppLogger()
appLogger.SetTestingLogger(t)
net, err := New(t, validatorTmpDir, cfg)
// this is only done to support multi validator test
// race conditions(load/unload) on the CI
if err != nil && strings.Contains(err.Error(), "bind: address already in use") {
net, err = New(t, validatorTmpDir, cfg)
}
require.NoError(t, err)
_, err = net.WaitForHeight(1)
require.NoError(t, err)
t.Cleanup(net.Cleanup)
return net
}
// LoaderDefaultConfig will initialize config for the network with custom application,
// genesis and single validator. All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig
func LoaderDefaultConfig() Config {
var (
encoding = app.MakeEncodingConfig()
chainID = "chain-foobarbaz"
)
return Config{
Codec: encoding.Marshaler,
TxConfig: encoding.TxConfig,
LegacyAmino: encoding.Amino,
InterfaceRegistry: encoding.InterfaceRegistry,
AccountRetriever: authtypes.AccountRetriever{},
AppConstructor: func(val ValidatorI) servertypes.Application {
return app.New(
val.GetCtx().Logger,
tmdb.NewMemDB(),
nil,
true,
map[int64]bool{},
val.GetCtx().Config.RootDir,
0,
encoding,
simtestutil.EmptyAppOptions{},
baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
baseapp.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
baseapp.SetChainID(chainID),
)
},
GenesisState: app.ModuleBasics.DefaultGenesis(encoding.Marshaler),
TimeoutCommit: 2 * time.Second,
ChainID: chainID,
NumValidators: 1,
BondDenom: sdk.DefaultBondDenom,
MinGasPrices: "0.000003" + sample.FeeDenom,
AccountTokens: sdk.TokensFromConsensusPower(10000, sdk.DefaultPowerReduction),
StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction),
BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction),
PruningStrategy: pruningtypes.PruningOptionNothing,
CleanupDir: true,
SigningAlgo: string(hd.Secp256k1Type),
KeyringOptions: []keyring.Option{},
AccountDenom: sample.FeeDenom,
}
}

View File

@ -1,101 +1,829 @@
package network
import (
"bufio"
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"sync"
"testing"
"time"
tmdb "github.com/cometbft/cometbft-db"
dbm "github.com/cometbft/cometbft-db"
tmrand "github.com/cometbft/cometbft/libs/rand"
"github.com/cometbft/cometbft/node"
tmclient "github.com/cometbft/cometbft/rpc/client"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/lib"
"github.com/planetmint/planetmint-go/testutil/sample"
"github.com/planetmint/planetmint-go/util"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"cosmossdk.io/math"
tmlog "github.com/cometbft/cometbft/libs/log"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/configurator"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
"cosmossdk.io/depinject"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
pruningtypes "github.com/cosmos/cosmos-sdk/store/pruning/types"
"github.com/cosmos/cosmos-sdk/testutil/network"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/stretchr/testify/require"
"github.com/planetmint/planetmint-go/app"
"github.com/planetmint/planetmint-go/config"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// package-wide network lock to only allow one test network at a time
var lock = new(sync.Mutex)
// AppConstructor defines a function which accepts a network configuration and
// creates an ABCI Application to provide to Tendermint.
type (
AppConstructor = func(val ValidatorI) servertypes.Application
TestFixtureFactory = func() TestFixture
)
type TestFixture struct {
AppConstructor AppConstructor
GenesisState map[string]json.RawMessage
EncodingConfig moduletestutil.TestEncodingConfig
}
// Config defines the necessary configuration used to bootstrap and start an
// in-process local testing network.
type Config struct {
Codec codec.Codec
LegacyAmino *codec.LegacyAmino // TODO: Remove!
InterfaceRegistry codectypes.InterfaceRegistry
TxConfig client.TxConfig
AccountRetriever client.AccountRetriever
AppConstructor AppConstructor // the ABCI application constructor
GenesisState map[string]json.RawMessage // custom genesis state to provide
TimeoutCommit time.Duration // the consensus commitment timeout
ChainID string // the network chain-id
NumValidators int // the total number of validators to create and bond
Mnemonics []string // custom user-provided validator operator mnemonics
BondDenom string // the staking bond denomination
MinGasPrices string // the minimum gas prices each validator will accept
AccountTokens math.Int // the amount of unique validator tokens (e.g. 1000node0)
StakingTokens math.Int // the amount of tokens each validator has available to stake
BondedTokens math.Int // the amount of tokens each validator stakes
PruningStrategy string // the pruning strategy each validator will have
EnableTMLogging bool // enable Tendermint logging to STDOUT
CleanupDir bool // remove base temporary directory during cleanup
SigningAlgo string // signing algorithm for keys
KeyringOptions []keyring.Option // keyring configuration options
RPCAddress string // RPC listen address (including port)
APIAddress string // REST API listen address (including port)
GRPCAddress string // GRPC server listen address (including port)
PrintMnemonic bool // print the mnemonic of first validator as log output for testing
AccountDenom string // the denominator of the account tokens
}
// DefaultConfig returns a sane default configuration suitable for nearly all
// testing requirements.
func DefaultConfig(factory TestFixtureFactory) Config {
fixture := factory()
return Config{
Codec: fixture.EncodingConfig.Codec,
TxConfig: fixture.EncodingConfig.TxConfig,
LegacyAmino: fixture.EncodingConfig.Amino,
InterfaceRegistry: fixture.EncodingConfig.InterfaceRegistry,
AccountRetriever: authtypes.AccountRetriever{},
AppConstructor: fixture.AppConstructor,
GenesisState: fixture.GenesisState,
TimeoutCommit: 2 * time.Second,
ChainID: "chain-" + tmrand.Str(6),
NumValidators: 4,
BondDenom: sdk.DefaultBondDenom,
MinGasPrices: "0.000006" + sample.FeeDenom,
AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction),
StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction),
BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction),
PruningStrategy: pruningtypes.PruningOptionNothing,
CleanupDir: true,
SigningAlgo: string(hd.Secp256k1Type),
KeyringOptions: []keyring.Option{},
PrintMnemonic: false,
AccountDenom: sample.FeeDenom,
}
}
// MinimumAppConfig defines the minimum of modules required for a call to New to succeed
func MinimumAppConfig() depinject.Config {
return configurator.NewAppConfig(
configurator.AuthModule(),
configurator.ParamsModule(),
configurator.BankModule(),
configurator.GenutilModule(),
configurator.StakingModule(),
configurator.ConsensusModule(),
configurator.TxModule())
}
func DefaultConfigWithAppConfig(appConfig depinject.Config) (Config, error) {
var (
appBuilder *runtime.AppBuilder
txConfig client.TxConfig
legacyAmino *codec.LegacyAmino
cdc codec.Codec
interfaceRegistry codectypes.InterfaceRegistry
)
if err := depinject.Inject(appConfig,
&appBuilder,
&txConfig,
&cdc,
&legacyAmino,
&interfaceRegistry,
); err != nil {
return Config{}, err
}
cfg := DefaultConfig(func() TestFixture {
return TestFixture{}
})
cfg.Codec = cdc
cfg.TxConfig = txConfig
cfg.LegacyAmino = legacyAmino
cfg.InterfaceRegistry = interfaceRegistry
cfg.GenesisState = appBuilder.DefaultGenesis()
cfg.AppConstructor = func(val ValidatorI) servertypes.Application {
// we build a unique app instance for every validator here
var appBuilder *runtime.AppBuilder
if err := depinject.Inject(appConfig, &appBuilder); err != nil {
panic(err)
}
app := appBuilder.Build(
val.GetCtx().Logger,
dbm.NewMemDB(),
nil,
baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
baseapp.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
baseapp.SetChainID(cfg.ChainID),
)
testdata.RegisterQueryServer(app.GRPCQueryRouter(), testdata.QueryImpl{})
if err := app.Load(true); err != nil {
panic(err)
}
return app
}
return cfg, nil
}
type (
Network = network.Network
Config = network.Config
// Network defines a local in-process testing network using SimApp. It can be
// configured to start any number of validators, each with its own RPC and API
// clients. Typically, this test network would be used in client and integration
// testing where user input is expected.
//
// Note, due to Tendermint constraints in regards to RPC functionality, there
// may only be one test network running at a time. Thus, any caller must be
// sure to Cleanup after testing is finished in order to allow other tests
// to create networks. In addition, only the first validator will have a valid
// RPC and API server/client.
Network struct {
Logger Logger
BaseDir string
Validators []*Validator
Config Config
}
// Validator defines an in-process Tendermint validator node. Through this object,
// a client can make RPC and API calls and interact with any client command
// or handler.
Validator struct {
AppConfig *srvconfig.Config
ClientCtx client.Context
Ctx *server.Context
Dir string
NodeID string
PubKey cryptotypes.PubKey
Moniker string
APIAddress string
RPCAddress string
P2PAddress string
Address sdk.AccAddress
ValAddress sdk.ValAddress
RPCClient tmclient.Client
tmNode *node.Node
api *api.Server
grpc *grpc.Server
grpcWeb *http.Server
}
// ValidatorI expose a validator's context and configuration
ValidatorI interface {
GetCtx() *server.Context
GetAppConfig() *srvconfig.Config
}
// Logger is a network logger interface that exposes testnet-level Log() methods for an in-process testing network
// This is not to be confused with logging that may happen at an individual node or validator level
Logger interface {
Log(args ...interface{})
Logf(format string, args ...interface{})
}
)
// New creates instance with fully configured cosmos network.
// Accepts optional config, that will be used in place of the DefaultConfig() if provided.
func New(t *testing.T, configs ...Config) *Network {
if len(configs) > 1 {
panic("at most one config should be provided")
}
var cfg network.Config
if len(configs) == 0 {
cfg = DefaultConfig()
} else {
cfg = configs[0]
}
validatorTmpDir := t.TempDir()
var (
_ Logger = (*testing.T)(nil)
_ Logger = (*CLILogger)(nil)
_ ValidatorI = Validator{}
)
// set the proper root dir for the test environment so that the abci.go logic works
appConfig := config.GetConfig()
appConfig.SetRoot(validatorTmpDir + "/node0/simd")
net, err := network.New(t, validatorTmpDir, cfg)
appConfig.ValidatorAddress = net.Validators[0].Address.String()
require.NoError(t, err)
_, err = net.WaitForHeight(1)
require.NoError(t, err)
t.Cleanup(net.Cleanup)
return net
func (v Validator) GetCtx() *server.Context {
return v.Ctx
}
// DefaultConfig will initialize config for the network with custom application,
// genesis and single validator. All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig
func DefaultConfig() network.Config {
func (v Validator) GetAppConfig() *srvconfig.Config {
return v.AppConfig
}
// CLILogger wraps a cobra.Command and provides command logging methods.
type CLILogger struct {
cmd *cobra.Command
}
// Log logs given args.
func (s CLILogger) Log(args ...interface{}) {
s.cmd.Println(args...)
}
// Logf logs given args according to a format specifier.
func (s CLILogger) Logf(format string, args ...interface{}) {
s.cmd.Printf(format, args...)
}
// NewCLILogger creates a new CLILogger.
func NewCLILogger(cmd *cobra.Command) CLILogger {
return CLILogger{cmd}
}
// New creates a new Network for integration tests or in-process testnets run via the CLI
func New(l Logger, baseDir string, cfg Config) (*Network, error) {
// only one caller/test can create and use a network at a time
l.Log("acquiring test network lock")
lock.Lock()
network := &Network{
Logger: l,
BaseDir: baseDir,
Validators: make([]*Validator, cfg.NumValidators),
Config: cfg,
}
l.Logf("preparing test network with chain-id \"%s\"\n", cfg.ChainID)
monikers := make([]string, cfg.NumValidators)
nodeIDs := make([]string, cfg.NumValidators)
valPubKeys := make([]cryptotypes.PubKey, cfg.NumValidators)
var (
encoding = app.MakeEncodingConfig()
chainID = "chain-foobarbaz"
genAccounts []authtypes.GenesisAccount
genBalances []banktypes.Balance
genFiles []string
)
return network.Config{
Codec: encoding.Marshaler,
TxConfig: encoding.TxConfig,
LegacyAmino: encoding.Amino,
InterfaceRegistry: encoding.InterfaceRegistry,
AccountRetriever: authtypes.AccountRetriever{},
AppConstructor: func(val network.ValidatorI) servertypes.Application {
return app.New(
val.GetCtx().Logger,
tmdb.NewMemDB(),
nil,
true,
map[int64]bool{},
val.GetCtx().Config.RootDir,
0,
encoding,
simtestutil.EmptyAppOptions{},
baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
baseapp.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
baseapp.SetChainID(chainID),
)
},
GenesisState: app.ModuleBasics.DefaultGenesis(encoding.Marshaler),
TimeoutCommit: 2 * time.Second,
ChainID: chainID,
NumValidators: 1,
BondDenom: sdk.DefaultBondDenom,
MinGasPrices: fmt.Sprintf("0.000003%s", sdk.DefaultBondDenom),
AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction),
StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction),
BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction),
PruningStrategy: pruningtypes.PruningOptionNothing,
CleanupDir: true,
SigningAlgo: string(hd.Secp256k1Type),
KeyringOptions: []keyring.Option{},
buf := bufio.NewReader(os.Stdin)
// generate private keys, node IDs, and initial transactions
for i := 0; i < cfg.NumValidators; i++ {
appCfg := srvconfig.DefaultConfig()
appCfg.Pruning = cfg.PruningStrategy
appCfg.MinGasPrices = cfg.MinGasPrices
appCfg.API.Enable = true
appCfg.API.Swagger = false
appCfg.Telemetry.Enabled = false
ctx := server.NewDefaultContext()
tmCfg := ctx.Config
tmCfg.Consensus.TimeoutCommit = cfg.TimeoutCommit
tmCfg.Consensus.TimeoutPrecommit = cfg.TimeoutCommit
tmCfg.Consensus.TimeoutPrevote = cfg.TimeoutCommit
tmCfg.Consensus.TimeoutPropose = cfg.TimeoutCommit
// Only allow the first validator to expose an RPC, API and gRPC
// server/client due to Tendermint in-process constraints.
apiAddr := ""
tmCfg.RPC.ListenAddress = ""
appCfg.GRPC.Enable = false
appCfg.GRPCWeb.Enable = false
apiListenAddr := ""
if i == 0 {
if cfg.APIAddress != "" {
apiListenAddr = cfg.APIAddress
} else {
var err error
apiListenAddr, _, err = server.FreeTCPAddr()
if err != nil {
return nil, err
}
}
appCfg.API.Address = apiListenAddr
apiURL, err := url.Parse(apiListenAddr)
if err != nil {
return nil, err
}
apiAddr = net.JoinHostPort("http://"+apiURL.Hostname(), apiURL.Port())
if cfg.RPCAddress != "" {
// The above code is likely declaring a variable or constant named "tmCfg" in the Go programming
// language. However, without more context or code, it is difficult to determine the exact purpose
// or functionality of this code.
tmCfg.RPC.ListenAddress = cfg.RPCAddress
} else {
rpcAddr, _, err := server.FreeTCPAddr()
if err != nil {
return nil, err
}
tmCfg.RPC.ListenAddress = rpcAddr
}
if cfg.GRPCAddress != "" {
appCfg.GRPC.Address = cfg.GRPCAddress
} else {
_, grpcPort, err := server.FreeTCPAddr()
if err != nil {
return nil, err
}
appCfg.GRPC.Address = "0.0.0.0:" + grpcPort
}
appCfg.GRPC.Enable = true
_, grpcWebPort, err := server.FreeTCPAddr()
if err != nil {
return nil, err
}
appCfg.GRPCWeb.Address = "0.0.0.0:" + grpcWebPort
appCfg.GRPCWeb.Enable = true
}
logger := tmlog.NewNopLogger()
if cfg.EnableTMLogging {
logger = tmlog.NewTMLogger(tmlog.NewSyncWriter(os.Stdout))
}
ctx.Logger = logger
nodeDirName := fmt.Sprintf("node%d", i)
nodeDir := filepath.Join(network.BaseDir, nodeDirName, "simd")
clientDir := filepath.Join(network.BaseDir, nodeDirName, "simcli")
gentxsDir := filepath.Join(network.BaseDir, "gentxs")
err := os.MkdirAll(filepath.Join(nodeDir, "config"), 0o755)
if err != nil {
return nil, err
}
err = os.MkdirAll(clientDir, 0o755)
if err != nil {
return nil, err
}
tmCfg.SetRoot(nodeDir)
tmCfg.Moniker = nodeDirName
monikers[i] = nodeDirName
proxyAddr, _, err := server.FreeTCPAddr()
if err != nil {
return nil, err
}
tmCfg.ProxyApp = proxyAddr
p2pAddr, _, err := server.FreeTCPAddr()
if err != nil {
return nil, err
}
tmCfg.P2P.ListenAddress = p2pAddr
tmCfg.P2P.AddrBookStrict = false
tmCfg.P2P.AllowDuplicateIP = true
nodeID, pubKey, err := genutil.InitializeNodeValidatorFiles(tmCfg)
if err != nil {
return nil, err
}
nodeIDs[i] = nodeID
valPubKeys[i] = pubKey
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.Codec, cfg.KeyringOptions...)
if err != nil {
return nil, err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos)
if err != nil {
return nil, err
}
var mnemonic string
if i < len(cfg.Mnemonics) {
mnemonic = cfg.Mnemonics[i]
}
addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, mnemonic, true, algo)
if err != nil {
return nil, err
}
// if PrintMnemonic is set to true, we print the first validator node's secret to the network's logger
// for debugging and manual testing
if cfg.PrintMnemonic && i == 0 {
printMnemonic(l, secret)
}
info := map[string]string{"secret": secret}
infoBz, err := json.Marshal(info)
if err != nil {
return nil, err
}
// save private key seed words
err = writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, infoBz)
if err != nil {
return nil, err
}
balances := sdk.NewCoins(
sdk.NewCoin(cfg.AccountDenom, cfg.AccountTokens),
sdk.NewCoin(cfg.BondDenom, cfg.StakingTokens),
)
genFiles = append(genFiles, tmCfg.GenesisFile())
genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: balances.Sort()})
genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0))
commission, err := sdk.NewDecFromStr("0.5")
if err != nil {
return nil, err
}
createValMsg, err := stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(addr),
valPubKeys[i],
sdk.NewCoin(cfg.BondDenom, cfg.BondedTokens),
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
stakingtypes.NewCommissionRates(commission, math.LegacyOneDec(), math.LegacyOneDec()),
math.OneInt(),
)
if err != nil {
return nil, err
}
p2pURL, err := url.Parse(p2pAddr)
if err != nil {
return nil, err
}
memo := fmt.Sprintf("%s@%s:%s", nodeIDs[i], p2pURL.Hostname(), p2pURL.Port())
fee := sdk.NewCoins(sdk.NewCoin(cfg.AccountDenom, sdk.NewInt(0)))
txBuilder := cfg.TxConfig.NewTxBuilder()
err = txBuilder.SetMsgs(createValMsg)
if err != nil {
return nil, err
}
txBuilder.SetFeeAmount(fee) // Arbitrary fee
txBuilder.SetGasLimit(1000000) // Need at least 100386
txBuilder.SetMemo(memo)
txFactory := tx.Factory{}
txFactory = txFactory.
WithChainID(cfg.ChainID).
WithMemo(memo).
WithKeybase(kb).
WithTxConfig(cfg.TxConfig)
err = tx.Sign(txFactory, nodeDirName, txBuilder, true)
if err != nil {
return nil, err
}
txBz, err := cfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
if err != nil {
return nil, err
}
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz)
if err != nil {
return nil, err
}
srvconfig.WriteConfigFile(filepath.Join(nodeDir, "config", "app.toml"), appCfg)
clientCtx := client.Context{}.
WithKeyringDir(clientDir).
WithKeyring(kb).
WithHomeDir(tmCfg.RootDir).
WithChainID(cfg.ChainID).
WithInterfaceRegistry(cfg.InterfaceRegistry).
WithCodec(cfg.Codec).
WithLegacyAmino(cfg.LegacyAmino).
WithTxConfig(cfg.TxConfig).
WithAccountRetriever(cfg.AccountRetriever)
// Provide ChainID here since we can't modify it in the Comet config.
ctx.Viper.Set(flags.FlagChainID, cfg.ChainID)
network.Validators[i] = &Validator{
AppConfig: appCfg,
ClientCtx: clientCtx,
Ctx: ctx,
Dir: filepath.Join(network.BaseDir, nodeDirName),
NodeID: nodeID,
PubKey: pubKey,
Moniker: nodeDirName,
RPCAddress: tmCfg.RPC.ListenAddress,
P2PAddress: tmCfg.P2P.ListenAddress,
APIAddress: apiAddr,
Address: addr,
ValAddress: sdk.ValAddress(addr),
}
}
err := initGenFiles(cfg, genAccounts, genBalances, genFiles)
if err != nil {
return nil, err
}
err = collectGenFiles(cfg, network.Validators, network.BaseDir)
if err != nil {
return nil, err
}
l.Log("starting test network...")
for idx, v := range network.Validators {
err := startInProcess(cfg, v)
if err != nil {
return nil, err
}
l.Log("started validator", idx)
if idx == 0 {
os.Setenv(config.ValAddr, network.Validators[0].Address.String())
// set missing validator client context values for sending txs
var output bytes.Buffer
network.Validators[0].ClientCtx.BroadcastMode = "sync"
network.Validators[0].ClientCtx.FromAddress = network.Validators[0].Address
network.Validators[0].ClientCtx.FromName = network.Validators[0].Moniker
network.Validators[0].ClientCtx.NodeURI = network.Validators[0].RPCAddress
network.Validators[0].ClientCtx.Output = &output
network.Validators[0].ClientCtx.SkipConfirm = true
libConfig := lib.GetConfig()
libConfig.SetClientCtx(network.Validators[0].ClientCtx)
libConfig.SetRoot(network.Validators[0].ClientCtx.HomeDir)
}
}
height := int64(0)
for height < 7 {
height, err = network.LatestHeight()
if err != nil {
return nil, err
}
}
l.Log("started test network at height:", height)
// Ensure we cleanup incase any test was abruptly halted (e.g. SIGINT) as any
// defer in a test would not be called.
server.TrapSignal(network.Cleanup)
return network, nil
}
// LatestHeight returns the latest height of the network or an error if the
// query fails or no validators exist.
func (n *Network) LatestHeight() (int64, error) {
if len(n.Validators) == 0 {
return 0, errors.New("no validators available")
}
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
timeout := time.NewTimer(time.Second * 5)
defer timeout.Stop()
var latestHeight int64
val := n.Validators[0]
queryClient := tmservice.NewServiceClient(val.ClientCtx)
for {
select {
case <-timeout.C:
return latestHeight, errors.New("timeout exceeded waiting for block")
case <-ticker.C:
res, err := queryClient.GetLatestBlock(context.Background(), &tmservice.GetLatestBlockRequest{})
if err == nil && res != nil {
return res.SdkBlock.Header.Height, nil
}
}
}
}
// WaitForHeight performs a blocking check where it waits for a block to be
// committed after a given block. If that height is not reached within a timeout,
// an error is returned. Regardless, the latest height queried is returned.
func (n *Network) WaitForHeight(h int64) (int64, error) {
return n.WaitForHeightWithTimeout(h, 10*time.Second)
}
// WaitForHeightWithTimeout is the same as WaitForHeight except the caller can
// provide a custom timeout.
func (n *Network) WaitForHeightWithTimeout(h int64, t time.Duration) (int64, error) {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
timeout := time.NewTimer(t)
defer timeout.Stop()
if len(n.Validators) == 0 {
return 0, errors.New("no validators available")
}
var latestHeight int64
val := n.Validators[0]
queryClient := tmservice.NewServiceClient(val.ClientCtx)
for {
select {
case <-timeout.C:
return latestHeight, errors.New("timeout exceeded waiting for block")
case <-ticker.C:
res, err := queryClient.GetLatestBlock(context.Background(), &tmservice.GetLatestBlockRequest{})
if err == nil && res != nil {
latestHeight = res.GetSdkBlock().Header.Height
if latestHeight >= h {
return latestHeight, nil
}
}
}
}
}
// RetryForBlocks will wait for the next block and execute the function provided.
// It will do this until the function returns a nil error or until the number of
// blocks has been reached.
func (n *Network) RetryForBlocks(retryFunc func() error, blocks int) error {
for i := 0; i < blocks; i++ {
err := n.WaitForNextBlock()
if err == nil {
return nil
}
err = retryFunc()
if err == nil {
return nil
}
// we've reached the last block to wait, return the error
if i == blocks-1 {
return err
}
}
return nil
}
// WaitForNextBlock waits for the next block to be committed, returning an error
// upon failure.
func (n *Network) WaitForNextBlock() error {
lastBlock, err := n.LatestHeight()
if err != nil {
return err
}
_, err = n.WaitForHeight(lastBlock + 1)
if err != nil {
return err
}
return err
}
// Cleanup removes the root testing (temporary) directory and stops both the
// Tendermint and API services. It allows other callers to create and start
// test networks. This method must be called when a test is finished, typically
// in a defer.
func (n *Network) Cleanup() {
defer func() {
lock.Unlock()
n.Logger.Log("released test network lock")
}()
n.Logger.Log("cleaning up test network...")
n.Logger.Log("Stage 1 APIs...")
for i := len(n.Validators) - 1; i >= 0; i-- {
v := n.Validators[i]
if v.api != nil {
_ = v.api.Close()
}
if v.grpc != nil {
v.grpc.Stop()
if v.grpcWeb != nil {
_ = v.grpcWeb.Close()
}
}
}
n.Logger.Log("Stage 2 CometBFT...")
for i := len(n.Validators) - 1; i >= 0; i-- {
v := n.Validators[i]
if v.tmNode != nil && v.tmNode.IsRunning() {
_ = v.tmNode.Stop()
}
}
n.Logger.Log("Stage 3 Application Threads...")
// waiting for all threads to be terminated
util.TerminationWaitGroup.Wait()
// Give a brief pause for things to finish closing in other processes. Hopefully this helps with the address-in-use errors.
// 100ms chosen randomly.
time.Sleep(100 * time.Millisecond)
n.Logger.Log("Stage 4 Files...")
if n.Config.CleanupDir {
_ = os.RemoveAll(n.BaseDir)
}
n.Logger.Log("finished cleaning up test network")
}
// printMnemonic prints a provided mnemonic seed phrase on a network logger
// for debugging and manual testing
func printMnemonic(l Logger, secret string) {
lines := []string{
"THIS MNEMONIC IS FOR TESTING PURPOSES ONLY",
"DO NOT USE IN PRODUCTION",
"",
strings.Join(strings.Fields(secret)[0:8], " "),
strings.Join(strings.Fields(secret)[8:16], " "),
strings.Join(strings.Fields(secret)[16:24], " "),
}
lineLengths := make([]int, len(lines))
for i, line := range lines {
lineLengths[i] = len(line)
}
maxLineLength := 0
for _, lineLen := range lineLengths {
if lineLen > maxLineLength {
maxLineLength = lineLen
}
}
l.Log("\n")
l.Log(strings.Repeat("+", maxLineLength+8))
for _, line := range lines {
l.Logf("++ %s ++\n", centerText(line, maxLineLength))
}
l.Log(strings.Repeat("+", maxLineLength+8))
l.Log("\n")
}
// centerText centers text across a fixed width, filling either side with whitespace buffers
func centerText(text string, width int) string {
textLen := len(text)
leftBuffer := strings.Repeat(" ", (width-textLen)/2)
rightBuffer := strings.Repeat(" ", (width-textLen)/2+(width-textLen)%2)
return fmt.Sprintf("%s%s%s", leftBuffer, text, rightBuffer)
}

204
testutil/network/util.go Normal file
View File

@ -0,0 +1,204 @@
package network
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"
"github.com/cometbft/cometbft/node"
"github.com/cometbft/cometbft/p2p"
pvm "github.com/cometbft/cometbft/privval"
"github.com/cometbft/cometbft/proxy"
"github.com/cometbft/cometbft/rpc/client/local"
"github.com/cometbft/cometbft/types"
tmtime "github.com/cometbft/cometbft/types/time"
"github.com/cosmos/cosmos-sdk/server/api"
servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
srvtypes "github.com/cosmos/cosmos-sdk/server/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
)
func startInProcess(cfg Config, val *Validator) error {
logger := val.Ctx.Logger
tmCfg := val.Ctx.Config
tmCfg.Instrumentation.Prometheus = false
if err := val.AppConfig.ValidateBasic(); err != nil {
return err
}
nodeKey, err := p2p.LoadOrGenNodeKey(tmCfg.NodeKeyFile())
if err != nil {
return err
}
app := cfg.AppConstructor(*val)
genDocProvider := node.DefaultGenesisDocProviderFunc(tmCfg)
tmNode, err := node.NewNode( //resleak:notresource
tmCfg,
pvm.LoadOrGenFilePV(tmCfg.PrivValidatorKeyFile(), tmCfg.PrivValidatorStateFile()),
nodeKey,
proxy.NewLocalClientCreator(app),
genDocProvider,
node.DefaultDBProvider,
node.DefaultMetricsProvider(tmCfg.Instrumentation),
logger.With("module", val.Moniker),
)
if err != nil {
return err
}
if err := tmNode.Start(); err != nil {
return err
}
val.tmNode = tmNode
if val.RPCAddress != "" {
val.RPCClient = local.New(tmNode)
}
// We'll need a RPC client if the validator exposes a gRPC or REST endpoint.
if val.APIAddress != "" || val.AppConfig.GRPC.Enable {
val.ClientCtx = val.ClientCtx.
WithClient(val.RPCClient)
app.RegisterTxService(val.ClientCtx)
app.RegisterTendermintService(val.ClientCtx)
app.RegisterNodeService(val.ClientCtx)
}
if val.APIAddress != "" {
apiSrv := api.New(val.ClientCtx, logger.With("module", "api-server"))
app.RegisterAPIRoutes(apiSrv, val.AppConfig.API)
errCh := make(chan error)
go func() {
if err := apiSrv.Start(*val.AppConfig); err != nil {
errCh <- err
}
}()
select {
case err := <-errCh:
return err
case <-time.After(srvtypes.ServerStartTime): // assume server started successfully
}
val.api = apiSrv
}
if val.AppConfig.GRPC.Enable {
grpcSrv, err := servergrpc.StartGRPCServer(val.ClientCtx, app, val.AppConfig.GRPC)
if err != nil {
return err
}
val.grpc = grpcSrv
if val.AppConfig.GRPCWeb.Enable {
val.grpcWeb, err = servergrpc.StartGRPCWeb(grpcSrv, *val.AppConfig)
if err != nil {
return err
}
}
}
return nil
}
func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error {
genTime := tmtime.Now()
for i := 0; i < cfg.NumValidators; i++ {
tmCfg := vals[i].Ctx.Config
nodeDir := filepath.Join(outputDir, vals[i].Moniker, "simd")
gentxsDir := filepath.Join(outputDir, "gentxs")
tmCfg.Moniker = vals[i].Moniker
tmCfg.SetRoot(nodeDir)
initCfg := genutiltypes.NewInitConfig(cfg.ChainID, gentxsDir, vals[i].NodeID, vals[i].PubKey)
genFile := tmCfg.GenesisFile()
genDoc, err := types.GenesisDocFromFile(genFile)
if err != nil {
return err
}
appState, err := genutil.GenAppStateFromConfig(cfg.Codec, cfg.TxConfig,
tmCfg, initCfg, *genDoc, banktypes.GenesisBalancesIterator{}, genutiltypes.DefaultMessageValidator)
if err != nil {
return err
}
// overwrite each validator's genesis file to have a canonical genesis time
if err := genutil.ExportGenesisFileWithTime(genFile, cfg.ChainID, nil, appState, genTime); err != nil {
return err
}
}
return nil
}
func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance, genFiles []string) error {
// set the accounts in the genesis state
var authGenState authtypes.GenesisState
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[authtypes.ModuleName], &authGenState)
accounts, err := authtypes.PackAccounts(genAccounts)
if err != nil {
return err
}
authGenState.Accounts = append(authGenState.Accounts, accounts...)
cfg.GenesisState[authtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&authGenState)
// set the balances in the genesis state
var bankGenState banktypes.GenesisState
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[banktypes.ModuleName], &bankGenState)
bankGenState.Balances = append(bankGenState.Balances, genBalances...)
cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState)
appGenStateJSON, err := json.MarshalIndent(cfg.GenesisState, "", " ")
if err != nil {
return err
}
genDoc := types.GenesisDoc{
ChainID: cfg.ChainID,
AppState: appGenStateJSON,
Validators: nil,
}
// generate empty genesis files for each validator and save
for i := 0; i < cfg.NumValidators; i++ {
if err := genDoc.SaveAs(genFiles[i]); err != nil {
return err
}
}
return nil
}
func writeFile(name string, dir string, contents []byte) error {
file := filepath.Join(dir, name)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("could not create directory %q: %w", dir, err)
}
if err := os.WriteFile(file, contents, 0o644); err != nil { //nolint: gosec
return err
}
return nil
}

View File

@ -1,167 +0,0 @@
package testutil
import (
"bytes"
"fmt"
"io"
"net/http"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/testutil/network"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)
// GetRequest defines a wrapper around an HTTP GET request with a provided URL.
// An error is returned if the request or reading the body fails.
func GetRequest(url string) ([]byte, error) {
res, err := http.Get(url) //nolint:gosec,noctx // only used for testing
if err != nil {
return nil, err
}
defer func() {
_ = res.Body.Close()
}()
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
return body, nil
}
// PostRequest defines a wrapper around an HTTP POST request with a provided URL and data.
// An error is returned if the request or reading the body fails.
func PostRequest(url, contentType string, data []byte) ([]byte, error) {
res, err := http.Post(url, contentType, bytes.NewBuffer(data)) //nolint:gosec,noctx // only used for testing
if err != nil {
return nil, fmt.Errorf("error while sending post request: %w", err)
}
defer func() {
_ = res.Body.Close()
}()
bz, err := io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
return bz, nil
}
func PrepareTx(val *network.Validator, msg sdk.Msg, signer string) ([]byte, error) {
k, err := val.ClientCtx.Keyring.Key(signer)
if err != nil {
return nil, err
}
addr, err := k.GetAddress()
if err != nil {
return nil, err
}
reqAccountInfo := fmt.Sprintf("%s/cosmos/auth/v1beta1/account_info/%s", val.APIAddress, addr.String())
respAccountInfo, err := GetRequest(reqAccountInfo)
if err != nil {
return nil, err
}
var resAccountInfo authtypes.QueryAccountInfoResponse
err = val.ClientCtx.Codec.UnmarshalJSON(respAccountInfo, &resAccountInfo)
if err != nil {
return nil, err
}
txBuilder := val.ClientCtx.TxConfig.NewTxBuilder()
err = txBuilder.SetMsgs(msg)
if err != nil {
return nil, err
}
txBuilder.SetGasLimit(200000)
txBuilder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin("stake", 2)})
txBuilder.SetTimeoutHeight(0)
pk, err := k.GetPubKey()
if err != nil {
return nil, err
}
sk := k.GetLocal().PrivKey
var priv cryptotypes.PrivKey
err = val.ClientCtx.Codec.UnpackAny(sk, &priv)
if err != nil {
return nil, err
}
sigV2 := signing.SignatureV2{
PubKey: pk,
Data: &signing.SingleSignatureData{
SignMode: val.ClientCtx.TxConfig.SignModeHandler().DefaultMode(),
Signature: nil,
},
Sequence: resAccountInfo.Info.Sequence,
}
err = txBuilder.SetSignatures(sigV2)
if err != nil {
return nil, err
}
signerData := xauthsigning.SignerData{
ChainID: val.ClientCtx.ChainID,
AccountNumber: resAccountInfo.Info.AccountNumber,
Sequence: resAccountInfo.Info.Sequence,
}
sigV2, err = tx.SignWithPrivKey(
val.ClientCtx.TxConfig.SignModeHandler().DefaultMode(), signerData,
txBuilder, priv, val.ClientCtx.TxConfig, resAccountInfo.Info.Sequence,
)
if err != nil {
return nil, err
}
err = txBuilder.SetSignatures(sigV2)
if err != nil {
return nil, err
}
txBytes, err := val.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
if err != nil {
return nil, err
}
return txBytes, nil
}
func BroadcastTx(val *network.Validator, txBytes []byte) (*txtypes.BroadcastTxResponse, error) {
broadcastTxURL := fmt.Sprintf("%s/cosmos/tx/v1beta1/txs", val.APIAddress)
req := txtypes.BroadcastTxRequest{
TxBytes: txBytes,
Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
}
broadCastTxBody, err := val.ClientCtx.Codec.MarshalJSON(&req)
if err != nil {
return nil, err
}
broadCastTxResponse, err := PostRequest(broadcastTxURL, "application/json", broadCastTxBody)
if err != nil {
return nil, err
}
var bctRes txtypes.BroadcastTxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(broadCastTxResponse, &bctRes)
if err != nil {
return nil, err
}
return &bctRes, nil
}

View File

@ -4,17 +4,9 @@ import (
"encoding/hex"
"fmt"
"github.com/planetmint/planetmint-go/config"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
machinetypes "github.com/planetmint/planetmint-go/x/machine/types"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/go-bip39"
)
// Mnemonic sample mnemonic to use in tests
@ -26,16 +18,13 @@ const PubKey = "021cd2a59c6f9402ce09effba89b3deb6bb5863733e625f22c06204918061db4
// Name is the name of the sample machine to use in tests
const Name = "machine"
// Amount is the amount to transfer to the machine account
const Amount = "1000stake"
// Fees is the amount of fees to use in tests
const Fees = "1stake"
// FeeDenom is the fee denomination for e2e test cases
const FeeDenom = "plmnt"
// DefaultDerivationPath is the BIP44Prefix for PLMNT (see https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
const DefaultDerivationPath = "m/44'/8680'/0'/0/0"
// ConstantBech32Addr for mocks
// ConstBech32Addr constant bech32 address for mocks
const ConstBech32Addr = "plmnt10mq5nj8jhh27z7ejnz2ql3nh0qhzjnfvy50877"
// KeyPair returns a sample private / public keypair
@ -63,88 +52,7 @@ func Secp256k1AccAddress() sdk.AccAddress {
return sdk.AccAddress(addr)
}
// TODO: make address deterministic for test cases
func Machine(name, pubKey string, prvKey string, address string) machinetypes.Machine {
metadata := Metadata()
_, liquidPubKey := ExtendedKeyPair(config.LiquidNetParams)
_, planetmintPubKey := ExtendedKeyPair(config.PlmntNetParams)
prvKeyBytes, _ := hex.DecodeString(prvKey)
sk := &secp256k1.PrivKey{Key: prvKeyBytes}
pubKeyBytes, _ := hex.DecodeString(pubKey)
sign, _ := sk.Sign(pubKeyBytes)
signatureHex := hex.EncodeToString(sign)
if address == "" {
address = Secp256k1AccAddress().String()
}
m := machinetypes.Machine{
Name: name,
Ticker: name + "_ticker",
Domain: "lab.r3c.network",
Reissue: true,
Amount: 1000,
Precision: 8,
IssuerPlanetmint: planetmintPubKey,
IssuerLiquid: liquidPubKey,
MachineId: pubKey,
Metadata: &metadata,
Type: 1,
MachineIdSignature: signatureHex,
Address: address,
}
return m
}
func MachineIndex(pubKey string, planetmintPubKey string, liquidPubKey string) machinetypes.MachineIndex {
return machinetypes.MachineIndex{
MachineId: pubKey,
IssuerPlanetmint: planetmintPubKey,
IssuerLiquid: liquidPubKey,
}
}
func Metadata() machinetypes.Metadata {
return machinetypes.Metadata{
Gps: "{\"Latitude\":\"-48.876667\",\"Longitude\":\"-123.393333\"}",
Device: "{\"Manufacturer\": \"RDDL\",\"Serial\":\"AdnT2uyt\"}",
AssetDefinition: "{\"Version\": \"0.1\"}",
AdditionalDataCID: "CID",
}
}
func Asset() string {
cid := "cid0"
return cid
}
func ExtendedKeyPair(cfg chaincfg.Params) (string, string) {
seed, err := bip39.NewSeedWithErrorChecking(Mnemonic, keyring.DefaultBIP39Passphrase)
if err != nil {
panic(err)
}
xprivKey, err := hdkeychain.NewMaster(seed, &cfg)
if err != nil {
panic(err)
}
xpubKey, err := xprivKey.Neuter()
if err != nil {
panic(err)
}
return xprivKey.String(), xpubKey.String()
}
func TrustAnchor(pubkey string) machinetypes.TrustAnchor {
return machinetypes.TrustAnchor{
Pubkey: pubkey,
}
}
func MintRequest(beneficiaryAddr string, amount uint64, txhash string) daotypes.MintRequest {
return daotypes.MintRequest{
Beneficiary: beneficiaryAddr,
Amount: amount,
LiquidTxHash: txhash,
}
}

View File

@ -8,9 +8,10 @@ import (
"path/filepath"
"strings"
"github.com/planetmint/planetmint-go/errormsg"
cometcfg "github.com/cometbft/cometbft/config"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/config"
)
type Key struct {
@ -24,37 +25,52 @@ type KeyFile struct {
PrivKey Key `json:"priv-key"`
}
func GetValidatorCometBFTIdentity(ctx sdk.Context) (string, bool) {
conf := config.GetConfig()
func GetValidatorCometBFTIdentity(ctx sdk.Context, rootDir string) (validatorIdentity string, err error) {
cfg := cometcfg.DefaultConfig()
jsonFilePath := filepath.Join(conf.ConfigRootDir, cfg.PrivValidatorKey)
jsonFilePath := filepath.Join(rootDir, cfg.PrivValidatorKey)
jsonFile, err := os.Open(jsonFilePath)
if err != nil {
GetAppLogger().Error(ctx, "error while opening config", err.Error())
return "", false
GetAppLogger().Error(ctx, err, "error while opening config: %v", jsonFilePath)
return
}
jsonBytes, err := io.ReadAll(jsonFile)
if err != nil {
GetAppLogger().Error(ctx, "error while reading file", err.Error())
return "", false
GetAppLogger().Error(ctx, err, "error while reading file: %v", jsonFile)
return
}
var keyFile KeyFile
err = json.Unmarshal(jsonBytes, &keyFile)
if err != nil {
GetAppLogger().Error(ctx, "error while unmarshaling key file", err.Error())
return "", false
GetAppLogger().Error(ctx, err, "error while unmarshaling key file")
return
}
return strings.ToLower(keyFile.Address), true
validatorIdentity = strings.ToLower(keyFile.Address)
return
}
func IsValidatorBlockProposer(ctx sdk.Context, proposerAddress []byte) bool {
validatorIdentity, validResult := GetValidatorCometBFTIdentity(ctx)
if !validResult {
return false
func IsValidatorBlockProposer(ctx sdk.Context, rootDir string) (result bool) {
validatorIdentity, err := GetValidatorCometBFTIdentity(ctx, rootDir)
if err != nil {
GetAppLogger().Error(ctx, err, errormsg.CouldNotGetValidatorIdentity)
return
}
hexProposerAddress := hex.EncodeToString(proposerAddress)
return hexProposerAddress == validatorIdentity
hexProposerAddress := hex.EncodeToString(ctx.BlockHeader().ProposerAddress)
result = hexProposerAddress == validatorIdentity
return
}
func IsValidAddress(address string) (valid bool, err error) {
// Attempt to decode the address
_, err = sdk.AccAddressFromBech32(address)
if err != nil {
return
}
if !strings.Contains(address, "plmnt") {
valid = false
return
}
valid = true
return
}

View File

@ -1,70 +0,0 @@
package util
import (
"bytes"
"encoding/json"
"errors"
"os/exec"
"strconv"
"strings"
"github.com/planetmint/planetmint-go/config"
)
type ReissueResult struct {
Txid string `json:"txid"`
Vin int `json:"vin"`
}
func ReissueAsset(reissueTx string) (txid string, err error) {
conf := config.GetConfig()
cmdArgs := strings.Split(reissueTx, " ")
cmd := exec.Command("/usr/local/bin/elements-cli", "-rpcpassword="+conf.RPCPassword,
"-rpcuser="+conf.RPCUser, "-rpcport="+strconv.Itoa(conf.RPCPort), "-rpcconnect="+conf.RPCHost,
cmdArgs[0], cmdArgs[1], cmdArgs[2])
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err = cmd.Run()
errstr := stderr.String()
if err != nil || len(errstr) > 0 {
err = errors.New("reissuance of RDDL failed: " + errstr)
} else {
var txobj ReissueResult
err = json.Unmarshal(stdout.Bytes(), &txobj)
if err == nil {
txid = txobj.Txid
}
}
return txid, err
}
func DistributeAsset(address string, amount string) (txid string, err error) {
conf := config.GetConfig()
cmd := exec.Command("/usr/local/bin/elements-cli", "-rpcpassword="+conf.RPCPassword,
"-rpcuser="+conf.RPCUser, "-rpcport="+strconv.Itoa(conf.RPCPort), "-rpcconnect="+conf.RPCHost,
"sendtoaddress", address, amount, "", "", "false", "true", "null", "\"unset\"", "false",
"\""+conf.ReissuanceAsset+"\"")
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err = cmd.Run()
errstr := stderr.String()
if err != nil || len(errstr) > 0 {
errormessage := "distribution of RDDL failed for " + address
err = errors.New(errormessage)
} else {
var txobj ReissueResult
err = json.Unmarshal(stdout.Bytes(), &txobj)
if err == nil {
txid = txobj.Txid
}
}
return txid, err
}

View File

@ -2,82 +2,113 @@ package util
import (
"context"
"strconv"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/lib"
daotypes "github.com/planetmint/planetmint-go/x/dao/types"
machinetypes "github.com/planetmint/planetmint-go/x/machine/types"
"sigs.k8s.io/yaml"
)
func setRPCConfig(goCtx context.Context) {
rpcConf := lib.GetConfig()
ctx := sdk.UnwrapSDKContext(goCtx)
rpcConf.SetChainID(ctx.ChainID())
}
func buildSignBroadcastTx(goCtx context.Context, loggingContext string, sendingValidatorAddress string, msg sdk.Msg) {
ctx := sdk.UnwrapSDKContext(goCtx)
GetAppLogger().Info(ctx, loggingContext+": "+msg.String())
TerminationWaitGroup.Add(1)
go func() {
setRPCConfig(goCtx)
defer TerminationWaitGroup.Done()
ctx := sdk.UnwrapSDKContext(goCtx)
addr := sdk.MustAccAddressFromBech32(sendingValidatorAddress)
txJSON, err := lib.BuildUnsignedTx(addr, msg)
if err != nil {
GetAppLogger().Error(ctx, loggingContext+" build unsigned tx failed: "+err.Error())
GetAppLogger().Error(ctx, err, loggingContext+" build unsigned tx failed for: %v, %v", addr, msg)
return
}
GetAppLogger().Info(ctx, loggingContext+" unsigned tx: "+txJSON)
_, err = lib.BroadcastTxWithFileLock(addr, msg)
GetAppLogger().Debug(ctx, loggingContext+" unsigned tx: "+txJSON)
out, err := lib.BroadcastTxWithFileLock(addr, msg)
if err != nil {
GetAppLogger().Error(ctx, loggingContext+" broadcast tx failed: "+err.Error())
GetAppLogger().Error(ctx, err, loggingContext+" broadcast tx failed: %v, %v", addr, msg)
return
}
GetAppLogger().Info(ctx, loggingContext+" broadcast tx succeeded")
txResponse, err := lib.GetTxResponseFromOut(out)
if err != nil {
GetAppLogger().Error(ctx, err, loggingContext+" getting tx response from out failed: %v", out)
return
}
if txResponse.Code == 0 {
GetAppLogger().Info(ctx, loggingContext+" broadcast tx succeeded")
return
}
txResponseJSON, err := yaml.YAMLToJSON([]byte(txResponse.String()))
if err != nil {
GetAppLogger().Error(ctx, err, loggingContext+" converting tx response from yaml to json failed: %v", txResponse)
return
}
GetAppLogger().Info(ctx, loggingContext+" broadcast tx failed: "+string(txResponseJSON))
}()
}
func InitRDDLReissuanceProcess(goCtx context.Context, proposerAddress string, txUnsigned string, blockHeight int64) {
ctx := sdk.UnwrapSDKContext(goCtx)
// get_last_PoPBlockHeight() // TODO: to be read form the upcoming PoP-store
sendingValidatorAddress := config.GetConfig().ValidatorAddress
GetAppLogger().Info(ctx, "create re-issuance proposal")
msg := daotypes.NewMsgReissueRDDLProposal(sendingValidatorAddress, proposerAddress, txUnsigned, blockHeight)
buildSignBroadcastTx(goCtx, "initializing RDDL re-issuance", sendingValidatorAddress, msg)
func SendInitReissuance(goCtx context.Context, proposerAddress string, txUnsigned string, blockHeight int64,
firstIncludedPop int64, lastIncludedPop int64) {
sendingValidatorAddress := config.GetConfig().GetNodeAddress()
msg := daotypes.NewMsgReissueRDDLProposal(sendingValidatorAddress, proposerAddress, txUnsigned, blockHeight,
firstIncludedPop, lastIncludedPop)
loggingContext := "reissuance proposal"
buildSignBroadcastTx(goCtx, loggingContext, sendingValidatorAddress, msg)
}
func SendRDDLReissuanceResult(goCtx context.Context, proposerAddress string, txID string, blockHeight int64) {
ctx := sdk.UnwrapSDKContext(goCtx)
sendingValidatorAddress := config.GetConfig().ValidatorAddress
GetAppLogger().Info(ctx, "create re-issuance result")
func SendReissuanceResult(goCtx context.Context, proposerAddress string, txID string, blockHeight int64) {
sendingValidatorAddress := config.GetConfig().GetNodeAddress()
msg := daotypes.NewMsgReissueRDDLResult(sendingValidatorAddress, proposerAddress, txID, blockHeight)
buildSignBroadcastTx(goCtx, "sending the re-issuance result", sendingValidatorAddress, msg)
loggingContext := "reissuance result"
buildSignBroadcastTx(goCtx, loggingContext, sendingValidatorAddress, msg)
}
func SendRDDLDistributionRequest(goCtx context.Context, distribution daotypes.DistributionOrder) {
ctx := sdk.UnwrapSDKContext(goCtx)
sendingValidatorAddress := config.GetConfig().ValidatorAddress
GetAppLogger().Info(ctx, "create Distribution Request")
func SendDistributionRequest(goCtx context.Context, distribution daotypes.DistributionOrder) {
sendingValidatorAddress := config.GetConfig().GetNodeAddress()
msg := daotypes.NewMsgDistributionRequest(sendingValidatorAddress, &distribution)
buildSignBroadcastTx(goCtx, "sending the distribution request", sendingValidatorAddress, msg)
loggingContext := "distribution request"
buildSignBroadcastTx(goCtx, loggingContext, sendingValidatorAddress, msg)
}
func SendRDDLDistributionResult(goCtx context.Context, lastPoP string, daoTxID string, invTxID string, popTxID string) {
ctx := sdk.UnwrapSDKContext(goCtx)
sendingValidatorAddress := config.GetConfig().ValidatorAddress
GetAppLogger().Info(ctx, "create Distribution Result")
iLastPoP, err := strconv.ParseInt(lastPoP, 10, 64)
if err != nil {
ctx.Logger().Error("Distribution Result: preparation failed ", err.Error())
return
}
msg := daotypes.NewMsgDistributionResult(sendingValidatorAddress, iLastPoP, daoTxID, invTxID, popTxID)
buildSignBroadcastTx(goCtx, "send distribution result", sendingValidatorAddress, msg)
func SendDistributionResult(goCtx context.Context, lastPoP int64, daoTxID string, invTxID string,
popTxID string, earlyInvestorTxID string, strategicTxID string) {
sendingValidatorAddress := config.GetConfig().GetNodeAddress()
msg := daotypes.NewMsgDistributionResult(sendingValidatorAddress, lastPoP, daoTxID, invTxID, popTxID, earlyInvestorTxID, strategicTxID)
loggingContext := "distribution result"
buildSignBroadcastTx(goCtx, loggingContext, sendingValidatorAddress, msg)
}
func SendLiquidAssetRegistration(goCtx context.Context, notarizedAsset machinetypes.LiquidAsset) {
ctx := sdk.UnwrapSDKContext(goCtx)
sendingValidatorAddress := config.GetConfig().ValidatorAddress
GetAppLogger().Info(ctx, "create Liquid Asset Registration")
sendingValidatorAddress := config.GetConfig().GetNodeAddress()
msg := machinetypes.NewMsgNotarizeLiquidAsset(sendingValidatorAddress, &notarizedAsset)
buildSignBroadcastTx(goCtx, "Liquid Asset Registration:", sendingValidatorAddress, msg)
loggingContext := "notarize liquid asset"
buildSignBroadcastTx(goCtx, loggingContext, sendingValidatorAddress, msg)
}
func SendInitPoP(goCtx context.Context, challenger string, challengee string, blockHeight int64) {
sendingValidatorAddress := config.GetConfig().GetNodeAddress()
msg := daotypes.NewMsgInitPop(sendingValidatorAddress, sendingValidatorAddress, challenger, challengee, blockHeight)
loggingContext := "PoP"
buildSignBroadcastTx(goCtx, loggingContext, sendingValidatorAddress, msg)
}
func SendUpdateRedeemClaim(goCtx context.Context, beneficiary string, id uint64, txID string) {
sendingValidatorAddress := config.GetConfig().GetNodeAddress()
msg := daotypes.NewMsgUpdateRedeemClaim(sendingValidatorAddress, beneficiary, txID, id)
loggingContext := "redeem claim"
buildSignBroadcastTx(goCtx, loggingContext, sendingValidatorAddress, msg)
}
func SendTokens(goCtx context.Context, beneficiary sdk.AccAddress, amount uint64, denominator string) {
sendingValidatorAddress := config.GetConfig().GetNodeAddress()
coin := sdk.NewCoin(denominator, sdk.NewIntFromUint64(amount))
coins := sdk.NewCoins(coin)
orgAddr := sdk.MustAccAddressFromBech32(sendingValidatorAddress)
msg := banktypes.NewMsgSend(orgAddr, beneficiary, coins)
loggingContext := "sending " + denominator + " tokens"
buildSignBroadcastTx(goCtx, loggingContext, sendingValidatorAddress, msg)
}

42
util/kv_serialize.go Normal file
View File

@ -0,0 +1,42 @@
package util
import (
"encoding/binary"
"encoding/hex"
)
func SerializeInt64(value int64) []byte {
// Adding 1 because 0 will be interpreted as nil, which is an invalid key
buf := make([]byte, 8)
// Use binary.BigEndian to write the int64 into the byte slice
binary.BigEndian.PutUint64(buf, uint64(value+1))
return buf
}
func DeserializeInt64(value []byte) int64 {
integer := binary.BigEndian.Uint64(value)
// Subtract 1 because addition in serialization
return int64(integer - 1)
}
func SerializeUint64(value uint64) []byte {
buf := make([]byte, 8)
// Adding 1 because 0 will be interpreted as nil, which is an invalid key
binary.BigEndian.PutUint64(buf, value+1)
return buf
}
func DeserializeUint64(value []byte) uint64 {
integer := binary.BigEndian.Uint64(value)
// Subtract 1 because addition in serialization
return integer - 1
}
func SerializeString(value string) []byte {
byteArray := []byte(value)
return byteArray
}
func SerializeHexString(value string) ([]byte, error) {
return hex.DecodeString(value)
}

View File

@ -1,11 +1,23 @@
package util
import sdk "github.com/cosmos/cosmos-sdk/types"
import (
"fmt"
"sync"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
)
type AppLogger struct {
testingLogger *testing.T
}
var globalApplicationLoggerTag string
var (
globalApplicationLoggerTag string
appLogger *AppLogger
initAppLogger sync.Once
syncTestingLog sync.RWMutex
)
func init() {
// Initialize the package-level variable
@ -13,17 +25,52 @@ func init() {
}
func GetAppLogger() *AppLogger {
return &AppLogger{}
initAppLogger.Do(func() {
appLogger = &AppLogger{
testingLogger: nil,
}
})
return appLogger
}
func (logger *AppLogger) SetTestingLogger(testingLogger *testing.T) *AppLogger {
syncTestingLog.Lock()
logger.testingLogger = testingLogger
syncTestingLog.Unlock()
return logger
}
func format(msg string, keyvals ...interface{}) string {
if len(keyvals) == 0 {
return msg
}
return fmt.Sprintf(msg, keyvals...)
}
func (logger *AppLogger) testingLog(msg string, keyvals ...interface{}) {
syncTestingLog.RLock()
defer syncTestingLog.RUnlock()
if logger.testingLogger == nil {
return
}
msg = format(msg, keyvals...)
logger.testingLogger.Log(msg)
}
func (logger *AppLogger) Info(ctx sdk.Context, msg string, keyvals ...interface{}) {
ctx.Logger().Info(globalApplicationLoggerTag+msg, keyvals...)
msg = format(msg, keyvals...)
logger.testingLog(globalApplicationLoggerTag + msg)
ctx.Logger().Info(globalApplicationLoggerTag + msg)
}
func (logger *AppLogger) Debug(ctx sdk.Context, msg string, keyvals ...interface{}) {
ctx.Logger().Debug(globalApplicationLoggerTag+msg, keyvals...)
msg = format(msg, keyvals...)
logger.testingLog(globalApplicationLoggerTag + msg)
ctx.Logger().Debug(globalApplicationLoggerTag + msg)
}
func (logger *AppLogger) Error(ctx sdk.Context, msg string, keyvals ...interface{}) {
ctx.Logger().Error(globalApplicationLoggerTag+msg, keyvals...)
func (logger *AppLogger) Error(ctx sdk.Context, err error, msg string, keyvals ...interface{}) {
msg = format(msg, keyvals...)
logger.testingLog(globalApplicationLoggerTag + msg + ": " + err.Error())
ctx.Logger().Error(globalApplicationLoggerTag + msg + ": " + err.Error())
}

104
util/machine_nft.go Normal file
View File

@ -0,0 +1,104 @@
package util
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/clients/shamir/coordinator"
"github.com/planetmint/planetmint-go/x/machine/types"
)
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
var (
RegisterAssetServiceHTTPClient HTTPClient
)
func init() {
RegisterAssetServiceHTTPClient = &http.Client{}
}
func IssueMachineNFT(goCtx context.Context, machine *types.Machine, scheme string, domain string, path string) error {
ctx := sdk.UnwrapSDKContext(goCtx)
// asset registration is in order to have the contact published
var notarizedAsset types.LiquidAsset
notarizedAsset.Registered = true
assetID, contract, hex, err := coordinator.IssueNFTAsset(goCtx, machine.Name, machine.Address, domain)
if err != nil {
GetAppLogger().Error(ctx, err, "")
return err
}
assetRegistryEndpoint := fmt.Sprintf("%s://%s/%s", scheme, domain, path)
GetAppLogger().Info(ctx, "Liquid Token Issuance assetID: "+assetID+" contract: "+contract+" tx: "+hex)
err = RegisterAsset(goCtx, assetID, contract, assetRegistryEndpoint)
if err != nil {
GetAppLogger().Error(ctx, err, "")
notarizedAsset.Registered = false
}
// issue message with:
notarizedAsset.AssetID = assetID
notarizedAsset.MachineID = machine.GetMachineId()
notarizedAsset.MachineAddress = machine.Address
SendLiquidAssetRegistration(goCtx, notarizedAsset)
return err
}
func RegisterAsset(goCtx context.Context, assetID string, contract string, assetRegistryEndpoint string) error {
var contractMap map[string]interface{}
err := json.Unmarshal([]byte(contract), &contractMap)
if err != nil {
return errorsmod.Wrap(types.ErrAssetRegistryReqFailure, "Unmarshal "+err.Error())
}
// Create your request payload
data := map[string]interface{}{
"asset_id": assetID,
"contract": contractMap,
}
jsonData, err := json.Marshal(data)
if err != nil {
return errorsmod.Wrap(types.ErrAssetRegistryReqFailure, "Marshall "+err.Error())
}
req, err := http.NewRequestWithContext(goCtx, http.MethodPost, assetRegistryEndpoint, bytes.NewBuffer(jsonData))
if err != nil {
return errorsmod.Wrap(types.ErrAssetRegistryReqFailure, "Request creation: "+err.Error())
}
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("accept", "application/json")
// Send request
resp, err := RegisterAssetServiceHTTPClient.Do(req)
if err != nil {
return errorsmod.Wrap(types.ErrAssetRegistryReqSending, err.Error())
}
defer resp.Body.Close()
// Read response
if resp.StatusCode > 299 {
return errorsmod.Wrap(types.ErrAssetRegistryRepsonse, "Error reading response body:"+strconv.Itoa(resp.StatusCode))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return errorsmod.Wrap(types.ErrAssetRegistryRepsonse, "Error reading response body:"+err.Error())
}
resultObj := string(body)
if strings.Contains(resultObj, assetID) {
return nil
}
return errorsmod.Wrap(types.ErrAssetRegistryRepsonse, "does not confirm asset registration")
}

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