Skip to content

Commit

Permalink
feat(genesis_bridge): revised genesis bridge impl (#565)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtsitrin authored Oct 9, 2024
1 parent baa5f01 commit 623826e
Show file tree
Hide file tree
Showing 37 changed files with 2,730 additions and 1,019 deletions.
7 changes: 4 additions & 3 deletions proto/hub-genesis/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package rollapp.hub_genesis;

import "gogoproto/gogo.proto";
import "hub-genesis/params.proto";
import "hub-genesis/state.proto";
import "hub-genesis/genesis_info.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types";

// GenesisState defines the hub-genesis module's genesis state.
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];

// accounts on the Hub to fund with some bootstrapping transfers
repeated GenesisAccount genesis_accounts = 2 [ (gogoproto.nullable) = false ];
}
22 changes: 22 additions & 0 deletions proto/hub-genesis/genesis_bridge_data.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

syntax = "proto3";
package rollapp.hub_genesis;

import "gogoproto/gogo.proto";
import "cosmos/bank/v1beta1/bank.proto";
import "ibc/applications/transfer/v2/packet.proto";
import "hub-genesis/genesis_info.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types";

// GenesisBridgeData is the data struct that is passed to the hub for the
// genesis bridge flow
message GenesisBridgeData {
// genesis_info is the genesis info of the rollapp. used for hub validation
GenesisInfo genesis_info = 1 [ (gogoproto.nullable) = false ];
// native_denom is the native denom of the rollapp. registered on the hub
cosmos.bank.v1beta1.Metadata native_denom = 2
[ (gogoproto.nullable) = false ];
// optional genesis transfer packet data
ibc.applications.transfer.v2.FungibleTokenPacketData genesis_transfer = 3;
}
45 changes: 45 additions & 0 deletions proto/hub-genesis/genesis_info.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

syntax = "proto3";
package rollapp.hub_genesis;

import "gogoproto/gogo.proto";
import "cosmos/bank/v1beta1/bank.proto";
import "hub-genesis/state.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types";

// The genesis info of the rollapp, that is passed to the hub for validation.
// it's populated on the InitGenesis of the rollapp
message GenesisInfo {
// checksum used to verify integrity of the genesis file. currently unused
string genesis_checksum = 1;
// unique bech32 prefix
string bech32_prefix = 2;
// native_denom is the base denom for the native token
DenomMetadata native_denom = 3;
// initial_supply is the initial supply of the native token
string initial_supply = 4 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
// accounts on the Hub to fund with some bootstrapping transfers
repeated GenesisAccount genesis_accounts = 5 [ (gogoproto.nullable) = false ];
}

message DenomMetadata {
string display = 1;
string base = 2;
uint32 exponent = 3;
}


// GenesisAccount is a struct for the genesis account for the rollapp
message GenesisAccount {
// amount of coins to be sent to the genesis address
string amount = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
// address is a bech-32 address of the genesis account
string address = 2;
}
24 changes: 21 additions & 3 deletions proto/hub-genesis/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "hub-genesis/params.proto";
import "hub-genesis/state.proto";
import "hub-genesis/genesis_info.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types";

Expand All @@ -16,11 +17,17 @@ service Query {
"/dymensionxyz/dymension-rdk/hub-genesis/params";
}

// State returns the state of the genesis event.
rpc State(QueryStateRequest) returns (QueryStateResponse) {
// State returns the state of the genesis event.
rpc State(QueryStateRequest) returns (QueryStateResponse) {
option (google.api.http).get =
"/dymensionxyz/dymension-rdk/hub-genesis/state";
}

// GenesisInfo returns the genesis info of the rollapp.
rpc GenesisInfo(QueryGenesisInfoRequest) returns (QueryGenesisInfoResponse) {
option (google.api.http).get =
"/dymensionxyz/dymension-rdk/hub-genesis/genesis_info";
}
}

// QueryParamsRequest is the request type for the Query/Params RPC method.
Expand All @@ -38,5 +45,16 @@ message QueryStateRequest {}
// QueryStateResponse is the response type for the Query/State RPC method.
message QueryStateResponse {
// state holds the state of the genesis event
State state = 1 [(gogoproto.nullable) = false];
State state = 1 [ (gogoproto.nullable) = false ];
}

// QueryGenesisInfoRequest is the request type for the Query/GenesisInfo RPC
// method.
message QueryGenesisInfoRequest {}

