Skip to content

Commit 0d78295

Browse files
mpokesainoe
andauthored
feat!: add memo to IBC transfers of ICS rewards (#2290)
* add consumer ID to consumer genesis * add RewardMemo to token transfer * handle memo on provider side * fix democ tests * wip * add e2e-test * refactor consumer reward tests * add consumer migration info * add changelog * fix changelog filename --------- Co-authored-by: Simon Noetzlin <[email protected]>
1 parent ccb2679 commit 0d78295

34 files changed

+624
-203
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- `[x/consumer]` Populate the memo on the IBC transfer packets used to send ICS rewards.
2+
with the required consumer chain Id to identify the consumer to the provider.
3+
- `[x/provider]` Identify the source of ICS rewards from the IBC transfer packet memo.
4+
([\#2290](https://github.com/cosmos/interchain-security/pull/2290))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- `[x/consumer]` Populate the memo on the IBC transfer packets used to send ICS rewards.
2+
with the required consumer chain Id to identify the consumer to the provider.
3+
- `[x/provider]` Identify the source of ICS rewards from the IBC transfer packet memo.
4+
([\#2290](https://github.com/cosmos/interchain-security/pull/2290))

UPGRADING.md

+20
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,26 @@
22

33
## Unreleased
44

5+
### Consumer
6+
7+
Upgrading a consumer from v4.4.x to v4.5.x and from v5.x or v6.1.x to v6.2.x requires state migrations. The following migrators should be added to the upgrade handler of the consumer chain:
8+
9+
10+
```go
11+
// InitializeConsumerId sets the consumer Id parameter in the consumer module,
12+
// to the consumer id for which the consumer is registered on the provider chain.
13+
// The consumer id can be obtained in by querying the provider, e.g. by using the
14+
// QueryConsumerIdFromClientId query.
15+
func InitializeConsumerId(ctx sdk.Context, consumerKeeper consumerkeeper.Keeper) error {
16+
params, err := consumerKeeper.GetParams(ctx)
17+
if err != nil {
18+
return err
19+
}
20+
params.ConsumerId = ConsumerId
21+
return consumerKeeper.SetParams(ctx, params)
22+
}
23+
```
24+
525
### Provider
626

727
Upgrading a provider from v5.1.x requires state migrations. The following migrators should be added to the upgrade handler of the provider chain:

proto/interchain_security/ccv/v1/shared_consumer.proto

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ message ConsumerParams {
7676
// The period after which a consumer can retry sending a throttled packet.
7777
google.protobuf.Duration retry_delay_period = 13
7878
[ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ];
79+
80+
// The consumer ID of this consumer chain. Used by the consumer module to send
81+
// ICS rewards.
82+
string consumer_id = 14;
7983
}
8084

8185
// ConsumerGenesisState defines shared genesis information between provider and

tests/e2e/action_rapid_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func CreateSubmitChangeRewardDenomsProposalActionGen() *rapid.Generator[SubmitCh
102102
Chain: GetChainIDGen().Draw(t, "Chain"),
103103
From: GetValidatorIDGen().Draw(t, "From"),
104104
Deposit: rapid.Uint().Draw(t, "Deposit"),
105-
Denom: rapid.String().Draw(t, "Denom"),
105+
Denoms: rapid.SliceOf(rapid.String()).Draw(t, "Denoms"),
106106
}
107107
})
108108
}

tests/e2e/actions.go

+96-4
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ func (tr Chain) UpdateConsumer(providerChain ChainID, validator ValidatorID, upd
495495
bz, err = cmd.CombinedOutput()
496496
if err != nil {
497497
fmt.Println("command failed: ", cmd)
498-
log.Fatal("update consumer failed error: %w, output: %s", err, string(bz))
498+
log.Fatalf("update consumer failed error: %s, output: %s", err, string(bz))
499499
}
500500

501501
// Check transaction
@@ -2536,14 +2536,14 @@ func (tr Chain) registerRepresentative(
25362536

25372537
type SubmitChangeRewardDenomsProposalAction struct {
25382538
Chain ChainID
2539-
Denom string
2539+
Denoms []string
25402540
Deposit uint
25412541
From ValidatorID
25422542
}
25432543

25442544
func (tr Chain) submitChangeRewardDenomsProposal(action SubmitChangeRewardDenomsProposalAction, verbose bool) {
25452545
changeRewMsg := types.MsgChangeRewardDenoms{
2546-
DenomsToAdd: []string{action.Denom},
2546+
DenomsToAdd: action.Denoms,
25472547
DenomsToRemove: []string{"stake"},
25482548
Authority: "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",
25492549
}
@@ -2604,7 +2604,7 @@ func (tr Chain) submitChangeRewardDenomsLegacyProposal(action SubmitChangeReward
26042604
ChangeRewardDenomsProposal: types.ChangeRewardDenomsProposal{
26052605
Title: "Change reward denoms",
26062606
Description: "Change reward denoms",
2607-
DenomsToAdd: []string{action.Denom},
2607+
DenomsToAdd: action.Denoms,
26082608
DenomsToRemove: []string{"stake"},
26092609
},
26102610
Deposit: fmt.Sprint(action.Deposit) + `stake`,
@@ -3309,3 +3309,95 @@ func (tr Commands) AssignConsumerPubKey(action e2e.AssignConsumerPubKeyAction, g
33093309

33103310
return cmd.CombinedOutput()
33113311
}
3312+
3313+
type CreateIbcClientAction struct {
3314+
ChainA ChainID
3315+
ChainB ChainID
3316+
}
3317+
3318+
func (tr Chain) createIbcClientHermes(
3319+
action CreateIbcClientAction,
3320+
verbose bool,
3321+
) {
3322+
cmd := tr.target.ExecCommand("hermes",
3323+
"create", "client",
3324+
"--host-chain", string(tr.testConfig.chainConfigs[action.ChainA].ChainId),
3325+
"--reference-chain", string(tr.testConfig.chainConfigs[action.ChainB].ChainId),
3326+
"--trusting-period", "1200000s",
3327+
)
3328+
3329+
cmdReader, err := cmd.StdoutPipe()
3330+
if err != nil {
3331+
log.Fatal(err)
3332+
}
3333+
cmd.Stderr = cmd.Stdout
3334+
3335+
if err := cmd.Start(); err != nil {
3336+
log.Fatal(err)
3337+
}
3338+
3339+
scanner := bufio.NewScanner(cmdReader)
3340+
3341+
for scanner.Scan() {
3342+
out := scanner.Text()
3343+
if verbose {
3344+
fmt.Println("createIbcClientHermes: " + out)
3345+
}
3346+
if out == done {
3347+
break
3348+
}
3349+
}
3350+
if err := scanner.Err(); err != nil {
3351+
log.Fatal(err)
3352+
}
3353+
}
3354+
3355+
type TransferIbcTokenAction struct {
3356+
Chain ChainID
3357+
DstAddr string
3358+
From ValidatorID
3359+
Amount uint
3360+
Channel uint
3361+
Memo string
3362+
}
3363+
3364+
func (tr Chain) transferIbcToken(
3365+
action TransferIbcTokenAction,
3366+
verbose bool,
3367+
) {
3368+
// Note: to get error response reported back from this command '--gas auto' needs to be set.
3369+
gas := "auto"
3370+
3371+
transferCmd := fmt.Sprintf(
3372+
`%s tx ibc-transfer transfer transfer \
3373+
%s %s %s --memo %q --from validator%s --chain-id %s \
3374+
--home %s --node %s --gas %s --keyring-backend test -y -o json`,
3375+
tr.testConfig.chainConfigs[action.Chain].BinaryName,
3376+
"channel-"+fmt.Sprint(action.Channel),
3377+
action.DstAddr,
3378+
fmt.Sprint(action.Amount)+`stake`,
3379+
action.Memo,
3380+
action.From,
3381+
string(tr.testConfig.chainConfigs[action.Chain].ChainId),
3382+
tr.getValidatorHome(action.Chain, action.From),
3383+
tr.getValidatorNode(action.Chain, action.From),
3384+
gas,
3385+
)
3386+
3387+
cmd := tr.target.ExecCommand(
3388+
"/bin/bash", "-c",
3389+
transferCmd,
3390+
)
3391+
3392+
if verbose {
3393+
fmt.Println("transferIbcToken cmd:", cmd.String())
3394+
}
3395+
3396+
bz, err := cmd.CombinedOutput()
3397+
if err != nil {
3398+
log.Fatalf("unexpected error during IBC token transfer: %s: %s", string(bz), err)
3399+
}
3400+
3401+
// wait for inclusion in a block -> '--broadcast-mode block' is deprecated
3402+
tr.waitBlocks(action.Chain, 2, 30*time.Second)
3403+
}

tests/e2e/state.go

+19-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"regexp"
1010
"sort"
1111
"strconv"
12+
"strings"
1213
"time"
1314

1415
clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
@@ -154,10 +155,10 @@ func (tr Chain) GetRewards(chain ChainID, modelState Rewards) Rewards {
154155
currentBlock = 1
155156
}
156157
for k := range modelState.IsRewarded {
157-
receivedRewards[k] = tr.target.GetReward(chain, k, nextBlock, modelState.IsNativeDenom) > tr.target.GetReward(chain, k, currentBlock, modelState.IsNativeDenom)
158+
receivedRewards[k] = tr.target.GetReward(chain, k, nextBlock, modelState.Denom) > tr.target.GetReward(chain, k, currentBlock, modelState.Denom)
158159
}
159160

160-
return Rewards{IsRewarded: receivedRewards, IsIncrementalReward: modelState.IsIncrementalReward, IsNativeDenom: modelState.IsNativeDenom}
161+
return Rewards{IsRewarded: receivedRewards, IsIncrementalReward: modelState.IsIncrementalReward, Denom: modelState.Denom}
161162
}
162163

163164
func (tr Chain) GetConsumerAddresses(chain ChainID, modelState map[ValidatorID]string) map[ValidatorID]string {
@@ -252,7 +253,7 @@ func (tr Commands) GetBlockHeight(chain ChainID) uint {
252253
return uint(blockHeight)
253254
}
254255

255-
func (tr Commands) GetReward(chain ChainID, validator ValidatorID, blockHeight uint, isNativeDenom bool) float64 {
256+
func (tr Commands) GetReward(chain ChainID, validator ValidatorID, blockHeight uint, denom string) float64 {
256257
valCfg := tr.validatorConfigs[validator]
257258
delAddresss := valCfg.DelAddress
258259
if chain != ChainID("provi") {
@@ -285,12 +286,23 @@ func (tr Commands) GetReward(chain ChainID, validator ValidatorID, blockHeight u
285286
log.Fatal("failed getting rewards: ", err, "\n", string(bz))
286287
}
287288

288-
denomCondition := `total.#(denom!="stake").amount`
289-
if isNativeDenom {
290-
denomCondition = `total.#(denom=="stake").amount`
289+
denomCondition := fmt.Sprintf(`total.#(%%"*%s*")`, denom)
290+
amount := strings.Split(gjson.Get(string(bz), denomCondition).String(), denom)[0]
291+
292+
fmt.Println("denomCondition:", denomCondition)
293+
fmt.Println("json:", gjson.Parse(string(bz)))
294+
295+
res := float64(0)
296+
if amount != "" {
297+
res, err = strconv.ParseFloat(amount, 64)
298+
if err != nil {
299+
log.Fatal("failed parsing consumer reward:", err)
300+
}
291301
}
292302

293-
return gjson.Get(string(bz), denomCondition).Float()
303+
fmt.Println("res", res)
304+
305+
return res
294306
}
295307

296308
// interchain-securityd query gov proposals

tests/e2e/state_rapid_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ func GetRewardsGen() *rapid.Generator[Rewards] {
104104
return rapid.Custom(func(t *rapid.T) Rewards {
105105
return Rewards{
106106
IsIncrementalReward: rapid.Bool().Draw(t, "IsIncrementalReward"),
107-
IsNativeDenom: rapid.Bool().Draw(t, "IsNativeDenom"),
108-
IsRewarded: rapid.MapOf(GetValidatorIDGen(), rapid.Bool()).Draw(t, "IsRewarded"),
107+
// Denom: rapid.Str,
108+
IsRewarded: rapid.MapOf(GetValidatorIDGen(), rapid.Bool()).Draw(t, "IsRewarded"),
109109
}
110110
})
111111
}

0 commit comments

Comments
 (0)