Compare commits

...

19 Commits

Author SHA1 Message Date
i-norden
21f42d27c7 update go modules 2022-03-01 08:27:52 -06:00
i-norden
a031f9abca fixes 2022-03-01 08:20:49 -06:00
i-norden
47bafe4619 port auth module here for old version of ante module 2022-03-01 08:20:37 -06:00
i-norden
fc0ade482d adjustments to work with smt/v0.44.6 2022-03-01 08:00:33 -06:00
Brian Ginsburg
dbaaef07c7
bgins instruction tweaks 2021-11-09 11:17:18 -08:00
Boris Mann
b9e7398220
Merge pull request #9 from gsk967/sai/testnet_docs
testnet docs
2021-11-08 11:40:02 -08:00
Sai Kumar
1aa98edb04 docs: update the genesis download instruction 2021-11-03 15:00:44 +05:30
Sai Kumar
9794007231 docs: update the testnet docs 2021-11-03 12:34:12 +05:30
Sai Kumar
d41612b891 docs: updated testnet readme 2021-10-27 11:51:33 +05:30
Sai Kumar
3ef957206c docs: add golang install instructions 2021-10-27 11:50:32 +05:30
Sai Kumar
151747bc81 docs: add testnet docs 2021-10-25 18:35:59 +05:30
Sai Kumar
5a6e2ec46f
Integrate graphql server (#5)
* WIP: migrating the nameservice module

* WIP: migrating the nameservice module from dxns to ethermint

* refactor: move the proto package version from `v1` to `v1beta1` for vulcanize modules

* refactor: added bond module dependency to nameserivce module

* feat: added graphql for bond module

* feat: added auction module dependency to nameservice module

* refactor: refactored the nameservice module

* refactor: add human-readable attributes output to cli nameservice `list`

* WIP: add grpc query test cases

* fix: fix the sub names authority storing issue

* WIP: add the test cases

* refactor: removed legacyCodec from nameservice

* fix: fix the responses for `authority-expiry` and `records-expiry` commands query result

* refactor: sort the imports in app

* WIP:  add test cases for cli query, tx for nameservice module

* feat: add test cases for grpc of nameservice module

1. renamed grpc gateway routes from ethermint to vulcanize

* refactor: refactored the test cases for grpc lookup of nameservice

* refactor: refactored the test cases for bond module

* feat: add node status for gql

* feat: add get actions by ids in gql

* feat: add lookup authorities,resolve name, lookup name queries to gql

* updated readme file
2021-10-14 11:00:39 +05:30
Bipul Prasad
34cc262218
Test cases for auction module (#8)
* Adding test cases for auction module

* Adding missing test cases and fixing failed ones

* Increasing the account balance to prevent test failures

* Addressing review comments

* Renaming test files as per directory structure

* Minor modification as per review comments

* Fixing test issues

Co-authored-by: bipulprasad <Bipul@qubecinema.com>
2021-10-14 10:49:37 +05:30
Sai Kumar
db925906f3
Nameservice module cli, grpc test cases (#7)
* WIP: migrating the nameservice module

* WIP: migrating the nameservice module from dxns to ethermint

* refactor: move the proto package version from `v1` to `v1beta1` for vulcanize modules

* refactor: added bond module dependency to nameserivce module

* feat: added auction module dependency to nameservice module

* refactor: refactored the nameservice module

* refactor: add human-readable attributes output to cli nameservice `list`

* WIP: add grpc query test cases

* fix: fix the sub names authority storing issue

* WIP: add the test cases

* refactor: removed legacyCodec from nameservice

* fix: fix the responses for `authority-expiry` and `records-expiry` commands query result

* refactor: sort the imports in app

* WIP:  add test cases for cli query, tx for nameservice module

* feat: add test cases for grpc of nameservice module

1. renamed grpc gateway routes from ethermint to vulcanize

* refactor: refactored the test cases for grpc lookup of nameservice

* refactor: refactored the test cases for bond module
2021-10-13 12:07:19 +05:30
Sai Kumar
95dde36e1c
Migrating the nameservice module from dxns (#2)
* WIP: migrating the nameservice module

* WIP: migrating the nameservice module from dxns to ethermint

* refactor: move the proto package version from `v1` to `v1beta1` for vulcanize modules

* refactor: added bond module dependency to nameserivce module

* feat: added auction module dependency to nameservice module

* refactor: refactored the nameservice module

* refactor: add human-readable attributes output to cli nameservice `list`

* fix: fix the sub names authority storing issue

* refactor: removed legacyCodec from nameservice

* fix: fix the responses for `authority-expiry` and `records-expiry` commands query result

* refactor: sort the imports in app

* refactor: removed json encoder and decoder
2021-10-06 11:35:51 +05:30
Bipul Prasad
9301487351
Rectifying empty params issue with auction module (#6)
Co-authored-by: bipulprasad <Bipul@qubecinema.com>
2021-10-01 16:52:55 +05:30
Bipul Prasad
505ad2ab70
[vulcanize/dxns#8] Migrating auctions module from DXNS (#3)
* Migrating auctions module from DXNS

* Adding appropriate comments on proto definitions

* Addressing review comments and fixing build issues

* Addressing review comments

* Adding README for auction module and fixing build/run issues

* Removing DXNS references and migrating DXNS utils to Ethermint

* Setting default genesis param values

* Defining constants in params and assigning ParamSetPairs

* Fixing issues with auction bid reveals

Co-authored-by: bipulprasad <Bipul@qubecinema.com>
2021-10-01 15:19:01 +05:30
Sai Kumar
d28ef888ff
dxns bond module test (#4)
* WIP : added bond module tx and query cli commands

* added bond module invariant

* update the go.mod

* addressed the pr changes

* update to proto files

* refactor: move the proto package version from `v1` to `v1beta1` for vulcanize modules

* WIP : addin the unit test scripts to bond module

* refactor: refactored the test cases for bond module

* refactor: refactored the bond module test cases
1. refactored grpc gateway  endpoints of bond module
2. added test cases to cli query , cli tx and grpc end points

* addressed the pr comments
1. changed query-by-owner to by-owner in cli cmd
2. changed bonds-by-owner route to by-owner in bond module
2021-09-29 18:18:30 +05:30
Sai Kumar
feb9790325
Migrating the bond module from dxns (#1)
* WIP : added bond module tx and query cli commands

* added bond module invariant

* update the go.mod

* addressed the pr changes

* update to proto files

* refactor: move the proto package version from `v1` to `v1beta1` for vulcanize modules

* updated the readme file for bond module

* refactor: address the pr changes
2021-09-27 12:11:16 +05:30
162 changed files with 60026 additions and 223 deletions

View File

@ -14,6 +14,7 @@ SIMAPP = ./app
HTTPS_GIT := https://github.com/tharsis/ethermint.git
DOCKER := $(shell which docker)
DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
export GO111MODULE = on
@ -422,25 +423,35 @@ format-fix:
### Protobuf ###
###############################################################################
containerProtoVer=v0.2
containerProtoImage=tendermintdev/sdk-proto-gen:$(containerProtoVer)
containerProtoGen=cosmos-sdk-proto-gen-$(containerProtoVer)
containerProtoGenSwagger=cosmos-sdk-proto-gen-swagger-$(containerProtoVer)
containerProtoFmt=cosmos-sdk-proto-fmt-$(containerProtoVer)
protoVer=v0.2
protoImageName=tendermintdev/sdk-proto-gen:$(protoVer)
containerProtoGen=$(PROJECT_NAME)-proto-gen-$(protoVer)
containerProtoGenAny=$(PROJECT_NAME)-proto-gen-any-$(protoVer)
containerProtoGenSwagger=$(PROJECT_NAME)-proto-gen-swagger-$(protoVer)
containerProtoFmt=$(PROJECT_NAME)-proto-fmt-$(protoVer)
proto-all: proto-format proto-lint proto-gen
proto-gen:
@echo "Generating Protobuf files"
$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen sh ./scripts/protocgen.sh
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) \
sh ./scripts/protocgen.sh; fi
# This generates the SDK's custom wrapper for google.protobuf.Any. It should only be run manually when needed
proto-gen-any:
@echo "Generating Protobuf Any"
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGenAny}$$"; then docker start -a $(containerProtoGenAny); else docker run --name $(containerProtoGenAny) -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) \
sh ./scripts/protocgen-any.sh; fi
proto-swagger-gen:
@echo "Generating Protobuf Swagger"
@./scripts/protoc-swagger-gen.sh
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGenSwagger}$$"; then docker start -a $(containerProtoGenSwagger); else docker run --name $(containerProtoGenSwagger) -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) \
sh ./scripts/protoc-swagger-gen.sh; fi
proto-format:
@echo "Formatting Protobuf files"
find ./ -not -path "./third_party/*" -name *.proto -exec clang-format -i {} \;
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \
find ./ -not -path "./third_party/*" -name "*.proto" -exec clang-format -i {} \; ; fi
proto-lint:
@$(DOCKER_BUF) lint --error-format=json
@ -576,3 +587,4 @@ release:
release --rm-dist --skip-validate
.PHONY: release-dry-run release

View File

@ -11,9 +11,9 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
authante "github.com/tharsis/ethermint/x/auth/ante"
channelkeeper "github.com/cosmos/ibc-go/modules/core/04-channel/keeper"
ibcante "github.com/cosmos/ibc-go/modules/core/ante"

View File

@ -4,9 +4,10 @@ import (
"errors"
"math/big"
authante "github.com/tharsis/ethermint/x/auth/ante"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/palantir/stacktrace"
ethermint "github.com/tharsis/ethermint/types"
@ -28,7 +29,7 @@ type EVMKeeper interface {
GetParams(ctx sdk.Context) evmtypes.Params
WithContext(ctx sdk.Context)
ResetRefundTransient(ctx sdk.Context)
NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address, tracer vm.Tracer) *vm.EVM
NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address, tracer vm.EVMLogger) *vm.EVM
GetCodeHash(addr common.Address) common.Hash
}

View File

@ -2,6 +2,16 @@ package app
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/db"
types2 "github.com/cosmos/cosmos-sdk/store/types"
types3 "github.com/cosmos/cosmos-sdk/store/v2"
"github.com/cosmos/cosmos-sdk/store/v2/multi"
"github.com/cosmos/cosmos-sdk/x/auth/middleware"
"errors"
"io"
"net/http"
"os"
@ -13,13 +23,10 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/server/api"
@ -63,6 +70,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
govv1beta2 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
"github.com/cosmos/cosmos-sdk/x/mint"
mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
@ -86,7 +95,6 @@ import (
ibctransferkeeper "github.com/cosmos/ibc-go/modules/apps/transfer/keeper"
ibctransfertypes "github.com/cosmos/ibc-go/modules/apps/transfer/types"
ibc "github.com/cosmos/ibc-go/modules/core"
ibcclient "github.com/cosmos/ibc-go/modules/core/02-client"
ibcclientclient "github.com/cosmos/ibc-go/modules/core/02-client/client"
porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types"
ibchost "github.com/cosmos/ibc-go/modules/core/24-host"
@ -95,9 +103,16 @@ import (
// unnamed import of statik for swagger UI support
_ "github.com/tharsis/ethermint/client/docs/statik"
"github.com/tharsis/ethermint/app/ante"
srvflags "github.com/tharsis/ethermint/server/flags"
ethermint "github.com/tharsis/ethermint/types"
"github.com/tharsis/ethermint/x/auction"
auctionkeeper "github.com/tharsis/ethermint/x/auction/keeper"
auctiontypes "github.com/tharsis/ethermint/x/auction/types"
"github.com/tharsis/ethermint/x/bond"
bondkeeper "github.com/tharsis/ethermint/x/bond/keeper"
bondtypes "github.com/tharsis/ethermint/x/bond/types"
"github.com/tharsis/ethermint/x/evm"
evmrest "github.com/tharsis/ethermint/x/evm/client/rest"
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
@ -105,6 +120,10 @@ import (
"github.com/tharsis/ethermint/x/feemarket"
feemarketkeeper "github.com/tharsis/ethermint/x/feemarket/keeper"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
"github.com/tharsis/ethermint/x/nameservice"
nameservicekeeper "github.com/tharsis/ethermint/x/nameservice/keeper"
nameservicetypes "github.com/tharsis/ethermint/x/nameservice/types"
)
func init() {
@ -150,6 +169,10 @@ var (
// Ethermint modules
evm.AppModuleBasic{},
feemarket.AppModuleBasic{},
// Vulcanize DXNS modules
auction.AppModuleBasic{},
bond.AppModuleBasic{},
nameservice.AppModuleBasic{},
)
// module account permissions
@ -162,6 +185,13 @@ var (
govtypes.ModuleName: {authtypes.Burner},
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, // used for secure addition and subtraction of balance using module account
auctiontypes.ModuleName: nil,
auctiontypes.AuctionBurnModuleAccountName: nil,
nameservicetypes.ModuleName: nil,
nameservicetypes.RecordRentModuleAccountName: nil,
nameservicetypes.AuthorityRentModuleAccountName: nil,
bondtypes.ModuleName: nil,
}
// module accounts that are allowed to receive tokens
@ -184,13 +214,15 @@ type EthermintApp struct {
cdc *codec.LegacyAmino
appCodec codec.Codec
interfaceRegistry types.InterfaceRegistry
legacyRouter *middleware.LegacyRouter
msgSvcRouter *middleware.MsgServiceRouter
invCheckPeriod uint
// keys to access the substores
keys map[string]*sdk.KVStoreKey
tkeys map[string]*sdk.TransientStoreKey
memKeys map[string]*sdk.MemoryStoreKey
keys map[string]*types2.KVStoreKey
tkeys map[string]*types2.TransientStoreKey
memKeys map[string]*types2.MemoryStoreKey
// keepers
AccountKeeper authkeeper.AccountKeeper
@ -218,6 +250,12 @@ type EthermintApp struct {
EvmKeeper *evmkeeper.Keeper
FeeMarketKeeper feemarketkeeper.Keeper
// DXNS keepers
AuctionKeeper auctionkeeper.Keeper
BondKeeper bondkeeper.Keeper
NameServiceKeeper nameservicekeeper.Keeper
NameServiceRecordKeeper nameservicekeeper.RecordKeeper
// the module manager
mm *module.Manager
@ -231,32 +269,19 @@ type EthermintApp struct {
// NewEthermintApp returns a reference to a new initialized Ethermint application.
func NewEthermintApp(
logger log.Logger,
db dbm.DB,
db db.DBConnection,
traceStore io.Writer,
loadLatest bool,
skipUpgradeHeights map[int64]bool,
homePath string,
invCheckPeriod uint,
encodingConfig simappparams.EncodingConfig,
appOpts servertypes.AppOptions,
baseAppOptions ...func(*baseapp.BaseApp),
baseAppOptions ...baseapp.AppOption,
) *EthermintApp {
appCodec := encodingConfig.Marshaler
appCodec := encodingConfig.Codec
cdc := encodingConfig.Amino
interfaceRegistry := encodingConfig.InterfaceRegistry
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
bApp := baseapp.NewBaseApp(
appName,
logger,
db,
encodingConfig.TxConfig.TxDecoder(),
baseAppOptions...,
)
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetVersion(version.Version)
bApp.SetInterfaceRegistry(interfaceRegistry)
keys := sdk.NewKVStoreKeys(
// SDK keys
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
@ -268,17 +293,67 @@ func NewEthermintApp(
ibchost.StoreKey, ibctransfertypes.StoreKey,
// ethermint keys
evmtypes.StoreKey, feemarkettypes.StoreKey,
// dxns keys
auctiontypes.StoreKey,
bondtypes.StoreKey,
nameservicetypes.StoreKey,
)
// Add the EVM transient store key
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey)
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
// initialize stores
setNamespaces := func(config *multi.StoreParams, ver uint64) error {
for _, key := range keys {
typ, err := types3.StoreKeyToType(key)
if err != nil {
return err
}
if err = config.RegisterSubstore(key, typ); err != nil {
return err
}
}
for _, key := range memKeys {
typ, err := types3.StoreKeyToType(key)
if err != nil {
return err
}
if err = config.RegisterSubstore(key, typ); err != nil {
return err
}
}
for _, key := range tkeys {
typ, err := types3.StoreKeyToType(key)
if err != nil {
return err
}
if err = config.RegisterSubstore(key, typ); err != nil {
return err
}
}
return nil
}
baseAppOptions = append(baseAppOptions, baseapp.StoreOption(setNamespaces))
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
bApp := baseapp.NewBaseApp(
appName,
logger,
db,
baseAppOptions...,
)
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetVersion(version.Version)
bApp.SetInterfaceRegistry(interfaceRegistry)
app := &EthermintApp{
BaseApp: bApp,
cdc: cdc,
appCodec: appCodec,
interfaceRegistry: interfaceRegistry,
legacyRouter: middleware.NewLegacyRouter(),
msgSvcRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
invCheckPeriod: invCheckPeriod,
keys: keys,
tkeys: tkeys,
@ -288,7 +363,7 @@ func NewEthermintApp(
// init params keeper and subspaces
app.ParamsKeeper = initParamsKeeper(appCodec, cdc, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey])
// set the BaseApp's parameter store
bApp.SetParamStore(app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramskeeper.ConsensusParamsKeyTable()))
bApp.SetParamStore(app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable()))
// add capability keeper and ScopeToModule for ibc module
app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey])
@ -303,6 +378,7 @@ func NewEthermintApp(
// use custom Ethermint account for contracts
app.AccountKeeper = authkeeper.NewAccountKeeper(
appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), ethermint.ProtoAccount, maccPerms,
sdk.Bech32MainPrefix,
)
app.BankKeeper = bankkeeper.NewBaseKeeper(
appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.BlockedAddrs(),
@ -316,7 +392,7 @@ func NewEthermintApp(
)
app.DistrKeeper = distrkeeper.NewKeeper(
appCodec, keys[distrtypes.StoreKey], app.GetSubspace(distrtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
&stakingKeeper, authtypes.FeeCollectorName, app.ModuleAccountAddrs(),
&stakingKeeper, authtypes.FeeCollectorName,
)
app.SlashingKeeper = slashingkeeper.NewKeeper(
appCodec, keys[slashingtypes.StoreKey], &stakingKeeper, app.GetSubspace(slashingtypes.ModuleName),
@ -333,7 +409,8 @@ func NewEthermintApp(
stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()),
)
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter())
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec,
app.msgSvcRouter, app.AccountKeeper)
tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer))
@ -348,22 +425,47 @@ func NewEthermintApp(
appCodec, keys[feemarkettypes.StoreKey], app.GetSubspace(feemarkettypes.ModuleName),
)
// Create Vulcanize dxns keepers
app.AuctionKeeper = auctionkeeper.NewKeeper(
app.AccountKeeper, app.BankKeeper, keys[auctiontypes.StoreKey],
appCodec, app.GetSubspace(auctiontypes.ModuleName),
)
app.NameServiceRecordKeeper = nameservicekeeper.NewRecordKeeper(app.AuctionKeeper, keys[nameservicetypes.StoreKey], appCodec)
app.AuctionKeeper.SetUsageKeepers([]auctiontypes.AuctionUsageKeeper{app.NameServiceRecordKeeper})
app.BondKeeper = bondkeeper.NewKeeper(
appCodec, app.AccountKeeper, app.BankKeeper,
[]bondtypes.BondUsageKeeper{app.NameServiceRecordKeeper}, keys[bondtypes.StoreKey], app.GetSubspace(bondtypes.ModuleName),
)
app.NameServiceKeeper = nameservicekeeper.NewKeeper(
appCodec, app.AccountKeeper, app.BankKeeper,
app.NameServiceRecordKeeper, app.BondKeeper, app.AuctionKeeper,
keys[nameservicetypes.StoreKey], app.GetSubspace(nameservicetypes.ModuleName),
)
// Create IBC Keeper
app.IBCKeeper = ibckeeper.NewKeeper(
appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper,
)
// register the proposal types
govRouter := govtypes.NewRouter()
govRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler).
govRouter := govv1beta1.NewRouter()
govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
AddRoute(ibchost.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper))
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper))
govConfig := govtypes.DefaultConfig()
/*
Example of setting gov params:
govConfig.MaxMetadataLen = 10000
*/
govKeeper := govkeeper.NewKeeper(
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
&stakingKeeper, govRouter,
&stakingKeeper, govRouter, app.msgSvcRouter, govConfig,
)
app.GovKeeper = *govKeeper.SetHooks(
@ -412,7 +514,7 @@ func NewEthermintApp(
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants),
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
@ -428,6 +530,10 @@ func NewEthermintApp(
// Ethermint app modules
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
feemarket.NewAppModule(app.FeeMarketKeeper),
// DXNs modules
auction.NewAppModule(appCodec, app.AuctionKeeper),
bond.NewAppModule(appCodec, app.BondKeeper),
nameservice.NewAppModule(app.NameServiceKeeper),
)
// During begin block slashing happens after distr.BeginBlocker so that
@ -448,6 +554,8 @@ func NewEthermintApp(
app.mm.SetOrderEndBlockers(
crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName,
evmtypes.ModuleName, feemarkettypes.ModuleName,
nameservicetypes.ModuleName,
auctiontypes.ModuleName,
)
// NOTE: The genutils module must occur after staking so that pools are
@ -463,14 +571,18 @@ func NewEthermintApp(
authz.ModuleName, feegrant.ModuleName,
// Ethermint modules
evmtypes.ModuleName, feemarkettypes.ModuleName,
// DXNS modules
auctiontypes.ModuleName,
bondtypes.ModuleName,
nameservicetypes.ModuleName,
// NOTE: crisis module must go at the end to check for invariants on each module
crisistypes.ModuleName,
)
app.mm.RegisterInvariants(&app.CrisisKeeper)
app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino)
app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())
app.mm.RegisterRoutes(app.legacyRouter, app.QueryRouter(), encodingConfig.Amino)
app.configurator = module.NewConfigurator(app.appCodec, app.msgSvcRouter, app.GRPCQueryRouter())
app.mm.RegisterServices(app.configurator)
// add test gRPC service for testing gRPC queries in isolation
@ -485,7 +597,7 @@ func NewEthermintApp(
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
@ -499,37 +611,54 @@ func NewEthermintApp(
app.sm.RegisterStoreDecoders()
// initialize stores
app.MountKVStores(keys)
app.MountTransientStores(tkeys)
app.MountMemoryStores(memKeys)
// initialize BaseApp
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
// use Ethermint's custom AnteHandler
app.SetAnteHandler(
ante.NewAnteHandler(
app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.FeeGrantKeeper, app.IBCKeeper.ChannelKeeper,
encodingConfig.TxConfig.SignModeHandler(),
),
)
// TODO: use Ethermint's custom AnteHandler
app.setTxHandler(encodingConfig.TxConfig, cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents)))
app.SetEndBlocker(app.EndBlocker)
if loadLatest {
if err := app.LoadLatestVersion(); err != nil {
tmos.Exit(err.Error())
}
}
app.ScopedIBCKeeper = scopedIBCKeeper
app.ScopedTransferKeeper = scopedTransferKeeper
return app
}
func (app *EthermintApp) setTxHandler(txConfig client.TxConfig, indexEventsStr []string) {
indexEvents := map[string]struct{}{}
for _, e := range indexEventsStr {
indexEvents[e] = struct{}{}
}
// need to sub in custom tx handler
/*
app.SetTxHandler(
ante.NewAnteHandler(
app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.FeeGrantKeeper, app.IBCKeeper.ChannelKeeper,
encodingConfig.TxConfig.SignModeHandler(),
),
)
*/
txHandler, err := middleware.NewDefaultTxHandler(middleware.TxHandlerOptions{
Debug: app.Trace(),
IndexEvents: indexEvents,
LegacyRouter: app.legacyRouter,
MsgServiceRouter: app.msgSvcRouter,
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
FeegrantKeeper: app.FeeGrantKeeper,
SignModeHandler: txConfig.SignModeHandler(),
SigGasConsumer: middleware.DefaultSigVerificationGasConsumer,
TxDecoder: txConfig.TxDecoder(),
})
if err != nil {
panic(err)
}
app.SetTxHandler(txHandler)
}
// Name returns the name of the App
func (app *EthermintApp) Name() string { return app.BaseApp.Name() }
@ -555,7 +684,7 @@ func (app *EthermintApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain)
// LoadHeight loads state at a particular height
func (app *EthermintApp) LoadHeight(height int64) error {
return app.LoadVersion(height)
return errors.New("cannot load arbitrary height")
}
// ModuleAccountAddrs returns all the app's module account addresses.
@ -603,21 +732,21 @@ func (app *EthermintApp) InterfaceRegistry() types.InterfaceRegistry {
// GetKey returns the KVStoreKey for the provided store key.
//
// NOTE: This is solely to be used for testing purposes.
func (app *EthermintApp) GetKey(storeKey string) *sdk.KVStoreKey {
func (app *EthermintApp) GetKey(storeKey string) *types3.KVStoreKey {
return app.keys[storeKey]
}
// GetTKey returns the TransientStoreKey for the provided store key.
//
// NOTE: This is solely to be used for testing purposes.
func (app *EthermintApp) GetTKey(storeKey string) *sdk.TransientStoreKey {
func (app *EthermintApp) GetTKey(storeKey string) *types3.TransientStoreKey {
return app.tkeys[storeKey]
}
// GetMemKey returns the MemStoreKey for the provided mem key.
//
// NOTE: This is solely used for testing purposes.
func (app *EthermintApp) GetMemKey(storeKey string) *sdk.MemoryStoreKey {
func (app *EthermintApp) GetMemKey(storeKey string) *types3.MemoryStoreKey {
return app.memKeys[storeKey]
}
@ -638,7 +767,6 @@ func (app *EthermintApp) SimulationManager() *module.SimulationManager {
// API server.
func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
clientCtx := apiSvr.ClientCtx
rpc.RegisterRoutes(clientCtx, apiSvr.Router)
evmrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
@ -688,7 +816,7 @@ func GetMaccPerms() map[string][]string {
// initParamsKeeper init params keeper and its subspaces
func initParamsKeeper(
appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper {
appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey types3.StoreKey) paramskeeper.Keeper {
paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)
// SDK subspaces
@ -698,12 +826,17 @@ func initParamsKeeper(
paramsKeeper.Subspace(minttypes.ModuleName)
paramsKeeper.Subspace(distrtypes.ModuleName)
paramsKeeper.Subspace(slashingtypes.ModuleName)
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable())
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1beta2.ParamKeyTable())
paramsKeeper.Subspace(crisistypes.ModuleName)
paramsKeeper.Subspace(ibctransfertypes.ModuleName)
paramsKeeper.Subspace(ibchost.ModuleName)
// ethermint subspaces
paramsKeeper.Subspace(evmtypes.ModuleName)
paramsKeeper.Subspace(feemarkettypes.ModuleName)
// dxns subspaces
paramsKeeper.Subspace(auctiontypes.ModuleName)
paramsKeeper.Subspace(bondtypes.ModuleName)
paramsKeeper.Subspace(nameservicetypes.ModuleName)
return paramsKeeper
}

View File

@ -2,23 +2,27 @@ package app
import (
"encoding/json"
"os"
"testing"
"github.com/cosmos/cosmos-sdk/db/memdb"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/simapp"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
"github.com/tharsis/ethermint/encoding"
)
func TestEthermintAppExport(t *testing.T) {
db := dbm.NewMemDB()
app := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
db := memdb.NewDB()
logger, err := log.NewDefaultLogger("plain", "info", false)
if err != nil {
t.Fatal(err)
}
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
genesisState := NewDefaultGenesisState()
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
@ -35,7 +39,11 @@ func TestEthermintAppExport(t *testing.T) {
app.Commit()
// Making a new app object with the db, so that initchain hasn't been called
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
logger, err = log.NewDefaultLogger("plain", "info", false)
if err != nil {
t.Fatal(err)
}
app2 := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
_, err = app2.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}

View File

@ -2,19 +2,18 @@ package app
import (
"encoding/json"
"io"
"testing"
"github.com/cosmos/cosmos-sdk/db/memdb"
"github.com/cosmos/cosmos-sdk/simapp"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
"github.com/tharsis/ethermint/encoding"
)
func BenchmarkEthermintApp_ExportAppStateAndValidators(b *testing.B) {
db := dbm.NewMemDB()
app := NewEthermintApp(log.NewTMLogger(io.Discard), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
db := memdb.NewDB()
app := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
genesisState := NewDefaultGenesisState()
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
@ -36,7 +35,7 @@ func BenchmarkEthermintApp_ExportAppStateAndValidators(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
// Making a new app object with the db, so that initchain hasn't been called
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(io.Discard)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
app2 := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
if _, err := app2.ExportAppStateAndValidators(false, []string{}); err != nil {
b.Fatal(err)
}

View File

@ -19,7 +19,7 @@ import (
// NewDefaultGenesisState generates the default state for the application.
func NewDefaultGenesisState() simapp.GenesisState {
encCfg := encoding.MakeConfig(ModuleBasics)
return ModuleBasics.DefaultGenesis(encCfg.Marshaler)
return ModuleBasics.DefaultGenesis(encCfg.Codec)
}
// ExportAppStateAndValidators exports the state of the application for a genesis

View File

@ -4,6 +4,10 @@ import (
"encoding/json"
"time"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/db/memdb"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/tharsis/ethermint/encoding"
@ -11,13 +15,12 @@ import (
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-db"
)
// DefaultConsensusParams defines the default Tendermint consensus params used in
// EthermintApp testing.
var DefaultConsensusParams = &abci.ConsensusParams{
Block: &abci.BlockParams{
var DefaultConsensusParams = &tmproto.ConsensusParams{
Block: &tmproto.BlockParams{
MaxBytes: 200000,
MaxGas: -1, // no limit
},
@ -35,7 +38,7 @@ var DefaultConsensusParams = &abci.ConsensusParams{
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
func Setup(isCheckTx bool) *EthermintApp {
db := dbm.NewMemDB()
db := memdb.NewDB()
app := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
if !isCheckTx {
// init chain must be called to stop deliverState from being nil
@ -58,3 +61,15 @@ func Setup(isCheckTx bool) *EthermintApp {
return app
}
// CreateRandomAccounts will generate random accounts
func CreateRandomAccounts(accNum int) []sdk.AccAddress {
// createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order.
testAddrs := make([]sdk.AccAddress, accNum)
for i := 0; i < accNum; i++ {
pk := ed25519.GenPrivKey().PubKey()
testAddrs[i] = sdk.AccAddress(pk.Address())
}
return testAddrs
}

View File

@ -120,6 +120,9 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
// add rosetta
rootCmd.AddCommand(sdkserver.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler))
// Add flags for GQL server.
rootCmd = srvflags.AddGQLFlags(rootCmd)
return rootCmd, encodingConfig
}
@ -228,6 +231,8 @@ func (a appCreator) newApp(logger tmlog.Logger, db dbm.DB, traceStore io.Writer,
baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(sdkserver.FlagStateSyncSnapshotKeepRecent))),
)
// Start
//go gql.Server(ethermintApp.BaseApp, ethermintApp.AppCodec(), ethermintApp.AccountKeeper, ethermintApp.BondKeeper)
return ethermintApp
}

File diff suppressed because it is too large Load Diff

43
go.mod
View File

@ -3,19 +3,24 @@ module github.com/tharsis/ethermint
go 1.17
require (
github.com/99designs/gqlgen v0.14.0
github.com/btcsuite/btcd v0.22.0-beta
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
github.com/cosmos/cosmos-sdk v0.44.0
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/ibc-go v1.2.0
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea
github.com/ethereum/go-ethereum v1.10.3
github.com/gibson042/canonicaljson-go v1.0.3
github.com/gogo/protobuf v1.3.3
github.com/golang/protobuf v1.5.2
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/improbable-eng/grpc-web v0.14.1
github.com/ipfs/go-ipld-cbor v0.0.5
github.com/miguelmota/go-ethereum-hdwallet v0.0.1
github.com/multiformats/go-multihash v0.0.10
github.com/palantir/stacktrace v0.0.0-20161112013806-78658fd2d177
github.com/pkg/errors v0.9.1
github.com/rakyll/statik v0.1.7
@ -30,13 +35,16 @@ require (
github.com/tendermint/tendermint v0.34.13
github.com/tendermint/tm-db v0.6.4
github.com/tyler-smith/go-bip39 v1.1.0
github.com/vektah/gqlparser/v2 v2.2.0
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect
golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4
google.golang.org/grpc v1.40.0
google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
require (
@ -44,13 +52,10 @@ require (
github.com/99designs/keyring v1.1.6 // indirect
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
github.com/DataDog/zstd v1.4.8 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/VictoriaMetrics/fastcache v1.5.7 // indirect
github.com/Workiva/go-datastructures v1.0.52 // indirect
github.com/aokoli/goutils v1.1.1 // indirect
github.com/agnivade/levenshtein v1.1.0 // indirect
github.com/armon/go-metrics v0.3.9 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
@ -63,7 +68,6 @@ require (
github.com/cosmos/ledger-go v0.9.2 // indirect
github.com/danieljoos/wincred v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v2 v2.2007.2 // indirect
github.com/dgraph-io/ristretto v0.0.3 // indirect
@ -72,7 +76,6 @@ require (
github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.1 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
@ -97,10 +100,12 @@ require (
github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/holiman/uint256 v1.1.1 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/ipfs/go-block-format v0.0.2 // indirect
github.com/ipfs/go-cid v0.0.3 // indirect
github.com/ipfs/go-ipfs-util v0.0.1 // indirect
github.com/ipfs/go-ipld-format v0.0.1 // indirect
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect
@ -111,27 +116,29 @@ require (
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/minio/highwayhash v1.0.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/mr-tron/base58 v1.1.2 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/mwitkow/go-proto-validators v0.3.2 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-multibase v0.0.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml v1.9.3 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 // indirect
github.com/prometheus/client_golang v1.11.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.29.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/prometheus/tsdb v0.7.1 // indirect
github.com/pseudomuto/protoc-gen-doc v1.5.0 // indirect
github.com/pseudomuto/protokit v0.2.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rjeczalik/notify v0.9.1 // indirect
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
@ -143,15 +150,15 @@ require (
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 // indirect
github.com/zondax/hid v0.9.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/protobuf v1.27.1 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
nhooyr.io/websocket v1.8.6 // indirect
)
@ -160,3 +167,5 @@ replace google.golang.org/grpc => google.golang.org/grpc v1.33.2
replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
replace github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76
replace github.com/cosmos/cosmos-sdk => github.com/vulcanize/cosmos-sdk v0.45.0-smt-alpha

122
go.sum
View File

@ -43,6 +43,8 @@ collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0-beta.2 h1:/BZRNzm8N4K4eWfK28dL4yescorxtO7YG1yun8fy+pI=
filippo.io/edwards25519 v1.0.0-beta.2/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o=
github.com/99designs/gqlgen v0.14.0 h1:Wg8aNYQUjMR/4v+W3xD+7SizOy6lSvVeQ06AobNQAXI=
github.com/99designs/gqlgen v0.14.0/go.mod h1:S7z4boV+Nx4VvzMUpVrY/YuHjFX4n7rDyuTqvAkuoRE=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=
@ -71,14 +73,6 @@ github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t
github.com/DataDog/zstd v1.4.8 h1:Rpmta4xZ/MgZnriKNd24iZMhGpP5dvUcs/uqfBapKZY=
github.com/DataDog/zstd v1.4.8/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
@ -102,6 +96,9 @@ github.com/adlio/schema v1.1.13 h1:LeNMVg5Z1FX+Qgz8tJUijBLRdcpbFUElz+d1489On98=
github.com/adlio/schema v1.1.13/go.mod h1:L5Z7tw+7lRK1Fnpi/LT/ooCP1elkXn0krMWBQHUhEDE=
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/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM=
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -111,14 +108,14 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
github.com/aokoli/goutils v1.1.1 h1:/hA+Ywo3AxoDZY5ZMnkiEkUvkK4BPp927ax110KCqqg=
github.com/aokoli/goutils v1.1.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks=
github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
@ -254,7 +251,6 @@ github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2
github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU=
github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U=
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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=
@ -276,6 +272,8 @@ 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/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
@ -302,9 +300,6 @@ github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 h1:2vLKys4RBU4
github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25/go.mod h1:hTr8+TLQmkUkgcuh3mcr5fjrT9c64ZzsBCdCEC6UppY=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.1 h1:4CF52PCseTFt4bE+Yk3dIpdVi7XWuPVMhPtm4FaIJPM=
github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ=
github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM=
github.com/ethereum/go-ethereum v1.10.1/go.mod h1:E5e/zvdfUVr91JZ0AwjyuJM3x+no51zZJRz61orLLSk=
github.com/ethereum/go-ethereum v1.10.3 h1:SEYOYARvbWnoDl1hOSks3ZJQpRiiRJe8ubaQGJQwq0s=
@ -336,6 +331,8 @@ github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gibson042/canonicaljson-go v1.0.3 h1:EAyF8L74AWabkyUmrvEFHEt/AGFQeD6RfwbAuf0j1bI=
github.com/gibson042/canonicaljson-go v1.0.3/go.mod h1:DsLpJTThXyGNO+KZlI85C1/KDcImpP67k/RKVjcaEqo=
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.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
@ -464,7 +461,6 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/protobuf v3.14.0+incompatible/go.mod h1:lUQ9D1ePzbH2PrIS7ob/bjm9HXyH5WHB0Akwh7URreM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -476,9 +472,11 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
@ -514,6 +512,8 @@ github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@ -553,21 +553,14 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU
github.com/holiman/uint256 v1.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw=
github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
github.com/huin/goupnp v1.0.1-0.20200620063722-49508fba0031/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo=
github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88 h1:bcAj8KroPf552TScjFPIakjH2/tdIrIH8F+cc4v4SRo=
github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/improbable-eng/grpc-web v0.14.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs=
github.com/improbable-eng/grpc-web v0.14.1 h1:NrN4PY71A6tAz2sKDvC5JCauENWp0ykG8Oq1H3cpFvw=
github.com/improbable-eng/grpc-web v0.14.1/go.mod h1:zEjGHa8DAlkoOXmswrNvhUGEYQA9UI7DhrGeHR1DMGU=
@ -584,6 +577,17 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y
github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=
github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=
github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE=
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms=
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50=
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
github.com/ipfs/go-ipld-cbor v0.0.5 h1:ovz4CHKogtG2KB/h1zUp5U0c/IzZrL435rCh5+K/5G8=
github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4=
github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80=
github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
@ -615,6 +619,7 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
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/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
@ -668,14 +673,16 @@ github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOS
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
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/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4=
github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
@ -683,6 +690,7 @@ github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HN
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.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
@ -701,23 +709,25 @@ github.com/miguelmota/go-ethereum-hdwallet v0.0.1 h1:DWqgZtKWTGcHR5QsprMJItZiJ2x
github.com/miguelmota/go-ethereum-hdwallet v0.0.1/go.mod h1:iowKavXnc0NVNiv/UKYYBo3SjADph5PUvYQTjOIV9as=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
@ -725,16 +735,23 @@ 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 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
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/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM=
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo=
github.com/mwitkow/go-proto-validators v0.3.2 h1:qRlmpTzm2pstMKKzTdvwPCF5QfBNURSlAgN/R+qbKos=
github.com/mwitkow/go-proto-validators v0.3.2/go.mod h1:ej0Qp0qMgHN/KtDyUt+Q1/tA7a5VarXUOUxD+oeD30w=
github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
@ -831,9 +848,10 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE=
github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
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=
@ -880,10 +898,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/pseudomuto/protoc-gen-doc v1.5.0 h1:pHZp0MEiT68jrZV8js8BS7E9ZEnlSLegoQbbtXj5lfo=
github.com/pseudomuto/protoc-gen-doc v1.5.0/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg=
github.com/pseudomuto/protokit v0.2.0 h1:hlnBDcy3YEDXH7kc9gV+NLaN0cDzhDvD1s7Y6FZ8RpM=
github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ=
github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@ -901,6 +915,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so=
github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM=
@ -924,10 +939,14 @@ github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KR
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -937,6 +956,7 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4=
@ -946,8 +966,6 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
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.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@ -987,8 +1005,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
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=
@ -1048,11 +1066,19 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
github.com/vektah/gqlparser/v2 v2.2.0 h1:bAc3slekAAJW6sZTi07aGq0OrfaCjj4jxARAaC7g2EM=
github.com/vektah/gqlparser/v2 v2.2.0/go.mod h1:i3mQIGIrbK2PD1RrCeMTlVbkF2FJ6WkU1KJlJlC+3F4=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI=
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc=
github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 h1:WXhVOwj2USAXB5oMDwRl3piOux2XMV9TANaYxXHdkoE=
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
@ -1101,14 +1127,15 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/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=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -1128,8 +1155,8 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1245,7 +1272,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
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=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1265,6 +1291,8 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1362,6 +1390,7 @@ golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiT
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -1370,6 +1399,7 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@ -1464,7 +1494,6 @@ google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
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-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -1513,8 +1542,8 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af h1:aLMMXFYqw01RA6XJim5uaN+afqNNjc9P8HPAbnpnc5s=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 h1:NBxB1XxiWpGqkPUiJ9PoBXkHV5A9+GohMOA+EmWoPbU=
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.1/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
@ -1597,3 +1626,4 @@ 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=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=

351
gql/README.md Normal file
View File

@ -0,0 +1,351 @@
# Vulcanize dxns gql
> Browser : http://localhost:9473 for gql
## Start server
```shell
./build/ethermintd start --gql-playground --gql-server
```
Basic node status:
```graphql
{
getStatus {
version
node {
id
network
moniker
}
sync {
latest_block_height
catching_up
}
num_peers
peers {
is_outbound
remote_ip
}
disk_usage
}
}
```
Full node status:
```graphql
{
getStatus {
version
node {
id
network
moniker
}
sync {
latest_block_hash
latest_block_time
latest_block_height
catching_up
}
validator {
address
voting_power
proposer_priority
}
validators {
address
voting_power
proposer_priority
}
num_peers
peers {
node {
id
network
moniker
}
is_outbound
remote_ip
}
disk_usage
}
}
```
Get records by IDs.
```graphql
{
getRecordsByIds(ids: ["QmYDtNCKtTu6u6jaHaFAC5PWZXcj7fAmry6NoWwMaixFHz"]) {
id
names
bondId
createTime
expiryTime
owners
attributes {
key
value {
string
}
}
}
}
```
Query records.
```graphql
{
queryRecords(attributes: [{ key: "type", value: { string: "wrn:bot" } }]) {
id
names
bondId
createTime
expiryTime
owners
attributes {
key
value {
string
}
}
}
}
```
Get account details:
```graphql
{
getAccounts(addresses: ["cosmos1wh8vvd0ymc5nt37h29z8kk2g2ays45ct2qu094"]) {
address
pubKey
number
sequence
balance {
type
quantity
}
}
}
```
Query bonds:
```graphql
{
queryBonds(
attributes: [
{
key: "owner"
value: { string: "cosmos1wh8vvd0ymc5nt37h29z8kk2g2ays45ct2qu094" }
}
]
) {
id
owner
balance {
type
quantity
}
}
}
```
Get bonds by IDs.
```graphql
{
getBondsByIds(ids :
[
"1c2b677cb2a27c88cc6bf8acf675c94b69051125b40c4fd073153b10f046dd87",
"c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440"
])
{
id
owner
balance{
type
quantity
}
}
}
```
Query Bonds by Owner
```graphql
{
queryBondsByOwner(ownerAddresses: ["ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk"])
{
owner
bonds{
id
owner
balance
{
type
quantity
}
}
}
}
```
Query auctions by ids
```graphql
{
getAuctionsByIds(ids: ["be98f2073c246194276554eefdb4c95b682a35a0f06fbe619a6da57c10c93e90"]){
id
ownerAddress
createTime
minimumBid{
type
quantity
}
commitFee{
type
quantity
}
commitsEndTime
revealFee{
type
quantity
}
revealsEndTime
winnerBid{
type
quantity
}
winnerPrice{
type
quantity
}
winnerAddress
bids{
bidderAddress
commitHash
commitTime
commitFee{
type
quantity
}
revealFee{
type
quantity
}
revealTime
bidAmount{
type
quantity
}
status
}
}
}
```
LookUp Authorities
```graphql
{
lookupAuthorities(names: []){
ownerAddress
ownerAddress
height
bondId
status
expiryTime
auction {
id
ownerAddress
createTime
minimumBid{
type
quantity
}
commitFee{
type
quantity
}
commitsEndTime
revealFee{
type
quantity
}
revealsEndTime
winnerBid{
type
quantity
}
winnerPrice{
type
quantity
}
winnerAddress
bids{
bidderAddress
commitHash
commitTime
commitFee{
type
quantity
}
revealFee{
type
quantity
}
revealTime
bidAmount{
type
quantity
}
status
}
}
}
}
```
LookUp Names
```graphql
{
lookupNames(names: ["wrn://hello/test"]){
latest{
id
height
}
history{
id
height
}
}
}
```
Resolve Names
```graphql
{
resolveNames(names: ["asd"]){
id
names
bondId
createTime
expiryTime
owners
attributes {
key
value {
string
}
}
}
}
```

8781
gql/generated.go Normal file

File diff suppressed because it is too large Load Diff

14
gql/gqlgen.yml Normal file
View File

@ -0,0 +1,14 @@
# .gqlgen.yml example
#
# Refer to https://gqlgen.com/config/
# for detailed .gqlgen.yml documentation.
schema:
- vulcanize/dxns/*.graphql
exec:
filename: generated.go
model:
filename: models_gen.go
resolver:
filename: resolver.go
type: Resolver

160
gql/models_gen.go Normal file
View File

@ -0,0 +1,160 @@
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
package gql
type Account struct {
Address string `json:"address"`
PubKey *string `json:"pubKey"`
Number string `json:"number"`
Sequence string `json:"sequence"`
Balance []*Coin `json:"balance"`
}
type Auction struct {
ID string `json:"id"`
Status string `json:"status"`
OwnerAddress string `json:"ownerAddress"`
CreateTime string `json:"createTime"`
CommitsEndTime string `json:"commitsEndTime"`
RevealsEndTime string `json:"revealsEndTime"`
CommitFee *Coin `json:"commitFee"`
RevealFee *Coin `json:"revealFee"`
MinimumBid *Coin `json:"minimumBid"`
WinnerAddress string `json:"winnerAddress"`
WinnerBid *Coin `json:"winnerBid"`
WinnerPrice *Coin `json:"winnerPrice"`
Bids []*AuctionBid `json:"bids"`
}
type AuctionBid struct {
BidderAddress string `json:"bidderAddress"`
Status string `json:"status"`
CommitHash string `json:"commitHash"`
CommitTime string `json:"commitTime"`
CommitFee *Coin `json:"commitFee"`
RevealTime string `json:"revealTime"`
RevealFee *Coin `json:"revealFee"`
BidAmount *Coin `json:"bidAmount"`
}
type AuthorityRecord struct {
OwnerAddress string `json:"ownerAddress"`
OwnerPublicKey string `json:"ownerPublicKey"`
Height string `json:"height"`
Status string `json:"status"`
BondID string `json:"bondId"`
ExpiryTime string `json:"expiryTime"`
Auction *Auction `json:"auction"`
}
type Bond struct {
ID string `json:"id"`
Owner string `json:"owner"`
Balance []*Coin `json:"balance"`
}
type Coin struct {
Type string `json:"type"`
Quantity string `json:"quantity"`
}
type KeyValue struct {
Key string `json:"key"`
Value *Value `json:"value"`
}
type KeyValueInput struct {
Key string `json:"key"`
Value *ValueInput `json:"value"`
}
type NameRecord struct {
Latest *NameRecordEntry `json:"latest"`
History []*NameRecordEntry `json:"history"`
}
type NameRecordEntry struct {
ID string `json:"id"`
Height string `json:"height"`
}
type NodeInfo struct {
ID string `json:"id"`
Network string `json:"network"`
Moniker string `json:"moniker"`
}
type OwnerBonds struct {
Owner string `json:"owner"`
Bonds []*Bond `json:"bonds"`
}
type PeerInfo struct {
Node *NodeInfo `json:"node"`
IsOutbound bool `json:"is_outbound"`
RemoteIP string `json:"remote_ip"`
}
type Record struct {
ID string `json:"id"`
Names []string `json:"names"`
BondID string `json:"bondId"`
CreateTime string `json:"createTime"`
ExpiryTime string `json:"expiryTime"`
Owners []string `json:"owners"`
Attributes []*KeyValue `json:"attributes"`
References []*Record `json:"references"`
}
type Reference struct {
ID string `json:"id"`
}
type ReferenceInput struct {
ID string `json:"id"`
}
type Status struct {
Version string `json:"version"`
Node *NodeInfo `json:"node"`
Sync *SyncInfo `json:"sync"`
Validator *ValidatorInfo `json:"validator"`
Validators []*ValidatorInfo `json:"validators"`
NumPeers string `json:"num_peers"`
Peers []*PeerInfo `json:"peers"`
DiskUsage string `json:"disk_usage"`
}
type SyncInfo struct {
LatestBlockHash string `json:"latest_block_hash"`
LatestBlockHeight string `json:"latest_block_height"`
LatestBlockTime string `json:"latest_block_time"`
CatchingUp bool `json:"catching_up"`
}
type ValidatorInfo struct {
Address string `json:"address"`
VotingPower string `json:"voting_power"`
ProposerPriority *string `json:"proposer_priority"`
}
type Value struct {
Null *bool `json:"null"`
Int *int `json:"int"`
Float *float64 `json:"float"`
String *string `json:"string"`
Boolean *bool `json:"boolean"`
JSON *string `json:"json"`
Reference *Reference `json:"reference"`
Values []*Value `json:"values"`
}
type ValueInput struct {
Null *bool `json:"null"`
Int *int `json:"int"`
Float *float64 `json:"float"`
String *string `json:"string"`
Boolean *bool `json:"boolean"`
Reference *ReferenceInput `json:"reference"`
Values []*ValueInput `json:"values"`
}

335
gql/resolver.go Normal file
View File

@ -0,0 +1,335 @@
package gql
import (
"context"
"encoding/base64"
"github.com/cosmos/cosmos-sdk/client"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
auctiontypes "github.com/tharsis/ethermint/x/auction/types"
bondtypes "github.com/tharsis/ethermint/x/bond/types"
nstypes "github.com/tharsis/ethermint/x/nameservice/types"
"strconv"
)
// DefaultLogNumLines is the number of log lines to tail by default.
const DefaultLogNumLines = 50
// MaxLogNumLines is the max number of log lines that can be tailed.
const MaxLogNumLines = 1000
type Resolver struct {
ctx client.Context
logFile string
}
// Query is the entry point to query execution.
func (r *Resolver) Query() QueryResolver {
return &queryResolver{r}
}
type queryResolver struct{ *Resolver }
func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([]*AuthorityRecord, error) {
nsQueryClient := nstypes.NewQueryClient(q.ctx)
auctionQueryClient := auctiontypes.NewQueryClient(q.ctx)
var gqlResponse []*AuthorityRecord
for _, name := range names {
res, err := nsQueryClient.Whois(context.Background(), &nstypes.QueryWhoisRequest{Name: name})
if err != nil {
return nil, err
}
nameAuthority := res.GetNameAuthority()
gqlNameAuthorityRecord, err := GetGQLNameAuthorityRecord(&nameAuthority)
if err != nil {
return nil, err
}
if nameAuthority.AuctionId == "" {
auctionResp, err := auctionQueryClient.GetAuction(context.Background(), &auctiontypes.AuctionRequest{Id: nameAuthority.GetAuctionId()})
if err != nil {
return nil, err
}
bidsResp, err := auctionQueryClient.GetBids(context.Background(), &auctiontypes.BidsRequest{AuctionId: nameAuthority.GetAuctionId()})
if err != nil {
return nil, err
}
gqlAuctionRecord, err := GetGQLAuction(auctionResp.GetAuction(), bidsResp.GetBids())
if err != nil {
return nil, err
}
gqlNameAuthorityRecord.Auction = gqlAuctionRecord
}
gqlResponse = append(gqlResponse, gqlNameAuthorityRecord)
}
return gqlResponse, nil
}
func (q queryResolver) ResolveNames(ctx context.Context, names []string) ([]*Record, error) {
nsQueryClient := nstypes.NewQueryClient(q.ctx)
var gqlResponse []*Record
for _, name := range names {
res, err := nsQueryClient.ResolveWrn(context.Background(), &nstypes.QueryResolveWrn{Wrn: name})
if err != nil {
return nil, err
}
gqlRecord, err := getGQLRecord(context.Background(), q, *res.GetRecord())
if err != nil {
return nil, err
}
gqlResponse = append(gqlResponse, gqlRecord)
}
return gqlResponse, nil
}
func (q queryResolver) LookupNames(ctx context.Context, names []string) ([]*NameRecord, error) {
nsQueryClient := nstypes.NewQueryClient(q.ctx)
var gqlResponse []*NameRecord
for _, name := range names {
res, err := nsQueryClient.LookupWrn(context.Background(), &nstypes.QueryLookupWrn{Wrn: name})
if err != nil {
return nil, err
}
gqlRecord, err := getGQLNameRecord(res.GetName())
if err != nil {
return nil, err
}
gqlResponse = append(gqlResponse, gqlRecord)
}
return gqlResponse, nil
}
func (q queryResolver) QueryRecords(ctx context.Context, attributes []*KeyValueInput, all *bool) ([]*Record, error) {
nsQueryClient := nstypes.NewQueryClient(q.ctx)
res, err := nsQueryClient.ListRecords(context.Background(), &nstypes.QueryListRecordsRequest{})
if err != nil {
return nil, err
}
records := res.GetRecords()
gqlResponse := make([]*Record, len(records))
for i, record := range records {
gqlRecord, err := getGQLRecord(context.Background(), q, record)
if err != nil {
return nil, err
}
gqlResponse[i] = gqlRecord
}
return gqlResponse, nil
}
func (q queryResolver) GetRecordsByIds(ctx context.Context, ids []string) ([]*Record, error) {
nsQueryClient := nstypes.NewQueryClient(q.ctx)
gqlResponse := make([]*Record, len(ids))
for i, id := range ids {
res, err := nsQueryClient.GetRecord(context.Background(), &nstypes.QueryRecordByIdRequest{Id: id})
if err != nil {
return nil, err
}
record, err := getGQLRecord(context.Background(), q, res.GetRecord())
if err != nil {
return nil, err
}
gqlResponse[i] = record
}
return gqlResponse, nil
}
func (q queryResolver) GetStatus(ctx context.Context) (*Status, error) {
nodeInfo, syncInfo, validatorInfo, err := getStatusInfo(q.ctx)
if err != nil {
return nil, err
}
numPeers, peers, err := getNetInfo(q.ctx)
if err != nil {
return nil, err
}
validatorSet, err := getValidatorSet(q.ctx)
if err != nil {
return nil, err
}
diskUsage, err := GetDiskUsage(NodeDataPath)
if err != nil {
return nil, err
}
return &Status{
Version: NameServiceVersion,
Node: nodeInfo,
Sync: syncInfo,
Validator: validatorInfo,
Validators: validatorSet,
NumPeers: numPeers,
Peers: peers,
DiskUsage: diskUsage,
}, nil
}
func (q queryResolver) GetAccounts(ctx context.Context, addresses []string) ([]*Account, error) {
accounts := make([]*Account, len(addresses))
for index, address := range addresses {
account, err := q.GetAccount(ctx, address)
if err != nil {
return nil, err
}
accounts[index] = account
}
return accounts, nil
}
func (q queryResolver) GetAccount(ctx context.Context, address string) (*Account, error) {
authQueryClient := authtypes.NewQueryClient(q.ctx)
accountResponse, err := authQueryClient.Account(ctx, &authtypes.QueryAccountRequest{Address: address})
if err != nil {
return nil, err
}
var account authtypes.AccountI
err = q.ctx.Codec.UnpackAny(accountResponse.GetAccount(), &account)
if err != nil {
return nil, err
}
var pubKey *string
if account.GetPubKey() != nil {
pubKeyStr := base64.StdEncoding.EncodeToString(account.GetPubKey().Bytes())
pubKey = &pubKeyStr
}
// Get the account balance
bankQueryClient := banktypes.NewQueryClient(q.ctx)
balance, err := bankQueryClient.AllBalances(ctx, &banktypes.QueryAllBalancesRequest{Address: address})
accNum := strconv.FormatUint(account.GetAccountNumber(), 10)
seq := strconv.FormatUint(account.GetSequence(), 10)
return &Account{
Address: address,
Number: accNum,
Sequence: seq,
PubKey: pubKey,
Balance: getGQLCoins(balance.GetBalances()),
}, nil
}
func (q queryResolver) GetBondsByIds(ctx context.Context, ids []string) ([]*Bond, error) {
bonds := make([]*Bond, len(ids))
for index, id := range ids {
bondObj, err := q.GetBond(ctx, id)
if err != nil {
return nil, err
}
bonds[index] = bondObj
}
return bonds, nil
}
func (q *queryResolver) GetBond(ctx context.Context, id string) (*Bond, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bondResp, err := bondQueryClient.GetBondById(context.Background(), &bondtypes.QueryGetBondByIdRequest{Id: id})
if err != nil {
return nil, err
}
bond := bondResp.GetBond()
if bond == nil {
return nil, nil
}
return getGQLBond(bondResp.GetBond())
}
func (q queryResolver) QueryBonds(ctx context.Context, attributes []*KeyValueInput) ([]*Bond, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bonds, err := bondQueryClient.Bonds(context.Background(), &bondtypes.QueryGetBondsRequest{})
if err != nil {
return nil, err
}
gqlResponse := make([]*Bond, len(bonds.GetBonds()))
for i, bondObj := range bonds.GetBonds() {
gqlBond, err := getGQLBond(bondObj)
if err != nil {
return nil, err
}
gqlResponse[i] = gqlBond
}
return gqlResponse, nil
}
// QueryBondsByOwner will return bonds by owner
func (q queryResolver) QueryBondsByOwner(ctx context.Context, ownerAddresses []string) ([]*OwnerBonds, error) {
ownerBonds := make([]*OwnerBonds, len(ownerAddresses))
for index, ownerAddress := range ownerAddresses {
bondsObj, err := q.GetBondsByOwner(ctx, ownerAddress)
if err != nil {
return nil, err
}
ownerBonds[index] = bondsObj
}
return ownerBonds, nil
}
func (q queryResolver) GetBondsByOwner(ctx context.Context, address string) (*OwnerBonds, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bondResp, err := bondQueryClient.GetBondsByOwner(context.Background(), &bondtypes.QueryGetBondsByOwnerRequest{Owner: address})
if err != nil {
return nil, err
}
ownerBonds := make([]*Bond, len(bondResp.GetBonds()))
for i, bond := range bondResp.GetBonds() {
bondObj, err := getGQLBond(&bond)
if err != nil {
return nil, err
}
ownerBonds[i] = bondObj
}
return &OwnerBonds{Bonds: ownerBonds, Owner: address}, nil
}
func (q queryResolver) GetAuctionsByIds(ctx context.Context, ids []string) ([]*Auction, error) {
auctionQueryClient := auctiontypes.NewQueryClient(q.ctx)
gqlAuctionResponse := make([]*Auction, len(ids))
for i, id := range ids {
auctionObj, err := auctionQueryClient.GetAuction(context.Background(), &auctiontypes.AuctionRequest{Id: id})
if err != nil {
return nil, err
}
bidsObj, err := auctionQueryClient.GetBids(context.Background(), &auctiontypes.BidsRequest{AuctionId: id})
if err != nil {
return nil, err
}
gqlAuction, err := GetGQLAuction(auctionObj.GetAuction(), bidsObj.GetBids())
if err != nil {
return nil, err
}
gqlAuctionResponse[i] = gqlAuction
}
return gqlAuctionResponse, nil
}

44
gql/server.go Normal file
View File

@ -0,0 +1,44 @@
package gql
import (
"fmt"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/cosmos/cosmos-sdk/client"
"github.com/ethereum/go-ethereum/log"
"github.com/spf13/viper"
"net/http"
)
// Server configures and starts the GQL server.
func Server(ctx client.Context) {
if !viper.GetBool("gql-server") {
return
}
logFile := viper.GetString("log-file")
port := viper.GetString("gql-port")
srv := handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: &Resolver{
ctx: ctx,
logFile: logFile,
}}))
http.Handle("/", playground.Handler("GraphQL playground", "/api"))
if viper.GetBool("gql-playground") {
apiBase := viper.GetString("gql-playground-api-base")
http.Handle("/webui", playground.Handler("GraphQL playground", apiBase+"/api"))
http.Handle("/console", playground.Handler("GraphQL playground", apiBase+"/graphql"))
}
http.Handle("/api", srv)
http.Handle("/graphql", srv)
log.Info("Connect to GraphQL playground", "url", fmt.Sprintf("http://localhost:%s", port))
err := http.ListenAndServe(":"+port, nil)
if err != nil {
panic(err)
}
}

99
gql/status.go Normal file
View File

@ -0,0 +1,99 @@
package gql
import (
"context"
"github.com/cosmos/cosmos-sdk/client"
"os"
"os/exec"
"strconv"
"strings"
)
// NodeDataPath is the path to the ethermintd data folder.
var NodeDataPath = os.ExpandEnv("$HOME/.ethermintd/data")
func getStatusInfo(client client.Context) (*NodeInfo, *SyncInfo, *ValidatorInfo, error) {
nodeClient, err := client.GetNode()
if err != nil {
return nil, nil, nil, err
}
nodeStatus, err := nodeClient.Status(context.Background())
if err != nil {
return nil, nil, nil, err
}
return &NodeInfo{
ID: string(nodeStatus.NodeInfo.ID()),
Network: nodeStatus.NodeInfo.Network,
Moniker: nodeStatus.NodeInfo.Moniker,
}, &SyncInfo{
LatestBlockHash: nodeStatus.SyncInfo.LatestBlockHash.String(),
LatestBlockHeight: strconv.FormatInt(nodeStatus.SyncInfo.LatestBlockHeight, 10),
LatestBlockTime: nodeStatus.SyncInfo.LatestBlockTime.String(),
CatchingUp: nodeStatus.SyncInfo.CatchingUp,
}, &ValidatorInfo{
Address: nodeStatus.ValidatorInfo.Address.String(),
VotingPower: strconv.FormatInt(nodeStatus.ValidatorInfo.VotingPower, 10),
ProposerPriority: nil,
}, nil
}
func getNetInfo(client client.Context) (string, []*PeerInfo, error) {
nodeClient, err := client.GetNode()
if err != nil {
return "", nil, err
}
netInfo, err := nodeClient.NetInfo(context.Background())
if err != nil {
return "", nil, err
}
peers := netInfo.Peers
peersInfo := make([]*PeerInfo, len(peers))
for index, peer := range peers {
peersInfo[index] = &PeerInfo{
Node: &NodeInfo{
ID: string(peer.NodeInfo.ID()),
Moniker: peer.NodeInfo.Moniker,
Network: peer.NodeInfo.Network,
},
IsOutbound: peer.IsOutbound,
RemoteIP: peer.RemoteIP,
}
}
return strconv.FormatInt(int64(netInfo.NPeers), 10), peersInfo, nil
}
func getValidatorSet(client client.Context) ([]*ValidatorInfo, error) {
nodeClient, err := client.GetNode()
if err != nil {
return nil, err
}
res, err := nodeClient.Validators(context.Background(), nil, nil, nil)
if err != nil {
return nil, err
}
validatorSet := make([]*ValidatorInfo, len(res.Validators))
for index, validator := range res.Validators {
proposerPriority := strconv.FormatInt(validator.ProposerPriority, 10)
validatorSet[index] = &ValidatorInfo{
Address: validator.Address.String(),
VotingPower: strconv.FormatInt(validator.VotingPower, 10),
ProposerPriority: &proposerPriority,
}
}
return validatorSet, nil
}
// GetDiskUsage returns disk usage for the given path.
func GetDiskUsage(dirPath string) (string, error) {
out, err := exec.Command("du", "-sh", dirPath).Output()
if err != nil {
return "", err
}
return strings.Fields(string(out))[0], nil
}

267
gql/util.go Normal file
View File

@ -0,0 +1,267 @@
package gql
import (
"context"
"encoding/json"
sdk "github.com/cosmos/cosmos-sdk/types"
auctiontypes "github.com/tharsis/ethermint/x/auction/types"
bondtypes "github.com/tharsis/ethermint/x/bond/types"
nstypes "github.com/tharsis/ethermint/x/nameservice/types"
"reflect"
"strconv"
)
// OwnerAttributeName denotes the owner attribute name for a bond.
const OwnerAttributeName = "owner"
// BondIDAttributeName denotes the record bond ID.
const BondIDAttributeName = "bondId"
// ExpiryTimeAttributeName denotes the record expiry time.
const ExpiryTimeAttributeName = "expiryTime"
func getGQLCoin(coin sdk.Coin) *Coin {
gqlCoin := Coin{
Type: coin.Denom,
Quantity: strconv.FormatInt(coin.Amount.Int64(), 10),
}
return &gqlCoin
}
func getGQLCoins(coins sdk.Coins) []*Coin {
gqlCoins := make([]*Coin, len(coins))
for index, coin := range coins {
gqlCoins[index] = getGQLCoin(coin)
}
return gqlCoins
}
func GetGQLNameAuthorityRecord(record *nstypes.NameAuthority) (*AuthorityRecord, error) {
if record == nil {
return nil, nil
}
return &AuthorityRecord{
OwnerAddress: record.OwnerAddress,
OwnerPublicKey: record.OwnerPublicKey,
Height: strconv.FormatUint(record.Height, 10),
Status: record.Status,
BondID: record.GetBondId(),
ExpiryTime: record.GetExpiryTime().String(),
}, nil
}
func getGQLRecord(ctx context.Context, resolver QueryResolver, record nstypes.Record) (*Record, error) {
// Nil record.
if record.Deleted {
return nil, nil
}
recordType := record.ToRecordType()
attributes, err := getAttributes(&recordType)
if err != nil {
return nil, err
}
references, err := getReferences(ctx, resolver, &recordType)
if err != nil {
return nil, err
}
return &Record{
ID: record.Id,
BondID: record.GetBondId(),
CreateTime: record.GetCreateTime().String(),
ExpiryTime: record.GetExpiryTime().String(),
Owners: record.GetOwners(),
Attributes: attributes,
References: references,
}, nil
}
func getGQLNameRecord(record *nstypes.NameRecord) (*NameRecord, error) {
if record == nil {
return nil, nil
}
records := make([]*NameRecordEntry, len(record.History))
for index, entry := range record.History {
records[index] = getNameRecordEntry(entry)
}
return &NameRecord{
Latest: getNameRecordEntry(record.Latest),
History: records,
}, nil
}
func getNameRecordEntry(record *nstypes.NameRecordEntry) *NameRecordEntry {
return &NameRecordEntry{
ID: record.Id,
Height: strconv.FormatUint(record.Height, 10),
}
}
func getGQLBond(bondObj *bondtypes.Bond) (*Bond, error) {
// Nil record.
if bondObj == nil {
return nil, nil
}
return &Bond{
ID: bondObj.Id,
Owner: bondObj.Owner,
Balance: getGQLCoins(bondObj.Balance),
}, nil
}
func matchBondOnAttributes(bondObj *bondtypes.Bond, attributes []*KeyValueInput) bool {
for _, attr := range attributes {
switch attr.Key {
case OwnerAttributeName:
{
if attr.Value.String == nil || bondObj.Owner != *attr.Value.String {
return false
}
}
default:
{
// Only attributes explicitly listed in the switch are queryable.
return false
}
}
}
return true
}
func getAuctionBid(bid *auctiontypes.Bid) *AuctionBid {
return &AuctionBid{
BidderAddress: bid.BidderAddress,
Status: bid.Status,
CommitHash: bid.CommitHash,
CommitTime: bid.GetCommitTime(),
RevealTime: bid.GetRevealTime(),
CommitFee: getGQLCoin(bid.CommitFee),
RevealFee: getGQLCoin(bid.RevealFee),
BidAmount: getGQLCoin(bid.BidAmount),
}
}
func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*Auction, error) {
if auction == nil {
return nil, nil
}
gqlAuction := Auction{
ID: auction.Id,
Status: auction.Status,
OwnerAddress: auction.OwnerAddress,
CreateTime: auction.GetCreateTime(),
CommitsEndTime: auction.GetCommitsEndTime(),
RevealsEndTime: auction.GetRevealsEndTime(),
CommitFee: getGQLCoin(auction.CommitFee),
RevealFee: getGQLCoin(auction.RevealFee),
MinimumBid: getGQLCoin(auction.MinimumBid),
WinnerAddress: auction.WinnerAddress,
WinnerBid: getGQLCoin(auction.WinningBid),
WinnerPrice: getGQLCoin(auction.WinningPrice),
}
auctionBids := make([]*AuctionBid, len(bids))
for index, entry := range bids {
auctionBids[index] = getAuctionBid(entry)
}
gqlAuction.Bids = auctionBids
return &gqlAuction, nil
}
func getReferences(ctx context.Context, resolver QueryResolver, r *nstypes.RecordType) ([]*Record, error) {
var ids []string
for _, value := range r.Attributes {
switch value.(type) {
case interface{}:
if obj, ok := value.(map[string]interface{}); ok {
if _, ok := obj["/"]; ok && len(obj) == 1 {
if _, ok := obj["/"].(string); ok {
ids = append(ids, obj["/"].(string))
}
}
}
}
}
return resolver.GetRecordsByIds(ctx, ids)
}
func getAttributes(r *nstypes.RecordType) ([]*KeyValue, error) {
return mapToKeyValuePairs(r.Attributes)
}
func mapToKeyValuePairs(attrs map[string]interface{}) ([]*KeyValue, error) {
var kvPairs []*KeyValue
trueVal := true
falseVal := false
for key, value := range attrs {
kvPair := &KeyValue{
Key: key,
Value: &Value{},
}
switch val := value.(type) {
case nil:
kvPair.Value.Null = &trueVal
case int:
kvPair.Value.Int = &val
case float64:
kvPair.Value.Float = &val
case string:
kvPair.Value.String = &val
case bool:
kvPair.Value.Boolean = &val
case interface{}:
if obj, ok := value.(map[string]interface{}); ok {
if _, ok := obj["/"]; ok && len(obj) == 1 {
if _, ok := obj["/"].(string); ok {
kvPair.Value.Reference = &Reference{
ID: obj["/"].(string),
}
}
} else {
bytes, err := json.Marshal(obj)
if err != nil {
return nil, err
}
jsonStr := string(bytes)
kvPair.Value.JSON = &jsonStr
}
}
}
if kvPair.Value.Null == nil {
kvPair.Value.Null = &falseVal
}
valueType := reflect.ValueOf(value)
if valueType.Kind() == reflect.Slice {
bytes, err := json.Marshal(value)
if err != nil {
return nil, err
}
jsonStr := string(bytes)
kvPair.Value.JSON = &jsonStr
}
kvPairs = append(kvPairs, kvPair)
}
return kvPairs, nil
}

4
gql/version.go Normal file
View File

@ -0,0 +1,4 @@
package gql
// NameServiceVersion is the registry API version.
const NameServiceVersion = "0.3.0"

View File

@ -0,0 +1,260 @@
# Reference to another record.
type Reference {
id: String! # ID of linked record.
}
# Reference to another record.
input ReferenceInput {
id: String!
}
# Bonds contain funds that are used to pay rent on record registration and renewal.
type Bond {
id: String! # Primary key, auto-generated by the server.
owner: String! # Bond owner cosmos-sdk address.
balance: [Coin!] # Current balance for each coin type.
}
# OwnerBonds contains the bonds related the owner
type OwnerBonds {
owner: String!
bonds: [Bond!]
}
# Mutations require payment in coins (e.g. 100wire).
# Used by the wallet to get the account balance for display and mutations.
type Coin {
type: String! # e.g. 'WIRE'
quantity: String! # e.g. 1000000
}
# Represents an account on the blockchain.
# Mutations have to be signed by a particular account.
type Account {
address: String! # Blockchain address.
pubKey: String # Public key.
number: String! # Account number.
sequence: String! # Sequence number used to prevent replays.
balance: [Coin!] # Current balance for each coin type.
}
# Value of a given type.
type Value {
null: Boolean
int: Int
float: Float
string: String
boolean: Boolean
json: String
reference: Reference
values: [Value]
}
# Value of a given type used as input to queries.
input ValueInput {
null: Boolean
int: Int
float: Float
string: String
boolean: Boolean
reference: ReferenceInput
values: [ValueInput]
}
# Key/value pair.
type KeyValue {
key: String!
value: Value!
}
# Key/value pair for inputs.
input KeyValueInput {
key: String!
value: ValueInput!
}
# Status information about a node (https://docs.tendermint.com/master/rpc/#/Info/status).
type NodeInfo {
id: String! # Tendermint Node ID.
network: String! # Name of the network/blockchain.
moniker: String! # Name of the node.
}
# Node sync status.
type SyncInfo {
latest_block_hash: String!
latest_block_height: String!
latest_block_time: String!
catching_up: Boolean!
}
# Validator set info (https://docs.tendermint.com/master/rpc/#/Info/validators).
type ValidatorInfo {
address: String!
voting_power: String!
proposer_priority: String
}
# Network/peer info (https://docs.tendermint.com/master/rpc/#/Info/net_info).
type PeerInfo {
node: NodeInfo!
is_outbound: Boolean!
remote_ip: String!
}
# Vulcanize DXNS status.
type Status {
version: String!
node: NodeInfo!
sync: SyncInfo!
validator: ValidatorInfo
validators: [ValidatorInfo]!
num_peers: String!
peers: [PeerInfo]
disk_usage: String!
}
# An auction bid.
type AuctionBid {
bidderAddress: String!
status: String!
commitHash: String!
commitTime: String!
commitFee: Coin!
revealTime: String!
revealFee: Coin!
bidAmount: Coin!
}
# A sealed-bid, 2nd price auction.
type Auction {
id: String! # Auction ID.
status: String! # Auction status (commit, reveal, expired).
ownerAddress: String! # Auction owner time.
createTime: String! # Create time.
commitsEndTime: String! # Commit phase end time.
revealsEndTime: String! # Reveal phase end time.
commitFee: Coin! # Fee required to bid/participate in the auction.
revealFee: Coin! # Reveal fee (paid back to bidders only if they unseal/reveal the bid).
minimumBid: Coin! # Minimum bid amount.
winnerAddress: String! # Winner address.
winnerBid: Coin! # The winning bid amount.
winnerPrice: Coin! # The price that the winner actually pays (2nd highest bid).
bids: [AuctionBid] # Bids make in the auction.
}
# Record defines the basic properties of an entity in the graph database.
type Record {
id: String! # Computed attribute: Multibase encoded content hash (https://github.com/multiformats/multibase).
names: [String!] # Names pointing to this CID (reverse lookup).
bondId: String! # Associated bond ID.
createTime: String! # Record create time.
expiryTime: String! # Record expiry time.
owners: [String!] # Addresses of record owners.
attributes: [KeyValue] # Record attributes.
references: [Record] # Record references.
}
# Name authority record.
type AuthorityRecord {
ownerAddress: String! # Owner address.
ownerPublicKey: String! # Owner public key.
height: String! # Height at which record was created.
status: String! # Status (active, auction, expired).
bondId: String! # Associated bond ID.
expiryTime: String! # Authority expiry time.
auction: Auction # Authority auction.
}
# Name record entry, created at a particular height.
type NameRecordEntry {
id: String! # Target record ID.
height: String! # Height at which record was created.
}
# Name record stores the latest and historical name -> record ID mappings.
type NameRecord {
latest: NameRecordEntry! # Latest mame record entry.
history: [NameRecordEntry] # Historical name record entries.
}
type Query {
#
# Status API.
#
getStatus: Status!
# Get blockchain accounts.
getAccounts(
addresses: [String!]
): [Account]
# Get bonds by IDs.
getBondsByIds(
ids: [String!]
): [Bond]
# Query bonds.
queryBonds(
attributes: [KeyValueInput]
): [Bond]
# Query bonds by owner.
queryBondsByOwner(
ownerAddresses: [String!]
): [OwnerBonds]
#
# GraphDB API.
#
# Get records by IDs.
getRecordsByIds(
ids: [String!]
): [Record]
# Query records.
queryRecords(
# Multiple attribute conditions are in a logical AND.
attributes: [KeyValueInput]
# Whether to query all records, not just named ones (false by default).
all: Boolean
): [Record]
#
# Naming API.
#
# Lookup authority information.
lookupAuthorities(
names: [String!]
): [AuthorityRecord]!
# Lookup name to record mapping information.
lookupNames(
names: [String!]
): [NameRecord]!
# Resolve names to records.
resolveNames(
names: [String!]
): [Record]!
#
# Auctions API.
#
# Get auctions by IDs.
getAuctionsByIds(
ids: [String!]
): [Auction]
}

View File

@ -0,0 +1,15 @@
syntax = "proto3";
package vulcanize.auction.v1beta1;
import "gogoproto/gogo.proto";
import "vulcanize/auction/v1beta1/types.proto";
option go_package = "github.com/tharsis/ethermint/x/auction/types";
// GenesisState defines the genesis state of the auction module
message GenesisState {
Params params = 1 [(gogoproto.nullable) = false];
repeated Auction auctions = 2 [
(gogoproto.moretags) = "json:\"bonds\" yaml:\"bonds\""
];
}

View File

@ -0,0 +1,149 @@
syntax = "proto3";
package vulcanize.auction.v1beta1;
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/base/v1beta1/coin.proto";
import "vulcanize/auction/v1beta1/types.proto";
option go_package = "github.com/tharsis/ethermint/x/auction/types";
// AuctionsRequest is the format for querying all the auctions
message AuctionsRequest {
// pagination defines an optional pagination info for the next request
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// AuctionsResponse returns the list of all auctions
message AuctionsResponse {
// List of auctions
Auctions auctions = 1;
// pagination defines an optional pagination info for the next request
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}
// AuctionRequest is the format for querying a specific auction
message AuctionRequest {
// Auction ID
string id = 1;
}
// AuctionResponse returns the details of the queried auction
message AuctionResponse {
// Auction details
Auction auction = 1;
}
// BidRequest is the format for querying a specific bid in an auction
message BidRequest {
// Auction ID
string auction_id = 1;
// Bidder address
string bidder = 2;
}
// BidResponse returns the details of the queried bid
message BidResponse {
// Bid details
Bid bid = 1;
}
// BidsRequest is the format for querying all bids in an auction
message BidsRequest {
// Auction ID
string auction_id = 1;
}
// BidsResponse returns details of all bids in an auction
message BidsResponse {
// List of bids in the auction
repeated Bid bids = 1;
}
// AuctionsByBidderRequest is the format for querying all auctions containing a bidder address
message AuctionsByBidderRequest {
// Address of the bidder
string bidder_address = 1;
}
// AuctionsByBidderResponse returns all auctions containing a bidder
message AuctionsByBidderResponse {
// List of auctions
Auctions auctions = 1;
}
// AuctionsByOwnerRequest is the format for querying all auctions created by an owner
message AuctionsByOwnerRequest {
// Address of the owner
string owner_address = 1;
}
// AuctionsByOwnerResponse returns all auctions created by an owner
message AuctionsByOwnerResponse {
// List of auctions
Auctions auctions = 1;
}
// QueryParamsRequest is the format to query the parameters of the auction module
message QueryParamsRequest {
}
// QueryParamsResponse returns parameters of the auction module
message QueryParamsResponse {
Params params = 1;
}
// BalanceRequest is the format to fetch all balances
message BalanceRequest {
}
message BalanceResponse {
// Set of all balances within the auction
repeated cosmos.base.v1beta1.Coin balance = 1 [
(gogoproto.nullable) = false
];
}
// Query defines the gRPC querier interface for the auction module
service Query {
// Auctions queries all auctions
rpc Auctions(AuctionsRequest) returns (AuctionsResponse) {
option (google.api.http).get = "/vulcanize/auction/v1beta1/auctions";
}
// GetAuction queries an auction
rpc GetAuction(AuctionRequest) returns (AuctionResponse) {
option (google.api.http).get = "/vulcanize/auction/v1beta1/auctions/{id}";
}
// GetBid queries an auction bid
rpc GetBid(BidRequest) returns (BidResponse) {
option (google.api.http).get = "/vulcanize/auction/v1beta1/bids/{auction_id}/{bidder}";
}
// GetBids queries all auction bids
rpc GetBids(BidsRequest) returns (BidsResponse) {
option (google.api.http).get = "/vulcanize/auction/v1beta1/bids/{auction_id}";
}
// AuctionsByBidder queries auctions by bidder
rpc AuctionsByBidder(AuctionsByBidderRequest) returns (AuctionsByBidderResponse) {
option (google.api.http).get = "/vulcanize/auction/v1beta1/by-bidder/{bidder_address}";
}
// AuctionsByOwner queries auctions by owner
rpc AuctionsByOwner(AuctionsByOwnerRequest) returns (AuctionsByOwnerResponse) {
option (google.api.http).get = "/vulcanize/auction/v1beta1/by-owner/{owner_address}";
}
// QueryParams implements the params query command
rpc QueryParams(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/vulcanize/auction/v1beta1/params";
}
// Balance queries the auction module account balance
rpc Balance(BalanceRequest) returns (BalanceResponse) {
option (google.api.http).get = "/vulcanize/auction/v1beta1/balance";
}
}

View File

@ -0,0 +1,122 @@
syntax = "proto3";
package vulcanize.auction.v1beta1;
import "gogoproto/gogo.proto";
import "google/protobuf/duration.proto";
import "cosmos/base/v1beta1/coin.proto";
import "vulcanize/auction/v1beta1/types.proto";
option go_package = "github.com/tharsis/ethermint/x/auction/types";
// MsgCreateAuction defines a create auction message
message MsgCreateAuction {
option (gogoproto.goproto_getters) = false;
// Duration of the commits phase in seconds
google.protobuf.Duration commits_duration = 1 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"commits_duration\" yaml:\"commits_duration\""
];
// Duration of the reveals phase in seconds
google.protobuf.Duration reveals_duration = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"reveals_duration\" yaml:\"reveals_duration\""
];
// Commit fees
cosmos.base.v1beta1.Coin commit_fee = 3 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"commit_fee\" yaml:\"commit_fee\""
];
// Reveal fees
cosmos.base.v1beta1.Coin reveal_fee = 4 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"reveal_fee\" yaml:\"reveal_fee\""
];
// Minimum acceptable bid amount
cosmos.base.v1beta1.Coin minimum_bid = 5 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"minimum_bid\" yaml:\"minimum_bid\""
];
// Address of the signer
string signer = 6 [
(gogoproto.moretags) = "json:\"signer\" yaml:\"signer\""
];
}
// MsgCreateAuctionResponse returns the details of the created auction
message MsgCreateAuctionResponse {
option (gogoproto.goproto_getters) = false;
// Auction details
Auction auction = 1 [
(gogoproto.moretags) = "json:\"auction\" yaml:\"auction\""
];
}
// CommitBid defines the message to commit a bid
message MsgCommitBid {
option (gogoproto.goproto_getters) = false;
// Auction ID
string auction_id = 1 [
(gogoproto.moretags) = "json:\"auction_id\" yaml:\"auction_id\""
];
// Commit Hash
string commit_hash = 2 [
(gogoproto.moretags) = "json:\"commit_hash\" yaml:\"commit_hash\""
];
// Address of the signer
string signer = 3 [
(gogoproto.moretags) = "json:\"signer\" yaml:\"signer\""
];
}
// RevealBid defines the message to reveal a bid
message MsgRevealBid {
option (gogoproto.goproto_getters) = false;
// Auction ID
string auction_id = 1 [
(gogoproto.moretags) = "json:\"auction_id\" yaml:\"auction_id\""
];
// Commit Hash
string reveal = 2 [
(gogoproto.moretags) = "json:\"reveal\" yaml:\"reveal\""
];
// Address of the signer
string signer = 3 [
(gogoproto.moretags) = "json:\"signer\" yaml:\"signer\""
];
}
// MsgCommitBidResponse returns the state of the auction after the bid creation
message MsgCommitBidResponse {
option (gogoproto.goproto_getters) = false;
// Auction details
Bid bid = 1 [
(gogoproto.moretags) = "json:\"bid\" yaml:\"bid\""
];
}
// MsgRevealBidResponse returns the state of the auction after the bid reveal
message MsgRevealBidResponse {
option (gogoproto.goproto_getters) = false;
// Auction details
Auction auction = 1 [
(gogoproto.moretags) = "json:\"auction\" yaml:\"auction\""
];
}
// Tx defines the gRPC tx interface
service Msg {
// CreateAuction is the command for creating an auction
rpc CreateAuction(MsgCreateAuction) returns (MsgCreateAuctionResponse);
// CommitBid is the command for committing a bid
rpc CommitBid(MsgCommitBid) returns (MsgCommitBidResponse);
//RevealBid is the command for revealing a bid
rpc RevealBid(MsgRevealBid) returns (MsgRevealBidResponse);
}

View File

@ -0,0 +1,135 @@
syntax = "proto3";
package vulcanize.auction.v1beta1;
import "gogoproto/gogo.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "cosmos/base/v1beta1/coin.proto";
option go_package = "github.com/tharsis/ethermint/x/auction/types";
// Params defines the auction module parameters
message Params {
option (gogoproto.goproto_stringer) = false;
// Duration of the commits phase in seconds
google.protobuf.Duration commits_duration = 1 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"commits_duration\" yaml:\"commits_duration\""
];
// Duration of the reveals phase in seconds
google.protobuf.Duration reveals_duration = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"reveals_duration\" yaml:\"reveals_duration\""
];
// Commit fees
cosmos.base.v1beta1.Coin commit_fee = 3 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"commit_fee\" yaml:\"commit_fee\""
];
// Reveal fees
cosmos.base.v1beta1.Coin reveal_fee = 4 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"reveal_fee\" yaml:\"reveal_fee\""
];
// Minimum acceptable bid amount
cosmos.base.v1beta1.Coin minimum_bid = 5 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"minimum_bid\" yaml:\"minimum_bid\""
];
}
// Auction represents a sealed-bid on-chain auction
message Auction {
option (gogoproto.goproto_getters) = false;
string id = 1;
string status = 2;
// Address of the creator of the auction
string owner_address = 3;
// Timestamp at which the auction was created
google.protobuf.Timestamp create_time = 4 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"create_time\" yaml:\"create_time\""
];
// Timestamp at which the commits phase concluded
google.protobuf.Timestamp commits_end_time = 5 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"commits_end_time\" yaml:\"commits_end_time\""
];
// Timestamp at which the reveals phase concluded
google.protobuf.Timestamp reveals_end_time = 6 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"reveals_end_time\" yaml:\"reveals_end_time\""
];
// Commit and reveal fees must both be paid when committing a bid
// Reveal fee is returned only if the bid is revealed
cosmos.base.v1beta1.Coin commit_fee = 7 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"commit_fee\" yaml:\"commit_fee\""
];
cosmos.base.v1beta1.Coin reveal_fee = 8 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"reveal_fee\" yaml:\"reveal_fee\""
];
// Minimum acceptable bid amount for a valid commit
cosmos.base.v1beta1.Coin minimum_bid = 9 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"minimum_bid\" yaml:\"minimum_bid\""
];
// Address of the winner
string winner_address = 10;
// Winning bid, i.e., the highest bid
cosmos.base.v1beta1.Coin winning_bid = 11 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"winning_bid\" yaml:\"winning_bid\""
];
// Amount the winner pays, i.e. the second highest auction
cosmos.base.v1beta1.Coin winning_price = 12 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"winning_price\" yaml:\"winning_price\""
];
}
message Auctions {
option (gogoproto.goproto_getters) = false;
repeated Auction auctions = 1 [(gogoproto.nullable) = false];
}
// Bid represents a sealed bid (commit) made during the auction
message Bid {
option (gogoproto.goproto_getters) = false;
string auction_id = 1;
string bidder_address = 2;
string status = 3;
string commit_hash = 4;
google.protobuf.Timestamp commit_time = 5 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"commit_time\" yaml:\"commit_time\""
];
cosmos.base.v1beta1.Coin commit_fee = 6 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"commit_fee\" yaml:\"commit_fee\""
];
google.protobuf.Timestamp reveal_time = 7 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"reveal_time\" yaml:\"reveal_time\""
];
cosmos.base.v1beta1.Coin reveal_fee = 8 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"reveal_fee\" yaml:\"reveal_fee\""
];
cosmos.base.v1beta1.Coin bid_amount = 9 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"bid_amount\" yaml:\"bid_amount\""
];;
}

View File

@ -0,0 +1,29 @@
syntax = "proto3";
package vulcanize.bond.v1beta1;
option go_package = "github.com/tharsis/ethermint/x/bond/types";
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
// Params defines the bond module parameters
message Params {
// max_bond_amount is maximum amount to bond
cosmos.base.v1beta1.Coin max_bond_amount = 1 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"max_bond_amount\" yaml:\"max_bond_amount\""
];
}
// Bond represents funds deposited by an account for record rent payments.
message Bond {
// id is unique identifier of the bond
string id = 1;
// owner of the bond
string owner = 2;
// balance of the bond
repeated cosmos.base.v1beta1.Coin balance = 3 [
(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "json:\"balance\" yaml:\"balance\""
];
}

View File

@ -0,0 +1,18 @@
syntax = "proto3";
package vulcanize.bond.v1beta1;
import "gogoproto/gogo.proto";
import "vulcanize/bond/v1beta1/bond.proto";
option go_package = "github.com/tharsis/ethermint/x/bond/types";
// GenesisState defines the bond module's genesis state.
message GenesisState {
// params defines all the parameters of the module.
Params params = 1 [(gogoproto.nullable) = false];
// bonds defines all the bonds
repeated Bond bonds = 2 [
(gogoproto.moretags) = "json:\"bonds\" yaml:\"bonds\""
];
}

View File

@ -0,0 +1,109 @@
syntax = "proto3";
package vulcanize.bond.v1beta1;
import "gogoproto/gogo.proto";
import "vulcanize/bond/v1beta1/bond.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/base/v1beta1/coin.proto";
option go_package = "github.com/tharsis/ethermint/x/bond/types";
// Query defines the gRPC querier service for bond module
service Query {
// Params queries bonds module params.
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/vulcanize/bond/v1beta1/params";
}
// Bonds queries bonds list.
rpc Bonds(QueryGetBondsRequest) returns (QueryGetBondsResponse) {
option (google.api.http).get = "/vulcanize/bond/v1beta1/bonds";
}
// GetBondById
rpc GetBondById(QueryGetBondByIdRequest) returns (QueryGetBondByIdResponse){
option (google.api.http).get = "/vulcanize/bond/v1beta1/bonds/{id}";
}
// Get Bonds List by Owner
rpc GetBondsByOwner(QueryGetBondsByOwnerRequest) returns (QueryGetBondsByOwnerResponse){
option (google.api.http).get = "/vulcanize/bond/v1beta1/by-owner/{owner}";
}
// Get Bonds module balance
rpc GetBondsModuleBalance(QueryGetBondModuleBalanceRequest) returns (QueryGetBondModuleBalanceResponse){
option (google.api.http).get = "/vulcanize/bond/v1beta1/balance";
}
}
// QueryParamsRequest is request for query the bond module params
message QueryParamsRequest{
}
// QueryParamsResponse returns response type of bond module params
message QueryParamsResponse{
Params params = 1 [
(gogoproto.moretags) = "json:\"params\" yaml:\"params\""
];
}
// QueryGetBondById queries a bond by bond-id.
message QueryGetBondsRequest{
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryGetBondsResponse is response type for get the bonds by bond-id
message QueryGetBondsResponse{
repeated Bond bonds = 1 [
(gogoproto.moretags) = "json:\"bonds\" yaml:\"bonds\""
];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryGetBondById
message QueryGetBondByIdRequest{
string id = 1 [
(gogoproto.moretags) = "json:\"id\" yaml:\"id\""
];
}
// QueryGetBondByIdResponse returns QueryGetBondById query response
message QueryGetBondByIdResponse{
Bond bond = 1 [
(gogoproto.moretags) = "json:\"bond\" yaml:\"bond\""
];
}
// QueryGetBondsByOwnerRequest is request type for Query/GetBondsByOwner RPC Method
message QueryGetBondsByOwnerRequest{
string owner = 1;
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryGetBondsByOwnerResponse is response type for Query/GetBondsByOwner RPC Method
message QueryGetBondsByOwnerResponse {
repeated Bond bonds = 1 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"bonds\" yaml:\"bonds\""
];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryGetBondModuleBalanceRequest is request type for bond module balance rpc method
message QueryGetBondModuleBalanceRequest{
}
// QueryGetBondModuleBalanceResponse is the response type for bond module balance rpc method
message QueryGetBondModuleBalanceResponse{
repeated cosmos.base.v1beta1.Coin balance = 2 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "json:\"coins\" yaml:\"coins\""
];
}

View File

@ -0,0 +1,77 @@
syntax = "proto3";
package vulcanize.bond.v1beta1;
option go_package = "github.com/tharsis/ethermint/x/bond/types";
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
// Msg defines the bond Msg service.
service Msg {
// CreateBond defines a method for creating a new bond.
rpc CreateBond(MsgCreateBond) returns (MsgCreateBondResponse);
// RefillBond defines a method for refilling amount for bond.
rpc RefillBond(MsgRefillBond) returns (MsgRefillBondResponse);
// WithdrawBond defines a method for withdrawing amount from bond.
rpc WithdrawBond(MsgWithdrawBond) returns (MsgWithdrawBondResponse);
// CancelBond defines a method for cancelling a bond.
rpc CancelBond(MsgCancelBond) returns (MsgCancelBondResponse);
}
// MsgCreateBond defines a SDK message for creating a new bond.
message MsgCreateBond{
string signer = 1;
repeated cosmos.base.v1beta1.Coin coins = 2 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "json:\"coins\" yaml:\"coins\""
];
}
// MsgCreateBondResponse defines the Msg/CreateBond response type.
message MsgCreateBondResponse{
string id = 1;
}
// MsgRefillBond defines a SDK message for refill the amount for bond.
message MsgRefillBond{
string id = 1;
string signer = 2;
repeated cosmos.base.v1beta1.Coin coins = 3 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "json:\"coins\" yaml:\"coins\""
];
}
// MsgRefillBondResponse defines the Msg/RefillBond response type.
message MsgRefillBondResponse{
}
// MsgWithdrawBond defines a SDK message for withdrawing amount from bond.
message MsgWithdrawBond {
string id = 1;
string signer = 2;
repeated cosmos.base.v1beta1.Coin coins = 3 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "json:\"coins\" yaml:\"coins\""
];
}
// MsgWithdrawBondResponse defines the Msg/WithdrawBond response type.
message MsgWithdrawBondResponse{
}
// MsgCancelBond defines a SDK message for the cancel the bond.
message MsgCancelBond{
string id = 1;
string signer = 2;
}
// MsgCancelBondResponse defines the Msg/CancelBond response type.
message MsgCancelBondResponse{
}

View File

@ -0,0 +1,30 @@
syntax = "proto3";
package vulcanize.nameservice.v1beta1;
import "gogoproto/gogo.proto";
import "vulcanize/nameservice/v1beta1/nameservice.proto";
option go_package = "github.com/tharsis/ethermint/x/nameservice/types";
// GenesisState defines the nameservice module's genesis state.
message GenesisState {
// params defines all the params of nameservice module.
Params params = 1 [
(gogoproto.nullable) = false
];
// records
repeated Record records = 2 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"records\" yaml:\"records\""
];
// authorities
repeated AuthorityEntry authorities = 3 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"authorities\" yaml:\"authorities\""
];
// names
repeated NameEntry names = 4 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"names\" yaml:\"names\""
];
}

View File

@ -0,0 +1,170 @@
syntax = "proto3";
package vulcanize.nameservice.v1beta1;
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
option go_package = "github.com/tharsis/ethermint/x/nameservice/types";
// Params defines the nameservice module parameters
message Params {
cosmos.base.v1beta1.Coin record_rent = 1 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"record_rent\" yaml:\"record_rent\""
];
google.protobuf.Duration record_rent_duration = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"record_rent_duration\" yaml:\"record_rent_duration\""
];
cosmos.base.v1beta1.Coin authority_rent = 3 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"authority_rent\" yaml:\"authority_rent\""
];
google.protobuf.Duration authority_rent_duration = 4 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"authority_rent_duration\" yaml:\"authority_rent_duration\""
];
google.protobuf.Duration authority_grace_period = 5 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"authority_grace_period\" yaml:\"authority_grace_period\""
];
bool authority_auction_enabled = 6 [
(gogoproto.moretags) = "json:\"authority_auction_enabled\" yaml:\"authority_auction_enabled\""
];
google.protobuf.Duration authority_auction_commits_duration = 7 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"authority_auction_commits_duration\" yaml:\"authority_auction_commits_duration\""
];
google.protobuf.Duration authority_auction_reveals_duration = 8 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "json:\"authority_auction_reveals_duration\" yaml:\"authority_auction_reveals_duration\""
];
cosmos.base.v1beta1.Coin authority_auction_commit_fee = 9 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"authority_auction_commit_fee\" yaml:\"authority_auction_commit_fee\""
];
cosmos.base.v1beta1.Coin authority_auction_reveal_fee = 10 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"authority_auction_reveal_fee\" yaml:\"authority_auction_reveal_fee\""
];
cosmos.base.v1beta1.Coin authority_auction_minimum_bid = 11 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"authority_auction_minimum_bid\" yaml:\"authority_auction_minimum_bid\""
];
}
// Params defines the nameservice module records
message Record {
string id = 1 [
(gogoproto.moretags) = "json:\"id\" yaml:\"id\""
];
string bond_id = 2 [
(gogoproto.moretags) = "json:\"bondId\" yaml:\"bondId\""
];
google.protobuf.Timestamp create_time = 3 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"createTime\" yaml:\"createTime\""
];
google.protobuf.Timestamp expiry_time = 4 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"expiryTime\" yaml:\"expiryTime\""
];
bool deleted = 5;
repeated string owners = 6 [
(gogoproto.moretags) = "json:\"owners\" yaml:\"owners\""
];
bytes attributes = 7 [
(gogoproto.moretags) = "json:\"attributes\" yaml:\"attributes\""
];
}
// AuthorityEntry defines the nameservice module AuthorityEntries
message AuthorityEntry{
string name = 1;
NameAuthority entry = 2;
}
// NameAuthority
message NameAuthority {
// Owner public key.
string owner_public_key = 1 [
(gogoproto.moretags) = "json:\"ownerPublicKey\" yaml:\"ownerPublicKey\""
];
// Owner address.
string owner_address = 2 [
(gogoproto.moretags) = "json:\"ownerAddress\" yaml:\"ownerAddress\""
];
// height at which name/authority was created.
uint64 height = 3;
string status = 4;
string auction_id = 5 [
(gogoproto.moretags) = "json:\"auctionID\" yaml:\"auctionID\""
];
string bond_id = 6 [
(gogoproto.moretags) = "json:\"bondID\" yaml:\"bondID\""
];
google.protobuf.Timestamp expiry_time = 7 [
(gogoproto.nullable) = false,
(gogoproto.stdtime) = true,
(gogoproto.moretags) = "json:\"expiryTime\" yaml:\"expiryTime\""
];
}
// NameEntry
message NameEntry{
string name = 1;
NameRecord entry = 2;
}
// NameRecord
message NameRecord {
NameRecordEntry latest = 1;
repeated NameRecordEntry history = 2;
}
// NameRecordEntry
message NameRecordEntry{
string id = 1;
uint64 height = 2;
}
// Signature
message Signature{
string sig = 1 [
(gogoproto.moretags) = "json:\"sig\" yaml:\"sig\""
];
string pub_key = 2 [
(gogoproto.moretags) = "json:\"pubKey\" yaml:\"pubKey\""
];
}
// BlockChangeSet
message BlockChangeSet{
int64 height = 1;
repeated string records = 2;
repeated string auctions = 3;
repeated AuctionBidInfo auction_bids = 4 [
(gogoproto.moretags) = "json:\"auctionBids\" yaml:\"auctionBids\""
];
repeated string authorities = 5;
repeated string names = 6;
}
// AuctionBidInfo
message AuctionBidInfo {
string auction_id = 1 [
(gogoproto.moretags) = "json:\"auctionID\" yaml:\"auctionID\""
];
string bidder_address = 2 [
(gogoproto.moretags) = "json:\"bidderAddress\" yaml:\"bidderAddress\""
];
}

View File

@ -0,0 +1,211 @@
syntax = "proto3";
package vulcanize.nameservice.v1beta1;
import "vulcanize/nameservice/v1beta1/nameservice.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
option go_package = "github.com/tharsis/ethermint/x/nameservice/types";
// Query defines the gRPC querier service for nameservice module
service Query {
// Params queries the nameservice module params.
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/params";
}
// List records
rpc ListRecords(QueryListRecordsRequest) returns (QueryListRecordsResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/records";
}
// Get record by id
rpc GetRecord(QueryRecordByIdRequest) returns (QueryRecordByIdResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/records/{id}";
}
// Get records by bond id
rpc GetRecordByBondId(QueryRecordByBondIdRequest) returns (QueryRecordByBondIdResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/records-by-bond-id/{id}";
}
// Get nameservice module balance
rpc GetNameServiceModuleBalance(GetNameServiceModuleBalanceRequest) returns (GetNameServiceModuleBalanceResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/balance";
}
// List name records
rpc ListNameRecords(QueryListNameRecordsRequest) returns (QueryListNameRecordsResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/names";
}
// Whois method retrieve the name authority info
rpc Whois(QueryWhoisRequest) returns (QueryWhoisResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/whois/{name}";
}
// LookupWrn
rpc LookupWrn(QueryLookupWrn) returns (QueryLookupWrnResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/lookup";
}
// ResolveWrn
rpc ResolveWrn(QueryResolveWrn) returns (QueryResolveWrnResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/resolve";
}
// GetRecordExpiryQueue
rpc GetRecordExpiryQueue(QueryGetRecordExpiryQueue) returns (QueryGetRecordExpiryQueueResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/record-expiry";
}
// GetAuthorityExpiryQueue
rpc GetAuthorityExpiryQueue(QueryGetAuthorityExpiryQueue) returns (QueryGetAuthorityExpiryQueueResponse){
option (google.api.http).get = "/vulcanize/nameservice/v1beta1/authority-expiry";
}
}
// QueryParamsRequest is request type for nameservice params
message QueryParamsRequest{
}
// QueryParamsResponse is response type for nameservice params
message QueryParamsResponse{
Params params = 1;
}
// QueryListRecordsRequest is request type for nameservice records list
message QueryListRecordsRequest{
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryListRecordsResponse is response type for nameservice records list
message QueryListRecordsResponse{
repeated Record records = 1 [
(gogoproto.nullable) = false
];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
//QueryRecordByIdRequest is request type for nameservice records by id
message QueryRecordByIdRequest{
string id = 1 ;
}
// QueryRecordByIdResponse is response type for nameservice records by id
message QueryRecordByIdResponse{
Record record = 1[
(gogoproto.nullable) = false
];
}
// QueryRecordByBondIdRequest is request type for get the records by bond-id
message QueryRecordByBondIdRequest{
string id = 1;
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}
// QueryRecordByBondIdResponse is response type for records list by bond-id
message QueryRecordByBondIdResponse{
repeated Record records = 1 [
(gogoproto.nullable) = false
];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// GetNameServiceModuleBalanceRequest is request type for nameservice module accounts balance
message GetNameServiceModuleBalanceRequest{
}
// GetNameServiceModuleBalanceResponse is response type for nameservice module accounts balance
message GetNameServiceModuleBalanceResponse{
repeated AccountBalance balances = 1;
}
// AccountBalance is nameservice module account balance
message AccountBalance {
string account_name = 1 [
(gogoproto.moretags) = "json:\"accountName\" yaml:\"accountName\""
];
repeated cosmos.base.v1beta1.Coin balance = 3 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "json:\"balance\" yaml:\"balance\""
];
}
// QueryListNameRecordsRequest is request type for nameservice names records
message QueryListNameRecordsRequest{
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryListNameRecordsResponse is response type for nameservice names records
message QueryListNameRecordsResponse{
repeated NameEntry names = 1 [
(gogoproto.nullable) = false
];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryWhoisRequest is request type for Get NameAuthority
message QueryWhoisRequest{
string name = 1;
}
// QueryWhoisResponse is response type for whois request
message QueryWhoisResponse{
NameAuthority name_authority = 1 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"nameAuthority\" yaml:\"nameAuthority\""
];
}
// QueryLookupWrn is request type for LookupWrn
message QueryLookupWrn{
string wrn = 1;
}
// QueryLookupWrnResponse is response type for QueryLookupWrn
message QueryLookupWrnResponse{
NameRecord name = 1;
}
// QueryResolveWrn is request type for ResolveWrn
message QueryResolveWrn{
string wrn = 1;
}
// QueryResolveWrnResponse is response type for QueryResolveWrn
message QueryResolveWrnResponse{
Record record = 1;
}
// QueryGetRecordExpiryQueue
message QueryGetRecordExpiryQueue{
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryGetRecordExpiryQueueResponse
message QueryGetRecordExpiryQueueResponse{
repeated ExpiryQueueRecord records = 1;
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// ExpiryQueueRecord
message ExpiryQueueRecord{
string id = 1;
repeated string value = 2;
}
// QueryGetAuthorityExpiryQueue
message QueryGetAuthorityExpiryQueue{
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryGetAuthorityExpiryQueueResponse
message QueryGetAuthorityExpiryQueueResponse{
repeated ExpiryQueueRecord authorities = 1;
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

View File

@ -0,0 +1,167 @@
syntax = "proto3";
package vulcanize.nameservice.v1beta1;
import "gogoproto/gogo.proto";
import "vulcanize/nameservice/v1beta1/nameservice.proto";
option go_package = "github.com/tharsis/ethermint/x/nameservice/types";
// Msg
service Msg {
// SetRecord will records a new record with given payload and bond id
rpc SetRecord(MsgSetRecord) returns(MsgSetRecordResponse){}
// Renew Record will renew the expire record
rpc RenewRecord(MsgRenewRecord) returns (MsgRenewRecordResponse){}
// AssociateBond
rpc AssociateBond(MsgAssociateBond) returns (MsgAssociateBondResponse){}
// DissociateBond
rpc DissociateBond(MsgDissociateBond) returns (MsgDissociateBondResponse){}
// DissociateRecords
rpc DissociateRecords(MsgDissociateRecords) returns (MsgDissociateRecordsResponse){}
// ReAssociateRecords
rpc ReAssociateRecords(MsgReAssociateRecords) returns (MsgReAssociateRecordsResponse){}
// SetName will store the name with given wrn and name
rpc SetName(MsgSetName) returns (MsgSetNameResponse){}
// Reserve name
rpc ReserveName(MsgReserveAuthority) returns (MsgReserveAuthorityResponse){}
// Delete Name method will remove authority name
rpc DeleteName(MsgDeleteNameAuthority) returns (MsgDeleteNameAuthorityResponse){}
// SetAuthorityBond
rpc SetAuthorityBond(MsgSetAuthorityBond) returns (MsgSetAuthorityBondResponse){}
}
// MsgSetRecord
message MsgSetRecord{
string bond_id = 1 [
(gogoproto.moretags) = "json:\"bondId\" yaml:\"bondId\""
];
string signer = 2;
Payload payload = 3 [
(gogoproto.nullable) = false
];
}
// MsgSetRecordResponse
message MsgSetRecordResponse{
}
// Payload
message Payload {
Record record = 1;
repeated Signature signatures = 2 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "json:\"signatures\" yaml:\"signatures\""
];
}
// MsgSetName
message MsgSetName{
string wrn = 1;
string cid = 2;
string signer = 3;
}
// MsgSetNameResponse
message MsgSetNameResponse{
}
// MsgReserveName
message MsgReserveAuthority{
string name = 1;
string signer = 2;
// if creating a sub-authority.
string owner = 3;
}
// MsgReserveNameResponse
message MsgReserveAuthorityResponse{
}
// MsgSetAuthorityBond is SDK message for SetAuthorityBond
message MsgSetAuthorityBond{
string name = 1;
string bond_id = 2 [
(gogoproto.moretags) = "json:\"bondId\" yaml:\"bondId\""
];
string signer = 3;
}
// MsgSetAuthorityBondResponse
message MsgSetAuthorityBondResponse{
}
// MsgDeleteNameAuthority is SDK message for DeleteNameAuthority
message MsgDeleteNameAuthority{
string wrn = 1;
string signer = 2;
}
// MsgDeleteNameAuthorityResponse
message MsgDeleteNameAuthorityResponse{
}
//MsgRenewRecord is SDK message for Renew a record
message MsgRenewRecord{
string record_id = 1 [
(gogoproto.moretags) = "json:\"recordId\" yaml:\"recordId\""
];
string signer = 2;
}
// MsgRenewRecordResponse
message MsgRenewRecordResponse{
}
// MsgAssociateBond
message MsgAssociateBond{
string record_id = 1 [
(gogoproto.moretags) = "json:\"recordId\" yaml:\"recordId\""
];
string bond_id = 2 [
(gogoproto.moretags) = "json:\"bondId\" yaml:\"bondId\""
];
string signer = 3;
}
// MsgAssociateBondResponse
message MsgAssociateBondResponse{
}
// MsgDissociateBond is SDK message for Msg/DissociateBond
message MsgDissociateBond{
string record_id = 1 [
(gogoproto.moretags) = "json:\"recordId\" yaml:\"recordId\""
];
string signer = 2;
}
// MsgDissociateBondResponse is response type for MsgDissociateBond
message MsgDissociateBondResponse{
}
// MsgDissociateRecords is SDK message for Msg/DissociateRecords
message MsgDissociateRecords{
string bond_id = 1 [
(gogoproto.moretags) = "json:\"bondId\" yaml:\"bondId\""
];
string signer = 2;
}
// MsgDissociateRecordsResponse is response type for MsgDissociateRecords
message MsgDissociateRecordsResponse{
}
// MsgReAssociateRecords is SDK message for Msg/ReAssociateRecords
message MsgReAssociateRecords{
string new_bond_id = 1 [
(gogoproto.moretags) = "json:\"newBondId\" yaml:\"newBondId\""
];
string old_bond_id = 2 [
(gogoproto.moretags) = "json:\"oldBondId\" yaml:\"oldBondId\""
];
string signer = 3;
}
// MsgReAssociateRecordsResponse is response type for MsgReAssociateRecords
message MsgReAssociateRecordsResponse{
}

View File

@ -63,7 +63,7 @@ fi
# Compile ethermint
echo "compiling ethermint"
make build-ethermint
make build
# PID array declaration
arr=()
@ -120,15 +120,15 @@ echo "done sleeping"
set +e
if [[ -z $TEST || $TEST == "rpc" ]]; then
for i in $(seq 1 "$TEST_QTD"); do
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
echo "going to test ethermint node $HOST_RPC ..."
MODE=$MODE HOST=$HOST_RPC go test ./tests/... -timeout=300s -v -short
RPC_FAIL=$?
done
fi
stop_func() {

View File

@ -5,6 +5,7 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/spf13/cobra"
"github.com/spf13/viper"
tmcli "github.com/tendermint/tendermint/libs/cli"
)
// Tendermint full-node start flags
@ -48,6 +49,8 @@ func AddTxFlags(cmd *cobra.Command) *cobra.Command {
cmd.PersistentFlags().Float64(flags.FlagGasAdjustment, flags.DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ")
cmd.PersistentFlags().StringP(flags.FlagBroadcastMode, "b", flags.BroadcastSync, "Transaction broadcasting mode (sync|async|block)")
cmd.PersistentFlags().String(flags.FlagKeyringBackend, keyring.BackendOS, "Select keyring's backend")
cmd.PersistentFlags().BoolP(flags.FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation")
cmd.Flags().StringP(tmcli.OutputFlag, "o", "text", "Output format (text|json)")
// --gas can accept integers and "simulate"
// cmd.PersistentFlags().Var(&flags.GasFlagVar, "gas", fmt.Sprintf(
@ -66,3 +69,15 @@ func AddTxFlags(cmd *cobra.Command) *cobra.Command {
cmd.MarkFlagRequired(flags.FlagChainID)
return cmd
}
// AddGQLFlags adds gql flags for
func AddGQLFlags(cmd *cobra.Command) *cobra.Command {
// Add flags for GQL server.
cmd.PersistentFlags().Bool("gql-server", false, "Start GQL server.")
cmd.PersistentFlags().Bool("gql-playground", false, "Enable GQL playground.")
cmd.PersistentFlags().String("gql-playground-api-base", "", "GQL API base path to use in GQL playground.")
cmd.PersistentFlags().String("gql-port", "9473", "Port to use for the GQL server.")
cmd.PersistentFlags().String("log-file", "", "File to tail for GQL 'getLogs' API.")
return cmd
}

View File

@ -3,6 +3,7 @@ package server
import (
"context"
"fmt"
"github.com/tharsis/ethermint/gql"
"io"
"net/http"
"os"
@ -400,6 +401,9 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
}
}
// Start the GQL Server
go gql.Server(clientCtx)
defer func() {
if tmNode.IsRunning() {
_ = tmNode.Stop()

7
testnet/README.md Normal file
View File

@ -0,0 +1,7 @@
# Testnet
## Setup local ethermint multi node testnet
```shell
$ bash multinode_testnet.sh
```

201
testnet/full-node.md Normal file
View File

@ -0,0 +1,201 @@
# Instructions to Run Full Node
Hardware
---
#### Supported
- **Operating System (OS):** Ubuntu 20.04
- **CPU:** 1 core
- **RAM:** 2GB
- **Storage:** 25GB SSD
#### Recommended
- **Operating System (OS):** Ubuntu 20.04
- **CPU:** 2 core
- **RAM:** 4GB
- **Storage:** 50GB SSD
# A) Setup
## 1) Install Golang (go)
1.1) Remove any existing installation of `go`
```
sudo rm -rf /usr/local/go
```
1.2) Install latest/required Go version (installing `go1.17.2`)
```
curl https://golang.org/dl/go1.17.2.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.2.linux-amd64.tar.gz
```
1.3) Update env variables to include `go`
```
cat <<'EOF' >>$HOME/.profile
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export GO111MODULE=on
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
EOF
source $HOME/.profile
```
1.4) Check the version of go installed
```
go version
```
### 2) Install required software packages
```
sudo apt-get install git curl build-essential make jq -y
```
### 3) Install `ethermint`
```
git clone https://github.com/vulcanize/ethermint.git
cd ethermint
git fetch --all
git checkout v0.1.0-dev
make install
```
### 4) Verify your installation
```
ethermintd version --long
```
On running the above command, you should see a similar response like this. Make sure that the *version* and *commit
hash* are accurate
```
name: ethermint
server_name: ethermintd
```
### 5) Initialize Node
**Not required if you have already initialized before**
```
ethermintd init <your-node-moniker> --chain-id ethermint_81337-1
```
On running the above command, node will be initialized with default configuration. (config files will be saved in node's
default home directory (~/.ethermintd/config)
NOTE: Backup node and validator keys . You will need to use these keys at a later point in time.
---
# B) Starting Node
## 1) Download Final Genesis
Use `curl` to download the genesis file
**Replace your **genesis** file with published genesis file**
```shell
curl http://167.172.173.94:26657/genesis | jq .result.genesis > ~/.ethermintd/config/genesis.json
```
Verify sha256 hash of genesis file with the below command
```
jq -S -c -M '' ~/.ethermintd/config/genesis.json | shasum -a 256
```
genesis sha256 hash should be
```
4e5b68b5652a608c44c33e669c84ac179d9c0e301f958b5448f037a53c5cbb4e
```
## 2) Update Peers & Seeds in config.toml
```
peers="5ad2e6c35f2c84ff3ee31d89a95b34d92cb6afb1@157.230.101.237:26656,defc95b08547b6ef254723ad9621967a7e819020@161.35.223.44:26656"
sed -i.bak -e "s/^persistent_peers *=.*/persistent_peers = \"$peers\"/" ~/.ethermintd/config/config.toml
```
## 3) Start the Full Node
#### 3.1) Start node as `systemctl` service
3.1.1) Create the service file
```
sudo tee /etc/systemd/system/ethermintd.service > /dev/null <<EOF
[Unit]
Description=EthermintD Daemon
After=network-online.target
[Service]
User=$USER
ExecStart=$(which ethermintd) start --gql-playground --gql-server
Restart=always
RestartSec=3
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
```
3.1.2) Load service and start
```
sudo systemctl daemon-reload
sudo systemctl enable ethermintd
sudo systemctl start ethermintd
```
3.1.3) Check status of service
```
sudo systemctl status ethermintd
```
`NOTE:`
A helpful command here is `journalctl` that can be used to:
a) check logs
```
journalctl -u ethermintd
```
b) most recent logs
```
journalctl -xeu ethermintd
```
c) logs from previous day
```
journalctl --since "1 day ago" -u ethermintd
```
d) Check logs with follow flag
```
journalctl -f -u ethermintd
```

View File

@ -0,0 +1,231 @@
# Setting up a Genesis Validator for Vulcanize Ethermint Testnet (ethermint_9000-1)
Hardware
---
#### Supported
- **Operating System (OS):** Ubuntu 20.04
- **CPU:** 1 core
- **RAM:** 2GB
- **Storage:** 25GB SSD
#### Recommended
- **Operating System (OS):** Ubuntu 20.04
- **CPU:** 2 core
- **RAM:** 4GB
- **Storage:** 50GB SSD
# A) Setup
## 1) Install Golang (go)
1.1) Remove any existing installation of `go`
```
sudo rm -rf /usr/local/go
```
1.2) Install latest/required Go version (installing `go1.17.2`)
```
curl -O https://golang.org/dl/go1.17.2.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.2.linux-amd64.tar.gz
```
1.3) Update env variables to include `go`
```
cat <<'EOF' >>$HOME/.profile
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export GO111MODULE=on
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
EOF
source $HOME/.profile
```
1.4) Check the version of go installed
```
go version
```
### 2) Install required software packages
```
sudo apt-get update && sudo apt-get install git curl build-essential make jq -y
```
### 3) Install `ethermint`
```
git clone https://github.com/vulcanize/ethermint.git
cd ethermint
git fetch --all
git checkout v0.1.0-dev
make install
```
### 4) Verify your installation
```
ethermintd version --long
```
On running the above command, you should see a similar response like this. Make sure that the *version* and *commit
hash* are accurate
```
name: ethermint
server_name: ethermintd
```
### 5) Initialize Node
**Not required if you have already initialized before**
```
ethermintd init <your-node-moniker> --chain-id ethermint_81337-1
```
On running the above command, node will be initialized with default configuration. (config files will be saved in node's
default home directory (~/.ethermintd/config)
NOTE: Backup node and validator keys. You will need to use these keys at a later point in time.
---
## 6) Create Account keys
if you have participated in previous testnet and have mnemonic phrase, use below command to recover your account
```
ethermintd keys add <key-name> --recover
```
to create new account
```
ethermintd keys add <key-name>
```
NOTE: Save `mnemonic` and related account details (public key). You will need to use the need mnemonic/private key to
recover accounts at a later point in time.
## 7) Add Genesis Account
```
ethermintd add-genesis-account <key-name> 4500000000000000agnt --keyring-backend os
```
## 8) Create Your `gentx`
```
ethermintd gentx <key-name> 4500000000000000agnt \
--pubkey=$(ethermintd tendermint show-validator) \
--chain-id="ethermint_81337-1" \
--moniker="my-moniker" \
--website="https://yourweb.site" \
--details="description of my validator" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1"
```
Note:
- `<key-name>` and `chain-id` are required. other flags are optional
- Don't change amount value while creating your gentx
- Genesis transaction file will be saved in `~/.ethermintd/config/gentx` folder
## 9) Submit Your gentx
Submit your `gentx` file to the [testnets]() in the format of
`<validator-moniker>-gentx.json`
NOTE: (Do NOT use space in the file name)
To submit the gentx file, follow the below process:
- Fork the [testnets]() repository
- Upload your gentx file in `ethermint_81337-1/config/gentxs` folder
- Submit Pull Request to [testnets]() with name `ADD <your-moniker> gentx`
---
**Execute below instructions only after publishing of final genesis file**
genesis file will be published to [testnets/ethermint_9000-1]()
# B) Starting the validator
TBU
## 3) Start the Node
#### 3.1) Start node as `systemctl` service
3.1.1) Create the service file Note: this step is not required if you did setup before
```
sudo tee /etc/systemd/system/ethermintd.service > /dev/null <<EOF
[Unit]
Description=ethermintd Daemon
After=network-online.target
[Service]
User=$USER
ExecStart=$(which ethermintd) start
Restart=always
RestartSec=3
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
```
3.1.2) Load service and start
```
sudo systemctl daemon-reload
sudo systemctl enable ethermintd
sudo systemctl start ethermintd
```
3.1.3) Check status of service
```
sudo systemctl status ethermintd
```
`NOTE:`
A helpful command here is `journalctl` that can be used to:
a) check logs
```
journalctl -u ethermintd
```
b) most recent logs
```
journalctl -xeu ethermintd
```
c) logs from previous day
```
journalctl --since "1 day ago" -u ethermintd
```
d) Check logs with follow flag
```
journalctl -f -u ethermintd
```

View File

@ -0,0 +1,232 @@
#/bin/sh
# clean the existed chain
rm -rf ~/.testethermint*
echo "Installing the require tools "
sudo apt-get install git curl build-essential make nohup jq -y
echo "Done Installing the tools"
command_exists() {
type "$1" &>/dev/null
}
if command_exists go; then
echo "Golang is already installed"
else
echo "Installing golang dependencies"
wget https://golang.org/dl/go1.17.2.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.2.linux-amd64.tar.gz
echo "Updating the profile"
export GOPATH=$HOME/go
export GOROOT=/usr/local/go
export GOBIN=$GOPATH/bin
export PATH=$PATH:/usr/local/go/bin:$GOBIN
echo "" >>~/.profile
echo 'export GOPATH=$HOME/go' >>~/.profile
echo 'export GOROOT=/usr/local/go' >>~/.profile
echo 'export GOBIN=$GOPATH/bin' >>~/.profile
echo 'export PATH=$PATH:/usr/local/go/bin:$GOBIN' >>~/.profile
source ~/.profile
mkdir -p "$GOBIN"
mkdir -p $GOPATH/src/github.com
go version
fi
# chain env variables
export DAEMON_HOME=~/.testethermint
export CHAINID=ethermint_9000-1
export DENOM=uether
export GH_URL=https://github.com/vulcanize/ethermint.git
export CHAIN_VERSION=dev
export DAEMON=ethermintd
display_usage() {
printf "** Please check the exported values:: **\n Daemon : $DAEMON\n Denom : $DENOM\n ChainID : $CHAINID\n DaemonHome : $DAEMON_HOME\n \n Github URL : $GH_URL\n Chain Version : $CHAIN_VERSION\n"
exit 1
}
if [ -z $DAEMON ] || [ -z $DENOM ] || [ -z $CHAINID ] || [ -z $DAEMON_HOME ] || [ -z $GH_URL ] || [ -z $CHAIN_VERSION ]; then
display_usage
fi
echo "--------- Install $DAEMON ---------"
git clone -b $CHAIN_VERSION --single-branch $GH_URL && cd $(basename $_ .git)
git fetch && git checkout $CHAIN_VERSION
make install
cd $HOME
# check version
$DAEMON version --long
#echo "----------Create test keys-----------"
export DAEMON_HOME_1=$DAEMON_HOME-1
export DAEMON_HOME_2=$DAEMON_HOME-2
export DAEMON_HOME_3=$DAEMON_HOME-3
export DAEMON_HOME_4=$DAEMON_HOME-4
printf "DAEMON_HOME_1=$DAEMON_HOME_1\nDAEMON_HOME_2=$DAEMON_HOME_2\nDAEMON_HOME_3=$DAEMON_HOME_3\nDAEMON_HOME_4=$DAEMON_HOME_4\n"
rm -rf $DAEMON_HOME*
echo "-----Create daemon home directories if not exist------"
mkdir -p "$DAEMON_HOME_1"
mkdir -p "$DAEMON_HOME_2"
mkdir -p "$DAEMON_HOME_3"
mkdir -p "$DAEMON_HOME_4"
echo "--------Start initializing the chain ($CHAINID)---------"
$DAEMON init --chain-id $CHAINID $DAEMON_HOME_1 --home $DAEMON_HOME_1 --keyring-backend test
$DAEMON init --chain-id $CHAINID $DAEMON_HOME_2 --home $DAEMON_HOME_2 --keyring-backend test
$DAEMON init --chain-id $CHAINID $DAEMON_HOME_3 --home $DAEMON_HOME_3 --keyring-backend test
$DAEMON init --chain-id $CHAINID $DAEMON_HOME_4 --home $DAEMON_HOME_4 --keyring-backend test
echo "---------Creating four keys-------------"
$DAEMON keys add validator1 --home $DAEMON_HOME_1 --keyring-backend test
$DAEMON keys add validator2 --home $DAEMON_HOME_2 --keyring-backend test
$DAEMON keys add validator3 --home $DAEMON_HOME_3 --keyring-backend test
$DAEMON keys add validator4 --home $DAEMON_HOME_4 --keyring-backend test
echo "----------Genesis creation---------"
$DAEMON --home $DAEMON_HOME_1 add-genesis-account validator1 1000000000000$DENOM --keyring-backend test
$DAEMON --home $DAEMON_HOME_2 add-genesis-account validator2 1000000000000$DENOM --keyring-backend test
$DAEMON --home $DAEMON_HOME_3 add-genesis-account validator3 1000000000000$DENOM --keyring-backend test
$DAEMON --home $DAEMON_HOME_4 add-genesis-account validator4 1000000000000$DENOM --keyring-backend test
$DAEMON --home $DAEMON_HOME_1 add-genesis-account $($DAEMON keys show validator2 -a --home $DAEMON_HOME_2 --keyring-backend test) 1000000000000$DENOM
$DAEMON --home $DAEMON_HOME_1 add-genesis-account $($DAEMON keys show validator3 -a --home $DAEMON_HOME_3 --keyring-backend test) 1000000000000$DENOM
$DAEMON --home $DAEMON_HOME_1 add-genesis-account $($DAEMON keys show validator4 -a --home $DAEMON_HOME_4 --keyring-backend test) 1000000000000$DENOM
echo "--------Gentx--------"
$DAEMON gentx validator1 90000000000$DENOM --chain-id $CHAINID --keyring-backend test --home $DAEMON_HOME_1
$DAEMON gentx validator2 90000000000$DENOM --chain-id $CHAINID --keyring-backend test --home $DAEMON_HOME_2
$DAEMON gentx validator3 90000000000$DENOM --chain-id $CHAINID --keyring-backend test --home $DAEMON_HOME_3
$DAEMON gentx validator4 90000000000$DENOM --chain-id $CHAINID --keyring-backend test --home $DAEMON_HOME_4
echo "---------Copy all the genesis to $DAEMON_HOME_1----------"
cp $DAEMON_HOME_2/config/gentx/*.json $DAEMON_HOME_1/config/gentx/
cp $DAEMON_HOME_3/config/gentx/*.json $DAEMON_HOME_1/config/gentx/
cp $DAEMON_HOME_4/config/gentx/*.json $DAEMON_HOME_1/config/gentx/
echo "----------collect-gentxs------------"
$DAEMON collect-gentxs --home $DAEMON_HOME_1
echo "---------Updating $DAEMON_HOME_1 genesis.json ------------"
sed -i "s/172800000000000/600000000000/g" $DAEMON_HOME_1/config/genesis.json
sed -i "s/172800s/600s/g" $DAEMON_HOME_1/config/genesis.json
sed -i "s/stake/$DENOM/g" $DAEMON_HOME_1/config/genesis.json
echo "---------Distribute genesis.json of $DAEMON_HOME_1 to remaining nodes-------"
cp $DAEMON_HOME_1/config/genesis.json $DAEMON_HOME_2/config/
cp $DAEMON_HOME_1/config/genesis.json $DAEMON_HOME_3/config/
cp $DAEMON_HOME_1/config/genesis.json $DAEMON_HOME_4/config/
echo "---------Getting public IP address-----------"
IP="127.0.0.1"
echo "Public IP address: ${IP}"
echo "----------Update node-id of $DAEMON_HOME_1 in remaining nodes---------"
nodeID=$("${DAEMON}" tendermint show-node-id --home $DAEMON_HOME_1)
echo $nodeID
PERSISTENT_PEERS="$nodeID@$IP:16656"
echo "PERSISTENT_PEERS : $PERSISTENT_PEERS"
echo "----------Updating $DAEMON_HOME_1 chain config-----------"
sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:16657#g' $DAEMON_HOME_1/config/config.toml
sed -i 's#tcp://0.0.0.0:26656#tcp://0.0.0.0:16656#g' $DAEMON_HOME_1/config/config.toml
sed -i '/persistent_peers =/c\persistent_peers = "'""'"' $DAEMON_HOME_1/config/config.toml
sed -i '/max_num_inbound_peers =/c\max_num_inbound_peers = 140' $DAEMON_HOME_1/config/config.toml
sed -i '/max_num_outbound_peers =/c\max_num_outbound_peers = 110' $DAEMON_HOME_1/config/config.toml
sed -i '/pprof_laddr =/c\# pprof_laddr = "localhost:6060"' $DAEMON_HOME_1/config/config.toml
sed -i '/allow_duplicate_ip =/c\allow_duplicate_ip = true' $DAEMON_HOME_1/config/config.toml
sed -i 's#0.0.0.0:9090#0.0.0.0:1090#g' $DAEMON_HOME_1/config/app.toml
sed -i 's#0.0.0.0:9091#0.0.0.0:1091#g' $DAEMON_HOME_1/config/app.toml
sed -i 's#0.0.0.0:8545#0.0.0.0:1545#g' $DAEMON_HOME_1/config/app.toml
sed -i 's#0.0.0.0:8546#0.0.0.0:1546#g' $DAEMON_HOME_1/config/app.toml
echo "----------Updating $DAEMON_HOME_2 chain config-----------"
sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:26657#g' $DAEMON_HOME_2/config/config.toml
sed -i 's#tcp://0.0.0.0:26656#tcp://0.0.0.0:26656#g' $DAEMON_HOME_2/config/config.toml
sed -i '/persistent_peers =/c\persistent_peers = "'"$PERSISTENT_PEERS"'"' $DAEMON_HOME_2/config/config.toml
sed -i '/max_num_inbound_peers =/c\max_num_inbound_peers = 140' $DAEMON_HOME_2/config/config.toml
sed -i '/max_num_outbound_peers =/c\max_num_outbound_peers = 110' $DAEMON_HOME_2/config/config.toml
sed -i '/pprof_laddr =/c\# pprof_laddr = "localhost:6060"' $DAEMON_HOME_2/config/config.toml
sed -i '/allow_duplicate_ip =/c\allow_duplicate_ip = true' $DAEMON_HOME_2/config/config.toml
sed -i 's#0.0.0.0:9090#0.0.0.0:2090#g' $DAEMON_HOME_2/config/app.toml
sed -i 's#0.0.0.0:9091#0.0.0.0:2091#g' $DAEMON_HOME_2/config/app.toml
sed -i 's#0.0.0.0:8545#0.0.0.0:2545#g' $DAEMON_HOME_2/config/app.toml
sed -i 's#0.0.0.0:8546#0.0.0.0:2546#g' $DAEMON_HOME_2/config/app.toml
echo "----------Updating $DAEMON_HOME_3 chain config------------"
sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:36657#g' $DAEMON_HOME_3/config/config.toml
sed -i 's#tcp://0.0.0.0:26656#tcp://0.0.0.0:36656#g' $DAEMON_HOME_3/config/config.toml
sed -i '/persistent_peers =/c\persistent_peers = "'"$PERSISTENT_PEERS"'"' $DAEMON_HOME_3/config/config.toml
sed -i '/max_num_inbound_peers =/c\max_num_inbound_peers = 140' $DAEMON_HOME_3/config/config.toml
sed -i '/max_num_outbound_peers =/c\max_num_outbound_peers = 110' $DAEMON_HOME_3/config/config.toml
sed -i '/pprof_laddr =/c\# pprof_laddr = "localhost:6060"' $DAEMON_HOME_3/config/config.toml
sed -i '/allow_duplicate_ip =/c\allow_duplicate_ip = true' $DAEMON_HOME_3/config/config.toml
sed -i 's#0.0.0.0:9090#0.0.0.0:3090#g' $DAEMON_HOME_3/config/app.toml
sed -i 's#0.0.0.0:9091#0.0.0.0:3091#g' $DAEMON_HOME_3/config/app.toml
sed -i 's#0.0.0.0:8545#0.0.0.0:3545#g' $DAEMON_HOME_3/config/app.toml
sed -i 's#0.0.0.0:8546#0.0.0.0:3546#g' $DAEMON_HOME_3/config/app.toml
echo "----------Updating $DAEMON_HOME_4 chain config------------"
sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:46657#g' $DAEMON_HOME_4/config/config.toml
sed -i 's#tcp://0.0.0.0:26656#tcp://0.0.0.0:46656#g' $DAEMON_HOME_4/config/config.toml
sed -i '/persistent_peers =/c\persistent_peers = "'"$PERSISTENT_PEERS"'"' $DAEMON_HOME_4/config/config.toml
sed -i '/max_num_inbound_peers =/c\max_num_inbound_peers = 140' $DAEMON_HOME_4/config/config.toml
sed -i '/max_num_outbound_peers =/c\max_num_outbound_peers = 110' $DAEMON_HOME_4/config/config.toml
sed -i '/pprof_laddr =/c\# pprof_laddr = "localhost:6060"' $DAEMON_HOME_4/config/config.toml
sed -i '/allow_duplicate_ip =/c\allow_duplicate_ip = true' $DAEMON_HOME_4/config/config.toml
sed -i 's#0.0.0.0:9090#0.0.0.0:4090#g' $DAEMON_HOME_4/config/app.toml
sed -i 's#0.0.0.0:9091#0.0.0.0:4091#g' $DAEMON_HOME_4/config/app.toml
sed -i 's#0.0.0.0:8545#0.0.0.0:4545#g' $DAEMON_HOME_4/config/app.toml
sed -i 's#0.0.0.0:8546#0.0.0.0:4546#g' $DAEMON_HOME_4/config/app.toml
echo "starting the chains"
nohup $(which $DAEMON) start --gql-playground --gql-server --home $DAEMON_HOME_1 >$DAEMON_HOME_1.log &
sleep 5s
echo "Checking $DAEMON_HOME_1 chain status"
$DAEMON status --node tcp://localhost:16657
nohup $(which $DAEMON) start --gql-playground --gql-server --home $DAEMON_HOME_2 >$DAEMON_HOME_2.log &
sleep 5s
echo "Checking $DAEMON_HOME_2 chain status"
$DAEMON status --node tcp://localhost:26657
nohup $(which $DAEMON) start --gql-playground --gql-server --home $DAEMON_HOME_3 >$DAEMON_HOME_3.log &
sleep 5s
echo "Checking $DAEMON_HOME_3 chain status"
$DAEMON status --node tcp://localhost:36657
nohup $(which $DAEMON) start --gql-playground --gql-server --home $DAEMON_HOME_4 >$DAEMON_HOME_4.log &
sleep 5s
echo "Checking $DAEMON_HOME_4 chain status"
$DAEMON status --node tcp://localhost:46657

56
testnet/validator-node.md Normal file
View File

@ -0,0 +1,56 @@
### Create Validator Post Genesis
1. Run Full Node
2. Create Account and Get test tokens
3. Create Validator
### 1.Run Full Node
- Check "[Run Full Node](full-node.md)" section to Run a Full Node
### 2. Create Account & Get test tokens
```
ethermintd keys add <key-name> --keyring-backend test
```
NOTE: Save `mnemonic` and related account details (public key). You will need to use the need mnemonic/private key to
recover accounts at a later point in time.
##### Get Test tokens from faucet
- Open this link : http://167.172.173.94:1314/ and paste your account
- 1 gnt = 10^18 agnt
- Each Transaction you will get 500gnt
- Total Tokens 5000gnt for account
### 3.Create Validator
- ##### Check full node sync status
`ethermintd status 2>&1 | jq -r ".SyncInfo"`
`catching_up: false` means node is completely synced
- ##### Create validator
`Note:` Only execute below transaction after complete sync of your full node
Please replace `key_name` with your key name and `moniker` also
```
ethermintd tx staking create-validator \
--amount=4500000000000000000000agnt \
--pubkey=$(ethermintd tendermint show-validator) \
--moniker="my-moniker" \
--website="https://myweb.site" \
--details="description of your validator" \
--chain-id="ethermint_81337-1" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1" \
--gas="auto" \
--gas-adjustment="1.2" \
--gas-prices="0.025agnt" \
--from=<key_name>
```

52
utils/json.go Normal file
View File

@ -0,0 +1,52 @@
//
// Copyright 2020 Wireline, Inc.
//
package utils
import (
"bytes"
"errors"
canonicalJson "github.com/gibson042/canonicaljson-go"
cbor "github.com/ipfs/go-ipld-cbor"
mh "github.com/multiformats/go-multihash"
)
// GenerateHash returns the hash of the canonicalized JSON input.
func GenerateHash(json map[string]interface{}) (string, []byte, error) {
content, err := canonicalJson.Marshal(json)
if err != nil {
return "", nil, err
}
cid, err := CIDFromJSONBytes(content)
if err != nil {
return "", nil, err
}
return cid, content, nil
}
// CIDFromJSONBytes returns CID (cbor) for json (as bytes).
func CIDFromJSONBytes(content []byte) (string, error) {
cid, err := cbor.FromJSON(bytes.NewReader(content), mh.SHA2_256, -1)
if err != nil {
return "", err
}
return cid.String(), nil
}
// GetAttributeAsString returns a map attribute as string, if possible.
func GetAttributeAsString(obj map[string]interface{}, attr string) (string, error) {
if value, ok := obj[attr]; ok {
if valueStr, ok := value.(string); ok {
return valueStr, nil
}
return "", errors.New("attribute not of string type")
}
return "", errors.New("attribute not found")
}

25
utils/mnemonic.go Normal file
View File

@ -0,0 +1,25 @@
//
// Copyright 2020 Wireline, Inc.
//
package utils
import "github.com/cosmos/go-bip39"
const (
mnemonicEntropySize = 256
)
func GenerateMnemonic() (string, error) {
entropySeed, err := bip39.NewEntropy(mnemonicEntropySize)
if err != nil {
return "", err
}
mnemonic, err := bip39.NewMnemonic(entropySeed[:])
if err != nil {
return "", err
}
return mnemonic, nil
}

52
utils/types.go Normal file
View File

@ -0,0 +1,52 @@
//
// Copyright 2020 Wireline, Inc.
//
package utils
import (
"bytes"
"encoding/binary"
"sort"
set "github.com/deckarep/golang-set"
)
func Int64ToBytes(num int64) []byte {
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, num)
return buf.Bytes()
}
func SetToSlice(set set.Set) []string {
names := []string{}
for name := range set.Iter() {
if name, ok := name.(string); ok && name != "" {
names = append(names, name)
}
}
sort.SliceStable(names, func(i, j int) bool { return names[i] < names[j] })
return names
}
func SliceToSet(names []string) set.Set {
set := set.NewThreadUnsafeSet()
for _, name := range names {
if name != "" {
set.Add(name)
}
}
return set
}
func AppendUnique(list []string, element string) []string {
set := SliceToSet(list)
set.Add(element)
return SetToSlice(set)
}

298
x/auction/README.md Normal file
View File

@ -0,0 +1,298 @@
# Auction Module CLI Commands
## Build the Chain
The following command builds the Ethermint daemon and places the binary in the `build` directory
```
make build
```
## Setup the Chain
The following steps need to be followed only before running the chain for the first time.
1. Add the root key:
```
./build/ethermintd keys add root
```
Keep a note of the keyring passphrase if you set it.
2. Init the chain:
```
./build/ethermintd init test-moniker --chain-id ethermint_9000-1
```
3. Add genesis account:
```
./build/ethermintd add-genesis-account $(./build/ethermintd keys show root -a) 1000000000000000000aphoton,1000000000000000000stake
```
4. Make a genesis tx:
```
./build/ethermintd gentx root 1000000000000000000stake --chain-id ethermint_9000-1
```
5. Collect gentxs:
```
./build/ethermintd collect-gentxs
```
The chain can now be started using:
```
./build/ethermintd start
```
## Querying the Params
The following command will dislay the default params for the `auction` module:
```
# ./build/ethermintd q auction params -o json | jq
{
"params": {
"commits_duration": "0s",
"reveals_duration": "0s",
"commit_fee": {
"denom": "",
"amount": "0"
},
"reveal_fee": {
"denom": "",
"amount": "0"
},
"minimum_bid": {
"denom": "",
"amount": "0"
}
}
}
```
## Auction TX CLI Commands
### Create Auction
```
# ./build/ethermintd tx auction create 100s 100s 10aphoton 10aphoton 1000aphoton --from root --chain-id $(./build/ethermintd status | jq .NodeInfo.network -r)
Enter keyring passphrase:
{"body":{"messages":[{"@type":"/vulcanize.auction.v1beta1.MsgCreateAuction","commits_duration":"100s","reveals_duration":"100s","commit_fee":{"denom":"aphoton","amount":"10"},"reveal_fee":{"denom":"aphoton","amount":"10"},"minimum_bid":{"denom":"aphoton","amount":"1000"},"signer":"ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: ECAD6DF1ECA763FBD26EB7C2C0B77425FFE2FBEA2BEC57CE0FBC173AE0F45298
```
### Commit Bid
```
# ./build/ethermintd tx auction commit-bid e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d 2000aphoton --from root --chain-id $(./build/ethermintd status | jq .NodeInfo.network -r)
Enter keyring passphrase:
{"body":{"messages":[{"@type":"/vulcanize.auction.v1beta1.MsgCommitBid","auction_id":"e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d","commit_hash":"bafyreibt4twofrc3xi2es27cfrroy346iy6lr3gkw33i5dltkqqarlyltm","signer":"ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 71D8CF34026E32A3A34C2C2D4ADF25ABC8D7943A4619761BE27F196603D91B9D
```
### Reveal Bid
```
# ./build/ethermintd tx auction reveal-bid e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d root-bafyreibt4twofrc3xi2es27cfrroy346iy6lr3gkw33i5dltkqqarlyltm.json --from root --chain-id $(./build/ethermintd status | jq .NodeInfo.network -r)
Enter keyring passphrase:
{"body":{"messages":[{"@type":"/vulcanize.auction.v1beta1.MsgRevealBid","auction_id":"e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d","reveal":"7b2261756374696f6e4964223a2265376431346337653761366437353337636264623866626536326632326231353533633265663463653337303561646137633238663830666166326662653064222c22626964416d6f756e74223a22323030306170686f746f6e222c2262696464657241646472657373223a226574686d316c37637374777466326c76657632376b613637633233796b376d6d6a38616437746574707163222c22636861696e4964223a2265746865726d696e745f393030302d31222c226e6f697365223a22636c69666620737566666572206472616d6120676f7370656c2077656173656c207061706572206c696272617279206469736f726465722063757276652073706f74206375727461696e207a6562726120696e76657374206465766f74652072656e64657220636c6970207377616c6c6f77206d6f6e6b6579206f62736572766520726573706f6e7365206c696e6b206372616e6520766961626c6520736576656e227d","signer":"ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 4D1C0B3DDA4050F9BB32240FBD5234229E5C32543C1A0A78033B9531EB0CF8BA
```
## Auction Query CLI Commands
### List Auctions
```
# ./build/ethermintd q auction list
auctions:
auctions:
- commit_fee:
amount: "10"
denom: aphoton
commits_end_time: "2021-09-30T07:57:07.933412800Z"
create_time: "2021-09-30T07:55:27.933412800Z"
id: e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d
minimum_bid:
amount: "1000"
denom: aphoton
owner_address: ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc
reveal_fee:
amount: "10"
denom: aphoton
reveals_end_time: "2021-09-30T07:58:47.933412800Z"
status: commit
winner_address: ""
winning_bid:
amount: "0"
denom: ""
winning_price:
amount: "0"
denom: ""
pagination: null
```
### Get Bid
```
# ./build/ethermintd q auction get-bid e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0e ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc
bid:
auction_id: e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d
bid_amount:
amount: "0"
denom: ""
bidder_address: ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc
commit_fee:
amount: "10"
denom: aphoton
commit_hash: bafyreibt4twofrc3xi2es27cfrroy346iy6lr3gkw33i5dltkqqarlyltm
commit_time: "2021-09-30T08:49:48.358878200Z"
reveal_fee:
amount: "10"
denom: aphoton
reveal_time: "0001-01-01T00:00:00Z"
status: commit
```
### Get All Bids for an Auction
```
./build/ethermintd q auction get-bids e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d
bids:
- auction_id: e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d
bid_amount:
amount: "0"
denom: ""
bidder_address: ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc
commit_fee:
amount: "10"
denom: aphoton
commit_hash: bafyreibt4twofrc3xi2es27cfrroy346iy6lr3gkw33i5dltkqqarlyltm
commit_time: "2021-09-30T08:49:48.358878200Z"
reveal_fee:
amount: "10"
denom: aphoton
reveal_time: "0001-01-01T00:00:00Z"
status: commit
```
### Get Auction by AuctionID
```
# ./build/ethermintd q auction get e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d
auction:
commit_fee:
amount: "10"
denom: aphoton
commits_end_time: "2021-09-30T07:57:07.933412800Z"
create_time: "2021-09-30T07:55:27.933412800Z"
id: e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d
minimum_bid:
amount: "1000"
denom: aphoton
owner_address: ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc
reveal_fee:
amount: "10"
denom: aphoton
reveals_end_time: "2021-09-30T07:58:47.933412800Z"
status: commit
winner_address: ""
winning_bid:
amount: "0"
denom: ""
winning_price:
amount: "0"
denom: ""
```
### Get Auction by Bidder
```
# ./build/ethermintd q auction query-by-owner ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc
auctions:
auctions:
- commit_fee:
amount: "10"
denom: aphoton
commits_end_time: "2021-09-30T07:57:07.933412800Z"
create_time: "2021-09-30T07:55:27.933412800Z"
id: e7d14c7e7a6d7537cbdb8fbe62f22b1553c2ef4ce3705ada7c28f80faf2fbe0d
minimum_bid:
amount: "1000"
denom: aphoton
owner_address: ethm1l7cstwtf2lvev27ka67c23yk7mmj8ad7tetpqc
reveal_fee:
amount: "10"
denom: aphoton
reveals_end_time: "2021-09-30T07:58:47.933412800Z"
status: commit
winner_address: ""
winning_bid:
amount: "0"
denom: ""
winning_price:
amount: "0"
denom: ""
```
### Query Account Balance
```
# ./build/ethermintd q auction balance
balance:
- amount: "20"
denom: aphoton
```

13
x/auction/abci.go Normal file
View File

@ -0,0 +1,13 @@
package auction
import (
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tharsis/ethermint/x/auction/keeper"
)
// EndBlocker is called every block, returns updated validator set.
func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate {
k.EndBlockerProcessAuctions(ctx)
return []abci.ValidatorUpdate{}
}

View File

@ -0,0 +1,263 @@
package cli
import (
"fmt"
"strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
"github.com/spf13/cobra"
"github.com/tharsis/ethermint/x/auction/types"
)
func GetQueryCmd() *cobra.Command {
auctionQueryCmd := &cobra.Command{
Use: types.ModuleName,
Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
auctionQueryCmd.AddCommand(
GetCmdList(),
GetCmdGetAuction(),
GetCmdGetBid(),
GetCmdGetBids(),
GetCmdAuctionsByBidder(),
GetCmdAuctionsByOwner(),
GetCmdQueryParams(),
GetCmdBalance(),
)
return auctionQueryCmd
}
// GetCmdList queries all auctions.
func GetCmdList() *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List auctions.",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.Auctions(cmd.Context(), &types.AuctionsRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdGetBid queries an auction bid.
func GetCmdGetBid() *cobra.Command {
cmd := &cobra.Command{
Use: "get-bid [auction-id] [bidder]",
Short: "Get auction bid.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
id := args[0]
bidder := args[1]
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.GetBid(cmd.Context(), &types.BidRequest{AuctionId: id, Bidder: bidder})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdGetBids queries all auction bids.
func GetCmdGetBids() *cobra.Command {
cmd := &cobra.Command{
Use: "get-bids [auction-id]",
Short: "Get all auction bids.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
id := args[0]
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.GetBids(cmd.Context(), &types.BidsRequest{AuctionId: id})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdGetAuction queries an auction.
func GetCmdGetAuction() *cobra.Command {
cmd := &cobra.Command{
Use: "get [ID]",
Short: "Get auction.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
id := args[0]
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.GetAuction(cmd.Context(), &types.AuctionRequest{Id: id})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdAuctionsByBidder queries auctions by bidder.
func GetCmdAuctionsByBidder() *cobra.Command {
cmd := &cobra.Command{
Use: "query-by-bidder [address]",
Short: "Query auctions by bidder.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
address := args[0]
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.AuctionsByBidder(cmd.Context(), &types.AuctionsByBidderRequest{BidderAddress: address})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdAuctionsByOwner queries auctions by owner
func GetCmdAuctionsByOwner() *cobra.Command {
cmd := &cobra.Command{
Use: "query-by-owner [address]",
Short: "Query auctions by owner/creator.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
address := args[0]
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.AuctionsByOwner(cmd.Context(), &types.AuctionsByOwnerRequest{OwnerAddress: address})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryParams implements the params query command.
func GetCmdQueryParams() *cobra.Command {
cmd := &cobra.Command{
Use: "params",
Args: cobra.NoArgs,
Short: "Query the current auction parameters information.",
Long: strings.TrimSpace(
fmt.Sprintf(`Query values set as auction parameters.
Example:
$ %s query auction params
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.QueryParams(cmd.Context(), &types.QueryParamsRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdBalance queries the auction module account balance.
func GetCmdBalance() *cobra.Command {
cmd := &cobra.Command{
Use: "balance",
Short: "Get auction module account balance.",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.Balance(cmd.Context(), &types.BalanceRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

187
x/auction/client/cli/tx.go Normal file
View File

@ -0,0 +1,187 @@
package cli
import (
"encoding/hex"
"fmt"
"io/ioutil"
"time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tharsis/ethermint/x/auction/types"
wnsUtils "github.com/tharsis/ethermint/utils"
)
// GetTxCmd returns transaction commands for this module.
func GetTxCmd() *cobra.Command {
auctionTxCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Auction transactions subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
auctionTxCmd.AddCommand(
GetCmdCreateAuction(),
GetCmdCommitBid(),
GetCmdRevealBid(),
)
return auctionTxCmd
}
func GetCmdCreateAuction() *cobra.Command {
cmd := &cobra.Command{
Use: "create [commits-duration] [reveals-duration] [commit-fee] [reveal-fee] [minimum-bid]",
Short: "Create auction.",
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
commitsDuration, err := time.ParseDuration(args[0])
if err != nil {
return err
}
revealsDuration, err := time.ParseDuration(args[1])
if err != nil {
return err
}
commitFee, err := sdk.ParseCoinNormalized(args[2])
if err != nil {
return err
}
revealFee, err := sdk.ParseCoinNormalized(args[3])
if err != nil {
return err
}
minimumBid, err := sdk.ParseCoinNormalized(args[4])
if err != nil {
return err
}
params := types.Params{
CommitsDuration: commitsDuration,
RevealsDuration: revealsDuration,
CommitFee: commitFee,
RevealFee: revealFee,
MinimumBid: minimumBid,
}
msg := types.NewMsgCreateAuction(params, clientCtx.GetFromAddress())
err = msg.ValidateBasic()
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// GetCmdCommitBid is the CLI command for committing a bid.
func GetCmdCommitBid() *cobra.Command {
cmd := &cobra.Command{
Use: "commit-bid [auction-id] [bid-amount]",
Short: "Commit sealed bid.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
bidAmount, err := sdk.ParseCoinNormalized(args[1])
if err != nil {
return err
}
mnemonic, err := wnsUtils.GenerateMnemonic()
if err != nil {
return err
}
chainID := viper.GetString("chain-id")
auctionID := args[0]
reveal := map[string]interface{}{
"chainId": chainID,
"auctionId": auctionID,
"bidderAddress": clientCtx.GetFromAddress().String(),
"bidAmount": bidAmount.String(),
"noise": mnemonic,
}
commitHash, content, err := wnsUtils.GenerateHash(reveal)
if err != nil {
return err
}
// Save reveal file.
ioutil.WriteFile(fmt.Sprintf("%s-%s.json", clientCtx.GetFromName(), commitHash), content, 0600)
msg := types.NewMsgCommitBid(auctionID, commitHash, clientCtx.GetFromAddress())
err = msg.ValidateBasic()
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// GetCmdRevealBid is the CLI command for revealing a bid.
func GetCmdRevealBid() *cobra.Command {
cmd := &cobra.Command{
Use: "reveal-bid [auction-id] [reveal-file-path]",
Short: "Reveal bid.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
auctionID := args[0]
revealFilePath := args[1]
revealBytes, err := ioutil.ReadFile(revealFilePath)
if err != nil {
return err
}
msg := types.NewMsgRevealBid(auctionID, hex.EncodeToString(revealBytes), clientCtx.GetFromAddress())
err = msg.ValidateBasic()
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}

View File

@ -0,0 +1,15 @@
package testutil
import (
"testing"
"github.com/stretchr/testify/suite"
"github.com/tharsis/ethermint/testutil/network"
)
func TestIntegrationTestSuite(t *testing.T) {
cfg := network.DefaultConfig()
cfg.NumValidators = 1
suite.Run(t, NewIntegrationTestSuite(cfg))
}

View File

@ -0,0 +1,77 @@
package testutil
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/stretchr/testify/suite"
"github.com/tharsis/ethermint/testutil/network"
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
defaultAuctionID string
}
var (
ownerAccount = "owner"
bidderAccount = "bidder"
ownerAddress string
bidderAddress string
)
func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite {
return &IntegrationTestSuite{cfg: cfg}
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
s.network = network.New(s.T(), s.cfg)
_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
// setting up random owner and bidder accounts
s.createAccountWithBalance(ownerAccount, &ownerAddress)
s.createAccountWithBalance(bidderAccount, &bidderAddress)
s.defaultAuctionID = s.createAuctionAndBid(true, false)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
func (s *IntegrationTestSuite) createAccountWithBalance(accountName string, accountAddress *string) {
val := s.network.Validators[0]
sr := s.Require()
consPrivKey := ed25519.GenPrivKey()
consPubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(consPrivKey.PubKey())
sr.NoError(err)
sr.NotNil(consPubKeyBz)
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr := sdk.AccAddress(info.GetPubKey().Address())
_, err = banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200000))), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
)
sr.NoError(err)
*accountAddress = newAddr.String()
}

View File

@ -0,0 +1,255 @@
package testutil
import (
"fmt"
"github.com/cosmos/cosmos-sdk/types/rest"
auctiontypes "github.com/tharsis/ethermint/x/auction/types"
)
const (
randomAuctionID = "randomAuctionID"
randomBidderAddress = "randomBidderAddress"
randomOwnerAddress = "randomOwnerAddress"
)
func (suite *IntegrationTestSuite) TestGetAllAuctionsGrpc() {
val := suite.network.Validators[0]
sr := suite.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/auction/v1beta1/auctions", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
}{
{
"invalid request to get all auctions",
reqUrl + randomAuctionID,
"",
true,
},
{
"valid request to get all auctions",
reqUrl,
"",
false,
},
}
for _, tc := range testCases {
suite.Run(tc.msg, func() {
resp, err := rest.GetRequest(tc.url)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var auctions auctiontypes.AuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auctions)
sr.NotZero(len(auctions.Auctions.Auctions))
}
})
}
}
func (suite *IntegrationTestSuite) TestQueryParamsGrpc() {
val := suite.network.Validators[0]
sr := suite.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/auction/v1beta1/params", val.APIAddress)
suite.Run("valid request to get auction params", func() {
resp, err := rest.GetRequest(reqUrl)
suite.Require().NoError(err)
var params auctiontypes.QueryParamsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &params)
sr.NoError(err)
sr.Equal(*params.GetParams(), auctiontypes.DefaultParams())
})
}
func (suite *IntegrationTestSuite) TestGetAuctionGrpc() {
val := suite.network.Validators[0]
sr := suite.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/auction/v1beta1/auctions/", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
preRun func() string
}{
{
"invalid request to get an auction",
reqUrl + randomAuctionID,
"",
true,
func() string { return "" },
},
{
"valid request to get an auction",
reqUrl,
"",
false,
func() string { return suite.defaultAuctionID },
},
}
for _, tc := range testCases {
suite.Run(tc.msg, func() {
auctionID := tc.preRun()
resp, err := rest.GetRequest(tc.url + auctionID)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var auction auctiontypes.AuctionResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auction)
sr.NoError(err)
sr.Equal(auctionID, auction.Auction.Id)
}
})
}
}
func (suite *IntegrationTestSuite) TestGetBidsGrpc() {
val := suite.network.Validators[0]
sr := suite.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/auction/v1beta1/bids/", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
preRun func() string
}{
{
"invalid request to get all bids",
reqUrl,
"",
true,
func() string { return "" },
},
{
"valid request to get all bids",
reqUrl,
"",
false,
func() string { return suite.createAuctionAndBid(false, true) },
},
}
for _, tc := range testCases {
suite.Run(tc.msg, func() {
auctionID := tc.preRun()
tc.url += auctionID
resp, err := rest.GetRequest(tc.url)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var bids auctiontypes.BidsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bids)
sr.NoError(err)
sr.Equal(auctionID, bids.Bids[0].AuctionId)
}
})
}
}
func (suite *IntegrationTestSuite) TestGetBidGrpc() {
val := suite.network.Validators[0]
sr := suite.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/auction/v1beta1/bids/", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
}{
{
"invalid request to get bid",
fmt.Sprintf("%s/%s/", reqUrl, randomAuctionID),
"",
true,
},
{
"valid request to get bid",
fmt.Sprintf("%s/%s/%s", reqUrl, randomAuctionID, randomBidderAddress),
"",
false,
},
}
for _, tc := range testCases {
suite.Run(tc.msg, func() {
resp, err := rest.GetRequest(tc.url)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var bid auctiontypes.BidResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bid)
sr.NoError(err)
}
})
}
}
func (suite *IntegrationTestSuite) TestGetAuctionsByOwnerGrpc() {
val := suite.network.Validators[0]
sr := suite.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/auction/v1beta1/by-owner/", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
}{
{
"invalid request to get auctions by owner",
reqUrl,
"",
true,
},
{
"valid request to get auctions by owner",
fmt.Sprintf("%s/%s", reqUrl, randomOwnerAddress),
"",
false,
},
}
for _, tc := range testCases {
suite.Run(tc.msg, func() {
resp, err := rest.GetRequest(tc.url)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var auctions auctiontypes.AuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auctions)
sr.NoError(err)
}
})
}
}
func (suite *IntegrationTestSuite) TestQueryBalanceGrpc() {
val := suite.network.Validators[0]
sr := suite.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/auction/v1beta1/balance", val.APIAddress)
msg := "valid request to get the auction module balance"
suite.createAuctionAndBid(false, true)
suite.Run(msg, func() {
resp, err := rest.GetRequest(reqUrl)
sr.NoError(err)
var response auctiontypes.BalanceResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetBalance()))
})
}

View File

@ -0,0 +1,311 @@
package testutil
import (
"fmt"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/tharsis/ethermint/x/auction/client/cli"
"github.com/tharsis/ethermint/x/auction/types"
)
var queryJSONFlag = []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}
func (suite *IntegrationTestSuite) TestGetCmdQueryParams() {
val := suite.network.Validators[0]
sr := suite.Require()
suite.Run(fmt.Sprintf("Case %s", "fetch query params"), func() {
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdQueryParams(), queryJSONFlag)
sr.NoError(err)
var params types.QueryParamsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &params)
sr.NoError(err)
sr.Equal(types.DefaultParams(), *params.Params)
})
}
func (suite *IntegrationTestSuite) TestGetCmdBalance() {
val := suite.network.Validators[0]
sr := suite.Require()
testCases := []struct {
msg string
createAuctionAndBid bool
}{
{
"fetch module balance without creating auction and bid",
false,
},
{
"fetch module balance with valid auction and bid",
true,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctionAndBid {
suite.createAuctionAndBid(false, true)
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdBalance(), queryJSONFlag)
sr.NoError(err)
var balance types.BalanceResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &balance)
sr.NoError(err)
if test.createAuctionAndBid {
sr.NotZero(len(balance.Balance))
}
})
}
}
func (suite *IntegrationTestSuite) TestGetCmdList() {
val := suite.network.Validators[0]
sr := suite.Require()
testCases := []struct {
msg string
createAuction bool
}{
{
"list auctions when no auctions exist",
false,
},
{
"list auctions after creating an auction",
true,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), queryJSONFlag)
sr.NoError(err)
var auctions types.AuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &auctions)
sr.NoError(err)
if test.createAuction {
sr.NotZero(len(auctions.Auctions.Auctions))
}
})
}
}
func (suite *IntegrationTestSuite) TestGetCmdGetBid() {
val := suite.network.Validators[0]
sr := suite.Require()
testCases := []struct {
msg string
args []string
createAuctionAndBid bool
}{
{
"get bid without creating auction",
[]string{},
false,
},
{
"get bid after creating auction and bid",
[]string{},
true,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctionAndBid {
auctionID := suite.createAuctionAndBid(false, true)
test.args = append(test.args, auctionID)
getBidsArgs := []string{auctionID, queryJSONFlag[0]}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdGetBids(), getBidsArgs)
sr.NoError(err)
var bids types.BidsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &bids)
sr.NoError(err)
test.args = append(test.args, bids.GetBids()[0].BidderAddress)
}
test.args = append(test.args, queryJSONFlag...)
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdGetBid(), test.args)
if test.createAuctionAndBid {
sr.NoError(err)
var bid types.BidResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &bid)
sr.NoError(err)
sr.NotNil(bid.GetBid())
} else {
sr.Error(err)
}
})
}
}
func (suite *IntegrationTestSuite) TestGetCmdGetBids() {
val := suite.network.Validators[0]
sr := suite.Require()
testCases := []struct {
msg string
args []string
createAuctionAndBid bool
}{
{
"get bids without creating auction",
[]string{},
false,
},
{
"get bids after creating auction and bid",
[]string{},
true,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctionAndBid {
auctionID := suite.createAuctionAndBid(false, true)
test.args = append(test.args, auctionID)
}
test.args = append(test.args, queryJSONFlag...)
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdGetBids(), test.args)
if test.createAuctionAndBid {
sr.NoError(err)
var bids types.BidsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &bids)
sr.NoError(err)
sr.NotZero(len(bids.Bids))
} else {
sr.Error(err)
}
})
}
}
func (suite *IntegrationTestSuite) TestGetCmdGetAuction() {
val := suite.network.Validators[0]
sr := suite.Require()
testCases := []struct {
msg string
auctionID string
createAuction bool
}{
{
"get auction with empty auction ID",
"",
false,
},
{
"get auction with valid auction ID",
"",
true,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuction {
test.auctionID = suite.defaultAuctionID
}
args := []string{test.auctionID, queryJSONFlag[0]}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdGetAuction(), args)
if test.createAuction {
sr.NoError(err)
var auction types.AuctionResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &auction)
sr.NoError(err)
sr.NotNil(auction.GetAuction())
sr.Equal(test.auctionID, auction.GetAuction().Id)
} else {
sr.Error(err)
}
})
}
}
func (suite *IntegrationTestSuite) TestGetCmdAuctionsByBidder() {
val := suite.network.Validators[0]
sr := suite.Require()
testCases := []struct {
msg string
createAuctionAndBid bool
bidderAddress string
}{
{
"get auctions by bidder without creating auctions",
false,
"",
},
{
"get auctions by bidder for valid bidder address",
true,
"",
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctionAndBid {
auctionID := suite.createAuctionAndBid(false, true)
args := []string{auctionID, queryJSONFlag[0]}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdGetBids(), args)
sr.NoError(err)
var bids types.BidsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &bids)
sr.NoError(err)
test.bidderAddress = bids.Bids[0].BidderAddress
}
getByBidderArgs := []string{test.bidderAddress, queryJSONFlag[0]}
_, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdAuctionsByBidder(), getByBidderArgs)
if test.createAuctionAndBid {
sr.NoError(err)
} else {
sr.Error(err)
}
})
}
}
func (suite IntegrationTestSuite) createAuctionAndBid(createAuction, createBid bool) string {
val := suite.network.Validators[0]
sr := suite.Require()
auctionID := ""
if createAuction {
auctionArgs := []string{
sampleCommitTime, sampleRevealTime,
fmt.Sprintf("10%s", suite.cfg.BondDenom),
fmt.Sprintf("10%s", suite.cfg.BondDenom),
fmt.Sprintf("100%s", suite.cfg.BondDenom),
}
resp, err := suite.executeTx(cli.GetCmdCreateAuction(), auctionArgs, ownerAccount)
sr.NoError(err)
sr.Zero(resp.Code)
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), queryJSONFlag)
sr.NoError(err)
var queryResponse types.AuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
auctionID = queryResponse.Auctions.Auctions[0].Id
} else {
auctionID = suite.defaultAuctionID
}
if createBid {
bidArgs := []string{auctionID, fmt.Sprintf("200%s", suite.cfg.BondDenom)}
resp, err := suite.executeTx(cli.GetCmdCommitBid(), bidArgs, bidderAccount)
sr.NoError(err)
sr.Zero(resp.Code)
}
return auctionID
}

