From efcca3b827d739f933b8055dd86d558c9d1912bd Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Thu, 12 Oct 2023 17:37:27 +0900 Subject: [PATCH 01/13] move stuffs related to metrics from NaiveStrategy to naiveStrategyMetrics Signed-off-by: Masanori Yoshida --- core/naive-strategy.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/naive-strategy.go b/core/naive-strategy.go index 63a76c01..cd06cba8 100644 --- a/core/naive-strategy.go +++ b/core/naive-strategy.go @@ -22,8 +22,13 @@ type NaiveStrategy struct { MaxMsgLength uint64 // maximum amount of messages in a bundled relay transaction srcNoAck bool dstNoAck bool - srcBacklog PacketInfoList - dstBacklog PacketInfoList + + metrics naiveStrategyMetrics +} + +type naiveStrategyMetrics struct { + srcBacklog PacketInfoList + dstBacklog PacketInfoList } var _ StrategyI = (*NaiveStrategy)(nil) @@ -131,7 +136,7 @@ func (st *NaiveStrategy) UnrelayedPackets(src, dst *ProvableChain, sh SyncHeader return nil, err } - if err := st.updateBacklogMetrics(context.TODO(), src, dst, srcPackets, dstPackets); err != nil { + if err := st.metrics.updateBacklogMetrics(context.TODO(), src, dst, srcPackets, dstPackets); err != nil { return nil, err } @@ -537,7 +542,7 @@ func collectAcks(ctx QueryContext, chain *ProvableChain, packets PacketInfoList, return msgs, nil } -func (st *NaiveStrategy) updateBacklogMetrics(ctx context.Context, src, dst ChainInfo, newSrcBacklog, newDstBacklog PacketInfoList) error { +func (st *naiveStrategyMetrics) updateBacklogMetrics(ctx context.Context, src, dst ChainInfo, newSrcBacklog, newDstBacklog PacketInfoList) error { srcAttrs := []attribute.KeyValue{ attribute.Key("chain_id").String(src.ChainID()), attribute.Key("direction").String("src"), From dd279530ed78a3230c5c8db3ca584b618a1b72af Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Thu, 12 Oct 2023 17:41:26 +0900 Subject: [PATCH 02/13] change the processing order in RelayService::Serve Signed-off-by: Masanori Yoshida --- core/service.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/core/service.go b/core/service.go index 913137bb..16b651b1 100644 --- a/core/service.go +++ b/core/service.go @@ -72,25 +72,27 @@ func (srv *RelayService) Serve(ctx context.Context) error { return err } - // relay packets if unrelayed seqs exist - + // get unrelayed packets pseqs, err := srv.st.UnrelayedPackets(srv.src, srv.dst, srv.sh, false) if err != nil { logger.Error("failed to get unrelayed sequences", err) return err } - if err := srv.st.RelayPackets(srv.src, srv.dst, pseqs, srv.sh); err != nil { - logger.Error("failed to relay packets", err) - return err - } - - // relay acks if unrelayed seqs exist + // get unrelayed acks aseqs, err := srv.st.UnrelayedAcknowledgements(srv.src, srv.dst, srv.sh, false) if err != nil { logger.Error("failed to get unrelayed acknowledgements", err) return err } + + // relay packets if unrelayed seqs exist + if err := srv.st.RelayPackets(srv.src, srv.dst, pseqs, srv.sh); err != nil { + logger.Error("failed to relay packets", err) + return err + } + + // relay acks if unrelayed seqs exist if err := srv.st.RelayAcknowledgements(srv.src, srv.dst, aseqs, srv.sh); err != nil { logger.Error("failed to relay acknowledgements", err) return err From 70b25fd05d46873b3c4c3c27934c618af852be47 Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Thu, 12 Oct 2023 23:08:41 +0900 Subject: [PATCH 03/13] add NaiveStrategy::UpdateClients and fix NaiveStrategy::Relay{Packets,Acknowledgements} Signed-off-by: Masanori Yoshida --- cmd/tx.go | 8 +++ core/naive-strategy.go | 150 +++++++++++++++++++++-------------------- core/service.go | 6 ++ core/strategies.go | 3 + 4 files changed, 94 insertions(+), 73 deletions(-) diff --git a/cmd/tx.go b/cmd/tx.go index c4c666c4..780a5dce 100644 --- a/cmd/tx.go +++ b/cmd/tx.go @@ -188,6 +188,10 @@ func relayMsgsCmd(ctx *config.Context) *cobra.Command { return err } + if err := st.UpdateClients(c[src], c[dst], sp, &core.RelayPackets{}, sh, false); err != nil { + return err + } + if err = st.RelayPackets(c[src], c[dst], sp, sh); err != nil { return err } @@ -230,6 +234,10 @@ func relayAcksCmd(ctx *config.Context) *cobra.Command { return err } + if err := st.UpdateClients(c[src], c[dst], &core.RelayPackets{}, sp, sh, false); err != nil { + return err + } + if err = st.RelayAcknowledgements(c[src], c[dst], sp, sh); err != nil { return err } diff --git a/core/naive-strategy.go b/core/naive-strategy.go index cd06cba8..91d983e0 100644 --- a/core/naive-strategy.go +++ b/core/naive-strategy.go @@ -213,35 +213,7 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, return err } - if len(rp.Src) > 0 { - hs, err := sh.SetupHeadersForUpdate(src, dst) - if err != nil { - logger.Error( - "error setting up headers for update", - err, - ) - return err - } - if len(hs) > 0 { - msgs.Dst = dst.Path().UpdateClients(hs, dstAddress) - } - } - - if len(rp.Dst) > 0 { - hs, err := sh.SetupHeadersForUpdate(dst, src) - if err != nil { - logger.Error( - "error setting up headers for update", - err, - ) - return err - } - if len(hs) > 0 { - msgs.Src = src.Path().UpdateClients(hs, srcAddress) - } - } - - packetsForDst, err := collectPackets(srcCtx, src, rp.Src, dstAddress) + msgs.Dst, err = collectPackets(srcCtx, src, rp.Src, dstAddress) if err != nil { logger.Error( "error collecting packets", @@ -249,7 +221,7 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, ) return err } - packetsForSrc, err := collectPackets(dstCtx, dst, rp.Dst, srcAddress) + msgs.Src, err = collectPackets(dstCtx, dst, rp.Dst, srcAddress) if err != nil { logger.Error( "error collecting packets", @@ -258,22 +230,19 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, return err } - if len(packetsForDst) == 0 && len(packetsForSrc) == 0 { + if len(msgs.Dst) == 0 && len(msgs.Src) == 0 { logger.Info( "no packates to relay", ) return nil } - msgs.Dst = append(msgs.Dst, packetsForDst...) - msgs.Src = append(msgs.Src, packetsForSrc...) - // send messages to their respective chains if msgs.Send(src, dst); msgs.Success() { - if num := len(packetsForDst); num > 0 { + if num := len(msgs.Dst); num > 0 { logPacketsRelayed(src, dst, num, "Packets", "src->dst") } - if num := len(packetsForSrc); num > 0 { + if num := len(msgs.Src); num > 0 { logPacketsRelayed(src, dst, num, "Packets", "dst->src") } } @@ -454,64 +423,32 @@ func (st *NaiveStrategy) RelayAcknowledgements(src, dst *ProvableChain, rp *Rela return err } - if !st.dstNoAck && len(rp.Src) > 0 { - hs, err := sh.SetupHeadersForUpdate(src, dst) - if err != nil { - logger.Error( - "error setting up headers", - err, - ) - return err - } - if len(hs) > 0 { - msgs.Dst = dst.Path().UpdateClients(hs, dstAddress) - } - } - - if !st.srcNoAck && len(rp.Dst) > 0 { - hs, err := sh.SetupHeadersForUpdate(dst, src) - if err != nil { - logger.Error( - "error setting up headers", - err, - ) - return err - } - if len(hs) > 0 { - msgs.Src = src.Path().UpdateClients(hs, srcAddress) - } - } - - var acksForSrc, acksForDst []sdk.Msg if !st.dstNoAck { - acksForDst, err = collectAcks(srcCtx, src, rp.Src, dstAddress) + msgs.Dst, err = collectAcks(srcCtx, src, rp.Src, dstAddress) if err != nil { return err } } if !st.srcNoAck { - acksForSrc, err = collectAcks(dstCtx, dst, rp.Dst, srcAddress) + msgs.Src, err = collectAcks(dstCtx, dst, rp.Dst, srcAddress) if err != nil { return err } } - if len(acksForDst) == 0 && len(acksForSrc) == 0 { + if len(msgs.Dst) == 0 && len(msgs.Src) == 0 { logger.Info( "no acknowledgements to relay", ) return nil } - msgs.Dst = append(msgs.Dst, acksForDst...) - msgs.Src = append(msgs.Src, acksForSrc...) - // send messages to their respective chains if msgs.Send(src, dst); msgs.Success() { - if num := len(acksForDst); num > 0 { + if num := len(msgs.Dst); num > 0 { logPacketsRelayed(src, dst, num, "Acknowledgements", "src->dst") } - if num := len(acksForSrc); num > 0 { + if num := len(msgs.Src); num > 0 { logPacketsRelayed(src, dst, num, "Acknowledgements", "dst->src") } } @@ -542,6 +479,73 @@ func collectAcks(ctx QueryContext, chain *ProvableChain, packets PacketInfoList, return msgs, nil } +func (st *NaiveStrategy) UpdateClients(src, dst *ProvableChain, rpForRecv, rpForAck *RelayPackets, sh SyncHeaders, doRefresh bool) error { + logger := GetChannelPairLogger(src, dst) + + // set the maximum relay transaction constraints + msgs := &RelayMsgs{ + Src: []sdk.Msg{}, + Dst: []sdk.Msg{}, + MaxTxSize: st.MaxTxSize, + MaxMsgLength: st.MaxMsgLength, + } + + // check if unrelayed packets or acks exist + needsUpdateForSrc := len(rpForRecv.Dst) > 0 || + !st.srcNoAck && len(rpForAck.Dst) > 0 + needsUpdateForDst := len(rpForRecv.Src) > 0 || + !st.dstNoAck && len(rpForAck.Src) > 0 + + // check if LC refresh is needed + if !needsUpdateForSrc && doRefresh { + //TODO: check if LC refresh is needed for src chain + } + if !needsUpdateForDst && doRefresh { + //TODO: check if LC refresh is needed for dst chain + } + + if needsUpdateForSrc { + srcAddress, err := src.GetAddress() + if err != nil { + return fmt.Errorf("failed to get relayer address on src chain: %v", err) + } + hs, err := sh.SetupHeadersForUpdate(dst, src) + if err != nil { + return fmt.Errorf("failed to set up headers for updating client on src chain: %v", err) + } + if len(hs) > 0 { + msgs.Src = src.Path().UpdateClients(hs, srcAddress) + } + } + + if needsUpdateForDst { + dstAddress, err := dst.GetAddress() + if err != nil { + return fmt.Errorf("failed to get relayer address on dst chain: %v", err) + } + hs, err := sh.SetupHeadersForUpdate(src, dst) + if err != nil { + return fmt.Errorf("failed to set up headers for updating client on dst chain: %v", err) + } + if len(hs) > 0 { + msgs.Dst = dst.Path().UpdateClients(hs, dstAddress) + } + } + + // send messages to their respective chains + if msgs.Send(src, dst); msgs.Success() { + if len(msgs.Src) > 0 { + logger.Info("client on src chain was updated", "num_sent_msgs", len(msgs.Src)) + } + if len(msgs.Dst) > 0 { + logger.Info("client on dst chain was updated", "num_sent_msgs", len(msgs.Dst)) + } + } + + return nil + +} + func (st *naiveStrategyMetrics) updateBacklogMetrics(ctx context.Context, src, dst ChainInfo, newSrcBacklog, newDstBacklog PacketInfoList) error { srcAttrs := []attribute.KeyValue{ attribute.Key("chain_id").String(src.ChainID()), diff --git a/core/service.go b/core/service.go index 16b651b1..b87e9dcd 100644 --- a/core/service.go +++ b/core/service.go @@ -86,6 +86,12 @@ func (srv *RelayService) Serve(ctx context.Context) error { return err } + // update clients + if err := srv.st.UpdateClients(srv.src, srv.dst, pseqs, aseqs, srv.sh, true); err != nil { + logger.Error("failed to update clients", err) + return err + } + // relay packets if unrelayed seqs exist if err := srv.st.RelayPackets(srv.src, srv.dst, pseqs, srv.sh); err != nil { logger.Error("failed to relay packets", err) diff --git a/core/strategies.go b/core/strategies.go index 4b8312c0..c66dc542 100644 --- a/core/strategies.go +++ b/core/strategies.go @@ -26,6 +26,9 @@ type StrategyI interface { // RelayAcknowledgements executes AcknowledgePacket to the packets contained in `rp` on both chains (`src` and `dst`). RelayAcknowledgements(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) error + + // UpdateClients executes UpdateClient only if needed + UpdateClients(src, dst *ProvableChain, rpForRecv, rpForAck *RelayPackets, sh SyncHeaders, doRefresh bool) error } // StrategyCfg defines which relaying strategy to take for a given path From 2f6a91027b506120f083d9855606f6f3b94742e0 Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Tue, 17 Oct 2023 18:29:32 +0900 Subject: [PATCH 04/13] add CheckRefreshRequired to the Prover iface and impl this for tendermint prover (and mock prover) Signed-off-by: Masanori Yoshida --- chains/tendermint/config.go | 3 + chains/tendermint/config.pb.go | 78 ++++++++++++------- chains/tendermint/prover.go | 49 ++++++++++++ core/provers.go | 4 + .../chains/tendermint/config/config.proto | 1 + provers/mock/prover.go | 5 ++ 6 files changed, 112 insertions(+), 28 deletions(-) diff --git a/chains/tendermint/config.go b/chains/tendermint/config.go index 26d1004e..10756abb 100644 --- a/chains/tendermint/config.go +++ b/chains/tendermint/config.go @@ -68,5 +68,8 @@ func (c ProverConfig) Validate() error { if isEmpty(c.TrustingPeriod) { return fmt.Errorf("config attribute \"trusting_period\" is empty") } + if c.RefreshThresholdRate <= 0 { + return fmt.Errorf("config attribute \"refresh_threshold_rate\" is too small: %v", c.RefreshThresholdRate) + } return nil } diff --git a/chains/tendermint/config.pb.go b/chains/tendermint/config.pb.go index a4aa9f33..73f3c6cd 100644 --- a/chains/tendermint/config.pb.go +++ b/chains/tendermint/config.pb.go @@ -69,7 +69,8 @@ func (m *ChainConfig) XXX_DiscardUnknown() { var xxx_messageInfo_ChainConfig proto.InternalMessageInfo type ProverConfig struct { - TrustingPeriod string `protobuf:"bytes,1,opt,name=trusting_period,json=trustingPeriod,proto3" json:"trusting_period,omitempty"` + TrustingPeriod string `protobuf:"bytes,1,opt,name=trusting_period,json=trustingPeriod,proto3" json:"trusting_period,omitempty"` + RefreshThresholdRate float64 `protobuf:"fixed64,2,opt,name=refresh_threshold_rate,json=refreshThresholdRate,proto3" json:"refresh_threshold_rate,omitempty"` } func (m *ProverConfig) Reset() { *m = ProverConfig{} } @@ -115,33 +116,34 @@ func init() { } var fileDescriptor_d67cd47cbc86ecb1 = []byte{ - // 404 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xcf, 0x8a, 0x14, 0x31, - 0x10, 0x87, 0x27, 0xbb, 0xeb, 0xfe, 0x89, 0xee, 0xaa, 0xcd, 0x80, 0x51, 0xb0, 0x19, 0x16, 0xc4, - 0xb9, 0x6c, 0xf7, 0x41, 0x44, 0x3c, 0xee, 0x0e, 0x08, 0x1e, 0x84, 0x61, 0x10, 0x04, 0x2f, 0x21, - 0x93, 0xd4, 0x64, 0xe2, 0x76, 0x3a, 0x4d, 0x25, 0xbd, 0x4c, 0xbf, 0x85, 0xcf, 0xe1, 0x93, 0xec, - 0x71, 0x8f, 0x1e, 0x75, 0xe6, 0x45, 0x24, 0xe9, 0x56, 0x4f, 0x7b, 0x4a, 0xe5, 0xfb, 0x7d, 0x55, - 0x87, 0x4a, 0xe8, 0x05, 0x42, 0x25, 0x3a, 0xc0, 0x52, 0xae, 0x85, 0xa9, 0x7d, 0x19, 0xa0, 0x56, - 0x80, 0xd6, 0xd4, 0xa1, 0x94, 0xae, 0x5e, 0x19, 0x3d, 0x1c, 0x45, 0x83, 0x2e, 0xb8, 0x6c, 0x32, - 0xe8, 0x45, 0xaf, 0x17, 0xff, 0xf5, 0xa2, 0xf7, 0x5e, 0x8c, 0xb5, 0xd3, 0x2e, 0xc9, 0x65, 0xac, - 0xfa, 0xbe, 0xf3, 0x1f, 0x7b, 0xf4, 0xe1, 0x2c, 0xb6, 0xcc, 0x92, 0x95, 0x3d, 0xa1, 0xfb, 0xd7, - 0xd0, 0x31, 0x32, 0x21, 0xd3, 0x93, 0x45, 0x2c, 0xb3, 0xe7, 0xf4, 0x38, 0xcd, 0xe4, 0x46, 0xb1, - 0xbd, 0x84, 0x8f, 0xd2, 0xfd, 0xa3, 0x8a, 0x11, 0x36, 0x92, 0x0b, 0xa5, 0x90, 0xed, 0xf7, 0x11, - 0x36, 0xf2, 0x52, 0x29, 0xcc, 0x5e, 0xd1, 0x33, 0x21, 0xa5, 0x6b, 0xeb, 0xc0, 0x1b, 0x84, 0x95, - 0xd9, 0xb0, 0x83, 0x24, 0x9c, 0x0e, 0x74, 0x9e, 0x60, 0xd4, 0xb4, 0xf0, 0x5c, 0xa8, 0x6f, 0xad, - 0x0f, 0x16, 0xea, 0xc0, 0x1e, 0x4c, 0xc8, 0x94, 0x2c, 0x4e, 0xb5, 0xf0, 0x97, 0xff, 0x60, 0xf6, - 0x92, 0xd2, 0xa8, 0x35, 0x68, 0x24, 0x78, 0x76, 0x98, 0x26, 0x9d, 0x68, 0xe1, 0xe7, 0x09, 0x64, - 0x6f, 0xe9, 0x33, 0x71, 0x03, 0x28, 0x34, 0xf0, 0x65, 0xe5, 0xe4, 0x35, 0x0f, 0xc6, 0x02, 0xb7, - 0x1e, 0x24, 0x3b, 0x9a, 0x90, 0xe9, 0xc1, 0x62, 0x3c, 0xc4, 0x57, 0x31, 0xfd, 0x6c, 0x2c, 0x7c, - 0xf2, 0x20, 0xb3, 0x92, 0x8e, 0xad, 0xd8, 0x70, 0x84, 0x80, 0x1d, 0x5f, 0x39, 0xe4, 0xd2, 0x59, - 0x6b, 0x02, 0x3b, 0x4e, 0x3d, 0x4f, 0xad, 0xd8, 0x2c, 0x62, 0xf4, 0xc1, 0xe1, 0x2c, 0x05, 0xe7, - 0xef, 0xe8, 0xa3, 0x39, 0xba, 0x1b, 0xc0, 0x61, 0x59, 0xaf, 0xe9, 0xe3, 0x80, 0xad, 0x0f, 0xa6, - 0xd6, 0xbc, 0x01, 0x34, 0x4e, 0x0d, 0x8b, 0x3b, 0xfb, 0x8b, 0xe7, 0x89, 0x5e, 0x7d, 0xb9, 0xfd, - 0x9d, 0x8f, 0x6e, 0xb7, 0x39, 0xb9, 0xdb, 0xe6, 0xe4, 0xd7, 0x36, 0x27, 0xdf, 0x77, 0xf9, 0xe8, - 0x6e, 0x97, 0x8f, 0x7e, 0xee, 0xf2, 0xd1, 0xd7, 0xf7, 0xda, 0x84, 0x75, 0xbb, 0x2c, 0xa4, 0xb3, - 0xe5, 0xba, 0x6b, 0x00, 0x2b, 0x50, 0x1a, 0xf0, 0xa2, 0x12, 0x4b, 0x5f, 0x76, 0xad, 0xb9, 0xff, - 0x2b, 0x2c, 0x0f, 0xd3, 0x2b, 0xbe, 0xf9, 0x13, 0x00, 0x00, 0xff, 0xff, 0x71, 0x84, 0x9b, 0xb4, - 0x2e, 0x02, 0x00, 0x00, + // 431 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xcf, 0x6e, 0xd4, 0x30, + 0x10, 0x87, 0xd7, 0x6d, 0xe9, 0x1f, 0x43, 0x0b, 0x44, 0x2b, 0x08, 0x48, 0x44, 0xab, 0x4a, 0x88, + 0xbd, 0x34, 0x39, 0x00, 0x07, 0x8e, 0xed, 0x4a, 0x48, 0x1c, 0x90, 0x56, 0x51, 0x25, 0x24, 0x2e, + 0x96, 0xd7, 0x9e, 0x75, 0x4c, 0xe3, 0x38, 0x1a, 0x3b, 0xd5, 0xe6, 0x2d, 0x78, 0x0e, 0x9e, 0xa4, + 0xc7, 0x1e, 0x39, 0xc2, 0xee, 0x8b, 0x20, 0x7b, 0xb3, 0x70, 0xe2, 0x34, 0x93, 0xdf, 0xf7, 0xcd, + 0x1c, 0x26, 0xa6, 0x17, 0x08, 0x35, 0xef, 0x01, 0x0b, 0x51, 0x71, 0xdd, 0xb8, 0xc2, 0x43, 0x23, + 0x01, 0x8d, 0x6e, 0x7c, 0x21, 0x6c, 0xb3, 0xd4, 0x6a, 0x28, 0x79, 0x8b, 0xd6, 0xdb, 0x64, 0x32, + 0xe8, 0xf9, 0x56, 0xcf, 0xff, 0xe9, 0xf9, 0xd6, 0x7b, 0x39, 0x56, 0x56, 0xd9, 0x28, 0x17, 0xa1, + 0xdb, 0xce, 0x9d, 0xff, 0xd8, 0xa3, 0x0f, 0x67, 0x61, 0x64, 0x16, 0xad, 0xe4, 0x09, 0xdd, 0xbf, + 0x81, 0x3e, 0x25, 0x13, 0x32, 0x3d, 0x29, 0x43, 0x9b, 0xbc, 0xa0, 0xc7, 0x71, 0x27, 0xd3, 0x32, + 0xdd, 0x8b, 0xf1, 0x51, 0xfc, 0xfe, 0x24, 0x03, 0xc2, 0x56, 0x30, 0x2e, 0x25, 0xa6, 0xfb, 0x5b, + 0x84, 0xad, 0xb8, 0x94, 0x12, 0x93, 0xd7, 0xf4, 0x8c, 0x0b, 0x61, 0xbb, 0xc6, 0xb3, 0x16, 0x61, + 0xa9, 0x57, 0xe9, 0x41, 0x14, 0x4e, 0x87, 0x74, 0x1e, 0xc3, 0xa0, 0x29, 0xee, 0x18, 0x97, 0xdf, + 0x3a, 0xe7, 0x0d, 0x34, 0x3e, 0x7d, 0x30, 0x21, 0x53, 0x52, 0x9e, 0x2a, 0xee, 0x2e, 0xff, 0x86, + 0xc9, 0x2b, 0x4a, 0x83, 0xd6, 0xa2, 0x16, 0xe0, 0xd2, 0xc3, 0xb8, 0xe9, 0x44, 0x71, 0x37, 0x8f, + 0x41, 0xf2, 0x9e, 0x3e, 0xe7, 0xb7, 0x80, 0x5c, 0x01, 0x5b, 0xd4, 0x56, 0xdc, 0x30, 0xaf, 0x0d, + 0x30, 0xe3, 0x40, 0xa4, 0x47, 0x13, 0x32, 0x3d, 0x28, 0xc7, 0x03, 0xbe, 0x0a, 0xf4, 0x5a, 0x1b, + 0xf8, 0xec, 0x40, 0x24, 0x05, 0x1d, 0x1b, 0xbe, 0x62, 0x08, 0x1e, 0x7b, 0xb6, 0xb4, 0xc8, 0x84, + 0x35, 0x46, 0xfb, 0xf4, 0x38, 0xce, 0x3c, 0x35, 0x7c, 0x55, 0x06, 0xf4, 0xd1, 0xe2, 0x2c, 0x82, + 0x73, 0x43, 0x1f, 0xcd, 0xd1, 0xde, 0x02, 0x0e, 0xc7, 0x7a, 0x43, 0x1f, 0x7b, 0xec, 0x9c, 0xd7, + 0x8d, 0x62, 0x2d, 0xa0, 0xb6, 0x72, 0x38, 0xdc, 0xd9, 0x2e, 0x9e, 0xc7, 0x34, 0x79, 0x47, 0x9f, + 0x21, 0x2c, 0x11, 0x5c, 0xc5, 0x7c, 0x15, 0x8a, 0xad, 0x25, 0x43, 0xee, 0x21, 0x5e, 0x94, 0x94, + 0xe3, 0x81, 0x5e, 0xef, 0x60, 0xc9, 0x3d, 0x5c, 0x7d, 0xb9, 0xfb, 0x9d, 0x8d, 0xee, 0xd6, 0x19, + 0xb9, 0x5f, 0x67, 0xe4, 0xd7, 0x3a, 0x23, 0xdf, 0x37, 0xd9, 0xe8, 0x7e, 0x93, 0x8d, 0x7e, 0x6e, + 0xb2, 0xd1, 0xd7, 0x0f, 0x4a, 0xfb, 0xaa, 0x5b, 0xe4, 0xc2, 0x9a, 0xa2, 0xea, 0x5b, 0xc0, 0x1a, + 0xa4, 0x02, 0xbc, 0xa8, 0xf9, 0xc2, 0x15, 0x7d, 0xa7, 0xff, 0xff, 0x80, 0x16, 0x87, 0xf1, 0xdf, + 0xbf, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0x40, 0xba, 0x69, 0x65, 0x64, 0x02, 0x00, 0x00, } func (m *ChainConfig) Marshal() (dAtA []byte, err error) { @@ -238,6 +240,12 @@ func (m *ProverConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.RefreshThresholdRate != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.RefreshThresholdRate)))) + i-- + dAtA[i] = 0x11 + } if len(m.TrustingPeriod) > 0 { i -= len(m.TrustingPeriod) copy(dAtA[i:], m.TrustingPeriod) @@ -307,6 +315,9 @@ func (m *ProverConfig) Size() (n int) { if l > 0 { n += 1 + l + sovConfig(uint64(l)) } + if m.RefreshThresholdRate != 0 { + n += 9 + } return n } @@ -636,6 +647,17 @@ func (m *ProverConfig) Unmarshal(dAtA []byte) error { } m.TrustingPeriod = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field RefreshThresholdRate", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.RefreshThresholdRate = float64(math.Float64frombits(v)) default: iNdEx = preIndex skippy, err := skipConfig(dAtA[iNdEx:]) diff --git a/chains/tendermint/prover.go b/chains/tendermint/prover.go index 7d669a09..0b5d8206 100644 --- a/chains/tendermint/prover.go +++ b/chains/tendermint/prover.go @@ -116,6 +116,55 @@ func (pr *Prover) GetLatestFinalizedHeader() (latestFinalizedHeader core.Header, return h, nil } +func (pr *Prover) CheckRefreshRequired(counterparty core.Chain) (bool, error) { + cpQueryHeight, err := counterparty.LatestHeight() + if err != nil { + return false, fmt.Errorf("failed to get the latest height of the counterparty chain: %v", err) + } + cpQueryCtx := core.NewQueryContext(context.TODO(), cpQueryHeight) + + resCs, err := counterparty.QueryClientState(cpQueryCtx) + if err != nil { + return false, fmt.Errorf("failed to query the client state on the counterparty chain: %v", err) + } + + var cs tmclient.ClientState + if err := pr.chain.codec.UnpackAny(resCs.ClientState, &cs); err != nil { + return false, fmt.Errorf("failed to unpack Any into tendermint client state: %v", err) + } + + resCons, err := counterparty.QueryClientConsensusState(cpQueryCtx, cs.LatestHeight) + if err != nil { + return false, fmt.Errorf("failed to query the consensus state on the counterparty chain: %v", err) + } + + var cons tmclient.ConsensusState + if err := pr.chain.codec.UnpackAny(resCons.ConsensusState, &cons); err != nil { + return false, fmt.Errorf("failed to unpack Any into tendermint consensus state: %v", err) + } + + selfQueryHeight, err := pr.chain.LatestHeight() + if err != nil { + return false, fmt.Errorf("failed to get the latest height of the self chain: %v", err) + } + + selfTimestamp, err := pr.chain.Timestamp(selfQueryHeight) + if err != nil { + return false, fmt.Errorf("failed to get timestamp of the self chain: %v", err) + } + + elapsedTime := selfTimestamp.Sub(cons.Timestamp) + + durationMulByFloat := func(d time.Duration, f float64) time.Duration { + nsec := float64(d.Nanoseconds()) + nsec *= f + return time.Duration(nsec) * time.Nanosecond + } + needsRefresh := elapsedTime > durationMulByFloat(cs.TrustingPeriod, pr.config.RefreshThresholdRate) + + return needsRefresh, nil +} + /* Local LightClient implementation */ // GetLatestLightHeight uses the CLI utilities to pull the latest height from a given chain diff --git a/core/provers.go b/core/provers.go index 454bdfd9..5289e6b3 100644 --- a/core/provers.go +++ b/core/provers.go @@ -42,6 +42,10 @@ type LightClient interface { // The order of the returned header slice should be as: [..., ] // if the header slice's length == 0 and err == nil, the relayer should skips the update-client SetupHeadersForUpdate(dstChain ChainInfoICS02Querier, latestFinalizedHeader Header) ([]Header, error) + + // CheckRefreshRequired returns if the on-chain light client needs to be updated. + // For example, this requirement arises due to the trusting period mechanism. + CheckRefreshRequired(counterparty Chain) (bool, error) } // ChainInfoICS02Querier is ChainInfo + ICS02Querier diff --git a/proto/relayer/chains/tendermint/config/config.proto b/proto/relayer/chains/tendermint/config/config.proto index ee22b793..20fc3e30 100644 --- a/proto/relayer/chains/tendermint/config/config.proto +++ b/proto/relayer/chains/tendermint/config/config.proto @@ -19,4 +19,5 @@ message ChainConfig { message ProverConfig { string trusting_period = 1; + double refresh_threshold_rate = 2; } diff --git a/provers/mock/prover.go b/provers/mock/prover.go index 4f126316..87699e96 100644 --- a/provers/mock/prover.go +++ b/provers/mock/prover.go @@ -84,6 +84,11 @@ func (pr *Prover) GetLatestFinalizedHeader() (latestFinalizedHeader core.Header, }, nil } +// CheckRefreshRequired always returns false because mock clients don't need refresh. +func (pr *Prover) CheckRefreshRequired(dst core.Chain) (bool, error) { + return false, nil +} + // ProveState returns the proof of an IBC state specified by `path` and `value` func (pr *Prover) ProveState(ctx core.QueryContext, path string, value []byte) ([]byte, clienttypes.Height, error) { return makeProof(value), ctx.Height().(clienttypes.Height), nil From e488514d381d90beaf6544dba4690f2f5f7130d7 Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Tue, 17 Oct 2023 18:36:32 +0900 Subject: [PATCH 05/13] use narrower type for the argument of CheckRefreshRequired Signed-off-by: Masanori Yoshida --- chains/tendermint/prover.go | 2 +- core/provers.go | 2 +- provers/mock/prover.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/chains/tendermint/prover.go b/chains/tendermint/prover.go index 0b5d8206..256973d6 100644 --- a/chains/tendermint/prover.go +++ b/chains/tendermint/prover.go @@ -116,7 +116,7 @@ func (pr *Prover) GetLatestFinalizedHeader() (latestFinalizedHeader core.Header, return h, nil } -func (pr *Prover) CheckRefreshRequired(counterparty core.Chain) (bool, error) { +func (pr *Prover) CheckRefreshRequired(counterparty core.ChainInfoICS02Querier) (bool, error) { cpQueryHeight, err := counterparty.LatestHeight() if err != nil { return false, fmt.Errorf("failed to get the latest height of the counterparty chain: %v", err) diff --git a/core/provers.go b/core/provers.go index 5289e6b3..ff706500 100644 --- a/core/provers.go +++ b/core/provers.go @@ -45,7 +45,7 @@ type LightClient interface { // CheckRefreshRequired returns if the on-chain light client needs to be updated. // For example, this requirement arises due to the trusting period mechanism. - CheckRefreshRequired(counterparty Chain) (bool, error) + CheckRefreshRequired(counterparty ChainInfoICS02Querier) (bool, error) } // ChainInfoICS02Querier is ChainInfo + ICS02Querier diff --git a/provers/mock/prover.go b/provers/mock/prover.go index 87699e96..19fdc8b0 100644 --- a/provers/mock/prover.go +++ b/provers/mock/prover.go @@ -85,7 +85,7 @@ func (pr *Prover) GetLatestFinalizedHeader() (latestFinalizedHeader core.Header, } // CheckRefreshRequired always returns false because mock clients don't need refresh. -func (pr *Prover) CheckRefreshRequired(dst core.Chain) (bool, error) { +func (pr *Prover) CheckRefreshRequired(dst core.ChainInfoICS02Querier) (bool, error) { return false, nil } From 53927706e3afb882a488c2d1ad02155190a8eda9 Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Tue, 17 Oct 2023 18:37:34 +0900 Subject: [PATCH 06/13] use CheckRefreshRequired in NaiveStrategy Signed-off-by: Masanori Yoshida --- core/naive-strategy.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/naive-strategy.go b/core/naive-strategy.go index 91d983e0..a028c8ed 100644 --- a/core/naive-strategy.go +++ b/core/naive-strategy.go @@ -490,10 +490,21 @@ func (st *NaiveStrategy) UpdateClients(src, dst *ProvableChain, rpForRecv, rpFor MaxMsgLength: st.MaxMsgLength, } + needsRefreshForSrc, err := src.CheckRefreshRequired(dst) + if err != nil { + return fmt.Errorf("failed to check if the LC on the src chain needs to be refreshed: %v", err) + } + needsRefreshForDst, err := dst.CheckRefreshRequired(src) + if err != nil { + return fmt.Errorf("failed to check if the LC on the dst chain needs to be refreshed: %v", err) + } + // check if unrelayed packets or acks exist - needsUpdateForSrc := len(rpForRecv.Dst) > 0 || + needsUpdateForSrc := needsRefreshForSrc || + len(rpForRecv.Dst) > 0 || !st.srcNoAck && len(rpForAck.Dst) > 0 - needsUpdateForDst := len(rpForRecv.Src) > 0 || + needsUpdateForDst := needsRefreshForDst || + len(rpForRecv.Src) > 0 || !st.dstNoAck && len(rpForAck.Src) > 0 // check if LC refresh is needed From f4dba2d03865c672b74e856d19b685c7f8d972d2 Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Tue, 17 Oct 2023 20:38:26 +0900 Subject: [PATCH 07/13] fix some codes and configs to make CheckRefreshRequired work Signed-off-by: Masanori Yoshida --- chains/tendermint/prover.go | 18 +++++++++++++----- tests/cases/tm2tm/configs/demo/ibc-0.json | 3 ++- tests/cases/tm2tm/configs/demo/ibc-1.json | 3 ++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/chains/tendermint/prover.go b/chains/tendermint/prover.go index 256973d6..9dbce63c 100644 --- a/chains/tendermint/prover.go +++ b/chains/tendermint/prover.go @@ -128,20 +128,28 @@ func (pr *Prover) CheckRefreshRequired(counterparty core.ChainInfoICS02Querier) return false, fmt.Errorf("failed to query the client state on the counterparty chain: %v", err) } - var cs tmclient.ClientState + var cs ibcexported.ClientState if err := pr.chain.codec.UnpackAny(resCs.ClientState, &cs); err != nil { return false, fmt.Errorf("failed to unpack Any into tendermint client state: %v", err) } + tmCs, ok := cs.(*tmclient.ClientState) + if !ok { + return false, fmt.Errorf("unexpected instance type of exported.ClientState: %T", cs) + } - resCons, err := counterparty.QueryClientConsensusState(cpQueryCtx, cs.LatestHeight) + resCons, err := counterparty.QueryClientConsensusState(cpQueryCtx, tmCs.LatestHeight) if err != nil { return false, fmt.Errorf("failed to query the consensus state on the counterparty chain: %v", err) } - var cons tmclient.ConsensusState + var cons ibcexported.ConsensusState if err := pr.chain.codec.UnpackAny(resCons.ConsensusState, &cons); err != nil { return false, fmt.Errorf("failed to unpack Any into tendermint consensus state: %v", err) } + tmCons, ok := cons.(*tmclient.ConsensusState) + if !ok { + return false, fmt.Errorf("unexpected instance type of exported.ConsensusState: %T", cons) + } selfQueryHeight, err := pr.chain.LatestHeight() if err != nil { @@ -153,14 +161,14 @@ func (pr *Prover) CheckRefreshRequired(counterparty core.ChainInfoICS02Querier) return false, fmt.Errorf("failed to get timestamp of the self chain: %v", err) } - elapsedTime := selfTimestamp.Sub(cons.Timestamp) + elapsedTime := selfTimestamp.Sub(tmCons.Timestamp) durationMulByFloat := func(d time.Duration, f float64) time.Duration { nsec := float64(d.Nanoseconds()) nsec *= f return time.Duration(nsec) * time.Nanosecond } - needsRefresh := elapsedTime > durationMulByFloat(cs.TrustingPeriod, pr.config.RefreshThresholdRate) + needsRefresh := elapsedTime > durationMulByFloat(tmCs.TrustingPeriod, pr.config.RefreshThresholdRate) return needsRefresh, nil } diff --git a/tests/cases/tm2tm/configs/demo/ibc-0.json b/tests/cases/tm2tm/configs/demo/ibc-0.json index e9058559..a7c90a27 100644 --- a/tests/cases/tm2tm/configs/demo/ibc-0.json +++ b/tests/cases/tm2tm/configs/demo/ibc-0.json @@ -12,6 +12,7 @@ }, "prover": { "@type": "/relayer.chains.tendermint.config.ProverConfig", - "trusting_period": "336h" + "trusting_period": "336h", + "refresh_threshold_rate": 0.5 } } diff --git a/tests/cases/tm2tm/configs/demo/ibc-1.json b/tests/cases/tm2tm/configs/demo/ibc-1.json index b072ec76..27ef490e 100644 --- a/tests/cases/tm2tm/configs/demo/ibc-1.json +++ b/tests/cases/tm2tm/configs/demo/ibc-1.json @@ -12,6 +12,7 @@ }, "prover": { "@type": "/relayer.chains.tendermint.config.ProverConfig", - "trusting_period": "336h" + "trusting_period": "336h", + "refresh_threshold_rate": 0.5 } } From c710b24558dda68cefdad6d582232fa301c8b36d Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Fri, 20 Oct 2023 12:47:38 +0900 Subject: [PATCH 08/13] tendermint: fix Prover::CheckRefreshRequired to be indentent of concrete types of ClientState/ConsensusState Signed-off-by: Masanori Yoshida --- chains/tendermint/config.go | 16 +++++++++++----- chains/tendermint/prover.go | 15 ++++----------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/chains/tendermint/config.go b/chains/tendermint/config.go index 10756abb..13e547b8 100644 --- a/chains/tendermint/config.go +++ b/chains/tendermint/config.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "strings" + "time" "github.com/hyperledger-labs/yui-relayer/core" ) @@ -62,14 +63,19 @@ func (c ProverConfig) Build(chain core.Chain) (core.Prover, error) { } func (c ProverConfig) Validate() error { - isEmpty := func(s string) bool { - return strings.TrimSpace(s) == "" - } - if isEmpty(c.TrustingPeriod) { - return fmt.Errorf("config attribute \"trusting_period\" is empty") + if _, err := time.ParseDuration(c.TrustingPeriod); err != nil { + return fmt.Errorf("config attribute \"trusting_period\" is invalid: %v", err) } if c.RefreshThresholdRate <= 0 { return fmt.Errorf("config attribute \"refresh_threshold_rate\" is too small: %v", c.RefreshThresholdRate) } return nil } + +func (c ProverConfig) GetTrustingPeriod() time.Duration { + if d, err := time.ParseDuration(c.TrustingPeriod); err != nil { + panic(err) + } else { + return d + } +} diff --git a/chains/tendermint/prover.go b/chains/tendermint/prover.go index 9dbce63c..dbb1c9a3 100644 --- a/chains/tendermint/prover.go +++ b/chains/tendermint/prover.go @@ -132,12 +132,8 @@ func (pr *Prover) CheckRefreshRequired(counterparty core.ChainInfoICS02Querier) if err := pr.chain.codec.UnpackAny(resCs.ClientState, &cs); err != nil { return false, fmt.Errorf("failed to unpack Any into tendermint client state: %v", err) } - tmCs, ok := cs.(*tmclient.ClientState) - if !ok { - return false, fmt.Errorf("unexpected instance type of exported.ClientState: %T", cs) - } - resCons, err := counterparty.QueryClientConsensusState(cpQueryCtx, tmCs.LatestHeight) + resCons, err := counterparty.QueryClientConsensusState(cpQueryCtx, cs.GetLatestHeight()) if err != nil { return false, fmt.Errorf("failed to query the consensus state on the counterparty chain: %v", err) } @@ -146,10 +142,7 @@ func (pr *Prover) CheckRefreshRequired(counterparty core.ChainInfoICS02Querier) if err := pr.chain.codec.UnpackAny(resCons.ConsensusState, &cons); err != nil { return false, fmt.Errorf("failed to unpack Any into tendermint consensus state: %v", err) } - tmCons, ok := cons.(*tmclient.ConsensusState) - if !ok { - return false, fmt.Errorf("unexpected instance type of exported.ConsensusState: %T", cons) - } + lcLastTimestamp := time.Unix(0, int64(cons.GetTimestamp())) selfQueryHeight, err := pr.chain.LatestHeight() if err != nil { @@ -161,14 +154,14 @@ func (pr *Prover) CheckRefreshRequired(counterparty core.ChainInfoICS02Querier) return false, fmt.Errorf("failed to get timestamp of the self chain: %v", err) } - elapsedTime := selfTimestamp.Sub(tmCons.Timestamp) + elapsedTime := selfTimestamp.Sub(lcLastTimestamp) durationMulByFloat := func(d time.Duration, f float64) time.Duration { nsec := float64(d.Nanoseconds()) nsec *= f return time.Duration(nsec) * time.Nanosecond } - needsRefresh := elapsedTime > durationMulByFloat(tmCs.TrustingPeriod, pr.config.RefreshThresholdRate) + needsRefresh := elapsedTime > durationMulByFloat(pr.config.GetTrustingPeriod(), pr.config.RefreshThresholdRate) return needsRefresh, nil } From eb9f93715c866d099b24512b46227879a58f8e00 Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Mon, 23 Oct 2023 17:44:22 +0900 Subject: [PATCH 09/13] fix NaiveStrategy::UpdateClients to call Prover::CheckRefreshRequired only when no relays are needed Signed-off-by: Masanori Yoshida --- core/naive-strategy.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/core/naive-strategy.go b/core/naive-strategy.go index a028c8ed..64d35638 100644 --- a/core/naive-strategy.go +++ b/core/naive-strategy.go @@ -490,29 +490,26 @@ func (st *NaiveStrategy) UpdateClients(src, dst *ProvableChain, rpForRecv, rpFor MaxMsgLength: st.MaxMsgLength, } - needsRefreshForSrc, err := src.CheckRefreshRequired(dst) - if err != nil { - return fmt.Errorf("failed to check if the LC on the src chain needs to be refreshed: %v", err) - } - needsRefreshForDst, err := dst.CheckRefreshRequired(src) - if err != nil { - return fmt.Errorf("failed to check if the LC on the dst chain needs to be refreshed: %v", err) - } - // check if unrelayed packets or acks exist - needsUpdateForSrc := needsRefreshForSrc || - len(rpForRecv.Dst) > 0 || + needsUpdateForSrc := len(rpForRecv.Dst) > 0 || !st.srcNoAck && len(rpForAck.Dst) > 0 - needsUpdateForDst := needsRefreshForDst || - len(rpForRecv.Src) > 0 || + needsUpdateForDst := len(rpForRecv.Src) > 0 || !st.dstNoAck && len(rpForAck.Src) > 0 // check if LC refresh is needed if !needsUpdateForSrc && doRefresh { - //TODO: check if LC refresh is needed for src chain + var err error + needsUpdateForSrc, err = src.CheckRefreshRequired(dst) + if err != nil { + return fmt.Errorf("failed to check if the LC on the src chain needs to be refreshed: %v", err) + } } if !needsUpdateForDst && doRefresh { - //TODO: check if LC refresh is needed for dst chain + var err error + needsUpdateForDst, err = dst.CheckRefreshRequired(src) + if err != nil { + return fmt.Errorf("failed to check if the LC on the dst chain needs to be refreshed: %v", err) + } } if needsUpdateForSrc { From 5d7285b201e01a3fdb92d15d752cb8ccbaf5cd18 Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Mon, 23 Oct 2023 17:55:06 +0900 Subject: [PATCH 10/13] add "--do-refresh" option to `tx relay/acks` subcommands Signed-off-by: Masanori Yoshida --- cmd/tx.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/cmd/tx.go b/cmd/tx.go index 780a5dce..49237450 100644 --- a/cmd/tx.go +++ b/cmd/tx.go @@ -8,6 +8,7 @@ import ( "github.com/hyperledger-labs/yui-relayer/config" "github.com/hyperledger-labs/yui-relayer/core" "github.com/spf13/cobra" + "github.com/spf13/viper" ) // transactionCmd represents the tx command @@ -157,6 +158,12 @@ func createChannelCmd(ctx *config.Context) *cobra.Command { } func relayMsgsCmd(ctx *config.Context) *cobra.Command { + const ( + flagDoRefresh = "do-refresh" + ) + const ( + defaultDoRefresh = false + ) cmd := &cobra.Command{ Use: "relay [path-name]", Short: "relay any packets that remain to be relayed on a given path, in both directions", @@ -188,7 +195,7 @@ func relayMsgsCmd(ctx *config.Context) *cobra.Command { return err } - if err := st.UpdateClients(c[src], c[dst], sp, &core.RelayPackets{}, sh, false); err != nil { + if err := st.UpdateClients(c[src], c[dst], sp, &core.RelayPackets{}, sh, viper.GetBool(flagDoRefresh)); err != nil { return err } @@ -199,11 +206,18 @@ func relayMsgsCmd(ctx *config.Context) *cobra.Command { return nil }, } + cmd.Flags().Bool(flagDoRefresh, defaultDoRefresh, "execute light client refresh (updateClient) if required") // TODO add option support for strategy return cmd } func relayAcksCmd(ctx *config.Context) *cobra.Command { + const ( + flagDoRefresh = "do-refresh" + ) + const ( + defaultDoRefresh = false + ) cmd := &cobra.Command{ Use: "relay-acknowledgements [path-name]", Aliases: []string{"acks"}, @@ -234,7 +248,7 @@ func relayAcksCmd(ctx *config.Context) *cobra.Command { return err } - if err := st.UpdateClients(c[src], c[dst], &core.RelayPackets{}, sp, sh, false); err != nil { + if err := st.UpdateClients(c[src], c[dst], &core.RelayPackets{}, sp, sh, viper.GetBool(flagDoRefresh)); err != nil { return err } @@ -245,6 +259,6 @@ func relayAcksCmd(ctx *config.Context) *cobra.Command { return nil }, } - + cmd.Flags().Bool(flagDoRefresh, defaultDoRefresh, "execute light client refresh (updateClient) if required") return cmd } From fdb2e2eefa4b65d3246f7baaa91bff349ef1520c Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Mon, 23 Oct 2023 19:53:58 +0900 Subject: [PATCH 11/13] use type Fraction for `refresh_threshold_rate` Signed-off-by: Masanori Yoshida --- chains/tendermint/config.go | 10 +- chains/tendermint/config.pb.go | 295 +++++++++++++++--- chains/tendermint/prover.go | 7 +- .../chains/tendermint/config/config.proto | 7 +- tests/cases/tm2tm/configs/demo/ibc-0.json | 5 +- tests/cases/tm2tm/configs/demo/ibc-1.json | 5 +- 6 files changed, 278 insertions(+), 51 deletions(-) diff --git a/chains/tendermint/config.go b/chains/tendermint/config.go index 13e547b8..d403efd5 100644 --- a/chains/tendermint/config.go +++ b/chains/tendermint/config.go @@ -66,8 +66,14 @@ func (c ProverConfig) Validate() error { if _, err := time.ParseDuration(c.TrustingPeriod); err != nil { return fmt.Errorf("config attribute \"trusting_period\" is invalid: %v", err) } - if c.RefreshThresholdRate <= 0 { - return fmt.Errorf("config attribute \"refresh_threshold_rate\" is too small: %v", c.RefreshThresholdRate) + if c.RefreshThresholdRate.Denominator == 0 { + return fmt.Errorf("config attribute \"refresh_threshold_rate.denominator\" must not be zero") + } + if c.RefreshThresholdRate.Numerator == 0 { + return fmt.Errorf("config attribute \"refresh_threshold_rate.numerator\" must not be zero") + } + if c.RefreshThresholdRate.Numerator > c.RefreshThresholdRate.Denominator { + return fmt.Errorf("config attribute \"refresh_threshold_rate\" must be less than or equal to 1.0: actual=%v/%v", c.RefreshThresholdRate.Numerator, c.RefreshThresholdRate.Denominator) } return nil } diff --git a/chains/tendermint/config.pb.go b/chains/tendermint/config.pb.go index 73f3c6cd..538204de 100644 --- a/chains/tendermint/config.pb.go +++ b/chains/tendermint/config.pb.go @@ -69,8 +69,8 @@ func (m *ChainConfig) XXX_DiscardUnknown() { var xxx_messageInfo_ChainConfig proto.InternalMessageInfo type ProverConfig struct { - TrustingPeriod string `protobuf:"bytes,1,opt,name=trusting_period,json=trustingPeriod,proto3" json:"trusting_period,omitempty"` - RefreshThresholdRate float64 `protobuf:"fixed64,2,opt,name=refresh_threshold_rate,json=refreshThresholdRate,proto3" json:"refresh_threshold_rate,omitempty"` + TrustingPeriod string `protobuf:"bytes,1,opt,name=trusting_period,json=trustingPeriod,proto3" json:"trusting_period,omitempty"` + RefreshThresholdRate *Fraction `protobuf:"bytes,2,opt,name=refresh_threshold_rate,json=refreshThresholdRate,proto3" json:"refresh_threshold_rate,omitempty"` } func (m *ProverConfig) Reset() { *m = ProverConfig{} } @@ -106,9 +106,48 @@ func (m *ProverConfig) XXX_DiscardUnknown() { var xxx_messageInfo_ProverConfig proto.InternalMessageInfo +type Fraction struct { + Numerator uint64 `protobuf:"varint,1,opt,name=numerator,proto3" json:"numerator,omitempty"` + Denominator uint64 `protobuf:"varint,2,opt,name=denominator,proto3" json:"denominator,omitempty"` +} + +func (m *Fraction) Reset() { *m = Fraction{} } +func (m *Fraction) String() string { return proto.CompactTextString(m) } +func (*Fraction) ProtoMessage() {} +func (*Fraction) Descriptor() ([]byte, []int) { + return fileDescriptor_d67cd47cbc86ecb1, []int{2} +} +func (m *Fraction) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Fraction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Fraction.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Fraction) XXX_Merge(src proto.Message) { + xxx_messageInfo_Fraction.Merge(m, src) +} +func (m *Fraction) XXX_Size() int { + return m.Size() +} +func (m *Fraction) XXX_DiscardUnknown() { + xxx_messageInfo_Fraction.DiscardUnknown(m) +} + +var xxx_messageInfo_Fraction proto.InternalMessageInfo + func init() { proto.RegisterType((*ChainConfig)(nil), "relayer.chains.tendermint.config.ChainConfig") proto.RegisterType((*ProverConfig)(nil), "relayer.chains.tendermint.config.ProverConfig") + proto.RegisterType((*Fraction)(nil), "relayer.chains.tendermint.config.Fraction") } func init() { @@ -116,34 +155,38 @@ func init() { } var fileDescriptor_d67cd47cbc86ecb1 = []byte{ - // 431 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xcf, 0x6e, 0xd4, 0x30, - 0x10, 0x87, 0xd7, 0x6d, 0xe9, 0x1f, 0x43, 0x0b, 0x44, 0x2b, 0x08, 0x48, 0x44, 0xab, 0x4a, 0x88, - 0xbd, 0x34, 0x39, 0x00, 0x07, 0x8e, 0xed, 0x4a, 0x48, 0x1c, 0x90, 0x56, 0x51, 0x25, 0x24, 0x2e, - 0x96, 0xd7, 0x9e, 0x75, 0x4c, 0xe3, 0x38, 0x1a, 0x3b, 0xd5, 0xe6, 0x2d, 0x78, 0x0e, 0x9e, 0xa4, - 0xc7, 0x1e, 0x39, 0xc2, 0xee, 0x8b, 0x20, 0x7b, 0xb3, 0x70, 0xe2, 0x34, 0x93, 0xdf, 0xf7, 0xcd, - 0x1c, 0x26, 0xa6, 0x17, 0x08, 0x35, 0xef, 0x01, 0x0b, 0x51, 0x71, 0xdd, 0xb8, 0xc2, 0x43, 0x23, - 0x01, 0x8d, 0x6e, 0x7c, 0x21, 0x6c, 0xb3, 0xd4, 0x6a, 0x28, 0x79, 0x8b, 0xd6, 0xdb, 0x64, 0x32, - 0xe8, 0xf9, 0x56, 0xcf, 0xff, 0xe9, 0xf9, 0xd6, 0x7b, 0x39, 0x56, 0x56, 0xd9, 0x28, 0x17, 0xa1, - 0xdb, 0xce, 0x9d, 0xff, 0xd8, 0xa3, 0x0f, 0x67, 0x61, 0x64, 0x16, 0xad, 0xe4, 0x09, 0xdd, 0xbf, - 0x81, 0x3e, 0x25, 0x13, 0x32, 0x3d, 0x29, 0x43, 0x9b, 0xbc, 0xa0, 0xc7, 0x71, 0x27, 0xd3, 0x32, - 0xdd, 0x8b, 0xf1, 0x51, 0xfc, 0xfe, 0x24, 0x03, 0xc2, 0x56, 0x30, 0x2e, 0x25, 0xa6, 0xfb, 0x5b, - 0x84, 0xad, 0xb8, 0x94, 0x12, 0x93, 0xd7, 0xf4, 0x8c, 0x0b, 0x61, 0xbb, 0xc6, 0xb3, 0x16, 0x61, - 0xa9, 0x57, 0xe9, 0x41, 0x14, 0x4e, 0x87, 0x74, 0x1e, 0xc3, 0xa0, 0x29, 0xee, 0x18, 0x97, 0xdf, - 0x3a, 0xe7, 0x0d, 0x34, 0x3e, 0x7d, 0x30, 0x21, 0x53, 0x52, 0x9e, 0x2a, 0xee, 0x2e, 0xff, 0x86, - 0xc9, 0x2b, 0x4a, 0x83, 0xd6, 0xa2, 0x16, 0xe0, 0xd2, 0xc3, 0xb8, 0xe9, 0x44, 0x71, 0x37, 0x8f, - 0x41, 0xf2, 0x9e, 0x3e, 0xe7, 0xb7, 0x80, 0x5c, 0x01, 0x5b, 0xd4, 0x56, 0xdc, 0x30, 0xaf, 0x0d, - 0x30, 0xe3, 0x40, 0xa4, 0x47, 0x13, 0x32, 0x3d, 0x28, 0xc7, 0x03, 0xbe, 0x0a, 0xf4, 0x5a, 0x1b, - 0xf8, 0xec, 0x40, 0x24, 0x05, 0x1d, 0x1b, 0xbe, 0x62, 0x08, 0x1e, 0x7b, 0xb6, 0xb4, 0xc8, 0x84, - 0x35, 0x46, 0xfb, 0xf4, 0x38, 0xce, 0x3c, 0x35, 0x7c, 0x55, 0x06, 0xf4, 0xd1, 0xe2, 0x2c, 0x82, - 0x73, 0x43, 0x1f, 0xcd, 0xd1, 0xde, 0x02, 0x0e, 0xc7, 0x7a, 0x43, 0x1f, 0x7b, 0xec, 0x9c, 0xd7, - 0x8d, 0x62, 0x2d, 0xa0, 0xb6, 0x72, 0x38, 0xdc, 0xd9, 0x2e, 0x9e, 0xc7, 0x34, 0x79, 0x47, 0x9f, - 0x21, 0x2c, 0x11, 0x5c, 0xc5, 0x7c, 0x15, 0x8a, 0xad, 0x25, 0x43, 0xee, 0x21, 0x5e, 0x94, 0x94, - 0xe3, 0x81, 0x5e, 0xef, 0x60, 0xc9, 0x3d, 0x5c, 0x7d, 0xb9, 0xfb, 0x9d, 0x8d, 0xee, 0xd6, 0x19, - 0xb9, 0x5f, 0x67, 0xe4, 0xd7, 0x3a, 0x23, 0xdf, 0x37, 0xd9, 0xe8, 0x7e, 0x93, 0x8d, 0x7e, 0x6e, - 0xb2, 0xd1, 0xd7, 0x0f, 0x4a, 0xfb, 0xaa, 0x5b, 0xe4, 0xc2, 0x9a, 0xa2, 0xea, 0x5b, 0xc0, 0x1a, - 0xa4, 0x02, 0xbc, 0xa8, 0xf9, 0xc2, 0x15, 0x7d, 0xa7, 0xff, 0xff, 0x80, 0x16, 0x87, 0xf1, 0xdf, - 0xbf, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0x40, 0xba, 0x69, 0x65, 0x64, 0x02, 0x00, 0x00, + // 482 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0x41, 0x6b, 0x13, 0x41, + 0x14, 0xc7, 0xb3, 0x6d, 0x6c, 0x93, 0x89, 0xad, 0xba, 0x04, 0x5d, 0x45, 0x97, 0x10, 0x10, 0x83, + 0xd0, 0x5d, 0x50, 0x3c, 0x78, 0x6c, 0x03, 0x05, 0x05, 0x21, 0x2c, 0x05, 0xc1, 0xcb, 0x38, 0x99, + 0x79, 0x99, 0x8c, 0xcd, 0xcc, 0x2c, 0x6f, 0x66, 0x4b, 0xf2, 0x2d, 0xbc, 0xfa, 0x15, 0xfc, 0x24, + 0x3d, 0xf6, 0xe8, 0x51, 0x93, 0x2f, 0x22, 0x3b, 0xd9, 0x58, 0x2f, 0xe2, 0x69, 0x66, 0x7f, 0xff, + 0xdf, 0x7b, 0x2c, 0x6f, 0x1e, 0x39, 0x41, 0x58, 0xb0, 0x15, 0x60, 0xce, 0xe7, 0x4c, 0x19, 0x97, + 0x7b, 0x30, 0x02, 0x50, 0x2b, 0xe3, 0x73, 0x6e, 0xcd, 0x4c, 0xc9, 0xe6, 0xc8, 0x4a, 0xb4, 0xde, + 0xc6, 0x83, 0x46, 0xcf, 0xb6, 0x7a, 0x76, 0xab, 0x67, 0x5b, 0xef, 0x49, 0x5f, 0x5a, 0x69, 0x83, + 0x9c, 0xd7, 0xb7, 0x6d, 0xdd, 0xf0, 0xfb, 0x1e, 0xe9, 0x8d, 0xeb, 0x92, 0x71, 0xb0, 0xe2, 0xfb, + 0x64, 0xff, 0x12, 0x56, 0x49, 0x34, 0x88, 0x46, 0xdd, 0xa2, 0xbe, 0xc6, 0x8f, 0x49, 0x27, 0xf4, + 0xa4, 0x4a, 0x24, 0x7b, 0x01, 0x1f, 0x86, 0xef, 0x77, 0xa2, 0x8e, 0xb0, 0xe4, 0x94, 0x09, 0x81, + 0xc9, 0xfe, 0x36, 0xc2, 0x92, 0x9f, 0x0a, 0x81, 0xf1, 0x73, 0x72, 0xcc, 0x38, 0xb7, 0x95, 0xf1, + 0xb4, 0x44, 0x98, 0xa9, 0x65, 0xd2, 0x0e, 0xc2, 0x51, 0x43, 0x27, 0x01, 0xd6, 0x9a, 0x64, 0x8e, + 0x32, 0xf1, 0xa5, 0x72, 0x5e, 0x83, 0xf1, 0xc9, 0x9d, 0x41, 0x34, 0x8a, 0x8a, 0x23, 0xc9, 0xdc, + 0xe9, 0x1f, 0x18, 0x3f, 0x23, 0xa4, 0xd6, 0x4a, 0x54, 0x1c, 0x5c, 0x72, 0x10, 0x3a, 0x75, 0x25, + 0x73, 0x93, 0x00, 0xe2, 0x37, 0xe4, 0x11, 0xbb, 0x02, 0x64, 0x12, 0xe8, 0x74, 0x61, 0xf9, 0x25, + 0xf5, 0x4a, 0x03, 0xd5, 0x0e, 0x78, 0x72, 0x38, 0x88, 0x46, 0xed, 0xa2, 0xdf, 0xc4, 0x67, 0x75, + 0x7a, 0xa1, 0x34, 0x7c, 0x70, 0xc0, 0xe3, 0x9c, 0xf4, 0x35, 0x5b, 0x52, 0x04, 0x8f, 0x2b, 0x3a, + 0xb3, 0x48, 0xb9, 0xd5, 0x5a, 0xf9, 0xa4, 0x13, 0x6a, 0x1e, 0x68, 0xb6, 0x2c, 0xea, 0xe8, 0xdc, + 0xe2, 0x38, 0x04, 0xc3, 0x6f, 0x11, 0xb9, 0x3b, 0x41, 0x7b, 0x05, 0xd8, 0x4c, 0xeb, 0x05, 0xb9, + 0xe7, 0xb1, 0x72, 0x5e, 0x19, 0x49, 0x4b, 0x40, 0x65, 0x45, 0x33, 0xb9, 0xe3, 0x1d, 0x9e, 0x04, + 0x1a, 0x7f, 0x26, 0x0f, 0x11, 0x66, 0x08, 0x6e, 0x4e, 0xfd, 0xbc, 0x3e, 0xec, 0x42, 0x50, 0x64, + 0x1e, 0xc2, 0x48, 0x7b, 0xaf, 0x5e, 0x66, 0xff, 0x7b, 0xbf, 0xec, 0x1c, 0x19, 0xf7, 0xca, 0x9a, + 0xa2, 0xdf, 0x74, 0xba, 0xd8, 0x35, 0x2a, 0x98, 0x87, 0xe1, 0x7b, 0xd2, 0xd9, 0x19, 0xf1, 0x53, + 0xd2, 0x35, 0x95, 0x06, 0x64, 0xde, 0x62, 0xf8, 0xa1, 0x76, 0x71, 0x0b, 0xe2, 0x01, 0xe9, 0x09, + 0x30, 0x56, 0x2b, 0x13, 0xf2, 0xbd, 0x90, 0xff, 0x8d, 0xce, 0x3e, 0x5e, 0xff, 0x4a, 0x5b, 0xd7, + 0xeb, 0x34, 0xba, 0x59, 0xa7, 0xd1, 0xcf, 0x75, 0x1a, 0x7d, 0xdd, 0xa4, 0xad, 0x9b, 0x4d, 0xda, + 0xfa, 0xb1, 0x49, 0x5b, 0x9f, 0xde, 0x4a, 0xe5, 0xe7, 0xd5, 0x34, 0xe3, 0x56, 0xe7, 0xf3, 0x55, + 0x09, 0xb8, 0x00, 0x21, 0x01, 0x4f, 0x16, 0x6c, 0xea, 0xf2, 0x55, 0xa5, 0xfe, 0xbd, 0xb9, 0xd3, + 0x83, 0xb0, 0x74, 0xaf, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x58, 0x5a, 0x44, 0xe1, 0xdd, 0x02, + 0x00, 0x00, } func (m *ChainConfig) Marshal() (dAtA []byte, err error) { @@ -240,11 +283,17 @@ func (m *ProverConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.RefreshThresholdRate != 0 { - i -= 8 - encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.RefreshThresholdRate)))) + if m.RefreshThresholdRate != nil { + { + size, err := m.RefreshThresholdRate.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintConfig(dAtA, i, uint64(size)) + } i-- - dAtA[i] = 0x11 + dAtA[i] = 0x12 } if len(m.TrustingPeriod) > 0 { i -= len(m.TrustingPeriod) @@ -256,6 +305,39 @@ func (m *ProverConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Fraction) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Fraction) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Fraction) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Denominator != 0 { + i = encodeVarintConfig(dAtA, i, uint64(m.Denominator)) + i-- + dAtA[i] = 0x10 + } + if m.Numerator != 0 { + i = encodeVarintConfig(dAtA, i, uint64(m.Numerator)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintConfig(dAtA []byte, offset int, v uint64) int { offset -= sovConfig(v) base := offset @@ -315,8 +397,24 @@ func (m *ProverConfig) Size() (n int) { if l > 0 { n += 1 + l + sovConfig(uint64(l)) } - if m.RefreshThresholdRate != 0 { - n += 9 + if m.RefreshThresholdRate != nil { + l = m.RefreshThresholdRate.Size() + n += 1 + l + sovConfig(uint64(l)) + } + return n +} + +func (m *Fraction) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Numerator != 0 { + n += 1 + sovConfig(uint64(m.Numerator)) + } + if m.Denominator != 0 { + n += 1 + sovConfig(uint64(m.Denominator)) } return n } @@ -648,16 +746,129 @@ func (m *ProverConfig) Unmarshal(dAtA []byte) error { m.TrustingPeriod = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 1 { + if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field RefreshThresholdRate", wireType) } - var v uint64 - if (iNdEx + 8) > l { + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthConfig + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthConfig + } + if postIndex > l { return io.ErrUnexpectedEOF } - v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - m.RefreshThresholdRate = float64(math.Float64frombits(v)) + if m.RefreshThresholdRate == nil { + m.RefreshThresholdRate = &Fraction{} + } + if err := m.RefreshThresholdRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipConfig(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthConfig + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Fraction) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Fraction: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Fraction: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Numerator", wireType) + } + m.Numerator = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Numerator |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Denominator", wireType) + } + m.Denominator = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Denominator |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipConfig(dAtA[iNdEx:]) diff --git a/chains/tendermint/prover.go b/chains/tendermint/prover.go index dbb1c9a3..325a6800 100644 --- a/chains/tendermint/prover.go +++ b/chains/tendermint/prover.go @@ -156,12 +156,11 @@ func (pr *Prover) CheckRefreshRequired(counterparty core.ChainInfoICS02Querier) elapsedTime := selfTimestamp.Sub(lcLastTimestamp) - durationMulByFloat := func(d time.Duration, f float64) time.Duration { - nsec := float64(d.Nanoseconds()) - nsec *= f + durationMulByFraction := func(d time.Duration, f *Fraction) time.Duration { + nsec := d.Nanoseconds() * int64(f.Numerator) / int64(f.Denominator) return time.Duration(nsec) * time.Nanosecond } - needsRefresh := elapsedTime > durationMulByFloat(pr.config.GetTrustingPeriod(), pr.config.RefreshThresholdRate) + needsRefresh := elapsedTime > durationMulByFraction(pr.config.GetTrustingPeriod(), pr.config.RefreshThresholdRate) return needsRefresh, nil } diff --git a/proto/relayer/chains/tendermint/config/config.proto b/proto/relayer/chains/tendermint/config/config.proto index 20fc3e30..b3a03b98 100644 --- a/proto/relayer/chains/tendermint/config/config.proto +++ b/proto/relayer/chains/tendermint/config/config.proto @@ -19,5 +19,10 @@ message ChainConfig { message ProverConfig { string trusting_period = 1; - double refresh_threshold_rate = 2; + Fraction refresh_threshold_rate = 2; +} + +message Fraction { + uint64 numerator = 1; + uint64 denominator = 2; } diff --git a/tests/cases/tm2tm/configs/demo/ibc-0.json b/tests/cases/tm2tm/configs/demo/ibc-0.json index a7c90a27..9f2b22e1 100644 --- a/tests/cases/tm2tm/configs/demo/ibc-0.json +++ b/tests/cases/tm2tm/configs/demo/ibc-0.json @@ -13,6 +13,9 @@ "prover": { "@type": "/relayer.chains.tendermint.config.ProverConfig", "trusting_period": "336h", - "refresh_threshold_rate": 0.5 + "refresh_threshold_rate": { + "numerator": 2, + "denominator": 3 + } } } diff --git a/tests/cases/tm2tm/configs/demo/ibc-1.json b/tests/cases/tm2tm/configs/demo/ibc-1.json index 27ef490e..eda642d4 100644 --- a/tests/cases/tm2tm/configs/demo/ibc-1.json +++ b/tests/cases/tm2tm/configs/demo/ibc-1.json @@ -13,6 +13,9 @@ "prover": { "@type": "/relayer.chains.tendermint.config.ProverConfig", "trusting_period": "336h", - "refresh_threshold_rate": 0.5 + "refresh_threshold_rate": { + "numerator": 2, + "denominator": 3 + } } } From 5f2b8783eaaa35e84aee1abc42a1aea1c8333d1a Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Mon, 23 Oct 2023 22:35:37 +0900 Subject: [PATCH 12/13] use "--do-refresh" option in e2e testing Signed-off-by: Masanori Yoshida --- tests/cases/tm2tm/scripts/test-tx | 4 ++-- tests/cases/tmmock2tmmock/scripts/test-tx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cases/tm2tm/scripts/test-tx b/tests/cases/tm2tm/scripts/test-tx index 254f41d3..e1f9c9e6 100755 --- a/tests/cases/tm2tm/scripts/test-tx +++ b/tests/cases/tm2tm/scripts/test-tx @@ -19,9 +19,9 @@ echo "Before ibc1 balance: $(${RLY} query balance ibc1 ${TM_ADDRESS1})" ${RLY} tx transfer ibc01 ibc0 ibc1 100samoleans ${TM_ADDRESS1} sleep ${TX_INTERNAL} -${RLY} tx relay ibc01 +${RLY} tx relay --do-refresh ibc01 sleep ${TX_INTERNAL} -${RLY} tx acks ibc01 +${RLY} tx acks --do-refresh ibc01 sleep ${TX_INTERNAL} echo "After ibc0 balance: $(${RLY} query balance ibc0 ${TM_ADDRESS0})" diff --git a/tests/cases/tmmock2tmmock/scripts/test-tx b/tests/cases/tmmock2tmmock/scripts/test-tx index 6b85cf85..cf73c68d 100755 --- a/tests/cases/tmmock2tmmock/scripts/test-tx +++ b/tests/cases/tmmock2tmmock/scripts/test-tx @@ -33,7 +33,7 @@ do done # relay the packet (recvPacket) -${RLY} tx relay ibc01 +${RLY} tx relay --do-refresh ibc01 # wait for the finalization of the recvPacket execution for i in `seq $RETRY_COUNT` @@ -48,7 +48,7 @@ do done # relay the ack for the packet (acknowledgePacket) -${RLY} tx acks ibc01 +${RLY} tx acks --do-refresh ibc01 # wait for the finalization of the recvPacket execution for i in `seq $RETRY_COUNT` From a95ff90aa9a8f5b643e678b8932e1a47d6897dc6 Mon Sep 17 00:00:00 2001 From: Masanori Yoshida Date: Wed, 25 Oct 2023 17:42:02 +0900 Subject: [PATCH 13/13] introduce StrategyI::Send and eliminate msg transmission in StrategyI::{RelayPackets,RelayAcks,UpdateClients} Signed-off-by: Masanori Yoshida --- cmd/tx.go | 24 +++++++-- core/naive-strategy.go | 114 +++++++++++++++++------------------------ core/relayMsgs.go | 6 +++ core/service.go | 18 +++++-- core/strategies.go | 9 ++-- 5 files changed, 95 insertions(+), 76 deletions(-) diff --git a/cmd/tx.go b/cmd/tx.go index 49237450..e53b0067 100644 --- a/cmd/tx.go +++ b/cmd/tx.go @@ -195,14 +195,22 @@ func relayMsgsCmd(ctx *config.Context) *cobra.Command { return err } - if err := st.UpdateClients(c[src], c[dst], sp, &core.RelayPackets{}, sh, viper.GetBool(flagDoRefresh)); err != nil { + msgs := core.NewRelayMsgs() + + if m, err := st.UpdateClients(c[src], c[dst], sp, &core.RelayPackets{}, sh, viper.GetBool(flagDoRefresh)); err != nil { return err + } else { + msgs.Merge(m) } - if err = st.RelayPackets(c[src], c[dst], sp, sh); err != nil { + if m, err := st.RelayPackets(c[src], c[dst], sp, sh); err != nil { return err + } else { + msgs.Merge(m) } + st.Send(c[src], c[dst], msgs) + return nil }, } @@ -248,14 +256,22 @@ func relayAcksCmd(ctx *config.Context) *cobra.Command { return err } - if err := st.UpdateClients(c[src], c[dst], &core.RelayPackets{}, sp, sh, viper.GetBool(flagDoRefresh)); err != nil { + msgs := core.NewRelayMsgs() + + if m, err := st.UpdateClients(c[src], c[dst], &core.RelayPackets{}, sp, sh, viper.GetBool(flagDoRefresh)); err != nil { return err + } else { + msgs.Merge(m) } - if err = st.RelayAcknowledgements(c[src], c[dst], sp, sh); err != nil { + if m, err := st.RelayAcknowledgements(c[src], c[dst], sp, sh); err != nil { return err + } else { + msgs.Merge(m) } + st.Send(c[src], c[dst], msgs) + return nil }, } diff --git a/core/naive-strategy.go b/core/naive-strategy.go index 64d35638..0557be03 100644 --- a/core/naive-strategy.go +++ b/core/naive-strategy.go @@ -12,6 +12,7 @@ import ( "github.com/hyperledger-labs/yui-relayer/metrics" "go.opentelemetry.io/otel/attribute" api "go.opentelemetry.io/otel/metric" + "golang.org/x/exp/slog" "golang.org/x/sync/errgroup" ) @@ -182,16 +183,11 @@ func (st *NaiveStrategy) UnrelayedPackets(src, dst *ProvableChain, sh SyncHeader }, nil } -func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) error { +func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) (*RelayMsgs, error) { logger := GetChannelPairLogger(src, dst) defer logger.TimeTrack(time.Now(), "RelayPackets") - // set the maximum relay transaction constraints - msgs := &RelayMsgs{ - Src: []sdk.Msg{}, - Dst: []sdk.Msg{}, - MaxTxSize: st.MaxTxSize, - MaxMsgLength: st.MaxMsgLength, - } + + msgs := NewRelayMsgs() srcCtx := sh.GetQueryContext(src.ChainID()) dstCtx := sh.GetQueryContext(dst.ChainID()) @@ -201,7 +197,7 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, "error getting address", err, ) - return err + return nil, err } dstAddress, err := dst.GetAddress() @@ -210,7 +206,7 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, "error getting address", err, ) - return err + return nil, err } msgs.Dst, err = collectPackets(srcCtx, src, rp.Src, dstAddress) @@ -219,7 +215,7 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, "error collecting packets", err, ) - return err + return nil, err } msgs.Src, err = collectPackets(dstCtx, dst, rp.Dst, srcAddress) if err != nil { @@ -227,18 +223,12 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, "error collecting packets", err, ) - return err + return nil, err } if len(msgs.Dst) == 0 && len(msgs.Src) == 0 { - logger.Info( - "no packates to relay", - ) - return nil - } - - // send messages to their respective chains - if msgs.Send(src, dst); msgs.Success() { + logger.Info("no packates to relay") + } else { if num := len(msgs.Dst); num > 0 { logPacketsRelayed(src, dst, num, "Packets", "src->dst") } @@ -247,7 +237,7 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, } } - return nil + return msgs, nil } func (st *NaiveStrategy) UnrelayedAcknowledgements(src, dst *ProvableChain, sh SyncHeaders, includeRelayedButUnfinalized bool) (*RelayPackets, error) { @@ -387,22 +377,17 @@ func collectPackets(ctx QueryContext, chain *ProvableChain, packets PacketInfoLi func logPacketsRelayed(src, dst Chain, num int, obj string, dir string) { logger := GetChannelPairLogger(src, dst) logger.Info( - fmt.Sprintf("★ %s relayed", obj), + fmt.Sprintf("★ %s are scheduled for relay", obj), "count", num, "direction", dir, ) } -func (st *NaiveStrategy) RelayAcknowledgements(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) error { +func (st *NaiveStrategy) RelayAcknowledgements(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) (*RelayMsgs, error) { logger := GetChannelPairLogger(src, dst) defer logger.TimeTrack(time.Now(), "RelayAcknowledgements") - // set the maximum relay transaction constraints - msgs := &RelayMsgs{ - Src: []sdk.Msg{}, - Dst: []sdk.Msg{}, - MaxTxSize: st.MaxTxSize, - MaxMsgLength: st.MaxMsgLength, - } + + msgs := NewRelayMsgs() srcCtx := sh.GetQueryContext(src.ChainID()) dstCtx := sh.GetQueryContext(dst.ChainID()) @@ -412,7 +397,7 @@ func (st *NaiveStrategy) RelayAcknowledgements(src, dst *ProvableChain, rp *Rela "error getting address", err, ) - return err + return nil, err } dstAddress, err := dst.GetAddress() if err != nil { @@ -420,31 +405,25 @@ func (st *NaiveStrategy) RelayAcknowledgements(src, dst *ProvableChain, rp *Rela "error getting address", err, ) - return err + return nil, err } if !st.dstNoAck { msgs.Dst, err = collectAcks(srcCtx, src, rp.Src, dstAddress) if err != nil { - return err + return nil, err } } if !st.srcNoAck { msgs.Src, err = collectAcks(dstCtx, dst, rp.Dst, srcAddress) if err != nil { - return err + return nil, err } } if len(msgs.Dst) == 0 && len(msgs.Src) == 0 { - logger.Info( - "no acknowledgements to relay", - ) - return nil - } - - // send messages to their respective chains - if msgs.Send(src, dst); msgs.Success() { + logger.Info("no acknowledgements to relay") + } else { if num := len(msgs.Dst); num > 0 { logPacketsRelayed(src, dst, num, "Acknowledgements", "src->dst") } @@ -453,7 +432,7 @@ func (st *NaiveStrategy) RelayAcknowledgements(src, dst *ProvableChain, rp *Rela } } - return nil + return msgs, nil } func collectAcks(ctx QueryContext, chain *ProvableChain, packets PacketInfoList, signer sdk.AccAddress) ([]sdk.Msg, error) { @@ -479,16 +458,10 @@ func collectAcks(ctx QueryContext, chain *ProvableChain, packets PacketInfoList, return msgs, nil } -func (st *NaiveStrategy) UpdateClients(src, dst *ProvableChain, rpForRecv, rpForAck *RelayPackets, sh SyncHeaders, doRefresh bool) error { +func (st *NaiveStrategy) UpdateClients(src, dst *ProvableChain, rpForRecv, rpForAck *RelayPackets, sh SyncHeaders, doRefresh bool) (*RelayMsgs, error) { logger := GetChannelPairLogger(src, dst) - // set the maximum relay transaction constraints - msgs := &RelayMsgs{ - Src: []sdk.Msg{}, - Dst: []sdk.Msg{}, - MaxTxSize: st.MaxTxSize, - MaxMsgLength: st.MaxMsgLength, - } + msgs := NewRelayMsgs() // check if unrelayed packets or acks exist needsUpdateForSrc := len(rpForRecv.Dst) > 0 || @@ -501,25 +474,25 @@ func (st *NaiveStrategy) UpdateClients(src, dst *ProvableChain, rpForRecv, rpFor var err error needsUpdateForSrc, err = src.CheckRefreshRequired(dst) if err != nil { - return fmt.Errorf("failed to check if the LC on the src chain needs to be refreshed: %v", err) + return nil, fmt.Errorf("failed to check if the LC on the src chain needs to be refreshed: %v", err) } } if !needsUpdateForDst && doRefresh { var err error needsUpdateForDst, err = dst.CheckRefreshRequired(src) if err != nil { - return fmt.Errorf("failed to check if the LC on the dst chain needs to be refreshed: %v", err) + return nil, fmt.Errorf("failed to check if the LC on the dst chain needs to be refreshed: %v", err) } } if needsUpdateForSrc { srcAddress, err := src.GetAddress() if err != nil { - return fmt.Errorf("failed to get relayer address on src chain: %v", err) + return nil, fmt.Errorf("failed to get relayer address on src chain: %v", err) } hs, err := sh.SetupHeadersForUpdate(dst, src) if err != nil { - return fmt.Errorf("failed to set up headers for updating client on src chain: %v", err) + return nil, fmt.Errorf("failed to set up headers for updating client on src chain: %v", err) } if len(hs) > 0 { msgs.Src = src.Path().UpdateClients(hs, srcAddress) @@ -529,29 +502,38 @@ func (st *NaiveStrategy) UpdateClients(src, dst *ProvableChain, rpForRecv, rpFor if needsUpdateForDst { dstAddress, err := dst.GetAddress() if err != nil { - return fmt.Errorf("failed to get relayer address on dst chain: %v", err) + return nil, fmt.Errorf("failed to get relayer address on dst chain: %v", err) } hs, err := sh.SetupHeadersForUpdate(src, dst) if err != nil { - return fmt.Errorf("failed to set up headers for updating client on dst chain: %v", err) + return nil, fmt.Errorf("failed to set up headers for updating client on dst chain: %v", err) } if len(hs) > 0 { msgs.Dst = dst.Path().UpdateClients(hs, dstAddress) } } - // send messages to their respective chains - if msgs.Send(src, dst); msgs.Success() { - if len(msgs.Src) > 0 { - logger.Info("client on src chain was updated", "num_sent_msgs", len(msgs.Src)) - } - if len(msgs.Dst) > 0 { - logger.Info("client on dst chain was updated", "num_sent_msgs", len(msgs.Dst)) - } + if len(msgs.Src) > 0 { + logger.Info("client on src chain was scheduled for update", "num_sent_msgs", len(msgs.Src)) + } + if len(msgs.Dst) > 0 { + logger.Info("client on dst chain was scheduled for update", "num_sent_msgs", len(msgs.Dst)) } - return nil + return msgs, nil +} + +func (st *NaiveStrategy) Send(src, dst Chain, msgs *RelayMsgs) { + logger := GetChannelPairLogger(src, dst) + msgs.MaxTxSize = st.MaxTxSize + msgs.MaxMsgLength = st.MaxMsgLength + msgs.Send(src, dst) + + logger.Info("msgs relayed", + slog.Group("src", "msg_count", len(msgs.Src)), + slog.Group("dst", "msg_count", len(msgs.Dst)), + ) } func (st *naiveStrategyMetrics) updateBacklogMetrics(ctx context.Context, src, dst ChainInfo, newSrcBacklog, newDstBacklog PacketInfoList) error { diff --git a/core/relayMsgs.go b/core/relayMsgs.go index 66e05890..4b0c9600 100644 --- a/core/relayMsgs.go +++ b/core/relayMsgs.go @@ -114,3 +114,9 @@ func (r *RelayMsgs) Send(src, dst Chain) { r.Succeeded = false } } + +// Merge merges the argument into the receiver +func (r *RelayMsgs) Merge(other *RelayMsgs) { + r.Src = append(r.Src, other.Src...) + r.Dst = append(r.Dst, other.Dst...) +} diff --git a/core/service.go b/core/service.go index b87e9dcd..abc8162a 100644 --- a/core/service.go +++ b/core/service.go @@ -66,6 +66,7 @@ func (srv *RelayService) Start(ctx context.Context) error { // Serve performs packet-relay func (srv *RelayService) Serve(ctx context.Context) error { logger := GetChannelPairLogger(srv.src, srv.dst) + // First, update the latest headers for src and dst if err := srv.sh.Updates(srv.src, srv.dst); err != nil { logger.Error("failed to update headers", err) @@ -86,23 +87,34 @@ func (srv *RelayService) Serve(ctx context.Context) error { return err } + msgs := NewRelayMsgs() + // update clients - if err := srv.st.UpdateClients(srv.src, srv.dst, pseqs, aseqs, srv.sh, true); err != nil { + if m, err := srv.st.UpdateClients(srv.src, srv.dst, pseqs, aseqs, srv.sh, true); err != nil { logger.Error("failed to update clients", err) return err + } else { + msgs.Merge(m) } // relay packets if unrelayed seqs exist - if err := srv.st.RelayPackets(srv.src, srv.dst, pseqs, srv.sh); err != nil { + if m, err := srv.st.RelayPackets(srv.src, srv.dst, pseqs, srv.sh); err != nil { logger.Error("failed to relay packets", err) return err + } else { + msgs.Merge(m) } // relay acks if unrelayed seqs exist - if err := srv.st.RelayAcknowledgements(srv.src, srv.dst, aseqs, srv.sh); err != nil { + if m, err := srv.st.RelayAcknowledgements(srv.src, srv.dst, aseqs, srv.sh); err != nil { logger.Error("failed to relay acknowledgements", err) return err + } else { + msgs.Merge(m) } + // send all msgs to src/dst chains + srv.st.Send(srv.src, srv.dst, msgs) + return nil } diff --git a/core/strategies.go b/core/strategies.go index c66dc542..46edae59 100644 --- a/core/strategies.go +++ b/core/strategies.go @@ -18,17 +18,20 @@ type StrategyI interface { UnrelayedPackets(src, dst *ProvableChain, sh SyncHeaders, includeRelayedButUnfinalized bool) (*RelayPackets, error) // RelayPackets executes RecvPacket to the packets contained in `rp` on both chains (`src` and `dst`). - RelayPackets(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) error + RelayPackets(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) (*RelayMsgs, error) // UnrelayedAcknowledgements returns packets to execute AcknowledgePacket to on `src` and `dst`. // `includeRelayedButUnfinalized` decides if the result includes packets of which acknowledgePacket has been executed but not finalized UnrelayedAcknowledgements(src, dst *ProvableChain, sh SyncHeaders, includeRelayedButUnfinalized bool) (*RelayPackets, error) // RelayAcknowledgements executes AcknowledgePacket to the packets contained in `rp` on both chains (`src` and `dst`). - RelayAcknowledgements(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) error + RelayAcknowledgements(src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders) (*RelayMsgs, error) // UpdateClients executes UpdateClient only if needed - UpdateClients(src, dst *ProvableChain, rpForRecv, rpForAck *RelayPackets, sh SyncHeaders, doRefresh bool) error + UpdateClients(src, dst *ProvableChain, rpForRecv, rpForAck *RelayPackets, sh SyncHeaders, doRefresh bool) (*RelayMsgs, error) + + // Send executes submission of msgs to src/dst chains + Send(src, dst Chain, msgs *RelayMsgs) } // StrategyCfg defines which relaying strategy to take for a given path