Skip to content

Commit

Permalink
feat: cli command to call recv packet and ack packet (#221)
Browse files Browse the repository at this point in the history
* feat: cli command to call recv packet and ack packet

* fix: handle trusted height

* fix: trusted height handle for recv

---------

Co-authored-by: Debendra Oli <[email protected]>
  • Loading branch information
izyak and debendraoli authored Jul 16, 2024
1 parent f49a76e commit 246017f
Show file tree
Hide file tree
Showing 5 changed files with 458 additions and 33 deletions.
122 changes: 122 additions & 0 deletions cmd/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ Most of these commands take a [path] argument. Make sure:
registerCounterpartyCmd(a),
lineBreakCommand(),
claimFeesCmd(a),
recvPacket(a),
ackPacket(a),
)

return cmd
Expand Down Expand Up @@ -933,6 +935,126 @@ $ %s tx flush demo-path channel-0`,
return cmd
}

func recvPacket(a *appState) *cobra.Command {
cmd := &cobra.Command{
Use: "recv-packet src_chain_name dst_chain_name path_name [txn-hash]",
Short: "update block [height] of src_chain on dst_chain",
Args: withUsage(cobra.RangeArgs(4, 5)),
Example: strings.TrimSpace(
fmt.Sprintf(`
$ %s transact recv-packet icon archway icon-archway [tx_hash] [trusted_height OR {empty} OR {skip-update}]
$ %s transact recv-packet icon archway icon-archway [tx_hash] [trusted_height]
$ %s transact recv-packet icon archway icon-archway [tx_hash]
$ %s transact recv-packet icon archway icon-archway [tx_hash] [skip-update]
`, appName, appName, appName, appName),
),
RunE: func(cmd *cobra.Command, args []string) error {
src, ok := a.config.Chains[args[0]]
if !ok {
return errChainNotFound(args[0])
}
dst, ok := a.config.Chains[args[1]]
if !ok {
return errChainNotFound(args[1])
}
_, _, _, err := a.config.ChainsFromPath(args[2])
if err != nil {
return err
}

// ensure that keys exist
if exists := src.ChainProvider.KeyExists(src.ChainProvider.Key()); !exists {
return fmt.Errorf("key %s not found on src chain %s", src.ChainProvider.Key(), src.ChainID())
}
if exists := dst.ChainProvider.KeyExists(dst.ChainProvider.Key()); !exists {
return fmt.Errorf("key %s not found on dst chain %s", dst.ChainProvider.Key(), dst.ChainID())
}

// get transaction hash
txnHash := args[3]

// get trusted height
var trustedHeight int
var skipUpdate bool
skipUpdate = false
if len(args) == 5 {
var err error
if args[4] == "skip-update" {
skipUpdate = true
} else {
trustedHeight, err = strconv.Atoi(args[4])
if err != nil {
return fmt.Errorf("error: %w, arg: %s", err, args[4])
}
}
}

return relayer.UpdateClientAndRecvMessage(cmd.Context(), src, dst, a.config.memo(cmd), txnHash, int64(trustedHeight), skipUpdate)

},
}
return cmd
}

func ackPacket(a *appState) *cobra.Command {
cmd := &cobra.Command{
Use: "ack-packet src_chain_name dst_chain_name path_name [txn-hash]",
Short: "update block [height] of src_chain on dst_chain, then acknowlede packet based on the txn-hash",
Args: withUsage(cobra.RangeArgs(4, 5)),
Example: strings.TrimSpace(
fmt.Sprintf(`
$ %s transact ack-packet icon archway icon-archway [tx_hash] [trusted_height OR {empty} OR {skip-update}]
$ %s transact ack-packet icon archway icon-archway [tx_hash] [trusted_height]
$ %s transact ack-packet icon archway icon-archway [tx_hash]
$ %s transact ack-packet icon archway icon-archway [tx_hash] [skip-update]
`, appName, appName, appName, appName),
),
RunE: func(cmd *cobra.Command, args []string) error {
src, ok := a.config.Chains[args[0]]
if !ok {
return errChainNotFound(args[0])
}
dst, ok := a.config.Chains[args[1]]
if !ok {
return errChainNotFound(args[1])
}
_, _, _, err := a.config.ChainsFromPath(args[2])
if err != nil {
return err
}

// ensure that keys exist
if exists := src.ChainProvider.KeyExists(src.ChainProvider.Key()); !exists {
return fmt.Errorf("key %s not found on src chain %s", src.ChainProvider.Key(), src.ChainID())
}
if exists := dst.ChainProvider.KeyExists(dst.ChainProvider.Key()); !exists {
return fmt.Errorf("key %s not found on dst chain %s", dst.ChainProvider.Key(), dst.ChainID())
}
// get transaction detail
txnHash := args[3]

// get trusted height
var trustedHeight int
var skipUpdate bool
skipUpdate = false
if len(args) == 5 {
var err error
if args[4] == "skip-update" {
skipUpdate = true
} else {
trustedHeight, err = strconv.Atoi(args[4])
if err != nil {
return fmt.Errorf("error: %w, arg: %s", err, args[4])
}
}
}

return relayer.UpdateClientAndAckMessage(cmd.Context(), src, dst, a.config.memo(cmd), txnHash, int64(trustedHeight), skipUpdate)
},
}
return cmd
}

func relayMsgsCmd(a *appState) *cobra.Command {
cmd := &cobra.Command{
Use: "relay-packets path_name src_channel_id",
Expand Down
40 changes: 38 additions & 2 deletions relayer/chains/icon/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,45 @@ func (icp *IconProvider) BlockTime(ctx context.Context, height int64) (time.Time
return time.Unix(header.Timestamp, 0), nil
}

// required for cosmos only
// WARN: Handles events only for write ack and send packet
// WARN: Used to call recv packet and ack packet via cli
func (icp *IconProvider) QueryTx(ctx context.Context, hashHex string) (*provider.RelayerTxResponse, error) {
panic(fmt.Sprintf("%s%s", icp.ChainName(), NOT_IMPLEMENTED))
txRes, err := icp.client.GetTransactionResult(&types.TransactionHashParam{
Hash: types.HexBytes(hashHex),
})
if err != nil {
return nil, err
}

ht, err := txRes.BlockHeight.Value()
if err != nil {
return nil, err
}

status, _ := txRes.Status.Int()
if status != 1 {
return &provider.RelayerTxResponse{}, fmt.Errorf("transaction failed: %v", err)
}
var eventLogs []provider.RelayerEvent
events := txRes.EventLogs

for _, event := range events {
if event.Indexed[0] == EventTypeSendPacket || event.Indexed[0] == EventTypeWriteAcknowledgement {
if event.Addr == types.Address(icp.PCfg.IbcHandlerAddress) {
evt := icp.parseSendPacketAndWriteAckEvent(event)
eventLogs = append(eventLogs, evt)
}
}
}

response := provider.RelayerTxResponse{
Height: ht,
TxHash: hashHex,
Code: uint32(status),
Data: string(txRes.SCOREAddress),
Events: eventLogs,
}
return &response, nil
}

// required for cosmos only
Expand Down
44 changes: 44 additions & 0 deletions relayer/chains/icon/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package icon
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"strings"
"sync"
Expand Down Expand Up @@ -606,6 +607,47 @@ func (icp *IconProvider) SendMessage(ctx context.Context, msg provider.RelayerMe
return rlyResp, true, callbackErr
}

func (icp *IconProvider) parseSendPacketAndWriteAckEvent(event types.EventLogStr) provider.RelayerEvent {
eventName := event.Indexed[0]
switch eventName {
case EventTypeSendPacket, EventTypeWriteAcknowledgement:
protoPacket, err := hex.DecodeString(strings.TrimPrefix(event.Indexed[1], "0x"))
if err != nil {
icp.log.Error("Error decoding packet data ", zap.String("packet_hex", event.Data[0]))
break
}

var packetInfo icon.Packet
err = proto.Unmarshal(protoPacket, &packetInfo)
if err != nil {
icp.log.Error("error marshaling packet", zap.String("packet_data", string(protoPacket)))
break
}

relayerEvent := provider.RelayerEvent{
EventType: IconCosmosEventMap[eventName],
Attributes: map[string]string{
chantypes.AttributeKeySequence: fmt.Sprintf("%d", packetInfo.Sequence),
chantypes.AttributeKeyDstChannel: packetInfo.DestinationChannel,
chantypes.AttributeKeyDstPort: packetInfo.DestinationPort,
chantypes.AttributeKeySrcChannel: packetInfo.SourceChannel,
chantypes.AttributeKeySrcPort: packetInfo.SourcePort,
chantypes.AttributeKeyDataHex: fmt.Sprintf("%x", packetInfo.Data),
chantypes.AttributeKeyTimeoutHeight: fmt.Sprintf("%d-%d", packetInfo.TimeoutHeight.RevisionNumber, packetInfo.TimeoutHeight.RevisionHeight),
chantypes.AttributeKeyTimeoutTimestamp: fmt.Sprintf("%d", packetInfo.TimeoutTimestamp),
},
}
var ackData string
if eventName == EventTypeWriteAcknowledgement {
ackData = strings.TrimPrefix(event.Data[0], "0x")
relayerEvent.Attributes[chantypes.AttributeKeyAckHex] = ackData
}

return relayerEvent
}
return provider.RelayerEvent{}
}

func (icp *IconProvider) parseConfirmedEventLogStr(event types.EventLogStr) provider.RelayerEvent {

eventName := event.Indexed[0]
Expand Down Expand Up @@ -793,6 +835,8 @@ func (icp *IconProvider) SendIconTransaction(

step, err := icp.client.EstimateStep(txParamEst)
if err != nil {
estimate_txn_bytes, _ := json.Marshal(txParamEst)
icp.log.Warn("Transaction data during estimate step", zap.ByteString("txn_data", estimate_txn_bytes))
return fmt.Errorf("failed estimating step: %w", err)
}
stepVal, err := step.Int()
Expand Down
Loading

0 comments on commit 246017f

Please sign in to comment.