View File

@ -0,0 +1,141 @@
package testutil
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/tharsis/ethermint/x/auction/client/cli"
"github.com/tharsis/ethermint/x/auction/types"
)
const (
sampleCommitTime = "90s"
sampleRevealTime = "5s"
placeholderAuctionID = "placeholder_auction_id"
)
func (suite *IntegrationTestSuite) TestTxCreateAuction() {
sr := suite.Require()
testCases := []struct {
msg string
args []string
expectErr bool
}{
{
"create auction with missing arguments",
[]string{sampleCommitTime, sampleRevealTime},
true,
},
{
"create auction with proper arguments",
[]string{
sampleCommitTime, sampleRevealTime,
fmt.Sprintf("10%s", suite.cfg.BondDenom),
fmt.Sprintf("10%s", suite.cfg.BondDenom),
fmt.Sprintf("100%s", suite.cfg.BondDenom),
},
false,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
resp, err := suite.executeTx(cli.GetCmdCreateAuction(), test.args, ownerAccount)
if test.expectErr {
sr.Error(err)
} else {
sr.NoError(err)
sr.Zero(resp.Code)
}
})
}
}
func (suite *IntegrationTestSuite) TestTxCommitBid() {
val := suite.network.Validators[0]
sr := suite.Require()
testCases := []struct {
msg string
args []string
createAuction bool
}{
{
"commit bid with missing args",
[]string{fmt.Sprintf("200%s", suite.cfg.BondDenom)},
false,
},
{
"commit bid with valid args",
[]string{
placeholderAuctionID,
fmt.Sprintf("200%s", suite.cfg.BondDenom),
},
true,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuction {
auctionArgs := []string{
sampleCommitTime, sampleRevealTime,
fmt.Sprintf("10%s", suite.cfg.BondDenom),
fmt.Sprintf("10%s", suite.cfg.BondDenom),
fmt.Sprintf("100%s", suite.cfg.BondDenom),
}
_, err := suite.executeTx(cli.GetCmdCreateAuction(), auctionArgs, ownerAccount)
sr.NoError(err)
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(),
[]string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)})
sr.NoError(err)
var queryResponse types.AuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
sr.NotNil(queryResponse.GetAuctions())
test.args[0] = queryResponse.GetAuctions().Auctions[0].Id
}
resp, err := suite.executeTx(cli.GetCmdCommitBid(), test.args, bidderAccount)
if test.createAuction {
sr.NoError(err)
sr.Zero(resp.Code)
} else {
sr.Error(err)
}
})
}
}
func (suite *IntegrationTestSuite) executeTx(cmd *cobra.Command, args []string, caller string) (sdk.TxResponse, error) {
val := suite.network.Validators[0]
additionalArgs := []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, caller),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", suite.cfg.BondDenom)),
}
args = append(args, additionalArgs...)
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
if err != nil {
return sdk.TxResponse{}, err
}
var resp sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp)
if err != nil {
return sdk.TxResponse{}, err
}
err = suite.network.WaitForNextBlock()
if err != nil {
return sdk.TxResponse{}, err
}
return resp, nil
}

