diff --git a/app/test_helper.go b/app/test_helper.go new file mode 100644 index 0000000000..b0d4181f88 --- /dev/null +++ b/app/test_helper.go @@ -0,0 +1,21 @@ +package app + +import ( + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite-hq/cli/ignite/pkg/cosmoscmd" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmdb "github.com/tendermint/tm-db" +) + +// Setup a new App for testing purposes +func TestSetup() (cosmoscmd.App, sdk.Context) { + db := tmdb.NewMemDB() + stateStore := store.NewCommitMultiStore(db) + ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) + encoding := cosmoscmd.MakeEncodingConfig(ModuleBasics) + app := New(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, encoding, simapp.EmptyAppOptions{}) + return app, ctx +} diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index de4124cc7d..ac580066f0 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -1997,33 +1997,44 @@ paths: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs from the + previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. data: type: object @@ -2095,6 +2106,7 @@ paths: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -2152,6 +2164,7 @@ paths: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -2240,35 +2253,48 @@ paths: last_commit_hash: type: string format: byte + description: >- + commit from validators from the last + block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: >- hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs + from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: >- Header defines the structure of a Tendermint block header. @@ -2751,33 +2777,44 @@ paths: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs from the + previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. data: type: object @@ -2849,6 +2886,7 @@ paths: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -2906,6 +2944,7 @@ paths: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -2994,35 +3033,48 @@ paths: last_commit_hash: type: string format: byte + description: >- + commit from validators from the last + block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: >- hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs + from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: >- Header defines the structure of a Tendermint block header. @@ -10915,7 +10967,10 @@ paths: description: >- RedelegationEntry defines a redelegation object with relevant metadata. - description: entries are the redelegation entries. + description: |- + entries are the redelegation entries. + + redelegation entries description: >- Redelegation contains the list of a particular delegator's redelegating bonds @@ -11315,7 +11370,10 @@ paths: description: >- UnbondingDelegationEntry defines an unbonding object with relevant metadata. - description: entries are the unbonding delegation entries. + description: |- + entries are the unbonding delegation entries. + + unbonding delegation entries description: >- UnbondingDelegation stores all of a single delegator's unbonding bonds @@ -12767,33 +12825,44 @@ paths: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs from the + previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. valset: type: array @@ -15482,7 +15551,10 @@ paths: description: >- UnbondingDelegationEntry defines an unbonding object with relevant metadata. - description: entries are the unbonding delegation entries. + description: |- + entries are the unbonding delegation entries. + + unbonding delegation entries description: >- UnbondingDelegation stores all of a single delegator's unbonding bonds @@ -15748,7 +15820,10 @@ paths: description: >- UnbondingDelegationEntry defines an unbonding object with relevant metadata. - description: entries are the unbonding delegation entries. + description: |- + entries are the unbonding delegation entries. + + unbonding delegation entries description: >- UnbondingDelegation stores all of a single delegator's unbonding bonds @@ -16088,6 +16163,7 @@ paths: format: byte index: type: boolean + title: nondeterministic description: >- EventAttribute is a single key-value pair, associated with an event. @@ -16294,6 +16370,9 @@ paths: } parameters: - name: body + description: |- + SimulateRequest is the request type for the Service.Simulate + RPC method. in: body required: true schema: @@ -16872,6 +16951,7 @@ paths: format: byte index: type: boolean + title: nondeterministic description: >- EventAttribute is a single key-value pair, associated with an event. @@ -17093,6 +17173,11 @@ paths: } parameters: - name: body + description: >- + BroadcastTxRequest is the request type for the + Service.BroadcastTxRequest + + RPC method. in: body required: true schema: @@ -28793,11 +28878,13 @@ paths: response: type: string format: byte - votersHash: - type: object - additionalProperties: + votes: + type: array + items: type: object properties: + address: + type: string Hash: type: string format: byte @@ -28960,11 +29047,13 @@ paths: response: type: string format: byte - votersHash: - type: object - additionalProperties: + votes: + type: array + items: type: object properties: + address: + type: string Hash: type: string format: byte @@ -32688,33 +32777,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. data: type: object @@ -32783,6 +32881,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -32840,6 +32939,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -32928,35 +33028,48 @@ definitions: last_commit_hash: type: string format: byte + description: >- + commit from validators from the last + block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: >- hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs + from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: >- Header defines the structure of a Tendermint block header. @@ -33239,33 +33352,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. data: type: object @@ -33334,6 +33456,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -33391,6 +33514,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -33479,35 +33603,48 @@ definitions: last_commit_hash: type: string format: byte + description: >- + commit from validators from the last + block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: >- hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs + from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: >- Header defines the structure of a Tendermint block header. @@ -34549,33 +34686,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. data: type: object @@ -34644,6 +34790,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -34701,6 +34848,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -34788,35 +34936,46 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: >- hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs from + the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: >- Header defines the structure of a Tendermint block header. @@ -35183,6 +35342,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -35239,6 +35399,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -35313,6 +35474,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -35369,6 +35531,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -35456,33 +35619,44 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs from the + previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. commit: type: object @@ -35686,6 +35860,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -35743,6 +35918,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -35830,33 +36006,44 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs from the + previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: >- Header defines the structure of a Tendermint block header. @@ -36060,33 +36247,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. tendermint.types.LightBlock: type: object @@ -36143,33 +36339,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. commit: type: object @@ -36338,33 +36543,44 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs from the previous + block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. commit: type: object @@ -36577,33 +36793,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. commit: type: object @@ -36790,6 +37015,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -39698,33 +39924,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. valset: type: array @@ -40257,7 +40492,10 @@ definitions: description: >- UnbondingDelegationEntry defines an unbonding object with relevant metadata. - description: entries are the unbonding delegation entries. + description: |- + entries are the unbonding delegation entries. + + unbonding delegation entries description: >- UnbondingDelegation stores all of a single delegator's unbonding bonds @@ -40945,33 +41183,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. valset: type: array @@ -41373,7 +41620,10 @@ definitions: description: >- RedelegationEntry defines a redelegation object with relevant metadata. - description: entries are the redelegation entries. + description: |- + entries are the redelegation entries. + + redelegation entries description: >- Redelegation contains the list of a particular delegator's redelegating bonds @@ -41492,7 +41742,10 @@ definitions: description: >- UnbondingDelegationEntry defines an unbonding object with relevant metadata. - description: entries are the unbonding delegation entries. + description: |- + entries are the unbonding delegation entries. + + unbonding delegation entries description: |- UnbondingDelegation stores all of a single delegator's unbonding bonds for a single validator in an time-ordered list. @@ -41904,7 +42157,10 @@ definitions: description: >- UnbondingDelegationEntry defines an unbonding object with relevant metadata. - description: entries are the unbonding delegation entries. + description: |- + entries are the unbonding delegation entries. + + unbonding delegation entries description: >- UnbondingDelegation stores all of a single delegator's unbonding bonds @@ -42293,7 +42549,10 @@ definitions: description: >- RedelegationEntry defines a redelegation object with relevant metadata. - description: entries are the redelegation entries. + description: |- + entries are the redelegation entries. + + redelegation entries description: >- Redelegation contains the list of a particular delegator's redelegating bonds @@ -42406,7 +42665,10 @@ definitions: description: >- RedelegationEntry defines a redelegation object with relevant metadata. - description: entries are the redelegation entries. + description: |- + entries are the redelegation entries. + + redelegation entries description: >- Redelegation contains the list of a particular delegator's redelegating bonds @@ -42496,7 +42758,10 @@ definitions: description: >- UnbondingDelegationEntry defines an unbonding object with relevant metadata. - description: entries are the unbonding delegation entries. + description: |- + entries are the unbonding delegation entries. + + unbonding delegation entries description: |- UnbondingDelegation stores all of a single delegator's unbonding bonds for a single validator in an time-ordered list. @@ -42891,6 +43156,7 @@ definitions: format: byte index: type: boolean + title: nondeterministic description: >- EventAttribute is a single key-value pair, associated with an event. @@ -43198,6 +43464,7 @@ definitions: format: byte index: type: boolean + title: nondeterministic description: >- EventAttribute is a single key-value pair, associated with an event. @@ -43681,6 +43948,7 @@ definitions: format: byte index: type: boolean + title: nondeterministic description: >- EventAttribute is a single key-value pair, associated with an event. @@ -43845,33 +44113,42 @@ definitions: last_commit_hash: type: string format: byte + description: commit from validators from the last block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: root hash of all results from the txs from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: Header defines the structure of a Tendermint block header. data: type: object @@ -43940,6 +44217,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -43997,6 +44275,7 @@ definitions: format: byte title: PartsetHeader title: BlockID + description: zero if vote is nil. timestamp: type: string format: date-time @@ -44085,35 +44364,48 @@ definitions: last_commit_hash: type: string format: byte + description: >- + commit from validators from the last + block title: hashes of block data data_hash: type: string format: byte + title: transactions validators_hash: type: string format: byte + description: validators for the current block title: >- hashes from the app output from the prev block next_validators_hash: type: string format: byte + title: validators for the next block consensus_hash: type: string format: byte + title: consensus params for current block app_hash: type: string format: byte + title: state after txs from the previous block last_results_hash: type: string format: byte + title: >- + root hash of all results from the txs + from the previous block evidence_hash: type: string format: byte + description: evidence included in the block title: consensus info proposer_address: type: string format: byte + title: original proposer of the block description: >- Header defines the structure of a Tendermint block header. @@ -44628,6 +44920,7 @@ definitions: format: byte index: type: boolean + title: nondeterministic description: >- EventAttribute is a single key-value pair, associated with an event. @@ -44950,6 +45243,7 @@ definitions: format: byte index: type: boolean + title: nondeterministic description: >- EventAttribute is a single key-value pair, associated with an event. @@ -45398,6 +45692,7 @@ definitions: format: byte index: type: boolean + title: nondeterministic description: >- EventAttribute is a single key-value pair, associated with an event. @@ -46556,6 +46851,7 @@ definitions: format: byte index: type: boolean + title: nondeterministic description: 'EventAttribute is a single key-value pair, associated with an event.' description: >- Event allows application developers to attach additional information to @@ -46575,6 +46871,7 @@ definitions: format: byte index: type: boolean + title: nondeterministic description: 'EventAttribute is a single key-value pair, associated with an event.' cosmos.upgrade.v1beta1.ModuleVersion: type: object @@ -51497,17 +51794,20 @@ definitions: properties: chainID: type: string - api_id: - type: integer - format: int64 + connection_type: + type: string api_url: type: string + title: >- + some relays have associated urls that are filled with params + ('/block/{height}') session_id: type: string format: uint64 cu_sum: type: string format: uint64 + title: total compute unit used including this relay data: type: string format: byte @@ -51545,6 +51845,7 @@ definitions: queryHash: type: string format: byte + title: we only need it for payment later sig: type: string format: byte @@ -51557,6 +51858,9 @@ definitions: type: string sync: type: string + unresponsive_providers: + type: string + format: byte reply: type: object properties: @@ -51566,6 +51870,7 @@ definitions: sig: type: string format: byte + title: sign the data hash+query hash+nonce nonce: type: integer format: int64 @@ -51578,6 +51883,9 @@ definitions: sig_blocks: type: string format: byte + title: >- + sign + latest_block+finalized_blocks_hashes+session_id+block_height+relay_num lavanet.lava.conflict.ConflictVote: type: object properties: @@ -51620,11 +51928,13 @@ definitions: response: type: string format: byte - votersHash: - type: object - additionalProperties: + votes: + type: array + items: type: object properties: + address: + type: string Hash: type: string format: byte @@ -51643,6 +51953,7 @@ definitions: sig: type: string format: byte + title: sign the data hash+query hash+nonce nonce: type: integer format: int64 @@ -51655,6 +51966,9 @@ definitions: sig_blocks: type: string format: byte + title: >- + sign + latest_block+finalized_blocks_hashes+session_id+block_height+relay_num relayReply1: type: object properties: @@ -51664,6 +51978,7 @@ definitions: sig: type: string format: byte + title: sign the data hash+query hash+nonce nonce: type: integer format: int64 @@ -51676,6 +51991,9 @@ definitions: sig_blocks: type: string format: byte + title: >- + sign + latest_block+finalized_blocks_hashes+session_id+block_height+relay_num lavanet.lava.conflict.MsgConflictVoteCommitResponse: type: object lavanet.lava.conflict.MsgConflictVoteRevealResponse: @@ -51758,11 +52076,13 @@ definitions: response: type: string format: byte - votersHash: - type: object - additionalProperties: + votes: + type: array + items: type: object properties: + address: + type: string Hash: type: string format: byte @@ -51839,11 +52159,13 @@ definitions: response: type: string format: byte - votersHash: - type: object - additionalProperties: + votes: + type: array + items: type: object properties: + address: + type: string Hash: type: string format: byte @@ -51886,17 +52208,20 @@ definitions: properties: chainID: type: string - api_id: - type: integer - format: int64 + connection_type: + type: string api_url: type: string + title: >- + some relays have associated urls that are filled with params + ('/block/{height}') session_id: type: string format: uint64 cu_sum: type: string format: uint64 + title: total compute unit used including this relay data: type: string format: byte @@ -51934,6 +52259,7 @@ definitions: queryHash: type: string format: byte + title: we only need it for payment later sig: type: string format: byte @@ -51946,6 +52272,9 @@ definitions: type: string sync: type: string + unresponsive_providers: + type: string + format: byte reply: type: object properties: @@ -51955,6 +52284,7 @@ definitions: sig: type: string format: byte + title: sign the data hash+query hash+nonce nonce: type: integer format: int64 @@ -51967,6 +52297,9 @@ definitions: sig_blocks: type: string format: byte + title: >- + sign + latest_block+finalized_blocks_hashes+session_id+block_height+relay_num conflictRelayData1: type: object properties: @@ -51975,17 +52308,20 @@ definitions: properties: chainID: type: string - api_id: - type: integer - format: int64 + connection_type: + type: string api_url: type: string + title: >- + some relays have associated urls that are filled with params + ('/block/{height}') session_id: type: string format: uint64 cu_sum: type: string format: uint64 + title: total compute unit used including this relay data: type: string format: byte @@ -52023,6 +52359,7 @@ definitions: queryHash: type: string format: byte + title: we only need it for payment later sig: type: string format: byte @@ -52035,6 +52372,9 @@ definitions: type: string sync: type: string + unresponsive_providers: + type: string + format: byte reply: type: object properties: @@ -52044,6 +52384,7 @@ definitions: sig: type: string format: byte + title: sign the data hash+query hash+nonce nonce: type: integer format: int64 @@ -52056,6 +52397,9 @@ definitions: sig_blocks: type: string format: byte + title: >- + sign + latest_block+finalized_blocks_hashes+session_id+block_height+relay_num lavanet.lava.conflict.Rewards: type: object properties: @@ -52068,6 +52412,8 @@ definitions: lavanet.lava.conflict.Vote: type: object properties: + address: + type: string Hash: type: string format: byte @@ -52113,9 +52459,8 @@ definitions: properties: chainID: type: string - api_id: - type: integer - format: int64 + connection_type: + type: string api_url: type: string title: >- @@ -52178,8 +52523,6 @@ definitions: type: string sync: type: string - connection_type: - type: string unresponsive_providers: type: string format: byte diff --git a/testutil/common/common.go b/testutil/common/common.go index b99aaa0e65..e0fb8e4b81 100644 --- a/testutil/common/common.go +++ b/testutil/common/common.go @@ -56,7 +56,6 @@ func StakeAccount(t *testing.T, ctx context.Context, keepers testkeeper.Keepers, vrfPk.Unmarshal(pk) _, err := servers.PairingServer.StakeClient(ctx, &types.MsgStakeClient{Creator: acc.Addr.String(), ChainID: spec.Name, Amount: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(stake)), Geolocation: 1, Vrfpk: vrfPk.String()}) require.Nil(t, err) - } } diff --git a/testutil/keeper/keepers_init.go b/testutil/keeper/keepers_init.go index aec445c9fa..34e3213762 100644 --- a/testutil/keeper/keepers_init.go +++ b/testutil/keeper/keepers_init.go @@ -180,8 +180,8 @@ func NewBlock(ctx context.Context, ks *Keepers) { ks.Epochstorage.FixateParams(unwrapedCtx, block) //begin block ks.Epochstorage.SetEpochDetailsStart(unwrapedCtx, block) - ks.Epochstorage.StoreEpochStakeStorage(unwrapedCtx, block, epochstoragetypes.ProviderKey) - ks.Epochstorage.StoreEpochStakeStorage(unwrapedCtx, block, epochstoragetypes.ClientKey) + ks.Epochstorage.StoreCurrentEpochStakeStorage(unwrapedCtx, block, epochstoragetypes.ProviderKey) + ks.Epochstorage.StoreCurrentEpochStakeStorage(unwrapedCtx, block, epochstoragetypes.ClientKey) ks.Pairing.RemoveOldEpochPayment(unwrapedCtx) ks.Pairing.CheckUnstakingForCommit(unwrapedCtx) diff --git a/x/conflict/types/expected_keepers.go b/x/conflict/types/expected_keepers.go index 755b7f2602..5cc2419dbb 100644 --- a/x/conflict/types/expected_keepers.go +++ b/x/conflict/types/expected_keepers.go @@ -25,8 +25,9 @@ type EpochstorageKeeper interface { GetStakeEntryForClientEpoch(ctx sdk.Context, chainID string, selectedClient sdk.AccAddress, epoch uint64) (entry *epochstoragetypes.StakeEntry, err error) GetStakeEntryForProviderEpoch(ctx sdk.Context, chainID string, selectedProvider sdk.AccAddress, epoch uint64) (entry *epochstoragetypes.StakeEntry, err error) GetStakeEntryForAllProvidersEpoch(ctx sdk.Context, chainID string, epoch uint64) (entrys *[]epochstoragetypes.StakeEntry, err error) - ModifyStakeEntry(ctx sdk.Context, storageType string, chainID string, stakeEntry epochstoragetypes.StakeEntry, removeIndex uint64) - StakeEntryByAddress(ctx sdk.Context, storageType string, chainID string, address sdk.AccAddress) (value epochstoragetypes.StakeEntry, found bool, index uint64) + ModifyStakeEntryCurrent(ctx sdk.Context, storageType string, chainID string, stakeEntry epochstoragetypes.StakeEntry, removeIndex uint64) + GetStakeEntryByAddressCurrent(ctx sdk.Context, storageType string, chainID string, address sdk.AccAddress) (value epochstoragetypes.StakeEntry, found bool, index uint64) + BypassCurrentAndAppendNewEpochStakeEntry(ctx sdk.Context, storageType string, chainID string, stakeEntry epochstoragetypes.StakeEntry) (added bool, err error) PushFixatedParams(ctx sdk.Context, block uint64, limit uint64) } diff --git a/x/epochstorage/keeper/stake_storage.go b/x/epochstorage/keeper/stake_storage.go index 3d038c7c9a..e45c02c49d 100644 --- a/x/epochstorage/keeper/stake_storage.go +++ b/x/epochstorage/keeper/stake_storage.go @@ -209,7 +209,7 @@ func (k Keeper) GetStakeEntryByAddressFromStorage(ctx sdk.Context, stakeStorage return } -func (k Keeper) StakeEntryByAddress(ctx sdk.Context, storageType string, chainID string, address sdk.AccAddress) (value types.StakeEntry, found bool, index uint64) { +func (k Keeper) GetStakeEntryByAddressCurrent(ctx sdk.Context, storageType string, chainID string, address sdk.AccAddress) (value types.StakeEntry, found bool, index uint64) { stakeStorage, found := k.GetStakeStorageCurrent(ctx, storageType, chainID) if !found { return types.StakeEntry{}, false, 0 @@ -226,7 +226,7 @@ func (k Keeper) StakeEntryByAddress(ctx sdk.Context, storageType string, chainID return } -func (k Keeper) RemoveStakeEntry(ctx sdk.Context, storageType string, chainID string, idx uint64) { +func (k Keeper) RemoveStakeEntryCurrent(ctx sdk.Context, storageType string, chainID string, idx uint64) { stakeStorage, found := k.GetStakeStorageCurrent(ctx, storageType, chainID) if !found { return @@ -235,7 +235,7 @@ func (k Keeper) RemoveStakeEntry(ctx sdk.Context, storageType string, chainID st k.SetStakeStorageCurrent(ctx, storageType, chainID, stakeStorage) } -func (k Keeper) AppendStakeEntry(ctx sdk.Context, storageType string, chainID string, stakeEntry types.StakeEntry) { +func (k Keeper) AppendStakeEntryCurrent(ctx sdk.Context, storageType string, chainID string, stakeEntry types.StakeEntry) { //this stake storage entries are sorted by stake amount stakeStorage, found := k.GetStakeStorageCurrent(ctx, storageType, chainID) var entries = []types.StakeEntry{} @@ -264,7 +264,7 @@ func (k Keeper) AppendStakeEntry(ctx sdk.Context, storageType string, chainID st k.SetStakeStorageCurrent(ctx, storageType, chainID, stakeStorage) } -func (k Keeper) ModifyStakeEntry(ctx sdk.Context, storageType string, chainID string, stakeEntry types.StakeEntry, removeIndex uint64) { +func (k Keeper) ModifyStakeEntryCurrent(ctx sdk.Context, storageType string, chainID string, stakeEntry types.StakeEntry, removeIndex uint64) { //this stake storage entries are sorted by stake amount stakeStorage, found := k.GetStakeStorageCurrent(ctx, storageType, chainID) if !found { @@ -423,7 +423,7 @@ func (k Keeper) PopUnstakeEntries(ctx sdk.Context, storageType string, block uin // ------------------------------------------------ // takes the current stake storage and puts it in epoch storage -func (k Keeper) StoreEpochStakeStorage(ctx sdk.Context, block uint64, storageType string) { +func (k Keeper) StoreCurrentEpochStakeStorage(ctx sdk.Context, block uint64, storageType string) { allChainIDs := k.specKeeper.GetAllChainIDs(ctx) for _, chainID := range allChainIDs { tmpStorage, found := k.GetStakeStorageCurrent(ctx, storageType, chainID) @@ -487,3 +487,48 @@ func (k Keeper) GetEpochStakeEntries(ctx sdk.Context, block uint64, storageType } return stakeStorage.StakeEntries, true } + +//append to epoch stake entries ONLY if it doesn't exist +func (k Keeper) BypassCurrentAndAppendNewEpochStakeEntry(ctx sdk.Context, storageType string, chainID string, stakeEntry types.StakeEntry) (added bool, err error) { + epoch := k.GetEpochStart(ctx) + stakeEntry.Deadline = epoch + storage, found := k.getStakeStorageEpoch(ctx, epoch, storageType, chainID) + if !found { + entries := []types.StakeEntry{} + //create a new one + storage = types.StakeStorage{Index: k.StakeStorageKey(storageType, epoch, chainID), StakeEntries: entries} + } + entryAddr, err := sdk.AccAddressFromBech32(stakeEntry.Address) + if err != nil { + return false, err + } + + for _, clientStakeEntry := range storage.StakeEntries { + clientAddr, err := sdk.AccAddressFromBech32(clientStakeEntry.Address) + if err != nil { + panic(fmt.Sprintf("invalid user address saved in keeper %s, err: %s", clientStakeEntry.Address, err)) + } + if clientAddr.Equals(entryAddr) { + return false, nil //stake already exists in this epoch + } + } + + //put it in the right place + entries := storage.StakeEntries + sortFunc := func(i int) bool { + return stakeEntry.Stake.Amount.LT(entries[i].Stake.Amount) + } + //returns the smallest index in which the sort func is true + index := sort.Search(len(entries), sortFunc) + if index < len(entries) { + entries = append(entries[:index+1], entries[index:]...) + entries[index] = stakeEntry + } else { + //put in the end + entries = append(entries, stakeEntry) + } + + storage.StakeEntries = entries + k.SetStakeStorage(ctx, storage) + return true, nil +} diff --git a/x/epochstorage/module.go b/x/epochstorage/module.go index 1e45901989..a6d90f8d54 100644 --- a/x/epochstorage/module.go +++ b/x/epochstorage/module.go @@ -185,9 +185,9 @@ func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { am.keeper.SetEpochDetailsStart(ctx, block) - am.keeper.StoreEpochStakeStorage(ctx, block, types.ProviderKey) + am.keeper.StoreCurrentEpochStakeStorage(ctx, block, types.ProviderKey) - am.keeper.StoreEpochStakeStorage(ctx, block, types.ClientKey) + am.keeper.StoreCurrentEpochStakeStorage(ctx, block, types.ClientKey) // Notify world we have a new session details := map[string]string{"height": fmt.Sprintf("%d", ctx.BlockHeight()), "description": "New Block Epoch Started"} logger := am.keeper.Logger(ctx) diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index c503f7c5d5..38b37321bb 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -294,7 +294,7 @@ func (k msgServer) dealWithUnresponsiveProviders(ctx sdk.Context, unresponsiveDa utils.LavaFormatError("unable to sdk.AccAddressFromBech32(unresponsive_provider)", err, &map[string]string{"unresponsive_provider_address": unresponsiveProvider}) continue } - existingEntry, entryExists, indexInStakeStorage := k.epochStorageKeeper.StakeEntryByAddress(ctx, epochstoragetypes.ProviderKey, chainID, sdkUnresponsiveProviderAddress) + existingEntry, entryExists, indexInStakeStorage := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, epochstoragetypes.ProviderKey, chainID, sdkUnresponsiveProviderAddress) // if !entryExists provider is alraedy unstaked if !entryExists { continue // if provider is not staked, nothing to do. @@ -362,6 +362,6 @@ func (k msgServer) getTotalPaymentsForPreviousEpochs(ctx sdk.Context, numberOfEp } func (k msgServer) unSafeUnstakeProviderEntry(ctx sdk.Context, providerKey string, chainID string, indexInStakeStorage uint64, existingEntry epochstoragetypes.StakeEntry) { - k.epochStorageKeeper.RemoveStakeEntry(ctx, epochstoragetypes.ProviderKey, chainID, indexInStakeStorage) + k.epochStorageKeeper.RemoveStakeEntryCurrent(ctx, epochstoragetypes.ProviderKey, chainID, indexInStakeStorage) k.epochStorageKeeper.AppendUnstakeEntry(ctx, epochstoragetypes.ProviderKey, existingEntry) } diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 63a367802a..54982c11c7 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -142,7 +142,7 @@ func TestRelayPaymentBlockHeight(t *testing.T) { Relays = append(Relays, relayRequest) balanceProvider := ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[0].address, epochstoragetypes.TokenDenom).Amount.Int64() - stakeClient, found, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) + stakeClient, found, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) require.Equal(t, true, found) _, err = ts.servers.PairingServer.RelayPayment(ts.ctx, &types.MsgRelayPayment{Creator: ts.providers[0].address.String(), Relays: Relays}) @@ -157,7 +157,7 @@ func TestRelayPaymentBlockHeight(t *testing.T) { ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[0].address, epochstoragetypes.TokenDenom).Amount.Int64()) burn := ts.keepers.Pairing.BurnCoinsPerCU(sdk.UnwrapSDKContext(ts.ctx)).MulInt64(int64(ts.spec.GetApis()[0].ComputeUnits * 10)) - newStakeClient, _, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) + newStakeClient, _, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) require.Nil(t, err) require.Equal(t, stakeClient.Stake.Amount.Int64()-burn.TruncateInt64(), newStakeClient.Stake.Amount.Int64()) @@ -222,7 +222,7 @@ func setupClientsAndProvidersForUnresponsiveness(t *testing.T, amountOfClients i ts.keepers.Spec.SetSpec(sdk.UnwrapSDKContext(ts.ctx), ts.spec) err := ts.addClient(amountOfClients) require.Nil(t, err) - err = ts.addProvider(3) + err = ts.addProvider(2) require.Nil(t, err) return ts } @@ -234,7 +234,7 @@ func TestRelayPaymentUnstakingProviderForUnresponsiveness(t *testing.T) { for i := 0; i < 2; i++ { // move to epoch 3 so we can check enough epochs in the past ts.ctx = testkeeper.AdvanceEpoch(ts.ctx, ts.keepers) } - staked_amount, _, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) + staked_amount, _, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) balanceProvideratBeforeStake := staked_amount.Stake.Amount.Int64() + ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[1].address, epochstoragetypes.TokenDenom).Amount.Int64() unresponsiveProvidersData, err := json.Marshal([]string{ts.providers[1].address.String()}) @@ -265,7 +265,7 @@ func TestRelayPaymentUnstakingProviderForUnresponsiveness(t *testing.T) { // testing that the provider was unstaked. and checking his balance after many epochs _, unStakeStoragefound, _ := ts.keepers.Epochstorage.UnstakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.providers[1].address) require.True(t, unStakeStoragefound) - _, stakeStorageFound, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) + _, stakeStorageFound, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) require.False(t, stakeStorageFound) OriginalBlockHeight := uint64(sdk.UnwrapSDKContext(ts.ctx).BlockHeight()) @@ -282,7 +282,7 @@ func TestRelayPaymentUnstakingProviderForUnresponsiveness(t *testing.T) { _, unStakeStoragefound, _ = ts.keepers.Epochstorage.UnstakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.providers[1].address) require.False(t, unStakeStoragefound) // also that the provider wasnt returned to stake pool - _, stakeStorageFound, _ = ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) + _, stakeStorageFound, _ = ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) require.False(t, stakeStorageFound) balanceProviderAfterUnstakeMoneyReturned := ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[1].address, epochstoragetypes.TokenDenom).Amount.Int64() @@ -325,7 +325,7 @@ func TestRelayPaymentUnstakingProviderForUnresponsivenessContinueComplainingAfte // testing that the provider wasnt unstaked. _, unStakeStoragefound, _ := ts.keepers.Epochstorage.UnstakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.providers[1].address) require.True(t, unStakeStoragefound) - _, stakeStorageFound, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) + _, stakeStorageFound, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) require.False(t, stakeStorageFound) // continue reporting provider after unstake @@ -337,10 +337,10 @@ func TestRelayPaymentUnstakingProviderForUnresponsivenessContinueComplainingAfte for clientIndex := 0; clientIndex < testClientAmount; clientIndex++ { // testing testClientAmount of complaints relayRequest := &types.RelayRequest{ - Provider: ts.providers[2].address.String(), + Provider: ts.providers[0].address.String(), ApiUrl: "", Data: []byte(ts.spec.Apis[0].Name), - SessionId: uint64(1), + SessionId: uint64(2), ChainID: ts.spec.Name, CuSum: ts.spec.Apis[0].ComputeUnits * 10, BlockHeight: sdk.UnwrapSDKContext(ts.ctx).BlockHeight(), @@ -354,10 +354,10 @@ func TestRelayPaymentUnstakingProviderForUnresponsivenessContinueComplainingAfte require.Nil(t, err) RelaysAfter = append(RelaysAfter, relayRequest) } - _, err = ts.servers.PairingServer.RelayPayment(ts.ctx, &types.MsgRelayPayment{Creator: ts.providers[2].address.String(), Relays: RelaysAfter}) + _, err = ts.servers.PairingServer.RelayPayment(ts.ctx, &types.MsgRelayPayment{Creator: ts.providers[0].address.String(), Relays: RelaysAfter}) require.Nil(t, err) - _, stakeStorageFound, _ = ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) + _, stakeStorageFound, _ = ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) require.False(t, stakeStorageFound) _, unStakeStoragefound, _ = ts.keepers.Epochstorage.UnstakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.providers[1].address) require.True(t, unStakeStoragefound) @@ -409,7 +409,7 @@ func TestRelayPaymentNotUnstakingProviderForUnresponsivenessIfNoEpochInformation // testing that the provider wasnt unstaked. _, unStakeStoragefound, _ := ts.keepers.Epochstorage.UnstakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.providers[1].address) require.False(t, unStakeStoragefound) - _, stakeStorageFound, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) + _, stakeStorageFound, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) require.True(t, stakeStorageFound) } @@ -529,7 +529,7 @@ func TestRelayPaymentNotUnstakingProviderForUnresponsivenessBecauseOfServices(t // testing that the provider wasnt unstaked. _, unStakeStoragefound, _ := ts.keepers.Epochstorage.UnstakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.providers[1].address) require.False(t, unStakeStoragefound) - _, stakeStorageFound, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) + _, stakeStorageFound, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ProviderKey, ts.spec.Name, ts.providers[1].address) require.True(t, stakeStorageFound) } @@ -568,7 +568,7 @@ func TestRelayPaymentDoubleSpending(t *testing.T) { Relays = append(Relays, &relayRequest2) balance := ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[0].address, epochstoragetypes.TokenDenom).Amount.Int64() - stakeClient, _, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) + stakeClient, _, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) _, err = ts.servers.PairingServer.RelayPayment(ts.ctx, &types.MsgRelayPayment{Creator: ts.providers[0].address.String(), Relays: Relays}) require.NotNil(t, err) @@ -578,7 +578,7 @@ func TestRelayPaymentDoubleSpending(t *testing.T) { require.Equal(t, balance+want.TruncateInt64(), ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[0].address, epochstoragetypes.TokenDenom).Amount.Int64()) burn := ts.keepers.Pairing.BurnCoinsPerCU(sdk.UnwrapSDKContext(ts.ctx)).MulInt64(int64(cuSum)) - newStakeClient, _, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) + newStakeClient, _, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) require.Equal(t, stakeClient.Stake.Amount.Int64()-burn.TruncateInt64(), newStakeClient.Stake.Amount.Int64()) } @@ -761,7 +761,7 @@ func TestRelayPaymentOldEpochs(t *testing.T) { Relays = append(Relays, relayRequest) balance := ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[0].address, epochstoragetypes.TokenDenom).Amount.Int64() - stakeClient, _, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) + stakeClient, _, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) _, err = ts.servers.PairingServer.RelayPayment(ts.ctx, &types.MsgRelayPayment{Creator: ts.providers[0].address.String(), Relays: Relays}) if tt.valid { @@ -771,7 +771,7 @@ func TestRelayPaymentOldEpochs(t *testing.T) { ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[0].address, epochstoragetypes.TokenDenom).Amount.Int64()) burn := ts.keepers.Pairing.BurnCoinsPerCU(sdk.UnwrapSDKContext(ts.ctx)).MulInt64(int64(cuSum)) - newStakeClient, _, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) + newStakeClient, _, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) require.Equal(t, stakeClient.Stake.Amount.Int64()-burn.TruncateInt64(), newStakeClient.Stake.Amount.Int64()) } else { @@ -836,7 +836,7 @@ func TestRelayPaymentQoS(t *testing.T) { Relays = append(Relays, &relay) balance := ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[0].address, epochstoragetypes.TokenDenom).Amount.Int64() - stakeClient, _, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) + stakeClient, _, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) _, err = ts.servers.PairingServer.RelayPayment(ts.ctx, &types.MsgRelayPayment{Creator: ts.providers[0].address.String(), Relays: Relays}) if tt.valid { @@ -852,7 +852,7 @@ func TestRelayPaymentQoS(t *testing.T) { ts.keepers.BankKeeper.GetBalance(sdk.UnwrapSDKContext(ts.ctx), ts.providers[0].address, epochstoragetypes.TokenDenom).Amount.Int64()) burn := ts.keepers.Pairing.BurnCoinsPerCU(sdk.UnwrapSDKContext(ts.ctx)).MulInt64(int64(cuSum)) - newStakeClient, _, _ := ts.keepers.Epochstorage.StakeEntryByAddress(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) + newStakeClient, _, _ := ts.keepers.Epochstorage.GetStakeEntryByAddressCurrent(sdk.UnwrapSDKContext(ts.ctx), epochstoragetypes.ClientKey, ts.spec.Index, ts.clients[0].address) require.Equal(t, stakeClient.Stake.Amount.Int64()-burn.TruncateInt64(), newStakeClient.Stake.Amount.Int64()) } else { diff --git a/x/pairing/keeper/msg_server_stake_client_test.go b/x/pairing/keeper/msg_server_stake_client_test.go index f21fa0191a..2fb72674fc 100644 --- a/x/pairing/keeper/msg_server_stake_client_test.go +++ b/x/pairing/keeper/msg_server_stake_client_test.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/relayer/sigs" + "github.com/lavanet/lava/testutil/common" testkeeper "github.com/lavanet/lava/testutil/keeper" "github.com/lavanet/lava/utils" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" @@ -62,7 +63,6 @@ func TestNewStakeClient(t *testing.T) { } }) } - } func TestAddStakeClient(t *testing.T) { @@ -119,3 +119,50 @@ func TestAddStakeClient(t *testing.T) { } } + +func TestStakeClientPairingimmediately(t *testing.T) { + servers, keepers, ctx := testkeeper.InitAllKeepers(t) + + //init keepers state + var balance int64 = 10000 + consumer := common.CreateNewAccount(ctx, *keepers, balance) + provider1 := common.CreateNewAccount(ctx, *keepers, balance) + provider2 := common.CreateNewAccount(ctx, *keepers, balance) + + spec := common.CreateMockSpec() + keepers.Spec.SetSpec(sdk.UnwrapSDKContext(ctx), spec) + + keepers.Epochstorage.SetEpochDetails(sdk.UnwrapSDKContext(ctx), *epochstoragetypes.DefaultGenesis().EpochDetails) + + stake := balance / 10 + ctx = testkeeper.AdvanceEpoch(ctx, keepers) + common.StakeAccount(t, ctx, *keepers, *servers, provider1, spec, stake, true) + common.StakeAccount(t, ctx, *keepers, *servers, provider2, spec, stake, true) + + ctx = testkeeper.AdvanceEpoch(ctx, keepers) + common.StakeAccount(t, ctx, *keepers, *servers, consumer, spec, stake, false) + + ctx = testkeeper.AdvanceBlock(ctx, keepers) + + //check pairing in the same epoch + clientStakeEntry, err := keepers.Pairing.VerifyPairingData(sdk.UnwrapSDKContext(ctx), spec.Index, consumer.Addr, uint64(sdk.UnwrapSDKContext(ctx).BlockHeight())) + require.Nil(t, err) + require.Equal(t, clientStakeEntry.Stake.Amount, sdk.NewInt(stake)) + + _, err = keepers.Pairing.GetPairingForClient(sdk.UnwrapSDKContext(ctx), spec.Index, consumer.Addr) + require.Nil(t, err) + + //try to change stake + common.StakeAccount(t, ctx, *keepers, *servers, consumer, spec, 2*stake, false) + clientStakeEntry, err = keepers.Pairing.VerifyPairingData(sdk.UnwrapSDKContext(ctx), spec.Index, consumer.Addr, uint64(sdk.UnwrapSDKContext(ctx).BlockHeight())) + require.Nil(t, err) + require.Equal(t, clientStakeEntry.Stake.Amount, sdk.NewInt(stake)) + + //new stake takes effect + ctx = testkeeper.AdvanceEpoch(ctx, keepers) + + clientStakeEntry, err = keepers.Pairing.VerifyPairingData(sdk.UnwrapSDKContext(ctx), spec.Index, consumer.Addr, uint64(sdk.UnwrapSDKContext(ctx).BlockHeight())) + require.Nil(t, err) + require.Equal(t, clientStakeEntry.Stake.Amount, sdk.NewInt(2*stake)) + +} diff --git a/x/pairing/keeper/msg_server_unstake_client_test.go b/x/pairing/keeper/msg_server_unstake_client_test.go index 355b3b0a2a..6532f0331d 100644 --- a/x/pairing/keeper/msg_server_unstake_client_test.go +++ b/x/pairing/keeper/msg_server_unstake_client_test.go @@ -8,7 +8,6 @@ import ( testkeeper "github.com/lavanet/lava/testutil/keeper" "github.com/lavanet/lava/utils" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" - epochtypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/pairing/types" spectypes "github.com/lavanet/lava/x/spec/types" "github.com/stretchr/testify/require" @@ -34,7 +33,7 @@ func TestUnstakeClient(t *testing.T) { spec.Apis = append(spec.Apis, spectypes.ServiceApi{Name: specName + "API", ComputeUnits: 100, Enabled: true, ApiInterfaces: nil}) keepers.Spec.SetSpec(sdk.UnwrapSDKContext(ctx), spec) - keepers.Epochstorage.SetEpochDetails(sdk.UnwrapSDKContext(ctx), *epochtypes.DefaultGenesis().EpochDetails) + keepers.Epochstorage.SetEpochDetails(sdk.UnwrapSDKContext(ctx), *epochstoragetypes.DefaultGenesis().EpochDetails) _, err := servers.PairingServer.StakeClient(ctx, &types.MsgStakeClient{Creator: clientAddr.String(), ChainID: spec.Name, Amount: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(amount/10)), Geolocation: 1, Vrfpk: vrfPk.String()}) require.Nil(t, err) ctx = testkeeper.AdvanceEpoch(ctx, keepers) @@ -83,7 +82,7 @@ func TestUnstakeNotStakedClient(t *testing.T) { vrfPk := &utils.VrfPubKey{} vrfPk.Unmarshal(pk) - keepers.Epochstorage.SetEpochDetails(sdk.UnwrapSDKContext(ctx), *epochtypes.DefaultGenesis().EpochDetails) + keepers.Epochstorage.SetEpochDetails(sdk.UnwrapSDKContext(ctx), *epochstoragetypes.DefaultGenesis().EpochDetails) specName := "mockSpec" spec := spectypes.Spec{} @@ -127,7 +126,7 @@ func TestDoubleUnstakeClient(t *testing.T) { vrfPk := &utils.VrfPubKey{} vrfPk.Unmarshal(pk) - keepers.Epochstorage.SetEpochDetails(sdk.UnwrapSDKContext(ctx), *epochtypes.DefaultGenesis().EpochDetails) + keepers.Epochstorage.SetEpochDetails(sdk.UnwrapSDKContext(ctx), *epochstoragetypes.DefaultGenesis().EpochDetails) specName := "mockSpec" spec := spectypes.Spec{} diff --git a/x/pairing/keeper/pairing.go b/x/pairing/keeper/pairing.go index 32d31805fa..2387240084 100644 --- a/x/pairing/keeper/pairing.go +++ b/x/pairing/keeper/pairing.go @@ -47,7 +47,7 @@ func (k Keeper) VerifyPairingData(ctx sdk.Context, chainID string, clientAddress verifiedUser := false //we get the user stakeEntries at the time of check. for unstaking users, we make sure users can't unstake sooner than blocksToSave so we can charge them if the pairing is valid - userStakedEntries, found := k.epochStorageKeeper.GetEpochStakeEntries(ctx, block, epochstoragetypes.ClientKey, chainID) + userStakedEntries, found := k.epochStorageKeeper.GetEpochStakeEntries(ctx, requestedEpochStart, epochstoragetypes.ClientKey, chainID) if !found { return nil, utils.LavaError(ctx, logger, "client_entries_pairing", map[string]string{"chainID": chainID, "query Epoch": strconv.FormatUint(requestedEpochStart, 10), "query block": strconv.FormatUint(block, 10), "current epoch": strconv.FormatUint(currentEpochStart, 10)}, "no EpochStakeEntries entries at all for this spec") } @@ -146,7 +146,7 @@ func (k Keeper) calculatePairingForClient(ctx sdk.Context, providers []epochstor if err != nil { return nil, nil, err } - validProviders = k.returnSubsetOfProvidersByStake(ctx, validProviders, servicersToPairCount, epochStartBlock, chainID) + validProviders = k.returnSubsetOfProvidersByStake(ctx, clientAddress, validProviders, servicersToPairCount, epochStartBlock, chainID) for _, stakeEntry := range validProviders { providerAddress := stakeEntry.Address @@ -160,7 +160,7 @@ func (k Keeper) calculatePairingForClient(ctx sdk.Context, providers []epochstor } //this function randomly chooses count providers by weight -func (k Keeper) returnSubsetOfProvidersByStake(ctx sdk.Context, providersMaps []epochstoragetypes.StakeEntry, count uint64, block uint64, chainID string) (returnedProviders []epochstoragetypes.StakeEntry) { +func (k Keeper) returnSubsetOfProvidersByStake(ctx sdk.Context, clientAddress sdk.AccAddress, providersMaps []epochstoragetypes.StakeEntry, count uint64, block uint64, chainID string) (returnedProviders []epochstoragetypes.StakeEntry) { var stakeSum sdk.Coin = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(0)) hashData := make([]byte, 0) for _, stakedProvider := range providersMaps { @@ -179,7 +179,8 @@ func (k Keeper) returnSubsetOfProvidersByStake(ctx sdk.Context, providersMaps [] } sessionBlockHash := epochStartBlock.Block.Hash() hashData = append(hashData, sessionBlockHash...) - hashData = append(hashData, chainID...) // to make this pairing unique per chainID + hashData = append(hashData, chainID...) // to make this pairing unique per chainID + hashData = append(hashData, clientAddress...) // to make this pairing unique per consumer indexToSkip := make(map[int]bool) // a trick to create a unique set in golang for it := 0; it < int(count); it++ { diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go new file mode 100644 index 0000000000..9d3dedd6f9 --- /dev/null +++ b/x/pairing/keeper/pairing_test.go @@ -0,0 +1,64 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/testutil/common" + testkeeper "github.com/lavanet/lava/testutil/keeper" + epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + "github.com/stretchr/testify/require" +) + +func TestPairingUniqueness(t *testing.T) { + servers, keepers, ctx := testkeeper.InitAllKeepers(t) + keepers.Epochstorage.SetEpochDetails(sdk.UnwrapSDKContext(ctx), *epochstoragetypes.DefaultGenesis().EpochDetails) + + //init keepers state + spec := common.CreateMockSpec() + keepers.Spec.SetSpec(sdk.UnwrapSDKContext(ctx), spec) + + ctx = testkeeper.AdvanceEpoch(ctx, keepers) + + var balance int64 = 10000 + stake := balance / 10 + + consumer1 := common.CreateNewAccount(ctx, *keepers, balance) + common.StakeAccount(t, ctx, *keepers, *servers, consumer1, spec, stake, false) + consumer2 := common.CreateNewAccount(ctx, *keepers, balance) + common.StakeAccount(t, ctx, *keepers, *servers, consumer2, spec, stake, false) + + providers := []common.Account{} + for i := 1; i <= 1000; i++ { + provider := common.CreateNewAccount(ctx, *keepers, balance) + common.StakeAccount(t, ctx, *keepers, *servers, provider, spec, stake, true) + providers = append(providers, provider) + } + + ctx = testkeeper.AdvanceEpoch(ctx, keepers) + + providers1, err := keepers.Pairing.GetPairingForClient(sdk.UnwrapSDKContext(ctx), spec.Index, consumer1.Addr) + require.Nil(t, err) + + providers2, err := keepers.Pairing.GetPairingForClient(sdk.UnwrapSDKContext(ctx), spec.Index, consumer2.Addr) + require.Nil(t, err) + + require.Equal(t, len(providers1), len(providers2)) + + diffrent := false + + for _, provider := range providers1 { + found := false + for _, provider2 := range providers2 { + if provider.Address == provider2.Address { + found = true + } + } + if !found { + diffrent = true + } + } + + require.True(t, diffrent) + +} diff --git a/x/pairing/keeper/stakeModify.go b/x/pairing/keeper/stakeModify.go index 7d3f38db5a..324139355a 100644 --- a/x/pairing/keeper/stakeModify.go +++ b/x/pairing/keeper/stakeModify.go @@ -14,7 +14,7 @@ func (k Keeper) BurnClientStake(ctx sdk.Context, chainID string, clientAddressTo } logger := k.Logger(ctx) //find the user in the stake list - clientEntry, found, indexFound := k.epochStorageKeeper.StakeEntryByAddress(ctx, epochstoragetypes.ClientKey, chainID, clientAddressToBurn) + clientEntry, found, indexFound := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, epochstoragetypes.ClientKey, chainID, clientAddressToBurn) if found { if clientEntry.Stake.IsLT(burnAmount) { if failBurnOnLeftover { @@ -25,7 +25,7 @@ func (k Keeper) BurnClientStake(ctx sdk.Context, chainID string, clientAddressTo //reduce the requested burn from the entry clientEntry.Stake = clientEntry.Stake.Sub(burnAmount) //now we need to save the entry - k.epochStorageKeeper.ModifyStakeEntry(ctx, epochstoragetypes.ClientKey, chainID, clientEntry, indexFound) + k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, epochstoragetypes.ClientKey, chainID, clientEntry, indexFound) if clientEntry.Stake.IsLT(k.MinStakeClient(ctx)) { //if user doesn't have enough stake to stay staked, we will unstake him now @@ -76,13 +76,13 @@ func (k Keeper) CreditStakeEntry(ctx sdk.Context, chainID string, lookUpAddress case false: storageType = epochstoragetypes.ClientKey } - entry, found, indexFound := k.epochStorageKeeper.StakeEntryByAddress(ctx, storageType, chainID, lookUpAddress) + entry, found, indexFound := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, storageType, chainID, lookUpAddress) if found { //add the requested credit to the entry entry.Stake = entry.Stake.Add(creditAmount) //now we need to save the entry k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(creditAmount)) - k.epochStorageKeeper.ModifyStakeEntry(ctx, storageType, chainID, entry, indexFound) + k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, storageType, chainID, entry, indexFound) return true, nil } diff --git a/x/pairing/keeper/staking.go b/x/pairing/keeper/staking.go index 48506ac6cd..8eecb275ce 100644 --- a/x/pairing/keeper/staking.go +++ b/x/pairing/keeper/staking.go @@ -45,15 +45,15 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, provider bool, creator string, ch return utils.LavaError(ctx, logger, "stake_"+stake_type()+"_addr", details, "invalid "+stake_type()+" address") } //define the function here for later use - verifySufficientAmountAndSendToModule := func(ctx sdk.Context, k Keeper, addr sdk.AccAddress, neededAmount sdk.Coin) (bool, error) { + verifySufficientAmountAndSendToModule := func(ctx sdk.Context, k Keeper, addr sdk.AccAddress, neededAmount sdk.Coin) error { if k.bankKeeper.GetBalance(ctx, addr, epochstoragetypes.TokenDenom).IsLT(neededAmount) { - return false, fmt.Errorf("insufficient balance for staking %s current balance: %s", neededAmount, k.bankKeeper.GetBalance(ctx, addr, epochstoragetypes.TokenDenom)) + return fmt.Errorf("insufficient balance for staking %s current balance: %s", neededAmount, k.bankKeeper.GetBalance(ctx, addr, epochstoragetypes.TokenDenom)) } err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, []sdk.Coin{neededAmount}) if err != nil { - return false, fmt.Errorf("invalid transfer coins to module, %s", err) + return fmt.Errorf("invalid transfer coins to module, %s", err) } - return true, nil + return nil } geolocations := k.specKeeper.GeolocationCount(ctx) if geolocation == 0 || geolocation > (1<