// QueryGenesisInfoResponse is the response type for the Query/GenesisInfo RPC
// method.
message QueryGenesisInfoResponse {
// genesis_info holds the genesis info of the rollapp
GenesisInfo genesis_info = 1 [ (gogoproto.nullable) = false ];
}
22 changes: 5 additions & 17 deletions proto/hub-genesis/state.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,18 @@ syntax = "proto3";
package rollapp.hub_genesis;

import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types";

// State holds the state of the genesis event
message State {
reserved 1;
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;
// are outboundTransfersEnabled? This is only true if the genesis protocol has finished
reserved 1 to 5;

// 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;
PortAndChannel hub_port_and_channel = 7;
}

message PortAndChannel {
Expand All @@ -26,11 +22,3 @@ message PortAndChannel {
// channel
string channel = 2;
}

// GenesisAccount is a struct for the genesis account for the rollapp
message GenesisAccount {
// amount of coins to be sent to the genesis address
cosmos.base.v1beta1.Coin amount = 1 [(gogoproto.nullable) = false];
// address is a bech-32 address of the genesis account
string address = 2;
}
25 changes: 15 additions & 10 deletions testutil/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,28 +454,33 @@ func NewRollapp(
keys[hubtypes.StoreKey],
)

denomMetadataMiddleware := denommetadata.NewICS4Wrapper(
app.IBCKeeper.ChannelKeeper,
app.HubKeeper,
app.BankKeeper,
app.HubGenesisKeeper.GetState,
)

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

genesisTransfersBlocker := hubgenkeeper.NewICS4Wrapper(denomMetadataMiddleware, app.HubGenesisKeeper)
// The IBC tranfer submit is wrapped with:
var ics4Wrapper ibcporttypes.ICS4Wrapper
// - denom metadata middleware
ics4Wrapper = denommetadata.NewICS4Wrapper(
app.IBCKeeper.ChannelKeeper,
app.HubKeeper,
app.BankKeeper,
app.HubGenesisKeeper.GetState,
)
// - transfer rejecter until genesis bridge phase is finished
ics4Wrapper = hubgenkeeper.NewICS4Wrapper(ics4Wrapper, app.HubGenesisKeeper)

// Create Transfer Keepers
app.TransferKeeper = ibctransferkeeper.NewKeeper(
appCodec,
keys[ibctransfertypes.StoreKey],
app.GetSubspace(ibctransfertypes.ModuleName),
genesisTransfersBlocker,
ics4Wrapper,
app.IBCKeeper.ChannelKeeper,
&app.IBCKeeper.PortKeeper,
app.AccountKeeper,
Expand All @@ -494,9 +499,9 @@ func NewRollapp(
)
transferStack = hubgenkeeper.NewIBCModule(
transferStack,
app.TransferKeeper,
app.HubGenesisKeeper,
app.BankKeeper,
app.IBCKeeper.ChannelKeeper,
)

app.GaslessKeeper = gaslesskeeper.NewKeeper(
Expand Down
82 changes: 56 additions & 26 deletions testutil/utils/test_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import (
"github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types"

app "github.com/dymensionxyz/dymension-rdk/testutil/app"
seqtypes "github.com/dymensionxyz/dymension-rdk/x/sequencers/types"

hubgenesistypes "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types"
rollappparamstypes "github.com/dymensionxyz/dymension-rdk/x/rollappparams/types"

"github.com/stretchr/testify/require"
Expand All @@ -33,9 +33,6 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"

// unnamed import of statik for swagger UI support
_ "github.com/cosmos/cosmos-sdk/client/docs/statik"
)

var DefaultConsensusParams = &abci.ConsensusParams{
Expand Down Expand Up @@ -92,34 +89,42 @@ func setup(withGenesis bool, invCheckPeriod uint) (*app.App, map[string]json.Raw
log.NewNopLogger(), db, nil, true, map[int64]bool{}, "/tmp", invCheckPeriod, encCdc, app.GetEnabledProposals(), EmptyAppOptions{}, emptyWasmOpts,
)
if withGenesis {
// override the rollapp version, so we'll have a valid default genesis
rollappparamstypes.Version = "5f8393904fb1e9c616fe89f013cafe7501a63f86"
return testApp, app.NewDefaultGenesisState(encCdc.Codec)
}
return testApp, map[string]json.RawMessage{}
}

// Setup initializes a new Rollapp. A Nop logger is set in Rollapp.
func Setup(t *testing.T, isCheckTx bool) *app.App {
// setGenesisAndInitChain contains the shared setup logic
func setGenesisAndInitChain(t *testing.T, app *app.App, genesisState map[string]json.RawMessage) {
t.Helper()

app, genesisState := setup(true, 5)

// setup for sequencer
seqGenesis := seqtypes.GenesisState{
Params: seqtypes.DefaultParams(),
}
genesisState[seqtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&seqGenesis)

// setup for rollapp params

rollappParamsGenesis := rollappparamstypes.GenesisState{
Params: rollappparamstypes.NewParams("mock", "5f8393904fb1e9c616fe89f013cafe7501a63f86"),
// setting bank genesis as required for genesis bridge
nativeDenomMetadata := banktypes.Metadata{
DenomUnits: []*banktypes.DenomUnit{
{
Denom: "stake",
Exponent: 0,
},
{
Denom: "TST",
Exponent: 18,
},
},
Base: "stake",
Display: "TST",
}
genesisState[rollappparamstypes.ModuleName] = app.AppCodec().MustMarshalJSON(&rollappParamsGenesis)

// for now bank genesis won't be set here, funding accounts should be called with fund utils.FundModuleAccount
var bankGenesis banktypes.GenesisState
err := json.Unmarshal(genesisState[banktypes.ModuleName], &bankGenesis)
require.NoError(t, err)
bankGenesis.DenomMetadata = append(bankGenesis.DenomMetadata, nativeDenomMetadata)
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(&bankGenesis)

stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)

// init chain will set the validator set and initialize the genesis accounts
app.InitChain(
abci.RequestInitChain{
Expand All @@ -133,22 +138,47 @@ func Setup(t *testing.T, isCheckTx bool) *app.App {
InitialHeight: 0,
},
)
}

func SetupWithGenesisBridge(t *testing.T, gbFunds sdk.Coin, genAcct []hubgenesistypes.GenesisAccount) *app.App {
t.Helper()
app, genesisState := setup(true, 5)

// Additional setup specific to SetupWithGenesisBridge
genesisBridgeFunds := []banktypes.Balance{
{
Address: authtypes.NewModuleAddress(hubgenesistypes.ModuleName).String(),
Coins: sdk.NewCoins(gbFunds),
},
}

bankGenesis := banktypes.DefaultGenesisState()
bankGenesis.Balances = append(bankGenesis.Balances, genesisBridgeFunds...)
bankGenesis.Supply = sdk.NewCoins(gbFunds)
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)

// set genesis transfer required accounts
genesisBridgeGenesisState := hubgenesistypes.DefaultGenesisState()
genesisBridgeGenesisState.GenesisAccounts = genAcct
genesisState[hubgenesistypes.ModuleName] = app.AppCodec().MustMarshalJSON(genesisBridgeGenesisState)

setGenesisAndInitChain(t, app, genesisState)
return app
}

func Setup(t *testing.T, isCheckTx bool) *app.App {
t.Helper()
app, genesisState := setup(true, 5)
setGenesisAndInitChain(t, app, genesisState)
return app
}

// TODO: tech debt - this is almost the same as in github.com/cosmos/ibc-go/v6/testing/app.go
// but unlike the other one, this one adds the sequencer to the genesis state on InitChain
func SetupWithGenesisValSet(t *testing.T, chainID, rollAppDenom string, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances []banktypes.Balance) *app.App {
t.Helper()

app, genesisState := setup(true, 5)

seqGenesis := seqtypes.GenesisState{
Params: seqtypes.DefaultParams(),
}
genesisState[seqtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&seqGenesis)

authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)

Expand Down
7 changes: 5 additions & 2 deletions x/denommetadata/ibc_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ import (
type ICS4Wrapper struct {
porttypes.ICS4Wrapper

hubKeeper types.HubKeeper
bankKeeper types.BankKeeper
hubKeeper types.HubKeeper
bankKeeper types.BankKeeper

// TODO: refactor to `IsCanonicalHubTransferChannel` directly
getHubGenState func(ctx sdk.Context) hgtypes.State
}

Expand Down Expand Up @@ -64,6 +66,7 @@ func (m *ICS4Wrapper) SendPacket(
return 0, errorsmod.Wrapf(errortypes.ErrJSONUnmarshal, "unmarshal ICS-20 transfer packet data: %s", err.Error())
}

// don't send metadata on non-canonical channels
if hubGenState := m.getHubGenState(ctx); !hubGenState.IsCanonicalHubTransferChannel(destinationPort, destinationChannel) {
return m.ICS4Wrapper.SendPacket(ctx, chanCap, destinationPort, destinationChannel, timeoutHeight, timeoutTimestamp, data)
}
Expand Down
Loading

0 comments on commit 623826e

Please sign in to comment.