44
x/auction/genesis.go Normal file
View File

@ -0,0 +1,44 @@
package auction
import (
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tharsis/ethermint/x/auction/keeper"
"github.com/tharsis/ethermint/x/auction/types"
)
// func NewGenesisState(params types.Params, auctions []types.Auction) types.GenesisState {
// return types.GenesisState{Params: params, Auctions: &types.Auctions{Auctions: auctions}}
// }
func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, data types.GenesisState) []abci.ValidatorUpdate {
keeper.SetParams(ctx, data.Params)
for _, auction := range data.Auctions {
keeper.SaveAuction(ctx, auction)
}
return []abci.ValidatorUpdate{}
}
func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) types.GenesisState {
params := keeper.GetParams(ctx)
auctions := keeper.ListAuctions(ctx)
var genesisAuctions []*types.Auction
for _, auction := range auctions {
genesisAuctions = append(genesisAuctions, &auction)
}
return types.GenesisState{Params: params, Auctions: genesisAuctions}
}
func ValidateGenesis(data types.GenesisState) error {
err := data.Params.Validate()
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,91 @@
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/tharsis/ethermint/x/auction/types"
)
type Querier struct {
Keeper
}
var _ types.QueryServer = Querier{}
// Auctions queries all auctions
func (q Querier) Auctions(c context.Context, req *types.AuctionsRequest) (*types.AuctionsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
resp := q.Keeper.ListAuctions(ctx)
return &types.AuctionsResponse{Auctions: &types.Auctions{Auctions: resp}}, nil
}
// GetAuction queries an auction
func (q Querier) GetAuction(c context.Context, req *types.AuctionRequest) (*types.AuctionResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
if req.Id == "" {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
}
resp := q.Keeper.GetAuction(ctx, req.Id)
return &types.AuctionResponse{Auction: resp}, nil
}
// GetBid queries and auction bid
func (q Querier) GetBid(c context.Context, req *types.BidRequest) (*types.BidResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
if req.AuctionId == "" {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
}
if req.Bidder == "" {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "bidder address is required")
}
resp := q.Keeper.GetBid(ctx, req.AuctionId, req.Bidder)
return &types.BidResponse{Bid: &resp}, nil
}
// GetBids queries all auction bids
func (q Querier) GetBids(c context.Context, req *types.BidsRequest) (*types.BidsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
if req.AuctionId == "" {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
}
resp := q.Keeper.GetBids(ctx, req.AuctionId)
return &types.BidsResponse{Bids: resp}, nil
}
// AuctionsByBidder queries auctions by bidder
func (q Querier) AuctionsByBidder(c context.Context, req *types.AuctionsByBidderRequest) (*types.AuctionsByBidderResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
if req.BidderAddress == "" {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "bidder address is required")
}
resp := q.Keeper.QueryAuctionsByBidder(ctx, req.BidderAddress)
return &types.AuctionsByBidderResponse{Auctions: &types.Auctions{Auctions: resp}}, nil
}
// AuctionsByOwner queries auctions by owner
func (q Querier) AuctionsByOwner(c context.Context, req *types.AuctionsByOwnerRequest) (*types.AuctionsByOwnerResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
if req.OwnerAddress == "" {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "owner address is required")
}
resp := q.Keeper.QueryAuctionsByOwner(ctx, req.OwnerAddress)
return &types.AuctionsByOwnerResponse{Auctions: &types.Auctions{Auctions: resp}}, nil
}
// QueryParams implements the params query command
func (q Querier) QueryParams(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
resp := q.Keeper.GetParams(ctx)
return &types.QueryParamsResponse{Params: &resp}, nil
}
// Balance queries the auction module account balance
func (q Querier) Balance(c context.Context, req *types.BalanceRequest) (*types.BalanceResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
resp := q.Keeper.GetAuctionModuleBalances(ctx)
return &types.BalanceResponse{Balance: resp}, nil
}

