owned this note
owned this note
Published
Linked with GitHub
# ica marker reflection
Security context of current ICA on controller chain:
authentication ante handler
```
// GetSigners implements sdk.Msg
func (msg MsgSubmitTx) GetSigners() []sdk.AccAddress {
accAddr, err := sdk.AccAddressFromBech32(msg.Owner)
if err != nil {
panic(err)
}
return []sdk.AccAddress{accAddr}
}
```
` Will use portid created by this owner so, security context is that owner has auth and signed this request`
Security context of current ICA on host chain:
main guanrantee here
`authenticateTx`
```
// executeTx attempts to execute the provided transaction. It begins by authenticating the transaction signer.
// If authentication succeeds, it does basic validation of the messages before attempting to deliver each message
// into state. The state changes will only be committed if all messages in the transaction succeed. Thus the
// execution of the transaction is atomic, all state changes are reverted if a single message fails.
func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel string, msgs []sdk.Msg) ([]byte, error) {
channel, found := k.channelKeeper.GetChannel(ctx, destPort, destChannel)
if !found {
return nil, channeltypes.ErrChannelNotFound
}
if err := k.authenticateTx(ctx, msgs, channel.ConnectionHops[0], sourcePort); err != nil {
return nil, err
}
txMsgData := &sdk.TxMsgData{
MsgResponses: make([]*codectypes.Any, len(msgs)),
}
// CacheContext returns a new context with the multi-store branched into a cached storage object
// writeCache is called only if all msgs succeed, performing state transitions atomically
cacheCtx, writeCache := ctx.CacheContext()
for i, msg := range msgs {
if err := msg.ValidateBasic(); err != nil {
return nil, err
}
any, err := k.executeMsg(cacheCtx, msg)
if err != nil {
return nil, err
}
txMsgData.MsgResponses[i] = any
}
// NOTE: The context returned by CacheContext() creates a new EventManager, so events must be correctly propagated back to the current context
ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events())
writeCache()
txResponse, err := proto.Marshal(txMsgData)
if err != nil {
return nil, sdkerrors.Wrap(err, "failed to marshal tx data")
}
return txResponse, nil
}
```
let's dig into authenticateTx
1. `allowMsgs := k.GetAllowMessages(ctx)`
2. get interchain account `k.GetInterchainAccountAddress(ctx, connectionID, portID)`
3. Make sure signer of inner messages
matches the interchain account of the `sent packet`
Taking the example of MsgSend
```
// GetSigners Implements Msg.
func (msg MsgSend) GetSigners() []sdk.AccAddress {
from, err := sdk.AccAddressFromBech32(msg.FromAddress)
if err != nil {
panic(err)
}
return []sdk.AccAddress{from}
}
```
```
// authenticateTx ensures the provided msgs contain the correct interchain account signer address retrieved
// from state using the provided controller port identifier
func (k Keeper) authenticateTx(ctx sdk.Context, msgs []sdk.Msg, connectionID, portID string) error {
interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, connectionID, portID)
if !found {
return sdkerrors.Wrapf(icatypes.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID)
}
allowMsgs := k.GetAllowMessages(ctx)
for _, msg := range msgs {
if !types.ContainsMsgType(allowMsgs, msg) {
return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "message type not allowed: %s", sdk.MsgTypeURL(msg))
}
for _, signer := range msg.GetSigners() {
if interchainAccountAddr != signer.String() {
return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "unexpected signer address: expected %s, got %s", interchainAccountAddr, signer.String())
}
}
}
return nil
}
```
## Marker Reflect flow
Assumption 1:
An account that has transfer right(we can change the permission but i think Transfer is good enough, from what i understand not all markers need an ADMIN, maybe wrong) on the marker creates registers an ICA account.
Assumption 2: only accounts with Transfer permission can reflect marker.
ICA sequence
```sequence
ICA Controller --> func(Register Account): func (k msgServer) RegisterAccount(goCtx context.Context, \n msg *types.MsgRegisterAccount) \n (*types.MsgRegisterAccountResponse, error)
func(Register Account) --> ICA Host :Calls host chain
ICA Host -- ICA Controller:Ack send to controller chain
```
### ICAReflect call:
Assumption: IBC denom has been transferred over at least once
i.e this method works
```
// DenomPathFromHash returns the full denomination path prefix from an ibc denom with a hash
// component.
func (k Keeper) DenomPathFromHash(ctx sdk.Context, denom string) (string, error) {
// trim the denomination prefix, by default "ibc/"
hexHash := denom[len(types.DenomPrefix+"/"):]
hash, err := types.ParseHexHash(hexHash)
if err != nil {
return "", sdkerrors.Wrap(types.ErrInvalidDenomForTransfer, err.Error())
}
denomTrace, found := k.GetDenomTrace(ctx, hash)
if !found {
return "", sdkerrors.Wrap(types.ErrTraceNotFound, hexHash)
}
fullDenomPath := denomTrace.GetFullDenomPath()
return fullDenomPath, nil
}
```
Request
```
//
message MsgICAReflectMarkerRequest {
string ibc_denom = 1 ;// eg. ibc/43322432foobarbaz
string administrator = 2;
}
```
auth module:
--from has to have signed, tansposed to `owner`
custom logic for `MsgICAReflectMarkerRequest` check transfer persmission of marker exists for owner.
the submitTx method creates the actual ICA message
will
1. get the base denom from the ibc store
2. get the active marker
3. copy the transfer access (and only transfer acesss)
4. copy type
5. copy status (should always be active check runs in step 2)
```
message MsgReflectMarkerRequest {
string ibcDenom = 1
string invoker = 2;
MarkerStatus status = 3;
MarkerType marker_type = 4;
repeated AccessGrant access_list = 5 //[(gogoproto.nullable) = false];
bool allow_governance_control = 6; // ???? not needed imo but check???
}
```
```
func (msg MsgReflectMarkerRequest) GetSigners() []sdk.AccAddress {
from, err := sdk.AccAddressFromBech32(msg.invoker)
if err != nil {
panic(err)
}
return []sdk.AccAddress{from}
}
```
invoker being the getSigner makes it pass the ica check on the host chain
`relay.go`.. `execute Message` ..will invoke the MsgServer method on Marker module..
Let's call this `CreateMarkerReflect`
will again check
* no `mint`
* no `burn`
* no supply fixed
* will check ibc denom exists in ibc store (will prevent self callback i think either by mistake or by some demented mind)
ICA reflect
```sequence
Client --> Auth Antehandler: *types.MsgSubmitTx
Auth Antehandler --> ICA Controller: if authenticated, owner is now from
ICA Controller --> func(SubmitTx Account): func (k msgServer) SubmitTx(goCtx context.Context,\n msg *types.MsgSubmitTx) (*types.MsgSubmitTxResponse, error)
func(SubmitTx Account) --> CreateMsgReflectMarkerRequest : make message 1. get the base denom from the ibc store \n 2. get the active marker \n 3. copy the transfer access (and only transfer acesss)\n 4. copy type \n 5. copy status (should always be active check runs in step 2)\n
ICA Host -- ICA Controller: Dispatch ICA packet
ICA host --> relay.go : checks AuthenticateTx on MsgReflectMarkerRequest \n calls signers on MsgReflectMarkerRequest
relay.go --> CreateMarkerReflect: call msg_server method
CreateMarkerReflect --> Marker keeper: money bags
ICA host --> ICA controller : Ack and callback invoke.
```