Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(genesis bridge): better UX for chains without genesis transfers #458

Merged
merged 80 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
257b0f9
lets start
danwt Jun 19, 2024
d28769c
del num transfers from memo
danwt Jun 19, 2024
e304a7d
TODO: disable transfers when genesis transfers have not yet all been …
danwt Jun 19, 2024
b1767c8
pause and think
danwt Jun 19, 2024
813e05b
partially done with the seq saving
danwt Jun 19, 2024
d4f60a3
adding a panic but Ill rip it out
danwt Jun 20, 2024
673f879
removes panic
danwt Jun 20, 2024
0a9d82e
time to test
danwt Jun 20, 2024
b03db02
ready to test
danwt Jun 20, 2024
21a4eba
pb
danwt Jun 20, 2024
a3e56d7
adds missing channel keeper
danwt Jun 20, 2024
3864b74
fix tests
danwt Jun 20, 2024
b32a3e1
address leftover comments
danwt Jun 20, 2024
5030b49
gonna just use an index
danwt Jun 20, 2024
b86c1d8
need to just do the logic now
danwt Jun 20, 2024
35f4804
pre regen proto
danwt Jun 20, 2024
1a139b6
regen proto
danwt Jun 20, 2024
6612b8d
just realised you cant use a cnter
danwt Jun 20, 2024
5051341
ready for a test, then will have to do genesis
danwt Jun 20, 2024
f4b5d69
lets test
danwt Jun 20, 2024
0e97d27
add an event
danwt Jun 20, 2024
3618724
pre del params
danwt Jun 20, 2024
85fe9c3
regen proto
danwt Jun 20, 2024
bec0a64
regen proto
danwt Jun 20, 2024
c9d7e89
I can actually do it easier and use a map only for the repeats
danwt Jun 20, 2024
6bdb0e3
simply delete teh acks
danwt Jun 20, 2024
e013381
regen proto
danwt Jun 20, 2024
2108e1b
pre simplify store
danwt Jun 20, 2024
02c6c4e
adds canonical channel
danwt Jun 20, 2024
549d435
need to sort the port and channel
danwt Jun 20, 2024
4a1fa4d
ready for another test
danwt Jun 20, 2024
f230a08
need to do genesis
danwt Jun 20, 2024
59fea0f
need to impl genesis
danwt Jun 20, 2024
6b104e9
impl the iterator
danwt Jun 20, 2024
a31d08a
adds back params for now
danwt Jun 20, 2024
38146aa
try to bring back params for now
danwt Jun 20, 2024
d2daabd
confirms installable
danwt Jun 20, 2024
48d533c
fix testapp
danwt Jun 20, 2024
e6a066d
ready to test
danwt Jun 20, 2024
6151749
fix nil deref
danwt Jun 21, 2024
479bab2
adds back params for now
danwt Jun 21, 2024
034e28f
restore unneedded diff
danwt Jun 21, 2024
9433bf5
renames and tweaks
danwt Jun 21, 2024
bd17c14
tweaks, going to add a test for genesis
danwt Jun 21, 2024
1f22ecf
simplify and make sure to handle empty genesis transfers case
danwt Jun 21, 2024
bdf4f63
simplification
danwt Jun 21, 2024
3872a7a
need to test genesis export/import an edges
danwt Jun 21, 2024
8716eac
adds a todo for the missing issue
danwt Jun 21, 2024
c72e968
fix genesis test
danwt Jun 21, 2024
8928404
fix test setup
danwt Jun 21, 2024
172d503
gonna refac stuf to the keeper
danwt Jun 21, 2024
c87ad27
del protocols test
danwt Jun 21, 2024
97b0d24
dump ack
danwt Jun 21, 2024
66c8012
gonna test again
danwt Jun 21, 2024
df87f2b
need to fix wiring
danwt Jun 21, 2024
59c8f02
adds debug
danwt Jun 21, 2024
788e322
fix state pointers
danwt Jun 21, 2024
6f81db2
try again
danwt Jun 21, 2024
3b13f2b
try again
danwt Jun 21, 2024
063958f
test
danwt Jun 21, 2024
8ba70e3
need to check state usages
danwt Jun 21, 2024
b01b829
lfg
danwt Jun 21, 2024
4465c22
typo
danwt Jun 21, 2024
b452d70
confirms working
danwt Jun 21, 2024
9075081
simplify
danwt Jun 21, 2024
dbac79e
need to test blocker
danwt Jun 21, 2024
3719e6d
remove bogus logs
danwt Jun 21, 2024
4252489
fix wrappers
danwt Jun 21, 2024
5587dc1
done
danwt Jun 21, 2024
40a790b
golangcilint
danwt Jun 21, 2024
3f4c6fe
use keeper interfaces
danwt Jun 21, 2024
d2bcfff
expand comment
danwt Jun 24, 2024
eebb279
remove else
danwt Jun 24, 2024
e24b739
flatter function
danwt Jun 24, 2024
4b2921a
tidy
danwt Jun 24, 2024
1af7677
fixes test regression
danwt Jun 24, 2024
76e8398
use main go.mod go.sum
danwt Jun 24, 2024
7f483ce
tidy
danwt Jun 24, 2024
638adbe
Merge branch 'main' into danwt/457-move-transfersenabled
danwt Jun 24, 2024
12b8ff9
tidy
danwt Jun 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/cosmos/gogoproto v1.4.11
github.com/cosmos/ibc-go/v6 v6.2.1
github.com/dymensionxyz/dymint v1.1.3-rc04
github.com/dymensionxyz/gerr-cosmos v1.0.0
github.com/dymensionxyz/sdk-utils v0.1.1
github.com/gogo/protobuf v1.3.3
github.com/golang/protobuf v1.5.4
Expand Down Expand Up @@ -101,7 +102,6 @@ require (
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/dymensionxyz/gerr-cosmos v1.0.0 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
github.com/ethereum/go-ethereum v1.12.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
Expand Down
1 change: 1 addition & 0 deletions proto/hub-genesis/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ message GenesisState {
// params defines all the parameters of the module.
Params params = 1 [ (gogoproto.nullable) = false ];
State state = 2 [(gogoproto.nullable) = false];
repeated uint64 unacked_transfer_seq_nums = 3 [(gogoproto.nullable) = false];
mtsitrin marked this conversation as resolved.
Show resolved Hide resolved
}
15 changes: 12 additions & 3 deletions proto/hub-genesis/state.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ message State {
reserved 2;
// accounts on the Hub to fund with some bootstrapping transfers
repeated GenesisAccount genesis_accounts = 3 [(gogoproto.nullable) = false];
// the number of genesis transfers for which an ack has not yet been received
uint64 num_unacked_transfers = 5;
mtsitrin marked this conversation as resolved.
Show resolved Hide resolved
// are outboundTransfersEnabled? This is only true if the genesis protocol has finished
bool outbound_transfers_enabled = 6;
// the canonical transfer port and channel for the hub
PortAndChannel hub_port_and_channel= 7;
}
/*

TODO: the below is copy pasted, clean up
*/
message PortAndChannel {
// port
string port = 1;
// channel
string channel = 2;
}

// GenesisAccount is a struct for the genesis account for the rollapp
message GenesisAccount {
Expand Down
25 changes: 17 additions & 8 deletions testutil/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,12 +417,21 @@ func NewRollapp(
),
)

app.HubGenesisKeeper = hubgenkeeper.NewKeeper(
appCodec,
keys[hubgentypes.StoreKey],
app.GetSubspace(hubgentypes.ModuleName),
app.AccountKeeper,
)

genesisTransfersBlocker := hubgenkeeper.NewICS4Wrapper(app.IBCKeeper.ChannelKeeper, app.HubGenesisKeeper)

// Create Transfer Keepers
app.TransferKeeper = ibctransferkeeper.NewKeeper(
appCodec,
keys[ibctransfertypes.StoreKey],
app.GetSubspace(ibctransfertypes.ModuleName),
app.IBCKeeper.ChannelKeeper,
genesisTransfersBlocker,
app.IBCKeeper.ChannelKeeper,
&app.IBCKeeper.PortKeeper,
app.AccountKeeper,
Expand All @@ -438,12 +447,11 @@ func NewRollapp(
app.TransferKeeper,
denommetadatamoduletypes.NewMultiDenommetadataHooks(),
)

app.HubGenesisKeeper = hubgenkeeper.NewKeeper(
appCodec,
keys[hubgentypes.StoreKey],
app.GetSubspace(hubgentypes.ModuleName),
app.AccountKeeper,
transferStack = hubgenkeeper.NewIBCModule(
transferStack,
app.TransferKeeper,
app.HubGenesisKeeper,
app.BankKeeper,
)

app.GaslessKeeper = gaslesskeeper.NewKeeper(
Expand Down Expand Up @@ -738,10 +746,11 @@ func (app *App) ModuleAccountAddrs() map[string]bool {
}

// BlockedModuleAccountAddrs returns all the app's blocked module account
// addresses.
// addresses. A true value means blocked. Absent or false means not blocked.
func (app *App) BlockedModuleAccountAddrs() map[string]bool {
modAccAddrs := app.ModuleAccountAddrs()
delete(modAccAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String())
delete(modAccAddrs, authtypes.NewModuleAddress(hubgentypes.ModuleName).String())

return modAccAddrs
}
Expand Down
5 changes: 4 additions & 1 deletion x/hub-genesis/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import (
func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) {
k.SetParams(ctx, genState.Params)
k.SetState(ctx, genState.State)
for _, seq := range genState.UnackedTransferSeqNums {
k.saveUnackedTransferSeqNum(ctx, seq)
}
}

// ExportGenesis returns a GenesisState for a given context and keeper.
func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
genesis := types.DefaultGenesisState()
genesis.Params = k.GetParams(ctx)
genesis.State = k.GetState(ctx)

genesis.UnackedTransferSeqNums = k.getAllUnackedTransferSeqNums(ctx)
return genesis
}
14 changes: 9 additions & 5 deletions x/hub-genesis/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ import (
"testing"

testkeepers "github.com/dymensionxyz/dymension-rdk/testutil/keepers"
"github.com/dymensionxyz/dymension-rdk/testutil/nullify"
"github.com/dymensionxyz/dymension-rdk/testutil/utils"
"github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types"
"github.com/stretchr/testify/require"
)

func TestGenesis(t *testing.T) {
genesisState := &types.GenesisState{}
app := utils.Setup(t, false)
k, ctx := testkeepers.NewTestHubGenesisKeeperFromApp(app)

k.InitGenesis(ctx, genesisState)
expect := &types.GenesisState{
State: types.State{
NumUnackedTransfers: 2,
},
UnackedTransferSeqNums: []uint64{42, 43},
}
k.InitGenesis(ctx, expect)
got := k.ExportGenesis(ctx)
require.NotNil(t, got)

nullify.Fill(&genesisState)
nullify.Fill(got)
require.ElementsMatch(t, expect.UnackedTransferSeqNums, got.UnackedTransferSeqNums)
require.Equal(t, expect.State.NumUnackedTransfers, got.State.NumUnackedTransfers)
}
122 changes: 88 additions & 34 deletions x/hub-genesis/keeper/ibc_module.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package keeper

import (
"context"
"errors"
"fmt"
"time"

errorsmod "cosmossdk.io/errors"

sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
"github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types"
"github.com/dymensionxyz/gerr-cosmos/gerrc"
"github.com/tendermint/tendermint/libs/log"
)

const (
Expand All @@ -20,20 +24,26 @@ const (

type IBCModule struct {
porttypes.IBCModule
k Keeper
transfer Transfer
getDenom GetDenomMetaData
mintCoins MintCoins
k Keeper
transfer TransferKeeper
bank BankKeeper
}

type (
Transfer func(ctx sdk.Context, transfer *transfertypes.MsgTransfer) error
GetDenomMetaData func(ctx sdk.Context, denom string) (banktypes.Metadata, bool)
MintCoins func(ctx sdk.Context, moduleName string, amt sdk.Coins) error
)
type TransferKeeper interface {
Transfer(goCtx context.Context, msg *transfertypes.MsgTransfer) (*transfertypes.MsgTransferResponse, error)
}

func NewIBCModule(next porttypes.IBCModule, t Transfer, k Keeper, d GetDenomMetaData, m MintCoins) *IBCModule {
return &IBCModule{next, k, t, d, m}
type BankKeeper interface {
GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool)
MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
}

func NewIBCModule(next porttypes.IBCModule, t TransferKeeper, k Keeper, bank BankKeeper) *IBCModule {
return &IBCModule{next, k, t, bank}
}

func (w IBCModule) logger(ctx sdk.Context) log.Logger {
return w.k.Logger(ctx).With("module", types.ModuleName, "component", "ibc module")
}

// OnChanOpenConfirm will send any unsent genesis account transfers over the channel.
Expand All @@ -50,42 +60,49 @@ func (w IBCModule) OnChanOpenConfirm(

err := w.IBCModule.OnChanOpenConfirm(ctx, portID, channelID)
if err != nil {
l.Error("Next middleware.", "err", err)
return err
}

state := w.k.GetState(ctx)

if state.CanonicalHubTransferChannelHasBeenSet() {
// We only set the canonical channel in this function, so if it's already been set, we don't need
// to send the transfers again.
return nil
}

state.SetCanonicalTransferChannel(portID, channelID)

state.NumUnackedTransfers = uint64(len(state.GetGenesisAccounts()))

w.k.SetState(ctx, state)

if len(state.GetGenesisAccounts()) == 0 {
// we want to handle the case where the rollapp doesn't have genesis transfers
// normally we would enable outbound transfers on an ack, but in this case we won't have an ack
w.k.enableOutboundTransfers(ctx)
danwt marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

srcAccount := w.k.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
srcAddr := srcAccount.GetAddress().String()

for i, a := range state.GetGenesisAccounts() {
if err := w.mintAndTransfer(ctx, len(state.GetGenesisAccounts()), a, srcAddr, portID, channelID); err != nil {
if err := w.mintAndTransfer(ctx, a, srcAddr, portID, channelID); err != nil {
// there is no feasible way to recover
panic(fmt.Errorf("mint and transfer: %w", err))
}
l.Info("Sent genesis transfer.", "index", i, "receiver", a.GetAddress(), "coin", a)
}

state.GenesisAccounts = nil

w.k.SetState(ctx, state)

l.Info("Sent all genesis transfers.")
l.Info("Sent all genesis transfers.", "n", len(state.GetGenesisAccounts()))

return nil
}

func (w IBCModule) mintAndTransfer(
ctx sdk.Context,
n int,
a types.GenesisAccount,
srcAddr string,
portID string,
channelID string,
) error {
coin := a.GetAmount()
err := w.mintCoins(ctx, types.ModuleName, sdk.Coins{coin})
func (w IBCModule) mintAndTransfer(ctx sdk.Context, account types.GenesisAccount, srcAddr string, portID string, channelID string) error {
coin := account.GetAmount()
err := w.bank.MintCoins(ctx, types.ModuleName, sdk.Coins{coin})
if err != nil {
return errorsmod.Wrap(err, "mint coins")
}
Expand All @@ -95,26 +112,63 @@ func (w IBCModule) mintAndTransfer(
// or commit anyway, so the packet will be cleared up.
// (Actually, since transfers may arrive out of order, we must include the
// denom metadata anyway).
memo, err := w.createMemo(ctx, a.Amount.Denom, n)
memo, err := w.createMemo(ctx, account.Amount.Denom)
if err != nil {
return errorsmod.Wrap(err, "create memo")
}

m := transfertypes.MsgTransfer{
SourcePort: portID,
SourceChannel: channelID,
Token: a.Amount,
Token: account.Amount,
Sender: srcAddr,
Receiver: a.GetAddress(),
Receiver: account.GetAddress(),
TimeoutHeight: clienttypes.Height{},
TimeoutTimestamp: uint64(ctx.BlockTime().Add(transferTimeout).UnixNano()),
Memo: memo,
}

err = w.transfer(skipContext(ctx), &m)
res, err := w.transfer.Transfer(sdk.WrapSDKContext(allowSpecialMemoCtx(ctx)), &m)
if err != nil {
return errorsmod.Wrap(err, "transfer")
}

w.k.saveUnackedTransferSeqNum(ctx, res.Sequence)
return nil
}

func (w IBCModule) OnAcknowledgementPacket(
ctx sdk.Context,
packet channeltypes.Packet,
acknowledgement []byte,
relayer sdk.AccAddress,
) error {
l := w.logger(ctx)
state := w.k.GetState(ctx)

if !state.IsCanonicalHubTransferChannel(packet.SourcePort, packet.SourceChannel) {
return w.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
}

if state.OutboundTransfersEnabled {
return w.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
}

var data transfertypes.FungibleTokenPacketData
err := transfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data)
if err != nil {
return err
}

var ack channeltypes.Acknowledgement
err = types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack)
if err != nil {
return err
}

err = w.k.ackTransferSeqNum(ctx, packet.Sequence, ack)
if err != nil {
l.Error("Processing ack from transfer.", "err", err)
return errorsmod.Wrap(errors.Join(err, gerrc.ErrUnknown), "ack transfer seq num")
}
return w.IBCModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
}
Loading
Loading