View File

@ -0,0 +1,355 @@
package keeper_test
import (
"context"
"fmt"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tharsis/ethermint/app"
"github.com/tharsis/ethermint/x/auction/types"
)
const testCommitHash = "71D8CF34026E32A3A34C2C2D4ADF25ABC8D7943A4619761BE27F196603D91B9D"
func (suite *KeeperTestSuite) TestGrpcGetAllAuctions() {
client, ctx, k := suite.queryClient, suite.ctx, suite.app.AuctionKeeper
testCases := []struct {
msg string
req *types.AuctionsRequest
createAuctions bool
auctionCount int
}{
{
"fetch auctions when no auctions exist",
&types.AuctionsRequest{},
false,
0,
},
{
"fetch auctions with one auction created",
&types.AuctionsRequest{},
true,
1,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctions {
account := app.CreateRandomAccounts(1)[0]
err := simapp.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(
sdk.Coin{Amount: sdk.NewInt(100), Denom: sdk.DefaultBondDenom},
))
_, err = k.CreateAuction(ctx, types.NewMsgCreateAuction(k.GetParams(ctx), account))
suite.Require().NoError(err)
}
resp, _ := client.Auctions(context.Background(), test.req)
suite.Require().Equal(test.auctionCount, len(resp.GetAuctions().Auctions))
})
}
}
func (suite *KeeperTestSuite) TestGrpcQueryParams() {
testCases := []struct {
msg string
req *types.QueryParamsRequest
}{
{
"fetch params",
&types.QueryParamsRequest{},
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
resp, err := suite.queryClient.QueryParams(context.Background(), test.req)
suite.Require().Nil(err)
suite.Require().Equal(*(resp.Params), types.DefaultParams())
})
}
}
func (suite *KeeperTestSuite) TestGrpcGetAuction() {
testCases := []struct {
msg string
req *types.AuctionRequest
createAuction bool
}{
{
"fetch auction with empty auction ID",
&types.AuctionRequest{},
false,
},
{
"fetch auction with valid auction ID",
&types.AuctionRequest{},
true,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuction {
auction, _, err := suite.createAuctionAndCommitBid(false)
suite.Require().NoError(err)
test.req.Id = auction.Id
}
resp, err := suite.queryClient.GetAuction(context.Background(), test.req)
if test.createAuction {
suite.Require().Nil(err)
suite.Require().NotNil(resp.GetAuction())
suite.Require().Equal(test.req.Id, resp.GetAuction().Id)
} else {
suite.Require().NotNil(err)
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestGrpcGetBids() {
testCases := []struct {
msg string
req *types.BidsRequest
createAuction bool
commitBid bool
bidCount int
}{
{
"fetch all bids when no auction exists",
&types.BidsRequest{},
false,
false,
0,
},
{
"fetch all bids for valid auction but no added bids",
&types.BidsRequest{},
true,
false,
0,
},
{
"fetch all bids for valid auction and valid bid",
&types.BidsRequest{},
true,
true,
1,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuction {
auction, _, err := suite.createAuctionAndCommitBid(test.commitBid)
suite.Require().NoError(err)
test.req.AuctionId = auction.Id
}
resp, err := suite.queryClient.GetBids(context.Background(), test.req)
if test.createAuction {
suite.Require().Nil(err)
suite.Require().Equal(test.bidCount, len(resp.GetBids()))
} else {
suite.Require().NotNil(err)
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestGrpcGetBid() {
testCases := []struct {
msg string
req *types.BidRequest
createAuctionAndBid bool
}{
{
"fetch bid when bid does not exist",
&types.BidRequest{},
false,
},
{
"fetch bid when valid bid exists",
&types.BidRequest{},
true,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctionAndBid {
auction, bid, err := suite.createAuctionAndCommitBid(test.createAuctionAndBid)
suite.Require().NoError(err)
test.req.AuctionId = auction.Id
test.req.Bidder = bid.BidderAddress
}
resp, err := suite.queryClient.GetBid(context.Background(), test.req)
if test.createAuctionAndBid {
suite.Require().NoError(err)
suite.Require().NotNil(resp.Bid)
suite.Require().Equal(test.req.Bidder, resp.Bid.BidderAddress)
} else {
suite.Require().NotNil(err)
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestGrpcGetAuctionsByBidder() {
testCases := []struct {
msg string
req *types.AuctionsByBidderRequest
createAuctionAndCommitBid bool
auctionCount int
}{
{
"get auctions by bidder with invalid bidder address",
&types.AuctionsByBidderRequest{},
false,
0,
},
{
"get auctions by bidder with valid auction and bid",
&types.AuctionsByBidderRequest{},
true,
1,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctionAndCommitBid {
_, bid, err := suite.createAuctionAndCommitBid(test.createAuctionAndCommitBid)
suite.Require().NoError(err)
test.req.BidderAddress = bid.BidderAddress
}
resp, err := suite.queryClient.AuctionsByBidder(context.Background(), test.req)
if test.createAuctionAndCommitBid {
suite.Require().NoError(err)
suite.Require().NotNil(resp.Auctions)
suite.Require().Equal(test.auctionCount, len(resp.Auctions.Auctions))
} else {
suite.Require().NotNil(err)
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestGrpcGetAuctionsByOwner() {
testCases := []struct {
msg string
req *types.AuctionsByOwnerRequest
createAuction bool
auctionCount int
}{
{
"get auctions by owner with invalid owner address",
&types.AuctionsByOwnerRequest{},
false,
0,
},
{
"get auctions by owner with valid auction",
&types.AuctionsByOwnerRequest{},
true,
1,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuction {
auction, _, err := suite.createAuctionAndCommitBid(false)
suite.Require().NoError(err)
test.req.OwnerAddress = auction.OwnerAddress
}
resp, err := suite.queryClient.AuctionsByOwner(context.Background(), test.req)
if test.createAuction {
suite.Require().NoError(err)
suite.Require().NotNil(resp.Auctions)
suite.Require().Equal(test.auctionCount, len(resp.Auctions.Auctions))
} else {
suite.Require().NotNil(err)
suite.Require().Error(err)
}
})
}
}
func (suite KeeperTestSuite) TestGrpcQueryBalance() {
testCases := []struct {
msg string
req *types.BalanceRequest
createAuction bool
auctionCount int
}{
{
"get balance with no auctions created",
&types.BalanceRequest{},
false,
0,
},
{
"get balance with single auction created",
&types.BalanceRequest{},
true,
1,
},
}
for _, test := range testCases {
if test.createAuction {
_, _, err := suite.createAuctionAndCommitBid(true)
suite.Require().NoError(err)
}
resp, err := suite.queryClient.Balance(context.Background(), test.req)
suite.Require().NoError(err)
suite.Require().Equal(test.auctionCount, len(resp.GetBalance()))
}
}
func (suite *KeeperTestSuite) createAuctionAndCommitBid(commitBid bool) (*types.Auction, *types.Bid, error) {
ctx, k := suite.ctx, suite.app.AuctionKeeper
accCount := 1
if commitBid {
accCount++
}
accounts := app.CreateRandomAccounts(accCount)
for _, account := range accounts {
err := simapp.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(
sdk.Coin{Amount: sdk.NewInt(100), Denom: sdk.DefaultBondDenom},
))
if err != nil {
return nil, nil, err
}
}
auction, err := k.CreateAuction(ctx, types.NewMsgCreateAuction(k.GetParams(ctx), accounts[0]))
if err != nil {
return nil, nil, err
}
if commitBid {
bid, err := k.CommitBid(ctx, types.NewMsgCommitBid(auction.Id, testCommitHash, accounts[1]))
if err != nil {
return nil, nil, err
}
return auction, bid, nil
}
return auction, nil, nil
}

View File

@ -0,0 +1,37 @@
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tharsis/ethermint/x/auction/types"
)
// RegisterInvariants registers all auction module invariants.
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ir.RegisterRoute(types.ModuleName, "module-account", ModuleAccountInvariant(k))
}
// ModuleAccountInvariant checks that the 'auction' module account balance is non-negative.
func ModuleAccountInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
moduleAddress := k.accountKeeper.GetModuleAddress(types.ModuleName)
if k.bankKeeper.GetAllBalances(ctx, moduleAddress).IsAnyNegative() {
return sdk.FormatInvariant(
types.ModuleName,
"module-account",
fmt.Sprintf("Module account '%s' has negative balance.", types.ModuleName)),
true
}
return "", false
}
}
// AllInvariants runs all invariants of the auctions module.
func AllInvariants(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
return ModuleAccountInvariant(k)(ctx)
}
}

658
x/auction/keeper/keeper.go Normal file
View File

@ -0,0 +1,658 @@
package keeper
import (
"encoding/hex"
"encoding/json"
"fmt"
"time"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
auth "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bank "github.com/cosmos/cosmos-sdk/x/bank/keeper"
params "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/tharsis/ethermint/x/auction/types"
wnsUtils "github.com/tharsis/ethermint/utils"
)
// CompletedAuctionDeleteTimeout => Completed auctions are deleted after this timeout (after reveals end time).
const CompletedAuctionDeleteTimeout = time.Hour * 24
// PrefixIDToAuctionIndex is the prefix for Id -> Auction index in the KVStore.
// Note: This is the primary index in the system.
// Note: Golang doesn't support const arrays.
var PrefixIDToAuctionIndex = []byte{0x00}
// prefixOwnerToAuctionsIndex is the prefix for the Owner -> [Auction] index in the KVStore.
var prefixOwnerToAuctionsIndex = []byte{0x01}
// PrefixAuctionBidsIndex is the prefix for the (auction, bidder) -> Bid index in the KVStore.
var PrefixAuctionBidsIndex = []byte{0x02}
// PrefixBidderToAuctionsIndex is the prefix for the Bidder -> [Auction] index in the KVStore.
var PrefixBidderToAuctionsIndex = []byte{0x03}
// Keeper maintains the link to storage and exposes getter/setter methods for the various parts of the state machine
type Keeper struct {
accountKeeper auth.AccountKeeper
bankKeeper bank.Keeper
// Track auction usage in other cosmos-sdk modules (more like a usage tracker).
usageKeepers []types.AuctionUsageKeeper
storeKey sdk.StoreKey // Unexposed key to access store from sdk.Context
cdc codec.BinaryCodec // The wire codec for binary encoding/decoding.
paramSubspace params.Subspace
}
// AuctionClientKeeper is the subset of functionality exposed to other modules.
type AuctionClientKeeper interface {
HasAuction(ctx sdk.Context, id string) bool
GetAuction(ctx sdk.Context, id string) types.Auction
MatchAuctions(ctx sdk.Context, matchFn func(*types.Auction) bool) []*types.Auction
}
// NewKeeper creates new instances of the auction Keeper
func NewKeeper(accountKeeper auth.AccountKeeper, bankKeeper bank.Keeper, storeKey sdk.StoreKey, cdc codec.BinaryCodec, ps params.Subspace) Keeper {
if !ps.HasKeyTable() {
ps = ps.WithKeyTable(types.ParamKeyTable())
}
return Keeper{
accountKeeper: accountKeeper,
bankKeeper: bankKeeper,
storeKey: storeKey,
cdc: cdc,
paramSubspace: ps,
}
}
func (k *Keeper) SetUsageKeepers(usageKeepers []types.AuctionUsageKeeper) {
k.usageKeepers = usageKeepers
}
func (k Keeper) GetUsageKeepers() []types.AuctionUsageKeeper {
return k.usageKeepers
}
// Generates Auction Id -> Auction index key.
func GetAuctionIndexKey(id string) []byte {
return append(PrefixIDToAuctionIndex, []byte(id)...)
}
// Generates Owner -> Auctions index key.
func GetOwnerToAuctionsIndexKey(owner string, auctionID string) []byte {
return append(append(prefixOwnerToAuctionsIndex, []byte(owner)...), []byte(auctionID)...)
}
func GetBidderToAuctionsIndexKey(bidder string, auctionID string) []byte {
return append(append(PrefixBidderToAuctionsIndex, []byte(bidder)...), []byte(auctionID)...)
}
func GetBidIndexKey(auctionID string, bidder string) []byte {
return append(GetAuctionBidsIndexPrefix(auctionID), []byte(bidder)...)
}
func GetAuctionBidsIndexPrefix(auctionID string) []byte {
return append(append(PrefixAuctionBidsIndex, []byte(auctionID)...))
}
// SaveAuction - saves a auction to the store.
func (k Keeper) SaveAuction(ctx sdk.Context, auction *types.Auction) {
store := ctx.KVStore(k.storeKey)
// Auction Id -> Auction index.
store.Set(GetAuctionIndexKey(auction.Id), k.cdc.MustMarshal(auction))
// Owner -> [Auction] index.
store.Set(GetOwnerToAuctionsIndexKey(auction.OwnerAddress, auction.Id), []byte{})
// Notify interested parties.
for _, keeper := range k.usageKeepers {
keeper.OnAuction(ctx, auction.Id)
}
}
func (k Keeper) SaveBid(ctx sdk.Context, bid *types.Bid) {
store := ctx.KVStore(k.storeKey)
store.Set(GetBidIndexKey(bid.AuctionId, bid.BidderAddress), k.cdc.MustMarshal(bid))
store.Set(GetBidderToAuctionsIndexKey(bid.BidderAddress, bid.AuctionId), []byte{})
// Notify interested parties.
for _, keeper := range k.usageKeepers {
keeper.OnAuctionBid(ctx, bid.AuctionId, bid.BidderAddress)
}
}
func (k Keeper) DeleteBid(ctx sdk.Context, bid types.Bid) {
store := ctx.KVStore(k.storeKey)
store.Delete(GetBidIndexKey(bid.AuctionId, bid.BidderAddress))
store.Delete(GetOwnerToAuctionsIndexKey(bid.BidderAddress, bid.AuctionId))
}
// HasAuction - checks if a auction by the given Id exists.
func (k Keeper) HasAuction(ctx sdk.Context, id string) bool {
store := ctx.KVStore(k.storeKey)
return store.Has(GetAuctionIndexKey(id))
}
func (k Keeper) HasBid(ctx sdk.Context, id string, bidder string) bool {
store := ctx.KVStore(k.storeKey)
return store.Has(GetBidIndexKey(id, bidder))
}
// DeleteAuction - deletes the auction.
func (k Keeper) DeleteAuction(ctx sdk.Context, auction types.Auction) {
// Delete all bids first.
bids := k.GetBids(ctx, auction.Id)
for _, bid := range bids {
k.DeleteBid(ctx, *bid)
}
// Delete the auction itself.
store := ctx.KVStore(k.storeKey)
store.Delete(GetAuctionIndexKey(auction.Id))
store.Delete(GetOwnerToAuctionsIndexKey(auction.OwnerAddress, auction.Id))
}
// GetAuction - gets a record from the store.
func (k Keeper) GetAuction(ctx sdk.Context, id string) *types.Auction {
store := ctx.KVStore(k.storeKey)
auctionKey := GetAuctionIndexKey(id)
if !store.Has(auctionKey) {
return nil
}
bz := store.Get(auctionKey)
var obj types.Auction
k.cdc.MustUnmarshal(bz, &obj)
return &obj
}
// GetBids gets the auction bids.
func (k Keeper) GetBids(ctx sdk.Context, id string) []*types.Bid {
store := ctx.KVStore(k.storeKey)
bids := []*types.Bid{}
itr := sdk.KVStorePrefixIterator(store, GetAuctionBidsIndexPrefix(id))
defer itr.Close()
for ; itr.Valid(); itr.Next() {
bz := store.Get(itr.Key())
if bz != nil {
var obj types.Bid
k.cdc.MustUnmarshal(bz, &obj)
bids = append(bids, &obj)
}
}
return bids
}
func (k Keeper) GetBid(ctx sdk.Context, id string, bidder string) types.Bid {
store := ctx.KVStore(k.storeKey)
bz := store.Get(GetBidIndexKey(id, bidder))
var obj types.Bid
k.cdc.MustUnmarshal(bz, &obj)
return obj
}
// ListAuctions - get all auctions.
func (k Keeper) ListAuctions(ctx sdk.Context) []types.Auction {
var auctions []types.Auction
store := ctx.KVStore(k.storeKey)
itr := sdk.KVStorePrefixIterator(store, PrefixIDToAuctionIndex)
defer itr.Close()
for ; itr.Valid(); itr.Next() {
bz := store.Get(itr.Key())
if bz != nil {
var obj types.Auction
k.cdc.MustUnmarshal(bz, &obj)
auctions = append(auctions, obj)
}
}
return auctions
}
// QueryAuctionsByOwner - query auctions by owner.
func (k Keeper) QueryAuctionsByOwner(ctx sdk.Context, ownerAddress string) []types.Auction {
auctions := []types.Auction{}
ownerPrefix := append(prefixOwnerToAuctionsIndex, []byte(ownerAddress)...)
store := ctx.KVStore(k.storeKey)
itr := sdk.KVStorePrefixIterator(store, ownerPrefix)
defer itr.Close()
for ; itr.Valid(); itr.Next() {
auctionID := itr.Key()[len(ownerPrefix):]
bz := store.Get(append(PrefixIDToAuctionIndex, auctionID...))
if bz != nil {
var obj types.Auction
k.cdc.MustUnmarshal(bz, &obj)
auctions = append(auctions, obj)
}
}
return auctions
}
// QueryAuctionsByBidder - query auctions by bidder
func (k Keeper) QueryAuctionsByBidder(ctx sdk.Context, bidderAddress string) []types.Auction {
auctions := []types.Auction{}
bidderPrefix := append(PrefixBidderToAuctionsIndex, []byte(bidderAddress)...)
store := ctx.KVStore(k.storeKey)
itr := sdk.KVStorePrefixIterator(store, []byte(bidderPrefix))
defer itr.Close()
for ; itr.Valid(); itr.Next() {
auctionID := itr.Key()[len(bidderPrefix):]
bz := store.Get(append(PrefixIDToAuctionIndex, auctionID...))
if bz != nil {
var obj types.Auction
k.cdc.MustUnmarshal(bz, &obj)
auctions = append(auctions, obj)
}
}
return auctions
}
// MatchAuctions - get all matching auctions.
func (k Keeper) MatchAuctions(ctx sdk.Context, matchFn func(*types.Auction) bool) []*types.Auction {
var auctions []*types.Auction
store := ctx.KVStore(k.storeKey)
itr := sdk.KVStorePrefixIterator(store, PrefixIDToAuctionIndex)
defer itr.Close()
for ; itr.Valid(); itr.Next() {
bz := store.Get(itr.Key())
if bz != nil {
var obj types.Auction
k.cdc.MustUnmarshal(bz, &obj)
if matchFn(&obj) {
auctions = append(auctions, &obj)
}
}
}
return auctions
}
// CreateAuction creates a new auction.
func (k Keeper) CreateAuction(ctx sdk.Context, msg types.MsgCreateAuction) (*types.Auction, error) {
// Might be called from another module directly, always validate.
err := msg.ValidateBasic()
if err != nil {
return nil, err
}
signerAddress, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return nil, err
}
// Generate auction Id.
account := k.accountKeeper.GetAccount(ctx, signerAddress)
if account == nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "Account not found.")
}
auctionID := types.AuctionID{
Address: signerAddress,
AccNum: account.GetAccountNumber(),
Sequence: account.GetSequence(),
}.Generate()
// Compute timestamps.
now := ctx.BlockTime()
commitsEndTime := now.Add(time.Duration(msg.CommitsDuration))
revealsEndTime := now.Add(time.Duration(msg.CommitsDuration + msg.RevealsDuration))
auction := types.Auction{
Id: auctionID,
Status: types.AuctionStatusCommitPhase,
OwnerAddress: signerAddress.String(),
CreateTime: now,
CommitsEndTime: commitsEndTime,
RevealsEndTime: revealsEndTime,
CommitFee: msg.CommitFee,
RevealFee: msg.RevealFee,
MinimumBid: msg.MinimumBid,
}
// Save auction in store.
k.SaveAuction(ctx, &auction)
return &auction, nil
}
func (k Keeper) CommitBid(ctx sdk.Context, msg types.MsgCommitBid) (*types.Bid, error) {
if !k.HasAuction(ctx, msg.AuctionId) {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Auction not found.")
}
auction := k.GetAuction(ctx, msg.AuctionId)
if auction.Status != types.AuctionStatusCommitPhase {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Auction is not in commit phase.")
}
signerAddress, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return nil, err
}
// Take auction fees from account.
totalFee := auction.CommitFee.Add(auction.RevealFee)
sdkErr := k.bankKeeper.SendCoinsFromAccountToModule(ctx, signerAddress, types.ModuleName, sdk.NewCoins(totalFee))
if sdkErr != nil {
return nil, sdkErr
}
// Check if an old bid already exists, if so, return old bids auction fee (update bid scenario).
bidder := signerAddress.String()
if k.HasBid(ctx, msg.AuctionId, bidder) {
oldBid := k.GetBid(ctx, msg.AuctionId, bidder)
oldTotalFee := oldBid.CommitFee.Add(oldBid.RevealFee)
sdkErr := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, signerAddress, sdk.NewCoins(oldTotalFee))
if sdkErr != nil {
return nil, sdkErr
}
}
// Save new bid.
bid := types.Bid{
AuctionId: msg.AuctionId,
BidderAddress: bidder,
Status: types.BidStatusCommitted,
CommitHash: msg.CommitHash,
CommitTime: ctx.BlockTime(),
CommitFee: auction.CommitFee,
RevealFee: auction.RevealFee,
}
k.SaveBid(ctx, &bid)
return &bid, nil
}
// RevealBid reeals a bid comitted earlier.
func (k Keeper) RevealBid(ctx sdk.Context, msg types.MsgRevealBid) (*types.Auction, error) {
if !k.HasAuction(ctx, msg.AuctionId) {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Auction not found.")
}
auction := k.GetAuction(ctx, msg.AuctionId)
if auction.Status != types.AuctionStatusRevealPhase {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Auction is not in reveal phase.")
}
signerAddress, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return nil, err
}
if !k.HasBid(ctx, msg.AuctionId, signerAddress.String()) {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bid not found.")
}
bid := k.GetBid(ctx, auction.Id, signerAddress.String())
if bid.Status != types.BidStatusCommitted {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bid not in committed state.")
}
revealBytes, err := hex.DecodeString(msg.Reveal)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal string.")
}
cid, err := wnsUtils.CIDFromJSONBytes(revealBytes)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal JSON.")
}
if bid.CommitHash != cid {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Commit hash mismatch.")
}
var reveal map[string]interface{}
err = json.Unmarshal(revealBytes, &reveal)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Reveal JSON unmarshal error.")
}
chainID, err := wnsUtils.GetAttributeAsString(reveal, "chainId")
if err != nil || chainID != ctx.ChainID() {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal chainID.")
}
auctionID, err := wnsUtils.GetAttributeAsString(reveal, "auctionId")
if err != nil || auctionID != msg.AuctionId {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal auction Id.")
}
bidderAddress, err := wnsUtils.GetAttributeAsString(reveal, "bidderAddress")
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid address.")
}
if bidderAddress != signerAddress.String() {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Reveal bid address mismatch.")
}
bidAmountStr, err := wnsUtils.GetAttributeAsString(reveal, "bidAmount")
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid amount.")
}
bidAmount, err := sdk.ParseCoinNormalized(bidAmountStr)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid amount.")
}
if bidAmount.IsLT(auction.MinimumBid) {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bid is lower than minimum bid.")
}
// Lock bid amount.
sdkErr := k.bankKeeper.SendCoinsFromAccountToModule(ctx, signerAddress, types.ModuleName, sdk.NewCoins(bidAmount))
if sdkErr != nil {
return nil, sdkErr
}
// Update bid.
bid.BidAmount = bidAmount
bid.RevealTime = ctx.BlockTime()
bid.Status = types.BidStatusRevealed
k.SaveBid(ctx, &bid)
return auction, nil
}
// GetAuctionModuleBalances gets the auction module account(s) balances.
func (k Keeper) GetAuctionModuleBalances(ctx sdk.Context) sdk.Coins {
moduleAddress := k.accountKeeper.GetModuleAddress(types.ModuleName)
balances := k.bankKeeper.GetAllBalances(ctx, moduleAddress)
return balances
}
func (k Keeper) EndBlockerProcessAuctions(ctx sdk.Context) {
// Transition auction state (commit, reveal, expired, completed).
k.processAuctionPhases(ctx)
// Delete stale auctions.
k.deleteCompletedAuctions(ctx)
}
func (k Keeper) processAuctionPhases(ctx sdk.Context) {
auctions := k.MatchAuctions(ctx, func(_ *types.Auction) bool {
return true
})
for _, auction := range auctions {
// Commit -> Reveal state.
if auction.Status == types.AuctionStatusCommitPhase && ctx.BlockTime().After(auction.CommitsEndTime) {
auction.Status = types.AuctionStatusRevealPhase
k.SaveAuction(ctx, auction)
ctx.Logger().Info(fmt.Sprintf("Moved auction %s to reveal phase.", auction.Id))
}
// Reveal -> Expired state.
if auction.Status == types.AuctionStatusRevealPhase && ctx.BlockTime().After(auction.RevealsEndTime) {
auction.Status = types.AuctionStatusExpired
k.SaveAuction(ctx, auction)
ctx.Logger().Info(fmt.Sprintf("Moved auction %s to expired state.", auction.Id))
}
// If auction has expired, pick a winner from revealed bids.
if auction.Status == types.AuctionStatusExpired {
k.pickAuctionWinner(ctx, auction)
}
}
}
// Delete completed stale auctions.
func (k Keeper) deleteCompletedAuctions(ctx sdk.Context) {
auctions := k.MatchAuctions(ctx, func(auction *types.Auction) bool {
deleteTime := auction.RevealsEndTime.Add(CompletedAuctionDeleteTimeout)
return auction.Status == types.AuctionStatusCompleted && ctx.BlockTime().After(deleteTime)
})
for _, auction := range auctions {
ctx.Logger().Info(fmt.Sprintf("Deleting completed auction %s after timeout.", auction.Id))
k.DeleteAuction(ctx, *auction)
}
}
func (k Keeper) pickAuctionWinner(ctx sdk.Context, auction *types.Auction) {
ctx.Logger().Info(fmt.Sprintf("Picking auction %s winner.", auction.Id))
var highestBid *types.Bid
var secondHighestBid *types.Bid
bids := k.GetBids(ctx, auction.Id)
for _, bid := range bids {
ctx.Logger().Info(fmt.Sprintf("Processing bid %s %s", bid.BidderAddress, bid.BidAmount.String()))
// Only consider revealed bids.
if bid.Status != types.BidStatusRevealed {
ctx.Logger().Info(fmt.Sprintf("Ignoring unrevealed bid %s %s", bid.BidderAddress, bid.BidAmount.String()))
continue
}
// Init highest bid.
if highestBid == nil {
highestBid = bid
ctx.Logger().Info(fmt.Sprintf("Initializing 1st bid %s %s", bid.BidderAddress, bid.BidAmount.String()))
continue
}
if highestBid.BidAmount.IsLT(bid.BidAmount) {
ctx.Logger().Info(fmt.Sprintf("New highest bid %s %s", bid.BidderAddress, bid.BidAmount.String()))
secondHighestBid = highestBid
highestBid = bid
ctx.Logger().Info(fmt.Sprintf("Updated 1st bid %s %s", highestBid.BidderAddress, highestBid.BidAmount.String()))
ctx.Logger().Info(fmt.Sprintf("Updated 2nd bid %s %s", secondHighestBid.BidderAddress, secondHighestBid.BidAmount.String()))
} else if secondHighestBid == nil || secondHighestBid.BidAmount.IsLT(bid.BidAmount) {
ctx.Logger().Info(fmt.Sprintf("New 2nd highest bid %s %s", bid.BidderAddress, bid.BidAmount.String()))
secondHighestBid = bid
ctx.Logger().Info(fmt.Sprintf("Updated 2nd bid %s %s", secondHighestBid.BidderAddress, secondHighestBid.BidAmount.String()))
} else {
ctx.Logger().Info(fmt.Sprintf("Ignoring bid as it doesn't affect 1st/2nd price %s %s", bid.BidderAddress, bid.BidAmount.String()))
}
}
// Highest bid is the winner, but pays second highest bid price.
auction.Status = types.AuctionStatusCompleted
if highestBid != nil {
auction.WinnerAddress = highestBid.BidderAddress
auction.WinningBid = highestBid.BidAmount
// Winner pays 2nd price, if a 2nd price exists.
auction.WinningPrice = highestBid.BidAmount
if secondHighestBid != nil {
auction.WinningPrice = secondHighestBid.BidAmount
}
ctx.Logger().Info(fmt.Sprintf("Auction %s winner %s.", auction.Id, auction.WinnerAddress))
ctx.Logger().Info(fmt.Sprintf("Auction %s winner bid %s.", auction.Id, auction.WinningBid.String()))
ctx.Logger().Info(fmt.Sprintf("Auction %s winner price %s.", auction.Id, auction.WinningPrice.String()))
} else {
ctx.Logger().Info(fmt.Sprintf("Auction %s has no valid revealed bids (no winner).", auction.Id))
}
k.SaveAuction(ctx, auction)
for _, bid := range bids {
bidderAddress, err := sdk.AccAddressFromBech32(bid.BidderAddress)
if err != nil {
ctx.Logger().Error(fmt.Sprintf("Invalid bidderAddress address. %v", err))
panic("Invalid bidder address.")
}
if bid.Status == types.BidStatusRevealed {
// Send reveal fee back to bidders that've revealed the bid.
sdkErr := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, bidderAddress, sdk.NewCoins(bid.RevealFee))
if sdkErr != nil {
ctx.Logger().Error(fmt.Sprintf("Auction error returning reveal fee: %v", sdkErr))
panic(sdkErr)
}
}
// Send back locked bid amount to all bidders.
sdkErr := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, bidderAddress, sdk.NewCoins(bid.BidAmount))
if sdkErr != nil {
ctx.Logger().Error(fmt.Sprintf("Auction error returning bid amount: %v", sdkErr))
panic(sdkErr)
}
}
// Process winner account (if nobody bids, there won't be a winner).
if auction.WinnerAddress != "" {
winnerAddress, err := sdk.AccAddressFromBech32(auction.WinnerAddress)
if err != nil {
ctx.Logger().Error(fmt.Sprintf("Invalid winner address. %v", err))
panic("Invalid winner address.")
}
// Take 2nd price from winner.
sdkErr := k.bankKeeper.SendCoinsFromAccountToModule(ctx, winnerAddress, types.ModuleName, sdk.NewCoins(auction.WinningPrice))
if sdkErr != nil {
ctx.Logger().Error(fmt.Sprintf("Auction error taking funds from winner: %v", sdkErr))
panic(sdkErr)
}
// Burn anything over the min. bid amount.
amountToBurn := auction.WinningPrice.Sub(auction.MinimumBid)
if amountToBurn.IsNegative() {
ctx.Logger().Error(fmt.Sprintf("Auction coins to burn cannot be negative."))
panic("Auction coins to burn cannot be negative.")
}
// Use auction burn module account instead of actually burning coins to better keep track of supply.
sdkErr = k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, types.AuctionBurnModuleAccountName, sdk.NewCoins(amountToBurn))
if sdkErr != nil {
ctx.Logger().Error(fmt.Sprintf("Auction error burning coins: %v", sdkErr))
panic(sdkErr)
}
}
// Notify other modules (hook).
ctx.Logger().Info(fmt.Sprintf("Auction %s notifying %d modules.", auction.Id, len(k.usageKeepers)))
for _, keeper := range k.usageKeepers {
ctx.Logger().Info(fmt.Sprintf("Auction %s notifying module %s.", auction.Id, keeper.ModuleName()))
keeper.OnAuctionWinnerSelected(ctx, auction.Id)
}
}

