Skip to content

Commit

Permalink
refactor state based relaying (fixes update client bug on retries) (#435
Browse files Browse the repository at this point in the history
)

* bump sdk version to v0.41.3 (#430)

* bump sdk version

* bump SDK to v0.41.3

* inital work for refactoring state based relaying

* Modify relayPacketFromSequence

* update tendermint client to not prune light blocks (#437)

* Address comments and fix lint issues

* Fix lint issues

* Remove onRtyErr (lint issue)

* typo fix (#438)

* disable tm pruning (#441)

* update release naming (#442)

* Implement swagger docs and fix path validation (#434)

* Add swagger setup

* Add some routes docs and swagger ui

* Add few more route docs

* Add swagger docs for remaining routes

* Fix golint issues

* Fix unused lint issues

* check chain-id in AddChain

* add a light client database lock (#447)

Add a lock to prevent multiple processes from attempting to access the light client database at the same time. This typically resulted in unnecessary errors or even panics

* Close database connection even if second error triggers (#449)

Co-authored-by: Mark <[email protected]>

* address comments

Co-authored-by: akhilkumarpilli <[email protected]>
Co-authored-by: Afanti <[email protected]>
Co-authored-by: Akhil Kumar P <[email protected]>
Co-authored-by: Mark | Microtick <[email protected]>
Co-authored-by: Mark <[email protected]>
  • Loading branch information
6 people authored Mar 9, 2021
1 parent 43caa85 commit 40c6949
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 64 deletions.
193 changes: 193 additions & 0 deletions relayer/msgs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package relayer

import (
"fmt"

retry "github.com/avast/retry-go"
sdk "github.com/cosmos/cosmos-sdk/types"
transfertypes "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
Expand Down Expand Up @@ -320,3 +323,193 @@ func (c *Chain) MsgTransfer(dst *PathEnd, amount sdk.Coin, dstAddr string,
timeoutTimestamp,
)
}

// MsgRelayRecvPacket constructs the MsgRecvPacket which is to be sent to the receiving chain.
// The counterparty represents the sending chain where the packet commitment would be stored.
func (c *Chain) MsgRelayRecvPacket(counterparty *Chain, packet *relayMsgRecvPacket) (msgs []sdk.Msg, err error) {
var comRes *chantypes.QueryPacketCommitmentResponse
if err = retry.Do(func() (err error) {
// NOTE: the proof height uses - 1 due to tendermint's delayed execution model
comRes, err = counterparty.QueryPacketCommitment(int64(counterparty.MustGetLatestLightHeight())-1, packet.seq)
if err != nil {
return err
}

if comRes.Proof == nil || comRes.Commitment == nil {
return fmt.Errorf("recv packet commitment query seq(%d) is nil", packet.seq)
}

return nil
}, rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, _ error) {
// clear messages
msgs = []sdk.Msg{}

// OnRetry we want to update the light clients and then debug log
updateMsg, err := c.UpdateClient(counterparty)
if err != nil {
return
}

msgs = append(msgs, updateMsg)

if counterparty.debug {
counterparty.Log(fmt.Sprintf("- [%s]@{%d} - try(%d/%d) query packet commitment: %s",
counterparty.ChainID, counterparty.MustGetLatestLightHeight()-1, n+1, rtyAttNum, err))
}

})); err != nil {
counterparty.Error(err)
return
}

if comRes == nil {
return nil, fmt.Errorf("receive packet [%s]seq{%d} has no associated proofs", c.ChainID, packet.seq)
}

version := clienttypes.ParseChainID(c.ChainID)
msg := chantypes.NewMsgRecvPacket(
chantypes.NewPacket(
packet.packetData,
packet.seq,
counterparty.PathEnd.PortID,
counterparty.PathEnd.ChannelID,
c.PathEnd.PortID,
c.PathEnd.ChannelID,
clienttypes.NewHeight(version, packet.timeout),
packet.timeoutStamp,
),
comRes.Proof,
comRes.ProofHeight,
c.MustGetAddress(),
)

return append(msgs, msg), nil
}

// MsgRelayAcknowledgement constructs the MsgAcknowledgement which is to be sent to the sending chain.
// The counterparty represents the receiving chain where the acknowledgement would be stored.
func (c *Chain) MsgRelayAcknowledgement(counterparty *Chain, packet *relayMsgPacketAck) (msgs []sdk.Msg, err error) {
var ackRes *chantypes.QueryPacketAcknowledgementResponse
if err = retry.Do(func() (err error) {
// NOTE: the proof height uses - 1 due to tendermint's delayed execution model
ackRes, err = counterparty.QueryPacketAcknowledgement(int64(counterparty.MustGetLatestLightHeight())-1, packet.seq)
if err != nil {
return err
}

if ackRes.Proof == nil || ackRes.Acknowledgement == nil {
return fmt.Errorf("ack packet acknowledgement query seq(%d) is nil", packet.seq)
}

return nil
}, rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, _ error) {
// clear messages
msgs = []sdk.Msg{}

// OnRetry we want to update the light clients and then debug log
updateMsg, err := c.UpdateClient(counterparty)
if err != nil {
return
}

msgs = append(msgs, updateMsg)

if counterparty.debug {
counterparty.Log(fmt.Sprintf("- [%s]@{%d} - try(%d/%d) query packet acknowledgement: %s",
counterparty.ChainID, counterparty.MustGetLatestLightHeight()-1, n+1, rtyAttNum, err))
}

})); err != nil {
counterparty.Error(err)
return
}

if ackRes == nil {
return nil, fmt.Errorf("ack packet [%s]seq{%d} has no associated proofs", counterparty.ChainID, packet.seq)
}

version := clienttypes.ParseChainID(counterparty.ChainID)
msg := chantypes.NewMsgAcknowledgement(
chantypes.NewPacket(
packet.packetData,
packet.seq,
c.PathEnd.PortID,
c.PathEnd.ChannelID,
counterparty.PathEnd.PortID,
counterparty.PathEnd.ChannelID,
clienttypes.NewHeight(version, packet.timeout),
packet.timeoutStamp,
),
packet.ack,
ackRes.Proof,
ackRes.ProofHeight,
c.MustGetAddress(),
)

return append(msgs, msg), nil
}

// MsgRelayTimeout constructs the MsgTimeout which is to be sent to the sending chain.
// The counterparty represents the receiving chain where the receipts would have been
// stored.
func (c *Chain) MsgRelayTimeout(counterparty *Chain, packet *relayMsgTimeout) (msgs []sdk.Msg, err error) {
var recvRes *chantypes.QueryPacketReceiptResponse
if err = retry.Do(func() (err error) {
// NOTE: Timeouts currently only work with ORDERED channels for nwo
// NOTE: the proof height uses - 1 due to tendermint's delayed execution model
recvRes, err = counterparty.QueryPacketReceipt(int64(counterparty.MustGetLatestLightHeight())-1, packet.seq)
if err != nil {
return err
}

if recvRes.Proof == nil {
return fmt.Errorf("timeout packet receipt proof seq(%d) is nil", packet.seq)
}

return nil
}, rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, _ error) {
// clear messages
msgs = []sdk.Msg{}

// OnRetry we want to update the light clients and then debug log
updateMsg, err := c.UpdateClient(counterparty)
if err != nil {
return
}

msgs = append(msgs, updateMsg)

if counterparty.debug {
counterparty.Log(fmt.Sprintf("- [%s]@{%d} - try(%d/%d) query packet receipt: %s",
counterparty.ChainID, counterparty.MustGetLatestLightHeight()-1, n+1, rtyAttNum, err))
}

})); err != nil {
counterparty.Error(err)
return
}

if recvRes == nil {
return nil, fmt.Errorf("timeout packet [%s]seq{%d} has no associated proofs", c.ChainID, packet.seq)
}

version := clienttypes.ParseChainID(counterparty.ChainID)
msg := chantypes.NewMsgTimeout(
chantypes.NewPacket(
packet.packetData,
packet.seq,
c.PathEnd.PortID,
c.PathEnd.ChannelID,
counterparty.PathEnd.PortID,
counterparty.PathEnd.ChannelID,
clienttypes.NewHeight(version, packet.timeout),
packet.timeoutStamp,
),
packet.seq,
recvRes.Proof,
recvRes.ProofHeight,
c.MustGetAddress(),
)

return append(msgs, msg), nil
}
Loading

0 comments on commit 40c6949

Please sign in to comment.