View File

@ -0,0 +1,51 @@
package keeper_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tharsis/ethermint/app"
auctionkeeper "github.com/tharsis/ethermint/x/auction/keeper"
"github.com/tharsis/ethermint/x/auction/types"
)
type KeeperTestSuite struct {
suite.Suite
app *app.EthermintApp
ctx sdk.Context
queryClient types.QueryClient
}
func (suite *KeeperTestSuite) SetupTest() {
testApp := app.Setup(false)
ctx := testApp.BaseApp.NewContext(false, tmproto.Header{})
querier := auctionkeeper.Querier{Keeper: testApp.AuctionKeeper}
queryHelper := baseapp.NewQueryServerTestHelper(ctx, testApp.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, querier)
queryClient := types.NewQueryClient(queryHelper)
suite.app, suite.ctx, suite.queryClient = testApp, ctx, queryClient
}
func TestParams(t *testing.T) {
testApp := app.Setup(false)
ctx := testApp.BaseApp.NewContext(false, tmproto.Header{})
expParams := types.DefaultParams()
params := testApp.AuctionKeeper.GetParams(ctx)
require.Equal(t, expParams.CommitsDuration, params.CommitsDuration)
require.Equal(t, expParams.RevealsDuration, params.RevealsDuration)
require.Equal(t, expParams.CommitFee, params.CommitFee)
require.Equal(t, expParams.RevealFee, params.RevealFee)
require.Equal(t, expParams.MinimumBid, params.MinimumBid)
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

View File

@ -0,0 +1,110 @@
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tharsis/ethermint/x/auction/types"
)
type msgServer struct {
Keeper
}
func NewMsgServer(keeper Keeper) types.MsgServer {
return &msgServer{Keeper: keeper}
}
var _ types.MsgServer = msgServer{}
func (s msgServer) CreateAuction(c context.Context, msg *types.MsgCreateAuction) (*types.MsgCreateAuctionResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
signerAddress, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return nil, err
}
resp, err := s.Keeper.CreateAuction(ctx, *msg)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeCreateAuction,
sdk.NewAttribute(types.AttributeKeyCommitsDuration, msg.CommitsDuration.String()),
sdk.NewAttribute(types.AttributeKeyCommitFee, msg.CommitFee.String()),
sdk.NewAttribute(types.AttributeKeyRevealFee, msg.RevealFee.String()),
sdk.NewAttribute(types.AttributeKeyMinimumBid, msg.MinimumBid.String()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(types.AttributeKeySigner, signerAddress.String()),
),
})
return &types.MsgCreateAuctionResponse{Auction: resp}, nil
}
// CommitBid is the command for committing a bid
func (s msgServer) CommitBid(c context.Context, msg *types.MsgCommitBid) (*types.MsgCommitBidResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
signerAddress, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return nil, err
}
resp, err := s.Keeper.CommitBid(ctx, *msg)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeCommitBid,
sdk.NewAttribute(types.AttributeKeyAuctionID, msg.AuctionId),
sdk.NewAttribute(types.AttributeKeyCommitHash, msg.CommitHash),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(types.AttributeKeySigner, signerAddress.String()),
),
})
return &types.MsgCommitBidResponse{Bid: resp}, nil
}
//RevealBid is the command for revealing a bid
func (s msgServer) RevealBid(c context.Context, msg *types.MsgRevealBid) (*types.MsgRevealBidResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
signerAddress, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return nil, err
}
resp, err := s.Keeper.RevealBid(ctx, *msg)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeRevealBid,
sdk.NewAttribute(types.AttributeKeyAuctionID, msg.AuctionId),
sdk.NewAttribute(types.AttributeKeyReveal, msg.Reveal),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(types.AttributeKeySigner, signerAddress.String()),
),
})
return &types.MsgRevealBidResponse{Auction: resp}, nil
}

View File

@ -0,0 +1,18 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tharsis/ethermint/x/auction/types"
)
// GetParams - Get all parameteras as types.Params.
func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
k.paramSubspace.GetParamSet(ctx, &params)
return
}
// SetParams - set the params.
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
k.paramSubspace.SetParamSet(ctx, &params)
}

142
x/auction/module.go Normal file
View File

@ -0,0 +1,142 @@
package auction
import (
"context"
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tharsis/ethermint/x/auction/client/cli"
"github.com/tharsis/ethermint/x/auction/keeper"
"github.com/tharsis/ethermint/x/auction/types"
)
// type check to ensure the interface is properly implemented
var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
)
// app module Basics object
type AppModuleBasic struct {
cdc codec.Codec
}
func (b AppModuleBasic) Name() string {
return types.ModuleName
}
func (b AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
types.RegisterLegacyAminoCodec(cdc)
}
func (b AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
types.RegisterInterfaces(registry)
}
func (b AppModuleBasic) DefaultGenesis(jsonCodec codec.JSONCodec) json.RawMessage {
return jsonCodec.MustMarshalJSON(types.DefaultGenesisState())
}
// Validation check of the Genesis
func (b AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
var data types.GenesisState
err := cdc.UnmarshalJSON(bz, &data)
if err != nil {
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
}
// Once json successfully marshalled, passes along to genesis.go
return ValidateGenesis(data)
}
// Register rest routes
func (b AppModuleBasic) RegisterRESTRoutes(ctx client.Context, rtr *mux.Router) {
// No-op.
}
func (b AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, serveMux *runtime.ServeMux) {
err := types.RegisterQueryHandlerClient(context.Background(), serveMux, types.NewQueryClient(clientCtx))
if err != nil {
panic(err)
}
}
// Get the root query command of this module
func (b AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd()
}
// Get the root tx command of this module
func (b AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.GetTxCmd()
}
type AppModule struct {
AppModuleBasic
keeper keeper.Keeper
}
// NewAppModule creates a new AppModule Object
func NewAppModule(cdc codec.Codec, k keeper.Keeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{cdc: cdc},
keeper: k,
}
}
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, am.keeper)
}
func (am AppModule) Route() sdk.Route {
return sdk.Route{}
}
func (am AppModule) QuerierRoute() string {
return types.QuerierRoute
}
func (am AppModule) LegacyQuerierHandler(cdc *codec.LegacyAmino) sdk.Querier {
return nil
}
func (am AppModule) RegisterServices(cfg module.Configurator) {
querier := keeper.Querier{Keeper: am.keeper}
types.RegisterQueryServer(cfg.QueryServer(), querier)
msgServer := keeper.NewMsgServer(am.keeper)
types.RegisterMsgServer(cfg.MsgServer(), msgServer)
}
func (am AppModule) ConsensusVersion() uint64 {
return 1
}
func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return EndBlocker(ctx, am.keeper)
}
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState types.GenesisState
cdc.MustUnmarshalJSON(data, &genesisState)
InitGenesis(ctx, am.keeper, genesisState)
return []abci.ValidatorUpdate{}
}
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
gs := ExportGenesis(ctx, am.keeper)
return cdc.MustMarshalJSON(&gs)
}

24
x/auction/module_test.go Normal file
View File

@ -0,0 +1,24 @@
package auction_test
import (
"testing"
"github.com/stretchr/testify/require"
abcitypes "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
app2 "github.com/tharsis/ethermint/app"
auctiontypes "github.com/tharsis/ethermint/x/auction/types"
)
func TestItCreatesModuleAccountOnInitBlock(t *testing.T) {
app := app2.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
app.InitChain(abcitypes.RequestInitChain{
AppStateBytes: []byte("{}"),
ChainId: "test-chain-id",
})
acc := app.AccountKeeper.GetModuleAccount(ctx, auctiontypes.ModuleName)
require.NotNil(t, acc)
}

37
x/auction/types/codec.go Normal file
View File

@ -0,0 +1,37 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)
// RegisterLegacyAminoCodec registers the necessary x/auction interfaces and concrete types
// on the provided LegacyAmino codec. These types are used for Amino JSON serialization.
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MsgCreateAuction{}, "auction/MsgCreateAuction", nil)
cdc.RegisterConcrete(&MsgCommitBid{}, "auction/MsgCommitBid", nil)
cdc.RegisterConcrete(&MsgRevealBid{}, "auction/MsgRevealBid", nil)
}
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.Msg)(nil),
&MsgCreateAuction{},
&MsgCommitBid{},
&MsgRevealBid{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
var (
amino = codec.NewLegacyAmino()
ModuleCdc = codec.NewAminoCodec(amino)
)
func init() {
RegisterLegacyAminoCodec(amino)
cryptocodec.RegisterCrypto(amino)
amino.Seal()
}

19
x/auction/types/events.go Normal file
View File

@ -0,0 +1,19 @@
package types
const (
EventTypeCreateAuction = "create-auction"
EventTypeCommitBid = "commit-bid"
EventTypeRevealBid = "reveal-bid"
AttributeKeyCommitsDuration = "commits-duration"
AttributeKeyRevealsDuration = "reveals-duration"
AttributeKeyCommitFee = "commit-fee"
AttributeKeyRevealFee = "reveal-fee"
AttributeKeyMinimumBid = "minimum-bid"
AttributeKeySigner = "signer"
AttributeKeyAuctionID = "auction-id"
AttributeKeyCommitHash = "commit-hash"
AttributeKeyReveal = "reveal"
AttributeValueCategory = ModuleName
)

View File

@ -0,0 +1,16 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// AuctionUsageKeeper keep track of auction usage in other modules.
// Used to, for example, prevent deletion of a auction that's in use.
type AuctionUsageKeeper interface {
ModuleName() string
UsesAuction(ctx sdk.Context, auctionID string) bool
OnAuction(ctx sdk.Context, auctionID string)
OnAuctionBid(ctx sdk.Context, auctionID string, bidderAddress string)
OnAuctionWinnerSelected(ctx sdk.Context, auctionID string)
}

View File

@ -0,0 +1,9 @@
package types
// DefaultGenesisState sets default evm genesis state with empty accounts and default params and
// chain config values.
func DefaultGenesisState() *GenesisState {
return &GenesisState{
Params: DefaultParams(),
}
}

View File

@ -0,0 +1,389 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: vulcanize/auction/v1beta1/genesis.proto
package types
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// GenesisState defines the genesis state of the auction module
type GenesisState struct {
Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"`
Auctions []*Auction `protobuf:"bytes,2,rep,name=auctions,proto3" json:"auctions,omitempty" json:"bonds" yaml:"bonds"`
}
func (m *GenesisState) Reset() { *m = GenesisState{} }
func (m *GenesisState) String() string { return proto.CompactTextString(m) }
func (*GenesisState) ProtoMessage() {}
func (*GenesisState) Descriptor() ([]byte, []int) {
return fileDescriptor_23ebfbd3a1e67fe6, []int{0}
}
func (m *GenesisState) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *GenesisState) XXX_Merge(src proto.Message) {
xxx_messageInfo_GenesisState.Merge(m, src)
}
func (m *GenesisState) XXX_Size() int {
return m.Size()
}
func (m *GenesisState) XXX_DiscardUnknown() {
xxx_messageInfo_GenesisState.DiscardUnknown(m)
}
var xxx_messageInfo_GenesisState proto.InternalMessageInfo
func (m *GenesisState) GetParams() Params {
if m != nil {
return m.Params
}
return Params{}
}
func (m *GenesisState) GetAuctions() []*Auction {
if m != nil {
return m.Auctions
}
return nil
}
func init() {
proto.RegisterType((*GenesisState)(nil), "vulcanize.auction.v1beta1.GenesisState")
}
func init() {
proto.RegisterFile("vulcanize/auction/v1beta1/genesis.proto", fileDescriptor_23ebfbd3a1e67fe6)
}
var fileDescriptor_23ebfbd3a1e67fe6 = []byte{
// 264 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2f, 0x2b, 0xcd, 0x49,
0x4e, 0xcc, 0xcb, 0xac, 0x4a, 0xd5, 0x4f, 0x2c, 0x4d, 0x2e, 0xc9, 0xcc, 0xcf, 0xd3, 0x2f, 0x33,
0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28,
0xca, 0x2f, 0xc9, 0x17, 0x92, 0x84, 0x2b, 0xd4, 0x83, 0x2a, 0xd4, 0x83, 0x2a, 0x94, 0x12, 0x49,
0xcf, 0x4f, 0xcf, 0x07, 0xab, 0xd2, 0x07, 0xb1, 0x20, 0x1a, 0xa4, 0x54, 0x71, 0x9b, 0x5c, 0x52,
0x59, 0x90, 0x0a, 0x35, 0x57, 0x69, 0x1d, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xa6, 0xe0, 0x92, 0xc4,
0x92, 0x54, 0x21, 0x7b, 0x2e, 0xb6, 0x82, 0xc4, 0xa2, 0xc4, 0xdc, 0x62, 0x09, 0x46, 0x05, 0x46,
0x0d, 0x6e, 0x23, 0x45, 0x3d, 0x9c, 0x36, 0xeb, 0x05, 0x80, 0x15, 0x3a, 0xb1, 0x9c, 0xb8, 0x27,
0xcf, 0x10, 0x04, 0xd5, 0x26, 0x14, 0xcb, 0xc5, 0x01, 0x55, 0x57, 0x2c, 0xc1, 0xa4, 0xc0, 0xac,
0xc1, 0x6d, 0xa4, 0x84, 0xc7, 0x08, 0x47, 0x08, 0xdf, 0x49, 0xf6, 0xd3, 0x3d, 0x79, 0xc9, 0xac,
0xe2, 0xfc, 0x3c, 0x2b, 0xa5, 0xa4, 0xfc, 0xbc, 0x94, 0x62, 0x25, 0x85, 0xca, 0xc4, 0xdc, 0x1c,
0x18, 0x27, 0x08, 0x6e, 0xa4, 0x93, 0xdb, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e,
0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31,
0x44, 0xe9, 0xa4, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x97, 0x64, 0x24,
0x16, 0x15, 0x67, 0x16, 0xeb, 0xa7, 0x96, 0x64, 0xa4, 0x16, 0xe5, 0x66, 0xe6, 0x95, 0xe8, 0x57,
0xc0, 0x83, 0x01, 0xec, 0xfd, 0x24, 0x36, 0xb0, 0xff, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff,
0x40, 0x0a, 0x31, 0x1a, 0x82, 0x01, 0x00, 0x00,
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Auctions) > 0 {
for iNdEx := len(m.Auctions) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Auctions[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
}
}
{
size, err := m.Params.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
return len(dAtA) - i, nil
}
func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int {
offset -= sovGenesis(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *GenesisState) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = m.Params.Size()
n += 1 + l + sovGenesis(uint64(l))
if len(m.Auctions) > 0 {
for _, e := range m.Auctions {
l = e.Size()
n += 1 + l + sovGenesis(uint64(l))
}
}
return n
}
func sovGenesis(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozGenesis(x uint64) (n int) {
return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *GenesisState) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GenesisState: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Auctions", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Auctions = append(m.Auctions, &Auction{})
if err := m.Auctions[len(m.Auctions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipGenesis(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthGenesis
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupGenesis
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthGenesis
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group")
)

18
x/auction/types/key.go Normal file
View File

@ -0,0 +1,18 @@
package types
const (
// ModuleName is the name of the module
ModuleName = "auction"
// AuctionBurnModuleAccountName is the name of the auction burn module account.
AuctionBurnModuleAccountName = "auction_burn"
// StoreKey to be used when creating the KVStore
StoreKey = ModuleName
// QuerierRoute is the querier route for the staking module
QuerierRoute = ModuleName
// RouterKey is the msg router key for the staking module
RouterKey = ModuleName
)

150
x/auction/types/msgs.go Normal file
View File

@ -0,0 +1,150 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
var (
_ sdk.Msg = &MsgCreateAuction{}
_ sdk.Msg = &MsgCommitBid{}
_ sdk.Msg = &MsgRevealBid{}
)
// NewMsgCreateAuction is the constructor function for MsgCreateAuction.
func NewMsgCreateAuction(params Params, signer sdk.AccAddress) MsgCreateAuction {
return MsgCreateAuction{
CommitsDuration: params.CommitsDuration,
RevealsDuration: params.RevealsDuration,
CommitFee: params.CommitFee,
RevealFee: params.RevealFee,
MinimumBid: params.MinimumBid,
Signer: signer.String(),
}
}
// Route Implements Msg.
func (msg MsgCreateAuction) Route() string { return RouterKey }
// Type Implements Msg.
func (msg MsgCreateAuction) Type() string { return "create" }
// ValidateBasic Implements Msg.
func (msg MsgCreateAuction) ValidateBasic() error {
if msg.Signer == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
}
if msg.CommitsDuration <= 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "commit phase duration invalid.")
}
if msg.RevealsDuration <= 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "reveal phase duration invalid.")
}
if !msg.MinimumBid.IsPositive() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "minimum bid should be greater than zero.")
}
return nil
}
// GetSignBytes Implements Msg.
func (msg MsgCreateAuction) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg))
}
// GetSigners Implements Msg.
func (msg MsgCreateAuction) GetSigners() []sdk.AccAddress {
accAddr, _ := sdk.AccAddressFromBech32(msg.Signer)
return []sdk.AccAddress{accAddr}
}
// NewMsgCommitBid is the constructor function for MsgCommitBid.
func NewMsgCommitBid(auctionID string, commitHash string, signer sdk.AccAddress) MsgCommitBid {
return MsgCommitBid{
AuctionId: auctionID,
CommitHash: commitHash,
Signer: signer.String(),
}
}
// Route Implements Msg.
func (msg MsgCommitBid) Route() string { return RouterKey }
// Type Implements Msg.
func (msg MsgCommitBid) Type() string { return "commit" }
// ValidateBasic Implements Msg.
func (msg MsgCommitBid) ValidateBasic() error {
if msg.Signer == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer address.")
}
if msg.AuctionId == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid auction ID.")
}
if msg.CommitHash == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid commit hash.")
}
return nil
}
// GetSignBytes Implements Msg.
func (msg MsgCommitBid) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg))
}
// GetSigners Implements Msg.
func (msg MsgCommitBid) GetSigners() []sdk.AccAddress {
accAddr, _ := sdk.AccAddressFromBech32(msg.Signer)
return []sdk.AccAddress{accAddr}
}
// NewMsgRevealBid is the constructor function for MsgRevealBid.
func NewMsgRevealBid(auctionID string, reveal string, signer sdk.AccAddress) MsgRevealBid {
return MsgRevealBid{
AuctionId: auctionID,
Reveal: reveal,
Signer: signer.String(),
}
}
// Route Implements Msg.
func (msg MsgRevealBid) Route() string { return RouterKey }
// Type Implements Msg.
func (msg MsgRevealBid) Type() string { return "reveal" }
// ValidateBasic Implements Msg.
func (msg MsgRevealBid) ValidateBasic() error {
if msg.Signer == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer address.")
}
if msg.AuctionId == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid auction ID.")
}
if msg.Reveal == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid reveal data.")
}
return nil
}
// GetSignBytes Implements Msg.
func (msg MsgRevealBid) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg))
}
// GetSigners Implements Msg.
func (msg MsgRevealBid) GetSigners() []sdk.AccAddress {
accAddr, _ := sdk.AccAddressFromBech32(msg.Signer)
return []sdk.AccAddress{accAddr}
}

173
x/auction/types/params.go Normal file
View File

@ -0,0 +1,173 @@
package types
import (
"bytes"
"errors"
"fmt"
"strings"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params/types"
)
// Default parameter namespace.
const (
DefaultParamspace = ModuleName
)
var (
DefaultCommitsDuration = 5 * time.Minute
DefaultRevealsDuration = 5 * time.Minute
DefaultCommitFee = sdk.Coin{Amount: sdk.NewInt(10), Denom: sdk.DefaultBondDenom}
DefaultRevealFee = sdk.Coin{Amount: sdk.NewInt(10), Denom: sdk.DefaultBondDenom}
DefaultMinimumBid = sdk.Coin{Amount: sdk.NewInt(1000), Denom: sdk.DefaultBondDenom}
ParamStoreKeyCommitsDuration = []byte("CommitsDuration")
ParamStoreKeyRevealsDuration = []byte("RevealsDuration")
ParamStoreKeyCommitFee = []byte("CommitFee")
ParamStoreKeyRevealFee = []byte("RevealFee")
ParamStoreKeyMinimumBid = []byte("MinimumBid")
)
var _ types.ParamSet = &Params{}
func NewParams() Params {
return DefaultParams()
}
// ParamKeyTable - ParamTable for bond module.
func ParamKeyTable() types.KeyTable {
return types.NewKeyTable().RegisterParamSet(&Params{})
}
// ParamSetPairs - implements params.ParamSet
func (p *Params) ParamSetPairs() types.ParamSetPairs {
return types.ParamSetPairs{
types.NewParamSetPair(ParamStoreKeyCommitsDuration, &p.CommitsDuration, validateCommitsDuration),
types.NewParamSetPair(ParamStoreKeyRevealsDuration, &p.RevealsDuration, validateRevealsDuration),
types.NewParamSetPair(ParamStoreKeyCommitFee, &p.CommitFee, validateCommitFee),
types.NewParamSetPair(ParamStoreKeyRevealFee, &p.RevealFee, validateRevealFee),
types.NewParamSetPair(ParamStoreKeyMinimumBid, &p.MinimumBid, validateMinimumBid),
}
}
// Equal returns a boolean determining if two Params types are identical.
func (p Params) Equal(p2 Params) bool {
bz1 := ModuleCdc.MustMarshalLengthPrefixed(&p)
bz2 := ModuleCdc.MustMarshalLengthPrefixed(&p2)
return bytes.Equal(bz1, bz2)
}
// DefaultParams returns a default set of parameters.
func DefaultParams() Params {
return Params{
CommitsDuration: DefaultCommitsDuration,
RevealsDuration: DefaultRevealsDuration,
CommitFee: DefaultCommitFee,
RevealFee: DefaultRevealFee,
MinimumBid: DefaultMinimumBid,
}
}
// String returns a human readable string representation of the parameters.
func (p Params) String() string {
var sb strings.Builder
sb.WriteString("Params: \n")
sb.WriteString(fmt.Sprintf("CommitsDuration: %s\n", p.CommitsDuration.String()))
sb.WriteString(fmt.Sprintf("RevealsDuration: %s\n", p.RevealsDuration.String()))
sb.WriteString(fmt.Sprintf("CommitFee: %s\n", p.CommitFee.String()))
sb.WriteString(fmt.Sprintf("RevealFee: %s\n", p.RevealFee.String()))
sb.WriteString(fmt.Sprintf("MinimumBid: %s\n", p.MinimumBid.String()))
return sb.String()
}
func validateCommitsDuration(i interface{}) error {
v, ok := i.(time.Duration)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if v < 0 {
return errors.New("commits duration cannot be negative")
}
return nil
}
func validateRevealsDuration(i interface{}) error {
v, ok := i.(time.Duration)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if v < 0 {
return errors.New("commits duration cannot be negative")
}
return nil
}
func validateCommitFee(i interface{}) error {
v, ok := i.(sdk.Coin)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if v.Amount.IsNegative() {
return errors.New("commit fee must be positive")
}
return nil
}
func validateRevealFee(i interface{}) error {
v, ok := i.(sdk.Coin)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if v.Amount.IsNegative() {
return errors.New("reveal fee must be positive")
}
return nil
}
func validateMinimumBid(i interface{}) error {
v, ok := i.(sdk.Coin)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if v.Amount.IsNegative() {
return errors.New("minimum bid must be positive")
}
return nil
}
// Validate a set of params.
func (p Params) Validate() error {
if err := validateCommitsDuration(p.CommitsDuration); err != nil {
return err
}
if err := validateRevealsDuration(p.RevealsDuration); err != nil {
return err
}
if err := validateCommitFee(p.CommitFee); err != nil {
return err
}
if err := validateRevealFee(p.RevealFee); err != nil {
return err
}
if err := validateMinimumBid(p.MinimumBid); err != nil {
return err
}
return nil
}

3390
x/auction/types/query.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,802 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: vulcanize/auction/v1beta1/query.proto
/*
Package types is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package types
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var (
filter_Query_Auctions_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Query_Auctions_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuctionsRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Auctions_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.Auctions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Auctions_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuctionsRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Auctions_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Auctions(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_GetAuction_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuctionRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.GetAuction(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_GetAuction_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuctionRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := server.GetAuction(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_GetBid_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BidRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["auction_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "auction_id")
}
protoReq.AuctionId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "auction_id", err)
}
val, ok = pathParams["bidder"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "bidder")
}
protoReq.Bidder, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "bidder", err)
}
msg, err := client.GetBid(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_GetBid_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BidRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["auction_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "auction_id")
}
protoReq.AuctionId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "auction_id", err)
}
val, ok = pathParams["bidder"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "bidder")
}
protoReq.Bidder, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "bidder", err)
}
msg, err := server.GetBid(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_GetBids_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BidsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["auction_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "auction_id")
}
protoReq.AuctionId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "auction_id", err)
}
msg, err := client.GetBids(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_GetBids_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BidsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["auction_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "auction_id")
}
protoReq.AuctionId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "auction_id", err)
}
msg, err := server.GetBids(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_AuctionsByBidder_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuctionsByBidderRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["bidder_address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "bidder_address")
}
protoReq.BidderAddress, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "bidder_address", err)
}
msg, err := client.AuctionsByBidder(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_AuctionsByBidder_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuctionsByBidderRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["bidder_address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "bidder_address")
}
protoReq.BidderAddress, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "bidder_address", err)
}
msg, err := server.AuctionsByBidder(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_AuctionsByOwner_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuctionsByOwnerRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["owner_address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "owner_address")
}
protoReq.OwnerAddress, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "owner_address", err)
}
msg, err := client.AuctionsByOwner(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_AuctionsByOwner_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuctionsByOwnerRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["owner_address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "owner_address")
}
protoReq.OwnerAddress, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "owner_address", err)
}
msg, err := server.AuctionsByOwner(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_QueryParams_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryParamsRequest
var metadata runtime.ServerMetadata
msg, err := client.QueryParams(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_QueryParams_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryParamsRequest
var metadata runtime.ServerMetadata
msg, err := server.QueryParams(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_Balance_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BalanceRequest
var metadata runtime.ServerMetadata
msg, err := client.Balance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Balance_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BalanceRequest
var metadata runtime.ServerMetadata
msg, err := server.Balance(ctx, &protoReq)
return msg, metadata, err
}
// RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
// UnaryRPC :call QueryServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead.
func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error {
mux.Handle("GET", pattern_Query_Auctions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Auctions_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Auctions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_GetAuction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_GetAuction_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_GetAuction_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_GetBid_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_GetBid_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_GetBid_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_GetBids_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_GetBids_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_GetBids_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_AuctionsByBidder_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_AuctionsByBidder_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_AuctionsByBidder_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_AuctionsByOwner_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_AuctionsByOwner_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_AuctionsByOwner_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_QueryParams_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_QueryParams_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_QueryParams_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Balance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Balance_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Balance_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterQueryHandler(ctx, mux, conn)
}
// RegisterQueryHandler registers the http handlers for service Query to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn))
}
// RegisterQueryHandlerClient registers the http handlers for service Query
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "QueryClient" to call the correct interceptors.
func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error {
mux.Handle("GET", pattern_Query_Auctions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Auctions_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Auctions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_GetAuction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_GetAuction_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_GetAuction_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_GetBid_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_GetBid_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_GetBid_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_GetBids_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_GetBids_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_GetBids_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_AuctionsByBidder_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_AuctionsByBidder_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_AuctionsByBidder_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_AuctionsByOwner_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_AuctionsByOwner_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_AuctionsByOwner_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_QueryParams_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_QueryParams_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_QueryParams_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Balance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Balance_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Balance_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Query_Auctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "auction", "v1beta1", "auctions"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_GetAuction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"vulcanize", "auction", "v1beta1", "auctions", "id"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_GetBid_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"vulcanize", "auction", "v1beta1", "bids", "auction_id", "bidder"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_GetBids_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"vulcanize", "auction", "v1beta1", "bids", "auction_id"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_AuctionsByBidder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"vulcanize", "auction", "v1beta1", "by-bidder", "bidder_address"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_AuctionsByOwner_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"vulcanize", "auction", "v1beta1", "by-owner", "owner_address"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_QueryParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "auction", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "auction", "v1beta1", "balance"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_Query_Auctions_0 = runtime.ForwardResponseMessage
forward_Query_GetAuction_0 = runtime.ForwardResponseMessage
forward_Query_GetBid_0 = runtime.ForwardResponseMessage
forward_Query_GetBids_0 = runtime.ForwardResponseMessage
forward_Query_AuctionsByBidder_0 = runtime.ForwardResponseMessage
forward_Query_AuctionsByOwner_0 = runtime.ForwardResponseMessage
forward_Query_QueryParams_0 = runtime.ForwardResponseMessage
forward_Query_Balance_0 = runtime.ForwardResponseMessage
)

1777
x/auction/types/tx.pb.go Normal file

File diff suppressed because it is too large Load Diff

65
x/auction/types/types.go Normal file
View File

@ -0,0 +1,65 @@
package types
import (
"crypto/sha256"
"encoding/hex"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Auction status values.
const (
// Auction is in commit phase.
AuctionStatusCommitPhase = "commit"
// Auction is in reveal phase.
AuctionStatusRevealPhase = "reveal"
// Auction has ended (no reveals allowed).
AuctionStatusExpired = "expired"
// Auction has completed (winner selected).
AuctionStatusCompleted = "completed"
)
// Bid status values.
const (
BidStatusCommitted = "commit"
BidStatusRevealed = "reveal"
)
// AuctionID simplifies generation of auction IDs.
type AuctionID struct {
Address sdk.Address
AccNum uint64
Sequence uint64
}
// Generate creates the auction ID.
func (auctionID AuctionID) Generate() string {
hasher := sha256.New()
str := fmt.Sprintf("%s:%d:%d", auctionID.Address.String(), auctionID.AccNum, auctionID.Sequence)
hasher.Write([]byte(str))
return hex.EncodeToString(hasher.Sum(nil))
}
func (auction Auction) GetCreateTime() string {
return string(sdk.FormatTimeBytes(auction.CreateTime))
}
func (auction Auction) GetCommitsEndTime() string {
return string(sdk.FormatTimeBytes(auction.CommitsEndTime))
}
func (auction Auction) GetRevealsEndTime() string {
return string(sdk.FormatTimeBytes(auction.RevealsEndTime))
}
func (bid Bid) GetCommitTime() string {
return string(sdk.FormatTimeBytes(bid.CommitTime))
}
func (bid Bid) GetRevealTime() string {
return string(sdk.FormatTimeBytes(bid.RevealTime))
}

1943
x/auction/types/types.pb.go Normal file

File diff suppressed because it is too large Load Diff

58
x/auth/ante/ante.go Normal file
View File

@ -0,0 +1,58 @@
package ante
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
// HandlerOptions are the options required for constructing a default SDK AnteHandler.
type HandlerOptions struct {
AccountKeeper AccountKeeper
BankKeeper types.BankKeeper
FeegrantKeeper FeegrantKeeper
SignModeHandler authsigning.SignModeHandler
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error
}
// NewAnteHandler returns an AnteHandler that checks and increments sequence
// numbers, checks signatures & account numbers, and deducts fees from the first
// signer.
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
if options.AccountKeeper == nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder")
}
if options.BankKeeper == nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder")
}
if options.SignModeHandler == nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
}
var sigGasConsumer = options.SigGasConsumer
if sigGasConsumer == nil {
sigGasConsumer = DefaultSigVerificationGasConsumer
}
anteDecorators := []sdk.AnteDecorator{
NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
NewRejectExtensionOptionsDecorator(),
NewMempoolFeeDecorator(),
NewValidateBasicDecorator(),
NewTxTimeoutHeightDecorator(),
NewValidateMemoDecorator(options.AccountKeeper),
NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper),
NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
NewValidateSigCountDecorator(options.AccountKeeper),
NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer),
NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
NewIncrementSequenceDecorator(options.AccountKeeper),
}
return sdk.ChainAnteDecorators(anteDecorators...), nil
}

1151
x/auth/ante/ante_test.go Normal file

File diff suppressed because it is too large Load Diff

206
x/auth/ante/basic.go Normal file
View File

@ -0,0 +1,206 @@
package ante
import (
"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)
// ValidateBasicDecorator will call tx.ValidateBasic and return any non-nil error.
// If ValidateBasic passes, decorator calls next AnteHandler in chain. Note,
// ValidateBasicDecorator decorator will not get executed on ReCheckTx since it
// is not dependent on application state.
type ValidateBasicDecorator struct{}
func NewValidateBasicDecorator() ValidateBasicDecorator {
return ValidateBasicDecorator{}
}
func (vbd ValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// no need to validate basic on recheck tx, call next antehandler
if ctx.IsReCheckTx() {
return next(ctx, tx, simulate)
}
if err := tx.ValidateBasic(); err != nil {
return ctx, err
}
return next(ctx, tx, simulate)
}
// ValidateMemoDecorator will validate memo given the parameters passed in
// If memo is too large decorator returns with error, otherwise call next AnteHandler
// CONTRACT: Tx must implement TxWithMemo interface
type ValidateMemoDecorator struct {
ak AccountKeeper
}
func NewValidateMemoDecorator(ak AccountKeeper) ValidateMemoDecorator {
return ValidateMemoDecorator{
ak: ak,
}
}
func (vmd ValidateMemoDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
memoTx, ok := tx.(sdk.TxWithMemo)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
params := vmd.ak.GetParams(ctx)
memoLength := len(memoTx.GetMemo())
if uint64(memoLength) > params.MaxMemoCharacters {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrMemoTooLarge,
"maximum number of characters is %d but received %d characters",
params.MaxMemoCharacters, memoLength,
)
}
return next(ctx, tx, simulate)
}
// ConsumeTxSizeGasDecorator will take in parameters and consume gas proportional
// to the size of tx before calling next AnteHandler. Note, the gas costs will be
// slightly over estimated due to the fact that any given signing account may need
// to be retrieved from state.
//
// CONTRACT: If simulate=true, then signatures must either be completely filled
// in or empty.
// CONTRACT: To use this decorator, signatures of transaction must be represented
// as legacytx.StdSignature otherwise simulate mode will incorrectly estimate gas cost.
type ConsumeTxSizeGasDecorator struct {
ak AccountKeeper
}
func NewConsumeGasForTxSizeDecorator(ak AccountKeeper) ConsumeTxSizeGasDecorator {
return ConsumeTxSizeGasDecorator{
ak: ak,
}
}
func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
}
params := cgts.ak.GetParams(ctx)
ctx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*sdk.Gas(len(ctx.TxBytes())), "txSize")
// simulate gas cost for signatures in simulate mode
if simulate {
// in simulate mode, each element should be a nil signature
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
return ctx, err
}
n := len(sigs)
for i, signer := range sigTx.GetSigners() {
// if signature is already filled in, no need to simulate gas cost
if i < n && !isIncompleteSignature(sigs[i].Data) {
continue
}
var pubkey cryptotypes.PubKey
acc := cgts.ak.GetAccount(ctx, signer)
// use placeholder simSecp256k1Pubkey if sig is nil
if acc == nil || acc.GetPubKey() == nil {
pubkey = simSecp256k1Pubkey
} else {
pubkey = acc.GetPubKey()
}
// use stdsignature to mock the size of a full signature
simSig := legacytx.StdSignature{ //nolint:staticcheck // this will be removed when proto is ready
Signature: simSecp256k1Sig[:],
PubKey: pubkey,
}
sigBz := legacy.Cdc.MustMarshal(simSig)
cost := sdk.Gas(len(sigBz) + 6)
// If the pubkey is a multi-signature pubkey, then we estimate for the maximum
// number of signers.
if _, ok := pubkey.(*multisig.LegacyAminoPubKey); ok {
cost *= params.TxSigLimit
}
ctx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*cost, "txSize")
}
}
return next(ctx, tx, simulate)
}
// isIncompleteSignature tests whether SignatureData is fully filled in for simulation purposes
func isIncompleteSignature(data signing.SignatureData) bool {
if data == nil {
return true
}
switch data := data.(type) {
case *signing.SingleSignatureData:
return len(data.Signature) == 0
case *signing.MultiSignatureData:
if len(data.Signatures) == 0 {
return true
}
for _, s := range data.Signatures {
if isIncompleteSignature(s) {
return true
}
}
}
return false
}
type (
// TxTimeoutHeightDecorator defines an AnteHandler decorator that checks for a
// tx height timeout.
TxTimeoutHeightDecorator struct{}
// TxWithTimeoutHeight defines the interface a tx must implement in order for
// TxHeightTimeoutDecorator to process the tx.
TxWithTimeoutHeight interface {
sdk.Tx
GetTimeoutHeight() uint64
}
)
// TxTimeoutHeightDecorator defines an AnteHandler decorator that checks for a
// tx height timeout.
func NewTxTimeoutHeightDecorator() TxTimeoutHeightDecorator {
return TxTimeoutHeightDecorator{}
}
// AnteHandle implements an AnteHandler decorator for the TxHeightTimeoutDecorator
// type where the current block height is checked against the tx's height timeout.
// If a height timeout is provided (non-zero) and is less than the current block
// height, then an error is returned.
func (txh TxTimeoutHeightDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
timeoutTx, ok := tx.(TxWithTimeoutHeight)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "expected tx to implement TxWithTimeoutHeight")
}
timeoutHeight := timeoutTx.GetTimeoutHeight()
if timeoutHeight > 0 && uint64(ctx.BlockHeight()) > timeoutHeight {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrTxTimeoutHeight, "block height: %d, timeout height: %d", ctx.BlockHeight(), timeoutHeight,
)
}
return next(ctx, tx, simulate)
}

224
x/auth/ante/basic_test.go Normal file
View File

@ -0,0 +1,224 @@
package ante_test
import (
"strings"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
)
func (suite *AnteTestSuite) TestValidateBasic() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
privs, accNums, accSeqs := []cryptotypes.PrivKey{}, []uint64{}, []uint64{}
invalidTx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
vbd := ante.NewValidateBasicDecorator()
antehandler := sdk.ChainAnteDecorators(vbd)
_, err = antehandler(suite.ctx, invalidTx, false)
suite.Require().NotNil(err, "Did not error on invalid tx")
privs, accNums, accSeqs = []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
validTx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
_, err = antehandler(suite.ctx, validTx, false)
suite.Require().Nil(err, "ValidateBasicDecorator returned error on valid tx. err: %v", err)
// test decorator skips on recheck
suite.ctx = suite.ctx.WithIsReCheckTx(true)
// decorator should skip processing invalidTx on recheck and thus return nil-error
_, err = antehandler(suite.ctx, invalidTx, false)
suite.Require().Nil(err, "ValidateBasicDecorator ran on ReCheck")
}
func (suite *AnteTestSuite) TestValidateMemo() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 500))
invalidTx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
// require that long memos get rejected
vmd := ante.NewValidateMemoDecorator(suite.app.AccountKeeper)
antehandler := sdk.ChainAnteDecorators(vmd)
_, err = antehandler(suite.ctx, invalidTx, false)
suite.Require().NotNil(err, "Did not error on tx with high memo")
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 10))
validTx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
// require small memos pass ValidateMemo Decorator
_, err = antehandler(suite.ctx, validTx, false)
suite.Require().Nil(err, "ValidateBasicDecorator returned error on valid tx. err: %v", err)
}
func (suite *AnteTestSuite) TestConsumeGasForTxSize() {
suite.SetupTest(true) // setup
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
cgtsd := ante.NewConsumeGasForTxSizeDecorator(suite.app.AccountKeeper)
antehandler := sdk.ChainAnteDecorators(cgtsd)
testCases := []struct {
name string
sigV2 signing.SignatureV2
}{
{"SingleSignatureData", signing.SignatureV2{PubKey: priv1.PubKey()}},
{"MultiSignatureData", signing.SignatureV2{PubKey: priv1.PubKey(), Data: multisig.NewMultisig(2)}},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 10))
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
txBytes, err := suite.clientCtx.TxConfig.TxJSONEncoder()(tx)
suite.Require().Nil(err, "Cannot marshal tx: %v", err)
params := suite.app.AccountKeeper.GetParams(suite.ctx)
expectedGas := sdk.Gas(len(txBytes)) * params.TxSizeCostPerByte
// Set suite.ctx with TxBytes manually
suite.ctx = suite.ctx.WithTxBytes(txBytes)
// track how much gas is necessary to retrieve parameters
beforeGas := suite.ctx.GasMeter().GasConsumed()
suite.app.AccountKeeper.GetParams(suite.ctx)
afterGas := suite.ctx.GasMeter().GasConsumed()
expectedGas += afterGas - beforeGas
beforeGas = suite.ctx.GasMeter().GasConsumed()
suite.ctx, err = antehandler(suite.ctx, tx, false)
suite.Require().Nil(err, "ConsumeTxSizeGasDecorator returned error: %v", err)
// require that decorator consumes expected amount of gas
consumedGas := suite.ctx.GasMeter().GasConsumed() - beforeGas
suite.Require().Equal(expectedGas, consumedGas, "Decorator did not consume the correct amount of gas")
// simulation must not underestimate gas of this decorator even with nil signatures
txBuilder, err := suite.clientCtx.TxConfig.WrapTxBuilder(tx)
suite.Require().NoError(err)
suite.Require().NoError(txBuilder.SetSignatures(tc.sigV2))
tx = txBuilder.GetTx()
simTxBytes, err := suite.clientCtx.TxConfig.TxJSONEncoder()(tx)
suite.Require().Nil(err, "Cannot marshal tx: %v", err)
// require that simulated tx is smaller than tx with signatures
suite.Require().True(len(simTxBytes) < len(txBytes), "simulated tx still has signatures")
// Set suite.ctx with smaller simulated TxBytes manually
suite.ctx = suite.ctx.WithTxBytes(simTxBytes)
beforeSimGas := suite.ctx.GasMeter().GasConsumed()
// run antehandler with simulate=true
suite.ctx, err = antehandler(suite.ctx, tx, true)
consumedSimGas := suite.ctx.GasMeter().GasConsumed() - beforeSimGas
// require that antehandler passes and does not underestimate decorator cost
suite.Require().Nil(err, "ConsumeTxSizeGasDecorator returned error: %v", err)
suite.Require().True(consumedSimGas >= expectedGas, "Simulate mode underestimates gas on AnteDecorator. Simulated cost: %d, expected cost: %d", consumedSimGas, expectedGas)
})
}
}
func (suite *AnteTestSuite) TestTxHeightTimeoutDecorator() {
suite.SetupTest(true)
antehandler := sdk.ChainAnteDecorators(ante.NewTxTimeoutHeightDecorator())
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
testCases := []struct {
name string
timeout uint64
height int64
expectErr bool
}{
{"default value", 0, 10, false},
{"no timeout (greater height)", 15, 10, false},
{"no timeout (same height)", 10, 10, false},
{"timeout (smaller height)", 9, 10, true},
}
for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 10))
suite.txBuilder.SetTimeoutHeight(tc.timeout)
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
ctx := suite.ctx.WithBlockHeight(tc.height)
_, err = antehandler(ctx, tx, true)
suite.Require().Equal(tc.expectErr, err != nil, err)
})
}
}

View File

@ -0,0 +1,20 @@
package ante
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
// AccountKeeper defines the contract needed for AccountKeeper related APIs.
// Interface provides support to use non-sdk AccountKeeper for AnteHandler's decorators.
type AccountKeeper interface {
GetParams(ctx sdk.Context) (params types.Params)
GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
SetAccount(ctx sdk.Context, acc types.AccountI)
GetModuleAddress(moduleName string) sdk.AccAddress
}
// FeegrantKeeper defines the expected feegrant keeper.
type FeegrantKeeper interface {
UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error
}

36
x/auth/ante/ext.go Normal file
View File

@ -0,0 +1,36 @@
package ante
import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
type HasExtensionOptionsTx interface {
GetExtensionOptions() []*codectypes.Any
GetNonCriticalExtensionOptions() []*codectypes.Any
}
// RejectExtensionOptionsDecorator is an AnteDecorator that rejects all extension
// options which can optionally be included in protobuf transactions. Users that
// need extension options should create a custom AnteHandler chain that handles
// needed extension options properly and rejects unknown ones.
type RejectExtensionOptionsDecorator struct{}
// NewRejectExtensionOptionsDecorator creates a new RejectExtensionOptionsDecorator
func NewRejectExtensionOptionsDecorator() RejectExtensionOptionsDecorator {
return RejectExtensionOptionsDecorator{}
}
var _ types.AnteDecorator = RejectExtensionOptionsDecorator{}
// AnteHandle implements the AnteDecorator.AnteHandle method
func (r RejectExtensionOptionsDecorator) AnteHandle(ctx types.Context, tx types.Tx, simulate bool, next types.AnteHandler) (newCtx types.Context, err error) {
if hasExtOptsTx, ok := tx.(HasExtensionOptionsTx); ok {
if len(hasExtOptsTx.GetExtensionOptions()) != 0 {
return ctx, sdkerrors.ErrUnknownExtensionOptions
}
}
return next(ctx, tx, simulate)
}

36
x/auth/ante/ext_test.go Normal file
View File

@ -0,0 +1,36 @@
package ante_test
import (
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
)
func (suite *AnteTestSuite) TestRejectExtensionOptionsDecorator() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
reod := ante.NewRejectExtensionOptionsDecorator()
antehandler := sdk.ChainAnteDecorators(reod)
// no extension options should not trigger an error
theTx := suite.txBuilder.GetTx()
_, err := antehandler(suite.ctx, theTx, false)
suite.Require().NoError(err)
extOptsTxBldr, ok := suite.txBuilder.(tx.ExtensionOptionsTxBuilder)
if !ok {
// if we can't set extension options, this decorator doesn't apply and we're done
return
}
// setting any extension option should cause an error
any, err := types.NewAnyWithValue(testdata.NewTestMsg())
suite.Require().NoError(err)
extOptsTxBldr.SetExtensionOptions(any)
theTx = suite.txBuilder.GetTx()
_, err = antehandler(suite.ctx, theTx, false)
suite.Require().EqualError(err, "unknown extension options")
}

141
x/auth/ante/fee.go Normal file
View File

@ -0,0 +1,141 @@
package ante
import (
"fmt"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
// MempoolFeeDecorator will check if the transaction's fee is at least as large
// as the local validator's minimum gasFee (defined in validator config).
// If fee is too low, decorator returns error and tx is rejected from mempool.
// Note this only applies when ctx.CheckTx = true
// If fee is high enough or not CheckTx, then call next AnteHandler
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
type MempoolFeeDecorator struct{}
func NewMempoolFeeDecorator() MempoolFeeDecorator {
return MempoolFeeDecorator{}
}
func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
}
feeCoins := feeTx.GetFee()
gas := feeTx.GetGas()
// Ensure that the provided fees meet a minimum threshold for the validator,
// if this is a CheckTx. This is only for local mempool purposes, and thus
// is only ran on check tx.
if ctx.IsCheckTx() && !simulate {
minGasPrices := ctx.MinGasPrices()
if !minGasPrices.IsZero() {
requiredFees := make(sdk.Coins, len(minGasPrices))
// Determine the required fees by multiplying each required minimum gas
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
glDec := sdk.NewDec(int64(gas))
for i, gp := range minGasPrices {
fee := gp.Amount.Mul(glDec)
requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
}
if !feeCoins.IsAnyGTE(requiredFees) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
}
}
}
return next(ctx, tx, simulate)
}
// DeductFeeDecorator deducts fees from the first signer of the tx
// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error
// Call next AnteHandler if fees successfully deducted
// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator
type DeductFeeDecorator struct {
ak AccountKeeper
bankKeeper evmtypes.BankKeeper
feegrantKeeper FeegrantKeeper
}
func NewDeductFeeDecorator(ak AccountKeeper, bk evmtypes.BankKeeper, fk FeegrantKeeper) DeductFeeDecorator {
return DeductFeeDecorator{
ak: ak,
bankKeeper: bk,
feegrantKeeper: fk,
}
}
func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
}
if addr := dfd.ak.GetModuleAddress(types.FeeCollectorName); addr == nil {
panic(fmt.Sprintf("%s module account has not been set", types.FeeCollectorName))
}
fee := feeTx.GetFee()
feePayer := feeTx.FeePayer()
feeGranter := feeTx.FeeGranter()
deductFeesFrom := feePayer
// if feegranter set deduct fee from feegranter account.
// this works with only when feegrant enabled.
if feeGranter != nil {
if dfd.feegrantKeeper == nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not enabled")
} else if !feeGranter.Equals(feePayer) {
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs())
if err != nil {
return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer)
}
}
deductFeesFrom = feeGranter
}
deductFeesFromAcc := dfd.ak.GetAccount(ctx, deductFeesFrom)
if deductFeesFromAcc == nil {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", deductFeesFrom)
}
// deduct the fees
if !feeTx.GetFee().IsZero() {
err = DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, feeTx.GetFee())
if err != nil {
return ctx, err
}
}
events := sdk.Events{sdk.NewEvent(sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeyFee, feeTx.GetFee().String()),
)}
ctx.EventManager().EmitEvents(events)
return next(ctx, tx, simulate)
}
// DeductFees deducts fees from the given account.
func DeductFees(bankKeeper evmtypes.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error {
if !fees.IsValid() {
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees)
}
err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
}
return nil
}

104
x/auth/ante/fee_test.go Normal file
View File

@ -0,0 +1,104 @@
package ante_test
import (
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
)
func (suite *AnteTestSuite) TestEnsureMempoolFees() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
mfd := ante.NewMempoolFeeDecorator()
antehandler := sdk.ChainAnteDecorators(mfd)
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
// Set high gas price so standard test fee fails
atomPrice := sdk.NewDecCoinFromDec("atom", sdk.NewDec(200).Quo(sdk.NewDec(100000)))
highGasPrice := []sdk.DecCoin{atomPrice}
suite.ctx = suite.ctx.WithMinGasPrices(highGasPrice)
// Set IsCheckTx to true
suite.ctx = suite.ctx.WithIsCheckTx(true)
// antehandler errors with insufficient fees
_, err = antehandler(suite.ctx, tx, false)
suite.Require().NotNil(err, "Decorator should have errored on too low fee for local gasPrice")
// Set IsCheckTx to false
suite.ctx = suite.ctx.WithIsCheckTx(false)
// antehandler should not error since we do not check minGasPrice in DeliverTx
_, err = antehandler(suite.ctx, tx, false)
suite.Require().Nil(err, "MempoolFeeDecorator returned error in DeliverTx")
// Set IsCheckTx back to true for testing sufficient mempool fee
suite.ctx = suite.ctx.WithIsCheckTx(true)
atomPrice = sdk.NewDecCoinFromDec("atom", sdk.NewDec(0).Quo(sdk.NewDec(100000)))
lowGasPrice := []sdk.DecCoin{atomPrice}
suite.ctx = suite.ctx.WithMinGasPrices(lowGasPrice)
_, err = antehandler(suite.ctx, tx, false)
suite.Require().Nil(err, "Decorator should not have errored on fee higher than local gasPrice")
}
func (suite *AnteTestSuite) TestDeductFees() {
suite.SetupTest(false) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
// Set account with insufficient funds
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
coins := sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(10)))
err = simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr1, coins)
suite.Require().NoError(err)
dfd := ante.NewDeductFeeDecorator(suite.app.AccountKeeper, suite.app.BankKeeper, nil)
antehandler := sdk.ChainAnteDecorators(dfd)
_, err = antehandler(suite.ctx, tx, false)
suite.Require().NotNil(err, "Tx did not error when fee payer had insufficient funds")
// Set account with sufficient funds
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
err = simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(200))))
suite.Require().NoError(err)
_, err = antehandler(suite.ctx, tx, false)
suite.Require().Nil(err, "Tx errored after account has been set with sufficient funds")
}

View File

@ -0,0 +1,233 @@
package ante_test
/* TODO: fix these tests
import (
"math/rand"
"testing"
"time"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
ante "github.com/tharsis/ethermint/x/auth/ante"
authsign "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/feegrant"
)
func (suite *AnteTestSuite) TestDeductFeesNoDelegation() {
suite.SetupTest(false)
// setup
app, ctx := suite.app, suite.ctx
protoTxCfg := tx.NewTxConfig(codec.NewProtoCodec(app.InterfaceRegistry()), tx.DefaultSignModes)
// this just tests our handler
dfd := ante.NewDeductFeeDecorator(app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper)
feeAnteHandler := sdk.ChainAnteDecorators(dfd)
// this tests the whole stack
anteHandlerStack := suite.anteHandler
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
priv2, _, addr2 := testdata.KeyTestPubAddr()
priv3, _, addr3 := testdata.KeyTestPubAddr()
priv4, _, addr4 := testdata.KeyTestPubAddr()
priv5, _, addr5 := testdata.KeyTestPubAddr()
// Set addr1 with insufficient funds
err := simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr1, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(10))})
suite.Require().NoError(err)
// Set addr2 with more funds
err = simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr2, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(99999))})
suite.Require().NoError(err)
// grant fee allowance from `addr2` to `addr3` (plenty to pay)
err = app.FeeGrantKeeper.GrantAllowance(ctx, addr2, addr3, &feegrant.BasicAllowance{
SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 500)),
})
suite.Require().NoError(err)
// grant low fee allowance (20atom), to check the tx requesting more than allowed.
err = app.FeeGrantKeeper.GrantAllowance(ctx, addr2, addr4, &feegrant.BasicAllowance{
SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 20)),
})
suite.Require().NoError(err)
cases := map[string]struct {
signerKey cryptotypes.PrivKey
signer sdk.AccAddress
feeAccount sdk.AccAddress
fee int64
valid bool
}{
"paying with low funds": {
signerKey: priv1,
signer: addr1,
fee: 50,
valid: false,
},
"paying with good funds": {
signerKey: priv2,
signer: addr2,
fee: 50,
valid: true,
},
"paying with no account": {
signerKey: priv3,
signer: addr3,
fee: 1,
valid: false,
},
"no fee with real account": {
signerKey: priv1,
signer: addr1,
fee: 0,
valid: true,
},
"no fee with no account": {
signerKey: priv5,
signer: addr5,
fee: 0,
valid: false,
},
"valid fee grant without account": {
signerKey: priv3,
signer: addr3,
feeAccount: addr2,
fee: 50,
valid: true,
},
"no fee grant": {
signerKey: priv3,
signer: addr3,
feeAccount: addr1,
fee: 2,
valid: false,
},
"allowance smaller than requested fee": {
signerKey: priv4,
signer: addr4,
feeAccount: addr2,
fee: 50,
valid: false,
},
"granter cannot cover allowed fee grant": {
signerKey: priv4,
signer: addr4,
feeAccount: addr1,
fee: 50,
valid: false,
},
}
for name, stc := range cases {
tc := stc // to make scopelint happy
suite.T().Run(name, func(t *testing.T) {
fee := sdk.NewCoins(sdk.NewInt64Coin("atom", tc.fee))
msgs := []sdk.Msg{testdata.NewTestMsg(tc.signer)}
acc := app.AccountKeeper.GetAccount(ctx, tc.signer)
privs, accNums, seqs := []cryptotypes.PrivKey{tc.signerKey}, []uint64{0}, []uint64{0}
if acc != nil {
accNums, seqs = []uint64{acc.GetAccountNumber()}, []uint64{acc.GetSequence()}
}
tx, err := genTxWithFeeGranter(protoTxCfg, msgs, fee, helpers.DefaultGenTxGas, ctx.ChainID(), accNums, seqs, tc.feeAccount, privs...)
suite.Require().NoError(err)
_, err = feeAnteHandler(ctx, tx, false) // tests only feegrant ante
if tc.valid {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
_, err = anteHandlerStack(ctx, tx, false) // tests while stack
if tc.valid {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
// don't consume any gas
func SigGasNoConsumer(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params authtypes.Params) error {
return nil
}
func genTxWithFeeGranter(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accNums,
accSeqs []uint64, feeGranter sdk.AccAddress, priv ...cryptotypes.PrivKey) (sdk.Tx, error) {
sigs := make([]signing.SignatureV2, len(priv))
// create a random length memo
r := rand.New(rand.NewSource(time.Now().UnixNano()))
memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100))
signMode := gen.SignModeHandler().DefaultMode()
// 1st round: set SignatureV2 with empty signatures, to set correct
// signer infos.
for i, p := range priv {
sigs[i] = signing.SignatureV2{
PubKey: p.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: signMode,
},
Sequence: accSeqs[i],
}
}
tx := gen.NewTxBuilder()
err := tx.SetMsgs(msgs...)
if err != nil {
return nil, err
}
err = tx.SetSignatures(sigs...)
if err != nil {
return nil, err
}
tx.SetMemo(memo)
tx.SetFeeAmount(feeAmt)
tx.SetGasLimit(gas)
tx.SetFeeGranter(feeGranter)
// 2nd round: once all signer infos are set, every signer can sign.
for i, p := range priv {
signerData := authsign.SignerData{
ChainID: chainID,
AccountNumber: accNums[i],
Sequence: accSeqs[i],
}
signBytes, err := gen.SignModeHandler().GetSignBytes(signMode, signerData, tx.GetTx())
if err != nil {
panic(err)
}
sig, err := p.Sign(signBytes)
if err != nil {
panic(err)
}
sigs[i].Data.(*signing.SingleSignatureData).Signature = sig
err = tx.SetSignatures(sigs...)
if err != nil {
panic(err)
}
}
return tx.GetTx(), nil
}
*/

76
x/auth/ante/setup.go Normal file
View File

@ -0,0 +1,76 @@
package ante
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/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{}
func NewSetUpContextDecorator() SetUpContextDecorator {
return SetUpContextDecorator{}
}
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, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
newCtx = SetGasMeter(simulate, ctx, gasTx.GetGas())
// 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 = sdkerrors.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))
}

99
x/auth/ante/setup_test.go Normal file
View File

@ -0,0 +1,99 @@
package ante_test
import (
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
)
func (suite *AnteTestSuite) TestSetup() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
sud := ante.NewSetUpContextDecorator()
antehandler := sdk.ChainAnteDecorators(sud)
// Set height to non-zero value for GasMeter to be set
suite.ctx = suite.ctx.WithBlockHeight(1)
// Context GasMeter Limit not set
suite.Require().Equal(uint64(0), suite.ctx.GasMeter().Limit(), "GasMeter set with limit before setup")
newCtx, err := antehandler(suite.ctx, tx, false)
suite.Require().Nil(err, "SetUpContextDecorator returned error")
// Context GasMeter Limit should be set after SetUpContextDecorator runs
suite.Require().Equal(gasLimit, newCtx.GasMeter().Limit(), "GasMeter not set correctly")
}
func (suite *AnteTestSuite) TestRecoverPanic() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
sud := ante.NewSetUpContextDecorator()
antehandler := sdk.ChainAnteDecorators(sud, OutOfGasDecorator{})
// Set height to non-zero value for GasMeter to be set
suite.ctx = suite.ctx.WithBlockHeight(1)
newCtx, err := antehandler(suite.ctx, tx, false)
suite.Require().NotNil(err, "Did not return error on OutOfGas panic")
suite.Require().True(sdkerrors.ErrOutOfGas.Is(err), "Returned error is not an out of gas error")
suite.Require().Equal(gasLimit, newCtx.GasMeter().Limit())
antehandler = sdk.ChainAnteDecorators(sud, PanicDecorator{})
suite.Require().Panics(func() { antehandler(suite.ctx, tx, false) }, "Recovered from non-Out-of-Gas panic") // nolint:errcheck
}
type OutOfGasDecorator struct{}
// AnteDecorator that will throw OutOfGas panic
func (ogd OutOfGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
overLimit := ctx.GasMeter().Limit() + 1
// Should panic with outofgas error
ctx.GasMeter().ConsumeGas(overLimit, "test panic")
// not reached
return next(ctx, tx, simulate)
}
type PanicDecorator struct{}
func (pd PanicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
panic("random error")
}

510
x/auth/ante/sigverify.go Normal file
View File

@ -0,0 +1,510 @@
package ante
import (
"bytes"
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
var (
// simulation signature values used to estimate gas consumption
key = make([]byte, secp256k1.PubKeySize)
simSecp256k1Pubkey = &secp256k1.PubKey{Key: key}
simSecp256k1Sig [64]byte
_ authsigning.SigVerifiableTx = (*legacytx.StdTx)(nil) // assert StdTx implements SigVerifiableTx
)
func init() {
// This decodes a valid hex string into a sepc256k1Pubkey for use in transaction simulation
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
copy(key, bz)
simSecp256k1Pubkey.Key = key
}
// SignatureVerificationGasConsumer is the type of function that is used to both
// consume gas when verifying signatures and also to accept or reject different types of pubkeys
// This is where apps can define their own PubKey
type SignatureVerificationGasConsumer = func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error
// SetPubKeyDecorator sets PubKeys in context for any signer which does not already have pubkey set
// PubKeys must be set in context for all signers before any other sigverify decorators run
// CONTRACT: Tx must implement SigVerifiableTx interface
type SetPubKeyDecorator struct {
ak AccountKeeper
}
func NewSetPubKeyDecorator(ak AccountKeeper) SetPubKeyDecorator {
return SetPubKeyDecorator{
ak: ak,
}
}
func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
}
pubkeys, err := sigTx.GetPubKeys()
if err != nil {
return ctx, err
}
signers := sigTx.GetSigners()
for i, pk := range pubkeys {
// PublicKey was omitted from slice since it has already been set in context
if pk == nil {
if !simulate {
continue
}
pk = simSecp256k1Pubkey
}
// Only make check if simulate=false
if !simulate && !bytes.Equal(pk.Address(), signers[i]) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey,
"pubKey does not match signer address %s with signer index: %d", signers[i], i)
}
acc, err := GetSignerAcc(ctx, spkd.ak, signers[i])
if err != nil {
return ctx, err
}
// account already has pubkey set,no need to reset
if acc.GetPubKey() != nil {
continue
}
err = acc.SetPubKey(pk)
if err != nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, err.Error())
}
spkd.ak.SetAccount(ctx, acc)
}
// Also emit the following events, so that txs can be indexed by these
// indices:
// - signature (via `tx.signature='<sig_as_base64>'`),
// - concat(address,"/",sequence) (via `tx.acc_seq='cosmos1abc...def/42'`).
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
return ctx, err
}
var events sdk.Events
for i, sig := range sigs {
events = append(events, sdk.NewEvent(sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signers[i], sig.Sequence)),
))
sigBzs, err := signatureDataToBz(sig.Data)
if err != nil {
return ctx, err
}
for _, sigBz := range sigBzs {
events = append(events, sdk.NewEvent(sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeySignature, base64.StdEncoding.EncodeToString(sigBz)),
))
}
}
ctx.EventManager().EmitEvents(events)
return next(ctx, tx, simulate)
}
// Consume parameter-defined amount of gas for each signature according to the passed-in SignatureVerificationGasConsumer function
// before calling the next AnteHandler
// CONTRACT: Pubkeys are set in context for all signers before this decorator runs
// CONTRACT: Tx must implement SigVerifiableTx interface
type SigGasConsumeDecorator struct {
ak AccountKeeper
sigGasConsumer SignatureVerificationGasConsumer
}
func NewSigGasConsumeDecorator(ak AccountKeeper, sigGasConsumer SignatureVerificationGasConsumer) SigGasConsumeDecorator {
return SigGasConsumeDecorator{
ak: ak,
sigGasConsumer: sigGasConsumer,
}
}
func (sgcd SigGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
params := sgcd.ak.GetParams(ctx)
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
return ctx, err
}
// stdSigs contains the sequence number, account number, and signatures.
// When simulating, this would just be a 0-length slice.
signerAddrs := sigTx.GetSigners()
for i, sig := range sigs {
signerAcc, err := GetSignerAcc(ctx, sgcd.ak, signerAddrs[i])
if err != nil {
return ctx, err
}
pubKey := signerAcc.GetPubKey()
// In simulate mode the transaction comes with no signatures, thus if the
// account's pubkey is nil, both signature verification and gasKVStore.Set()
// shall consume the largest amount, i.e. it takes more gas to verify
// secp256k1 keys than ed25519 ones.
if simulate && pubKey == nil {
pubKey = simSecp256k1Pubkey
}
// make a SignatureV2 with PubKey filled in from above
sig = signing.SignatureV2{
PubKey: pubKey,
Data: sig.Data,
Sequence: sig.Sequence,
}
err = sgcd.sigGasConsumer(ctx.GasMeter(), sig, params)
if err != nil {
return ctx, err
}
}
return next(ctx, tx, simulate)
}
// Verify all signatures for a tx and return an error if any are invalid. Note,
// the SigVerificationDecorator decorator will not get executed on ReCheck.
//
// CONTRACT: Pubkeys are set in context for all signers before this decorator runs
// CONTRACT: Tx must implement SigVerifiableTx interface
type SigVerificationDecorator struct {
ak AccountKeeper
signModeHandler authsigning.SignModeHandler
}
func NewSigVerificationDecorator(ak AccountKeeper, signModeHandler authsigning.SignModeHandler) SigVerificationDecorator {
return SigVerificationDecorator{
ak: ak,
signModeHandler: signModeHandler,
}
}
// OnlyLegacyAminoSigners checks SignatureData to see if all
// signers are using SIGN_MODE_LEGACY_AMINO_JSON. If this is the case
// then the corresponding SignatureV2 struct will not have account sequence
// explicitly set, and we should skip the explicit verification of sig.Sequence
// in the SigVerificationDecorator's AnteHandler function.
func OnlyLegacyAminoSigners(sigData signing.SignatureData) bool {
switch v := sigData.(type) {
case *signing.SingleSignatureData:
return v.SignMode == signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON
case *signing.MultiSignatureData:
for _, s := range v.Signatures {
if !OnlyLegacyAminoSigners(s) {
return false
}
}
return true
default:
return false
}
}
func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// no need to verify signatures on recheck tx
if ctx.IsReCheckTx() {
return next(ctx, tx, simulate)
}
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
// stdSigs contains the sequence number, account number, and signatures.
// When simulating, this would just be a 0-length slice.
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
return ctx, err
}
signerAddrs := sigTx.GetSigners()
// check that signer length and signature length are the same
if len(sigs) != len(signerAddrs) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs))
}
for i, sig := range sigs {
acc, err := GetSignerAcc(ctx, svd.ak, signerAddrs[i])
if err != nil {
return ctx, err
}
// retrieve pubkey
pubKey := acc.GetPubKey()
if !simulate && pubKey == nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
}
// Check account sequence number.
if sig.Sequence != acc.GetSequence() {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
}
// retrieve signer data
genesis := ctx.BlockHeight() == 0
chainID := ctx.ChainID()
var accNum uint64
if !genesis {
accNum = acc.GetAccountNumber()
}
signerData := authsigning.SignerData{
ChainID: chainID,
AccountNumber: accNum,
Sequence: acc.GetSequence(),
}
if !simulate {
err := authsigning.VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, tx)
if err != nil {
var errMsg string
if OnlyLegacyAminoSigners(sig.Data) {
// If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number,
// and therefore communicate sequence number as a potential cause of error.
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID)
} else {
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s)", accNum, chainID)
}
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg)
}
}
}
return next(ctx, tx, simulate)
}
// IncrementSequenceDecorator handles incrementing sequences of all signers.
// Use the IncrementSequenceDecorator decorator to prevent replay attacks. Note,
// there is no need to execute IncrementSequenceDecorator on RecheckTX since
// CheckTx would already bump the sequence number.
//
// NOTE: Since CheckTx and DeliverTx state are managed separately, subsequent and
// sequential txs orginating from the same account cannot be handled correctly in
// a reliable way unless sequence numbers are managed and tracked manually by a
// client. It is recommended to instead use multiple messages in a tx.
type IncrementSequenceDecorator struct {
ak AccountKeeper
}
func NewIncrementSequenceDecorator(ak AccountKeeper) IncrementSequenceDecorator {
return IncrementSequenceDecorator{
ak: ak,
}
}
func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
// increment sequence of all signers
for _, addr := range sigTx.GetSigners() {
acc := isd.ak.GetAccount(ctx, addr)
if err := acc.SetSequence(acc.GetSequence() + 1); err != nil {
panic(err)
}
isd.ak.SetAccount(ctx, acc)
}
return next(ctx, tx, simulate)
}
// ValidateSigCountDecorator takes in Params and returns errors if there are too many signatures in the tx for the given params
// otherwise it calls next AnteHandler
// Use this decorator to set parameterized limit on number of signatures in tx
// CONTRACT: Tx must implement SigVerifiableTx interface
type ValidateSigCountDecorator struct {
ak AccountKeeper
}
func NewValidateSigCountDecorator(ak AccountKeeper) ValidateSigCountDecorator {
return ValidateSigCountDecorator{
ak: ak,
}
}
func (vscd ValidateSigCountDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a sigTx")
}
params := vscd.ak.GetParams(ctx)
pubKeys, err := sigTx.GetPubKeys()
if err != nil {
return ctx, err
}
sigCount := 0
for _, pk := range pubKeys {
sigCount += CountSubKeys(pk)
if uint64(sigCount) > params.TxSigLimit {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrTooManySignatures,
"signatures: %d, limit: %d", sigCount, params.TxSigLimit)
}
}
return next(ctx, tx, simulate)
}
// DefaultSigVerificationGasConsumer is the default implementation of SignatureVerificationGasConsumer. It consumes gas
// for signature verification based upon the public key type. The cost is fetched from the given params and is matched
// by the concrete type.
func DefaultSigVerificationGasConsumer(
meter sdk.GasMeter, sig signing.SignatureV2, params types.Params,
) error {
pubkey := sig.PubKey
switch pubkey := pubkey.(type) {
case *ed25519.PubKey:
meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519")
return sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "ED25519 public keys are unsupported")
case *secp256k1.PubKey:
meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1")
return nil
case *secp256r1.PubKey:
meter.ConsumeGas(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1")
return nil
case multisig.PubKey:
multisignature, ok := sig.Data.(*signing.MultiSignatureData)
if !ok {
return fmt.Errorf("expected %T, got, %T", &signing.MultiSignatureData{}, sig.Data)
}
err := ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params, sig.Sequence)
if err != nil {
return err
}
return nil
default:
return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey)
}
}
// ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature
func ConsumeMultisignatureVerificationGas(
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
params types.Params, accSeq uint64,
) error {
size := sig.BitArray.Count()
sigIndex := 0
for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
continue
}
sigV2 := signing.SignatureV2{
PubKey: pubkey.GetPubKeys()[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++
}
return nil
}
// GetSignerAcc returns an account for a given address that is expected to sign
// a transaction.
func GetSignerAcc(ctx sdk.Context, ak AccountKeeper, addr sdk.AccAddress) (types.AccountI, error) {
if acc := ak.GetAccount(ctx, addr); acc != nil {
return acc, nil
}
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr)
}
// CountSubKeys counts the total number of keys for a multi-sig public key.
func CountSubKeys(pub cryptotypes.PubKey) int {
v, ok := pub.(*kmultisig.LegacyAminoPubKey)
if !ok {
return 1
}
numKeys := 0
for _, subkey := range v.GetPubKeys() {
numKeys += CountSubKeys(subkey)
}
return numKeys
}
// signatureDataToBz converts a SignatureData into raw bytes signature.
// For SingleSignatureData, it returns the signature raw bytes.
// For MultiSignatureData, it returns an array of all individual signatures,
// as well as the aggregated signature.
func signatureDataToBz(data signing.SignatureData) ([][]byte, error) {
if data == nil {
return nil, fmt.Errorf("got empty SignatureData")
}
switch data := data.(type) {
case *signing.SingleSignatureData:
return [][]byte{data.Signature}, nil
case *signing.MultiSignatureData:
sigs := [][]byte{}
var err error
for _, d := range data.Signatures {
nestedSigs, err := signatureDataToBz(d)
if err != nil {
return nil, err
}
sigs = append(sigs, nestedSigs...)
}
multisig := cryptotypes.MultiSignature{
Signatures: sigs,
}
aggregatedSig, err := multisig.Marshal()
if err != nil {
return nil, err
}
sigs = append(sigs, aggregatedSig)
return sigs, nil
default:
return nil, sdkerrors.ErrInvalidType.Wrapf("unexpected signature data type %T", data)
}
}

View File

@ -0,0 +1,44 @@
package ante_test
import (
"testing"
"github.com/stretchr/testify/require"
tmcrypto "github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
)
// This benchmark is used to asses the ante.Secp256k1ToR1GasFactor value
func BenchmarkSig(b *testing.B) {
require := require.New(b)
msg := tmcrypto.CRandBytes(1000)
skK := secp256k1.GenPrivKey()
pkK := skK.PubKey()
skR, _ := secp256r1.GenPrivKey()
pkR := skR.PubKey()
sigK, err := skK.Sign(msg)
require.NoError(err)
sigR, err := skR.Sign(msg)
require.NoError(err)
b.ResetTimer()
b.Run("secp256k1", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ok := pkK.VerifySignature(msg, sigK)
require.True(ok)
}
})
b.Run("secp256r1", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ok := pkR.VerifySignature(msg, sigR)
require.True(ok)
}
})
}

View File

@ -0,0 +1,390 @@
package ante_test
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
func (suite *AnteTestSuite) TestSetPubKey() {
suite.SetupTest(true) // setup
require := suite.Require()
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// keys and addresses
priv1, pub1, addr1 := testdata.KeyTestPubAddr()
priv2, pub2, addr2 := testdata.KeyTestPubAddr()
priv3, pub3, addr3 := testdata.KeyTestPubAddrSecp256R1(require)
addrs := []sdk.AccAddress{addr1, addr2, addr3}
pubs := []cryptotypes.PubKey{pub1, pub2, pub3}
msgs := make([]sdk.Msg, len(addrs))
// set accounts and create msg for each address
for i, addr := range addrs {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
require.NoError(acc.SetAccountNumber(uint64(i)))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
msgs[i] = testdata.NewTestMsg(addr)
}
require.NoError(suite.txBuilder.SetMsgs(msgs...))
suite.txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
suite.txBuilder.SetGasLimit(testdata.NewTestGasLimit())
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
require.NoError(err)
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
antehandler := sdk.ChainAnteDecorators(spkd)
ctx, err := antehandler(suite.ctx, tx, false)
require.NoError(err)
// Require that all accounts have pubkey set after Decorator runs
for i, addr := range addrs {
pk, err := suite.app.AccountKeeper.GetPubKey(ctx, addr)
require.NoError(err, "Error on retrieving pubkey from account")
require.True(pubs[i].Equals(pk),
"Wrong Pubkey retrieved from AccountKeeper, idx=%d\nexpected=%s\n got=%s", i, pubs[i], pk)
}
}
func (suite *AnteTestSuite) TestConsumeSignatureVerificationGas() {
params := types.DefaultParams()
msg := []byte{1, 2, 3, 4}
cdc := simapp.MakeTestEncodingConfig().Amino
p := types.DefaultParams()
skR1, _ := secp256r1.GenPrivKey()
pkSet1, sigSet1 := generatePubKeysAndSignatures(5, msg, false)
multisigKey1 := kmultisig.NewLegacyAminoPubKey(2, pkSet1)
multisignature1 := multisig.NewMultisig(len(pkSet1))
expectedCost1 := expectedGasCostByKeys(pkSet1)
for i := 0; i < len(pkSet1); i++ {
stdSig := legacytx.StdSignature{PubKey: pkSet1[i], Signature: sigSet1[i]}
sigV2, err := legacytx.StdSignatureToSignatureV2(cdc, stdSig)
suite.Require().NoError(err)
err = multisig.AddSignatureV2(multisignature1, sigV2, pkSet1)
suite.Require().NoError(err)
}
type args struct {
meter sdk.GasMeter
sig signing.SignatureData
pubkey cryptotypes.PubKey
params types.Params
}
tests := []struct {
name string
args args
gasConsumed uint64
shouldErr bool
}{
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), nil, ed25519.GenPrivKey().PubKey(), params}, p.SigVerifyCostED25519, true},
{"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), nil, secp256k1.GenPrivKey().PubKey(), params}, p.SigVerifyCostSecp256k1, false},
{"PubKeySecp256r1", args{sdk.NewInfiniteGasMeter(), nil, skR1.PubKey(), params}, p.SigVerifyCostSecp256r1(), false},
{"Multisig", args{sdk.NewInfiniteGasMeter(), multisignature1, multisigKey1, params}, expectedCost1, false},
{"unknown key", args{sdk.NewInfiniteGasMeter(), nil, nil, params}, 0, true},
}
for _, tt := range tests {
sigV2 := signing.SignatureV2{
PubKey: tt.args.pubkey,
Data: tt.args.sig,
Sequence: 0, // Arbitrary account sequence
}
err := ante.DefaultSigVerificationGasConsumer(tt.args.meter, sigV2, tt.args.params)
if tt.shouldErr {
suite.Require().NotNil(err)
} else {
suite.Require().Nil(err)
suite.Require().Equal(tt.gasConsumed, tt.args.meter.GasConsumed(), fmt.Sprintf("%d != %d", tt.gasConsumed, tt.args.meter.GasConsumed()))
}
}
}
func (suite *AnteTestSuite) TestSigVerification() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// make block height non-zero to ensure account numbers part of signBytes
suite.ctx = suite.ctx.WithBlockHeight(1)
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
priv2, _, addr2 := testdata.KeyTestPubAddr()
priv3, _, addr3 := testdata.KeyTestPubAddr()
addrs := []sdk.AccAddress{addr1, addr2, addr3}
msgs := make([]sdk.Msg, len(addrs))
// set accounts and create msg for each address
for i, addr := range addrs {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
suite.Require().NoError(acc.SetAccountNumber(uint64(i)))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
msgs[i] = testdata.NewTestMsg(addr)
}
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
svd := ante.NewSigVerificationDecorator(suite.app.AccountKeeper, suite.clientCtx.TxConfig.SignModeHandler())
antehandler := sdk.ChainAnteDecorators(spkd, svd)
type testCase struct {
name string
privs []cryptotypes.PrivKey
accNums []uint64
accSeqs []uint64
recheck bool
shouldErr bool
}
testCases := []testCase{
{"no signers", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, false, true},
{"not enough signers", []cryptotypes.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{0, 0}, false, true},
{"wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{2, 1, 0}, []uint64{0, 0, 0}, false, true},
{"wrong accnums", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{7, 8, 9}, []uint64{0, 0, 0}, false, true},
{"wrong sequences", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{3, 4, 5}, false, true},
{"valid tx", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}, false, false},
{"no err on recheck", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, true, false},
}
for i, tc := range testCases {
suite.ctx = suite.ctx.WithIsReCheckTx(tc.recheck)
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() // Create new txBuilder for each test
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
tx, err := suite.CreateTestTx(tc.privs, tc.accNums, tc.accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
_, err = antehandler(suite.ctx, tx, false)
if tc.shouldErr {
suite.Require().NotNil(err, "TestCase %d: %s did not error as expected", i, tc.name)
} else {
suite.Require().Nil(err, "TestCase %d: %s errored unexpectedly. Err: %v", i, tc.name, err)
}
}
}
// This test is exactly like the one above, but we set the codec explicitly to
// Amino.
// Once https://github.com/cosmos/cosmos-sdk/issues/6190 is in, we can remove
// this, since it'll be handled by the test matrix.
// In the meantime, we want to make double-sure amino compatibility works.
// ref: https://github.com/cosmos/cosmos-sdk/issues/7229
func (suite *AnteTestSuite) TestSigVerification_ExplicitAmino() {
suite.app, suite.ctx = createTestApp(true)
suite.ctx = suite.ctx.WithBlockHeight(1)
// Set up TxConfig.
aminoCdc := codec.NewLegacyAmino()
// We're using TestMsg amino encoding in some tests, so register it here.
txConfig := legacytx.StdTxConfig{Cdc: aminoCdc}
suite.clientCtx = client.Context{}.
WithTxConfig(txConfig)
anteHandler, err := ante.NewAnteHandler(
ante.HandlerOptions{
AccountKeeper: suite.app.AccountKeeper,
BankKeeper: suite.app.BankKeeper,
FeegrantKeeper: suite.app.FeeGrantKeeper,
SignModeHandler: txConfig.SignModeHandler(),
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
},
)
suite.Require().NoError(err)
suite.anteHandler = anteHandler
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// make block height non-zero to ensure account numbers part of signBytes
suite.ctx = suite.ctx.WithBlockHeight(1)
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
priv2, _, addr2 := testdata.KeyTestPubAddr()
priv3, _, addr3 := testdata.KeyTestPubAddr()
addrs := []sdk.AccAddress{addr1, addr2, addr3}
msgs := make([]sdk.Msg, len(addrs))
// set accounts and create msg for each address
for i, addr := range addrs {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
suite.Require().NoError(acc.SetAccountNumber(uint64(i)))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
msgs[i] = testdata.NewTestMsg(addr)
}
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
svd := ante.NewSigVerificationDecorator(suite.app.AccountKeeper, suite.clientCtx.TxConfig.SignModeHandler())
antehandler := sdk.ChainAnteDecorators(spkd, svd)
type testCase struct {
name string
privs []cryptotypes.PrivKey
accNums []uint64
accSeqs []uint64
recheck bool
shouldErr bool
}
testCases := []testCase{
{"no signers", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, false, true},
{"not enough signers", []cryptotypes.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{0, 0}, false, true},
{"wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{2, 1, 0}, []uint64{0, 0, 0}, false, true},
{"wrong accnums", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{7, 8, 9}, []uint64{0, 0, 0}, false, true},
{"wrong sequences", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{3, 4, 5}, false, true},
{"valid tx", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}, false, false},
{"no err on recheck", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, true, false},
}
for i, tc := range testCases {
suite.ctx = suite.ctx.WithIsReCheckTx(tc.recheck)
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() // Create new txBuilder for each test
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
tx, err := suite.CreateTestTx(tc.privs, tc.accNums, tc.accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
_, err = antehandler(suite.ctx, tx, false)
if tc.shouldErr {
suite.Require().NotNil(err, "TestCase %d: %s did not error as expected", i, tc.name)
} else {
suite.Require().Nil(err, "TestCase %d: %s errored unexpectedly. Err: %v", i, tc.name, err)
}
}
}
func (suite *AnteTestSuite) TestSigIntegration() {
// generate private keys
privs := []cryptotypes.PrivKey{
secp256k1.GenPrivKey(),
secp256k1.GenPrivKey(),
secp256k1.GenPrivKey(),
}
params := types.DefaultParams()
initialSigCost := params.SigVerifyCostSecp256k1
initialCost, err := suite.runSigDecorators(params, false, privs...)
suite.Require().Nil(err)
params.SigVerifyCostSecp256k1 *= 2
doubleCost, err := suite.runSigDecorators(params, false, privs...)
suite.Require().Nil(err)
suite.Require().Equal(initialSigCost*uint64(len(privs)), doubleCost-initialCost)
}
func (suite *AnteTestSuite) runSigDecorators(params types.Params, _ bool, privs ...cryptotypes.PrivKey) (sdk.Gas, error) {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
// Make block-height non-zero to include accNum in SignBytes
suite.ctx = suite.ctx.WithBlockHeight(1)
suite.app.AccountKeeper.SetParams(suite.ctx, params)
msgs := make([]sdk.Msg, len(privs))
accNums := make([]uint64, len(privs))
accSeqs := make([]uint64, len(privs))
// set accounts and create msg for each address
for i, priv := range privs {
addr := sdk.AccAddress(priv.PubKey().Address())
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
suite.Require().NoError(acc.SetAccountNumber(uint64(i)))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
msgs[i] = testdata.NewTestMsg(addr)
accNums[i] = uint64(i)
accSeqs[i] = uint64(0)
}
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
svgc := ante.NewSigGasConsumeDecorator(suite.app.AccountKeeper, ante.DefaultSigVerificationGasConsumer)
svd := ante.NewSigVerificationDecorator(suite.app.AccountKeeper, suite.clientCtx.TxConfig.SignModeHandler())
antehandler := sdk.ChainAnteDecorators(spkd, svgc, svd)
// Determine gas consumption of antehandler with default params
before := suite.ctx.GasMeter().GasConsumed()
ctx, err := antehandler(suite.ctx, tx, false)
after := ctx.GasMeter().GasConsumed()
return after - before, err
}
func (suite *AnteTestSuite) TestIncrementSequenceDecorator() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
priv, _, addr := testdata.KeyTestPubAddr()
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
suite.Require().NoError(acc.SetAccountNumber(uint64(50)))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
privs := []cryptotypes.PrivKey{priv}
accNums := []uint64{suite.app.AccountKeeper.GetAccount(suite.ctx, addr).GetAccountNumber()}
accSeqs := []uint64{suite.app.AccountKeeper.GetAccount(suite.ctx, addr).GetSequence()}
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
suite.Require().NoError(err)
isd := ante.NewIncrementSequenceDecorator(suite.app.AccountKeeper)
antehandler := sdk.ChainAnteDecorators(isd)
testCases := []struct {
ctx sdk.Context
simulate bool
expectedSeq uint64
}{
{suite.ctx.WithIsReCheckTx(true), false, 1},
{suite.ctx.WithIsCheckTx(true).WithIsReCheckTx(false), false, 2},
{suite.ctx.WithIsReCheckTx(true), false, 3},
{suite.ctx.WithIsReCheckTx(true), false, 4},
{suite.ctx.WithIsReCheckTx(true), true, 5},
}
for i, tc := range testCases {
_, err := antehandler(tc.ctx, tx, tc.simulate)
suite.Require().NoError(err, "unexpected error; tc #%d, %v", i, tc)
suite.Require().Equal(tc.expectedSeq, suite.app.AccountKeeper.GetAccount(suite.ctx, addr).GetSequence())
}
}

View File

@ -0,0 +1,200 @@
package ante_test
import (
"errors"
"fmt"
"testing"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// TestAccount represents an account used in the tests in x/auth/ante.
type TestAccount struct {
acc types.AccountI
priv cryptotypes.PrivKey
}
// AnteTestSuite is a test suite to be used with ante handler tests.
type AnteTestSuite struct {
suite.Suite
app *simapp.SimApp
anteHandler sdk.AnteHandler
ctx sdk.Context
clientCtx client.Context
txBuilder client.TxBuilder
}
// returns context and app with params set on account keeper
func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) {
app := simapp.Setup(isCheckTx)
ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{})
app.AccountKeeper.SetParams(ctx, authtypes.DefaultParams())
return app, ctx
}
// SetupTest setups a new test, with new app, context, and anteHandler.
func (suite *AnteTestSuite) SetupTest(isCheckTx bool) {
suite.app, suite.ctx = createTestApp(isCheckTx)
suite.ctx = suite.ctx.WithBlockHeight(1)
// Set up TxConfig.
encodingConfig := simapp.MakeTestEncodingConfig()
// We're using TestMsg encoding in some tests, so register it here.
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry)
suite.clientCtx = client.Context{}.
WithTxConfig(encodingConfig.TxConfig)
anteHandler, err := ante.NewAnteHandler(
ante.HandlerOptions{
AccountKeeper: suite.app.AccountKeeper,
BankKeeper: suite.app.BankKeeper,
FeegrantKeeper: suite.app.FeeGrantKeeper,
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
},
)
suite.Require().NoError(err)
suite.anteHandler = anteHandler
}
// CreateTestAccounts creates `numAccs` accounts, and return all relevant
// information about them including their private keys.
func (suite *AnteTestSuite) CreateTestAccounts(numAccs int) []TestAccount {
var accounts []TestAccount
for i := 0; i < numAccs; i++ {
priv, _, addr := testdata.KeyTestPubAddr()
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
err := acc.SetAccountNumber(uint64(i))
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
someCoins := sdk.Coins{
sdk.NewInt64Coin("atom", 10000000),
}
err = suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, someCoins)
suite.Require().NoError(err)
err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, minttypes.ModuleName, addr, someCoins)
suite.Require().NoError(err)
accounts = append(accounts, TestAccount{acc, priv})
}
return accounts
}
// CreateTestTx is a helper function to create a tx given multiple inputs.
func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string) (xauthsigning.Tx, error) {
// First round: we gather all the signer infos. We use the "set empty
// signature" hack to do that.
var sigsV2 []signing.SignatureV2
for i, priv := range privs {
sigV2 := signing.SignatureV2{
PubKey: priv.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(),
Signature: nil,
},
Sequence: accSeqs[i],
}
sigsV2 = append(sigsV2, sigV2)
}
err := suite.txBuilder.SetSignatures(sigsV2...)
if err != nil {
return nil, err
}
// Second round: all signer infos are set, so each signer can sign.
sigsV2 = []signing.SignatureV2{}
for i, priv := range privs {
signerData := xauthsigning.SignerData{
ChainID: chainID,
AccountNumber: accNums[i],
Sequence: accSeqs[i],
}
sigV2, err := tx.SignWithPrivKey(
suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(), signerData,
suite.txBuilder, priv, suite.clientCtx.TxConfig, accSeqs[i])
if err != nil {
return nil, err
}
sigsV2 = append(sigsV2, sigV2)
}
err = suite.txBuilder.SetSignatures(sigsV2...)
if err != nil {
return nil, err
}
return suite.txBuilder.GetTx(), nil
}
// TestCase represents a test case used in test tables.
type TestCase struct {
desc string
malleate func()
simulate bool
expPass bool
expErr error
}
// CreateTestTx is a helper function to create a tx given multiple inputs.
func (suite *AnteTestSuite) RunTestCase(privs []cryptotypes.PrivKey, msgs []sdk.Msg, feeAmount sdk.Coins, gasLimit uint64, accNums, accSeqs []uint64, chainID string, tc TestCase) {
suite.Run(fmt.Sprintf("Case %s", tc.desc), func() {
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
// Theoretically speaking, ante handler unit tests should only test
// ante handlers, but here we sometimes also test the tx creation
// process.
tx, txErr := suite.CreateTestTx(privs, accNums, accSeqs, chainID)
newCtx, anteErr := suite.anteHandler(suite.ctx, tx, tc.simulate)
if tc.expPass {
suite.Require().NoError(txErr)
suite.Require().NoError(anteErr)
suite.Require().NotNil(newCtx)
suite.ctx = newCtx
} else {
switch {
case txErr != nil:
suite.Require().Error(txErr)
suite.Require().True(errors.Is(txErr, tc.expErr))
case anteErr != nil:
suite.Require().Error(anteErr)
suite.Require().True(errors.Is(anteErr, tc.expErr))
default:
suite.Fail("expected one of txErr,anteErr to be an error")
}
}
})
}
func TestAnteTestSuite(t *testing.T) {
suite.Run(t, new(AnteTestSuite))
}

196
x/bond/README.md Normal file
View File

@ -0,0 +1,196 @@
# Build chain
```bash
# it will create binary in build folder with `ethermintd`
$ make build
```
# Setup Chain
```bash
./build/ethermintd keys add root
./build/ethermintd init test-moniker --chain-id ethermint_9000-1
./build/ethermintd add-genesis-account $(./build/ethermintd keys show root -a) 1000000000000000000aphoton,1000000000000000000stake
./build/ethermintd gentx root 1000000000000000000stake --chain-id ethermint_9000-1
./build/ethermintd collect-gentxs
./build/ethermintd start
```
# Params
```
$ ./build/ethermintd q bond params -o json | jq .
{
"params": {
"max_bond_amount": {
"denom": "stake",
"amount": "100000000000"
}
}
}
```
# Create Bond
```
$ ./build/ethermintd tx bond create 100aphoton --from root --chain-id $(./build/ethermintd status | jq .NodeInfo.network -r)
{"body":{"messages":[{"@type":"/vulcanize.bond.v1beta1.MsgCreateBond","signer":"ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk","coins":[{"denom":"aphoton","amount":"100"}]}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: C6D362E11D4C9FB06D620F3CCAF363A69A074297A00E9CAECBDA5BE1CC302EB8
```
# Refill Bond
```
$ ./build/ethermintd tx bond refill c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440 1000aphoton --from root --chain-id $(./build/ethermintd status | jq .NodeInfo.network -r)
{"body":{"messages":[{"@type":"/vulcanize.bond.v1beta1.MsgRefillBond","id":"c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440","signer":"ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk","coins":[{"denom":"aphoton","amount":"1000"}]}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 025B04E2C923EFE2299CD171B40829CB1FE4D1A69DA7563C64AAC3D5C27BDFC9
```
# Withdraw from bond
```
$ ./build/ethermintd tx bond withdraw c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440 1000aphoton --from root --chain-id $(./build/ethermintd status | jq .NodeInfo.network -r)
{"body":{"messages":[{"@type":"/vulcanize.bond.v1beta1.MsgWithdrawBond","id":"c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440","signer":"ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk","coins":[{"denom":"aphoton","amount":"1000"}]}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 7C5E2FE674577CD6BFFF9F92FCCBC61EDFE8F1A00CE29AC84D58FB8F013D2F03
```
# List Bond
```
$ ./build/ethermintd q bond list -o json | jq .
{
"bonds": [
{
"id": "c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440",
"owner": "ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk",
"balance": [
{
"denom": "aphoton",
"amount": "100"
}
]
}
],
"pagination": null
}
```
# Get Bond by Id
```
$ ./build/ethermintd q bond get c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440 -o json | jq .
{
"bond": {
"id": "c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440",
"owner": "ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk",
"balance": [
{
"denom": "aphoton",
"amount": "100"
}
]
}
}
```
# Get Bond Module Balance
```
$ ./build/ethermintd q bond balance -o json | jq .
{
"balance": [
{
"denom": "aphoton",
"amount": "100"
}
]
}
```
# Get Bonds By Owner
```
$ ./build/ethermintd q bond by-owner ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk -o json | jq .
{
"bonds": [
{
"id": "c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440",
"owner": "ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk",
"balance": [
{
"denom": "aphoton",
"amount": "100"
}
]
}
],
"pagination": null
}
```
# Cancel the bond
```
$ ./build/ethermintd tx bond cancel c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440 --from root --chain-id $(./build/ethermintd status | jq .NodeInfo.network -r)
{"body":{"messages":[{"@type":"/vulcanize.bond.v1beta1.MsgCancelBond","id":"c3f7a78c5042d2003880962ba31ff3b01fcf5942960e0bc3ca331f816346a440","signer":"ethm1mfdjngh5jvjs9lqtt9a7y2hlgw8v3syh3hsqzk"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 06440D0B35A862E3A6783E147F0E1CDD3374870DAE07E471D465E2830DAF7044
```
Note : After the bond create and withdraw bond and cancel bond , account amount needs change as per module
```
$ ./build/ethermintd q bank balances $(./build/ethermintd keys show root -a) -o json | jq .
{
"balances": [
{
"denom": "aphoton",
"amount": "1000000000000000000"
}
],
"pagination": {
"next_key": null,
"total": "0"
}
}
```

17
x/bond/abci.go Normal file
View File

@ -0,0 +1,17 @@
package bond
import (
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tharsis/ethermint/x/bond/keeper"
)
// BeginBlocker will persist the current header and validator set as a historical entry
// and prune the oldest entry based on the HistoricalEntries parameter
func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
}
// EndBlocker Called every block, update validator set
func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}

203
x/bond/client/cli/query.go Normal file
View File

@ -0,0 +1,203 @@
package cli
import (
"fmt"
"strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
"github.com/spf13/cobra"
"github.com/tharsis/ethermint/x/bond/types"
)
// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd() *cobra.Command {
bondQueryCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Querying commands for the bond module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
bondQueryCmd.AddCommand(
GetQueryParamsCmd(),
GetQueryBondLists(),
GetBondByIdCmd(),
GetBondListByOwnerCmd(),
GetBondModuleBalanceCmd(),
)
return bondQueryCmd
}
// GetQueryParamsCmd implements the params query command.
func GetQueryParamsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "params",
Args: cobra.NoArgs,
Short: "Query the current bond parameters information.",
Long: strings.TrimSpace(
fmt.Sprintf(`Query values set as bond parameters.
Example:
$ %s query %s params
`,
version.AppName, types.ModuleName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetQueryBondLists implements the bond lists query command.
func GetQueryBondLists() *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List bonds.",
Long: strings.TrimSpace(
fmt.Sprintf(`Get bond list .
Example:
$ %s query %s list
`,
version.AppName, types.ModuleName,
),
),
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.Bonds(cmd.Context(), &types.QueryGetBondsRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetBondByIdCmd implements the bond info by id query command.
func GetBondByIdCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "get [bond Id]",
Short: "Get bond.",
Long: strings.TrimSpace(
fmt.Sprintf(`Get bond info by bond id .
Example:
$ %s query bond get {BOND ID}
`,
version.AppName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
id := args[0]
res, err := queryClient.GetBondById(cmd.Context(), &types.QueryGetBondByIdRequest{Id: id})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetBondListByOwnerCmd queries the bond list by owner.
func GetBondListByOwnerCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "by-owner [address]",
Short: "Query bonds by owner.",
Long: strings.TrimSpace(
fmt.Sprintf(`Get bond list by owner.
Example:
$ %s query %s query-by-owner [address]
`,
version.AppName, types.ModuleName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
owner := args[0]
res, err := queryClient.GetBondsByOwner(cmd.Context(), &types.QueryGetBondsByOwnerRequest{Owner: owner})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetBondModuleBalanceCmd queries the bond module account balance.
func GetBondModuleBalanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "balance",
Short: "Get bond module account balance.",
Long: strings.TrimSpace(
fmt.Sprintf(`Get bond module balance.
Example:
$ %s query %s balance
`,
version.AppName, types.ModuleName,
),
),
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.GetBondsModuleBalance(cmd.Context(), &types.QueryGetBondModuleBalanceRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

125
x/bond/client/cli/tx.go Normal file
View File

@ -0,0 +1,125 @@
package cli
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"
"github.com/tharsis/ethermint/server/flags"
"github.com/tharsis/ethermint/x/bond/types"
)
// NewTxCmd returns a root CLI command handler for all x/bond transaction commands.
func NewTxCmd() *cobra.Command {
bondTxCmd := &cobra.Command{
Use: types.ModuleName,
Short: "bond transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
bondTxCmd.AddCommand(
NewCreateBondCmd(),
RefillBondCmd(),
WithdrawBondCmd(),
CancelBondCmd(),
)
return bondTxCmd
}
// NewCreateBondCmd is the CLI command for creating a bond.
func NewCreateBondCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create [amount]",
Short: "Create bond.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
coin, err := sdk.ParseCoinNormalized(args[0])
if err != nil {
return err
}
msg := types.NewMsgCreateBond(sdk.NewCoins(coin), clientCtx.GetFromAddress())
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
flags.AddTxFlags(cmd)
return cmd
}
// RefillBondCmd is the CLI command for creating a bond.
func RefillBondCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "refill [bond Id] [amount]",
Short: "Refill bond.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
bondId := args[0]
coin, err := sdk.ParseCoinNormalized(args[1])
if err != nil {
return err
}
msg := types.NewMsgRefillBond(bondId, coin, clientCtx.GetFromAddress())
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
flags.AddTxFlags(cmd)
return cmd
}
// WithdrawBondCmd is the CLI command for withdrawing funds from a bond.
func WithdrawBondCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw [bond Id] [amount]",
Short: "Withdraw amount from bond.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
bondId := args[0]
coin, err := sdk.ParseCoinNormalized(args[1])
if err != nil {
return err
}
msg := types.NewMsgWithdrawBond(bondId, coin, clientCtx.GetFromAddress())
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
flags.AddTxFlags(cmd)
return cmd
}
// CancelBondCmd is the CLI command for cancelling a bond.
func CancelBondCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "cancel [bond Id]",
Short: "cancel bond.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
bondId := args[0]
msg := types.NewMsgCancelBond(bondId, clientCtx.GetFromAddress())
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
flags.AddTxFlags(cmd)
return cmd
}

View File

@ -0,0 +1,13 @@
package testutil
import (
"github.com/stretchr/testify/suite"
"github.com/tharsis/ethermint/testutil/network"
"testing"
)
func TestIntegrationTestSuite(t *testing.T) {
cfg := network.DefaultConfig()
cfg.NumValidators = 1
suite.Run(t, NewIntegrationTestSuite(cfg))
}

View File

@ -0,0 +1,213 @@
package testutil
import (
"fmt"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/types/rest"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/tharsis/ethermint/x/bond/client/cli"
bondtypes "github.com/tharsis/ethermint/x/bond/types"
)
func (s *IntegrationTestSuite) TestGRPCGetBonds() {
val := s.network.Validators[0]
sr := s.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/bond/v1beta1/bonds", val.APIAddress)
testCases := []struct {
name string
url string
expErr bool
errorMsg string
preRun func()
}{
{
"invalid request with headers",
reqUrl + "asdasdas",
true,
"",
func() {
},
},
{
"valid request",
reqUrl,
false,
"",
func() {
s.createBond()
},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, _ := rest.GetRequest(tc.url)
if tc.expErr {
sr.Contains(string(resp), tc.errorMsg)
} else {
var response bondtypes.QueryGetBondsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetBonds()))
}
})
}
}
func (s *IntegrationTestSuite) TestGRPCGetParams() {
val := s.network.Validators[0]
sr := s.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/bond/v1beta1/params", val.APIAddress)
resp, err := rest.GetRequest(reqUrl)
s.Require().NoError(err)
var params bondtypes.QueryParamsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &params)
sr.NoError(err)
sr.Equal(params.GetParams().MaxBondAmount, bondtypes.DefaultParams().MaxBondAmount)
}
func (s *IntegrationTestSuite) TestGRPCGetBondsByOwner() {
val := s.network.Validators[0]
sr := s.Require()
reqUrl := val.APIAddress + "/vulcanize/bond/v1beta1/by-owner/%s"
testCases := []struct {
name string
url string
expErr bool
preRun func()
}{
{
"empty list",
fmt.Sprintf(reqUrl, "asdasd"),
true,
func() {
},
},
{
"valid request",
fmt.Sprintf(reqUrl, s.accountAddress),
false,
func() {
s.createBond()
},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
if !tc.expErr {
tc.preRun()
}
resp, err := rest.GetRequest(tc.url)
s.Require().NoError(err)
var bonds bondtypes.QueryGetBondsByOwnerResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bonds)
sr.NoError(err)
if tc.expErr {
sr.Empty(bonds.GetBonds())
} else {
bondsList := bonds.GetBonds()
sr.NotZero(len(bondsList))
sr.Equal(s.accountAddress, bondsList[0].GetOwner())
}
})
}
}
func (s *IntegrationTestSuite) TestGRPCGetBondById() {
val := s.network.Validators[0]
sr := s.Require()
reqUrl := val.APIAddress + "/vulcanize/bond/v1beta1/bonds/%s"
testCases := []struct {
name string
url string
expErr bool
preRun func() string
}{
{
"invalid request",
fmt.Sprintf(reqUrl, "asdadad"),
true,
func() string {
return ""
},
},
{
"valid request",
reqUrl,
false,
func() string {
// creating the bond
s.createBond()
// getting the bonds list and returning the bond-id
clientCtx := val.ClientCtx
cmd := cli.GetQueryBondLists()
args := []string{
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
}
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var queryResponse bondtypes.QueryGetBondsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
// extract bond id from bonds list
bond := queryResponse.GetBonds()[0]
return bond.GetId()
},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
var bondId string
if !tc.expErr {
bondId = tc.preRun()
tc.url = fmt.Sprintf(reqUrl, bondId)
}
resp, err := rest.GetRequest(tc.url)
s.Require().NoError(err)
var bonds bondtypes.QueryGetBondByIdResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bonds)
if tc.expErr {
sr.Empty(bonds.GetBond().GetId())
} else {
sr.NoError(err)
sr.NotZero(bonds.GetBond().GetId())
sr.Equal(bonds.GetBond().GetId(), bondId)
}
})
}
}
func (s *IntegrationTestSuite) TestGRPCGetBondModuleBalance() {
val := s.network.Validators[0]
sr := s.Require()
reqUrl := fmt.Sprintf("%s/vulcanize/bond/v1beta1/balance", val.APIAddress)
// creating the bond
s.createBond()
s.Run("valid request", func() {
resp, err := rest.GetRequest(reqUrl)
sr.NoError(err)
var response bondtypes.QueryGetBondModuleBalanceResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.False(response.GetBalance().IsZero())
})
}

View File

@ -0,0 +1,331 @@
package testutil
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/stretchr/testify/suite"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/tharsis/ethermint/testutil/network"
"github.com/tharsis/ethermint/x/bond/client/cli"
"github.com/tharsis/ethermint/x/bond/types"
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
accountName string
accountAddress string
}
func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite {
return &IntegrationTestSuite{cfg: cfg}
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
s.network = network.New(s.T(), s.cfg)
_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
s.accountName = "accountName"
// setting up random account
s.createAccountWithBalance(s.accountName)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
func (s *IntegrationTestSuite) TestGetCmdQueryParams() {
val := s.network.Validators[0]
testCases := []struct {
name string
args []string
outputType string
}{
{
"json output",
[]string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
"json",
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := cli.GetQueryParamsCmd()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
s.Require().NoError(err)
var response types.QueryParamsResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response)
s.Require().NoError(err)
s.Require().Equal(response.Params.MaxBondAmount, types.DefaultParams().MaxBondAmount)
})
}
}
func (s *IntegrationTestSuite) createAccountWithBalance(accountName string) {
val := s.network.Validators[0]
sr := s.Require()
consPrivKey := ed25519.GenPrivKey()
consPubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(consPrivKey.PubKey())
sr.NoError(err)
sr.NotNil(consPubKeyBz)
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr := sdk.AccAddress(info.GetPubKey().Address())
_, err = banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200))),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
)
sr.NoError(err)
s.accountAddress = newAddr.String()
}
func (s *IntegrationTestSuite) createBond() {
val := s.network.Validators[0]
sr := s.Require()
createBondCmd := cli.NewCreateBondCmd()
args := []string{
fmt.Sprintf("10%s", s.cfg.BondDenom),
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.accountName),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", s.cfg.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, createBondCmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.Zero(d.Code)
err = s.network.WaitForNextBlock()
sr.NoError(err)
}
func (s *IntegrationTestSuite) TestGetQueryBondLists() {
val := s.network.Validators[0]
sr := s.Require()
testCases := []struct {
name string
args []string
createBond bool
preRun func()
}{
{
"create and get bond lists",
[]string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
func() {
s.createBond()
},
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
if tc.createBond {
tc.preRun()
}
cmd := cli.GetQueryBondLists()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
sr.NoError(err)
var queryResponse types.QueryGetBondsResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
sr.NotZero(len(queryResponse.GetBonds()))
})
}
}
func (s *IntegrationTestSuite) TestGetQueryBondById() {
val := s.network.Validators[0]
sr := s.Require()
testCases := []struct {
name string
args []string
err bool
preRun func() string
}{
{
"invalid bond id",
[]string{
fmt.Sprint("not_found_bond_id"),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
func() string {
return ""
},
},
{
"create and get bond by id",
[]string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
func() string {
// creating the bond
s.createBond()
// getting the bonds list and returning the bond-id
clientCtx := val.ClientCtx
cmd := cli.GetQueryBondLists()
args := []string{
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
}
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var queryResponse types.QueryGetBondsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
// extract bond id from bonds list
bond := queryResponse.GetBonds()[0]
return bond.GetId()
},
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
if !tc.err {
bondId := tc.preRun()
tc.args = append([]string{bondId}, tc.args...)
}
cmd := cli.GetBondByIdCmd()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
sr.NoError(err)
var queryResponse types.QueryGetBondByIdResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
if tc.err {
sr.Zero(len(queryResponse.GetBond().GetId()))
} else {
sr.NotZero(len(queryResponse.GetBond().GetId()))
sr.Equal(s.accountAddress, queryResponse.GetBond().GetOwner())
}
})
}
}
func (s *IntegrationTestSuite) TestGetQueryBondListsByOwner() {
val := s.network.Validators[0]
sr := s.Require()
testCases := []struct {
name string
args []string
err bool
preRun func()
}{
{
"invalid owner address",
[]string{
fmt.Sprint("not_found_bond_id"),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
func() {
},
},
{
"get bond lists by owner address",
[]string{
fmt.Sprint(s.accountAddress),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
false,
func() {
s.createBond()
},
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
if !tc.err {
tc.preRun()
}
cmd := cli.GetBondListByOwnerCmd()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
sr.NoError(err)
var queryResponse types.QueryGetBondsByOwnerResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
if tc.err {
sr.Zero(len(queryResponse.GetBonds()))
} else {
sr.NotZero(len(queryResponse.GetBonds()))
sr.Equal(s.accountAddress, queryResponse.GetBonds()[0].GetOwner())
}
})
}
}
func (s *IntegrationTestSuite) TestGetQueryBondModuleBalance() {
val := s.network.Validators[0]
sr := s.Require()
testCases := []struct {
name string
args []string
err bool
preRun func()
}{
{
"get bond module balance",
[]string{
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
false,
func() {
s.createBond()
},
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
if !tc.err {
tc.preRun()
}
cmd := cli.GetBondModuleBalanceCmd()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
sr.NoError(err)
var queryResponse types.QueryGetBondModuleBalanceResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
sr.False(queryResponse.GetBalance().IsZero())
})
}
}

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