diff --git a/chains/tendermint/config.go b/chains/tendermint/config.go index 26d1004e..d403efd5 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,11 +63,25 @@ 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 _, err := time.ParseDuration(c.TrustingPeriod); err != nil { + return fmt.Errorf("config attribute \"trusting_period\" is invalid: %v", err) + } + 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 isEmpty(c.TrustingPeriod) { - return fmt.Errorf("config attribute \"trusting_period\" is empty") + 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 } + +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/config.pb.go b/chains/tendermint/config.pb.go index a4aa9f33..538204de 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 *Fraction `protobuf:"bytes,2,opt,name=refresh_threshold_rate,json=refreshThresholdRate,proto3" json:"refresh_threshold_rate,omitempty"` } func (m *ProverConfig) Reset() { *m = ProverConfig{} } @@ -105,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() { @@ -115,33 +155,38 @@ 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, + // 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) { @@ -238,6 +283,18 @@ func (m *ProverConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + 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] = 0x12 + } if len(m.TrustingPeriod) > 0 { i -= len(m.TrustingPeriod) copy(dAtA[i:], m.TrustingPeriod) @@ -248,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 @@ -307,6 +397,25 @@ func (m *ProverConfig) Size() (n int) { if l > 0 { n += 1 + l + sovConfig(uint64(l)) } + 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 } @@ -636,6 +745,130 @@ func (m *ProverConfig) Unmarshal(dAtA []byte) error { } m.TrustingPeriod = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RefreshThresholdRate", wireType) + } + 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 + } + 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 7d669a09..325a6800 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.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) + } + 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 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) + } + + 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) + } + + 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) + } + lcLastTimestamp := time.Unix(0, int64(cons.GetTimestamp())) + + 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(lcLastTimestamp) + + 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 > durationMulByFraction(pr.config.GetTrustingPeriod(), 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/cmd/tx.go b/cmd/tx.go index c4c666c4..e53b0067 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,18 +195,37 @@ func relayMsgsCmd(ctx *config.Context) *cobra.Command { return err } - if err = st.RelayPackets(c[src], c[dst], sp, sh); 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 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 }, } + 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"}, @@ -230,13 +256,25 @@ func relayAcksCmd(ctx *config.Context) *cobra.Command { return err } - if err = st.RelayAcknowledgements(c[src], c[dst], sp, sh); 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 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 }, } - + cmd.Flags().Bool(flagDoRefresh, defaultDoRefresh, "execute light client refresh (updateClient) if required") return cmd } diff --git a/core/naive-strategy.go b/core/naive-strategy.go index 63a76c01..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" ) @@ -22,8 +23,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 +137,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 } @@ -177,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()) @@ -196,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() @@ -205,75 +206,38 @@ func (st *NaiveStrategy) RelayPackets(src, dst *ProvableChain, rp *RelayPackets, "error getting address", err, ) - 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) - } + return nil, err } - 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", err, ) - return err + return nil, 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", err, ) - return err - } - - if len(packetsForDst) == 0 && len(packetsForSrc) == 0 { - logger.Info( - "no packates to relay", - ) - return nil + return nil, err } - 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 len(msgs.Dst) == 0 && len(msgs.Src) == 0 { + logger.Info("no packates to relay") + } else { + 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") } } - return nil + return msgs, nil } func (st *NaiveStrategy) UnrelayedAcknowledgements(src, dst *ProvableChain, sh SyncHeaders, includeRelayedButUnfinalized bool) (*RelayPackets, error) { @@ -413,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()) @@ -438,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 { @@ -446,72 +405,34 @@ func (st *NaiveStrategy) RelayAcknowledgements(src, dst *ProvableChain, rp *Rela "error getting address", err, ) - 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) - } + return nil, err } - 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 + return nil, 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 + return nil, err } } - if len(acksForDst) == 0 && len(acksForSrc) == 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 len(msgs.Dst) == 0 && len(msgs.Src) == 0 { + logger.Info("no acknowledgements to relay") + } else { + 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") } } - return nil + return msgs, nil } func collectAcks(ctx QueryContext, chain *ProvableChain, packets PacketInfoList, signer sdk.AccAddress) ([]sdk.Msg, error) { @@ -537,7 +458,85 @@ 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 *NaiveStrategy) UpdateClients(src, dst *ProvableChain, rpForRecv, rpForAck *RelayPackets, sh SyncHeaders, doRefresh bool) (*RelayMsgs, error) { + logger := GetChannelPairLogger(src, dst) + + msgs := NewRelayMsgs() + + // 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 { + var err error + needsUpdateForSrc, err = src.CheckRefreshRequired(dst) + if err != nil { + 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 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 nil, fmt.Errorf("failed to get relayer address on src chain: %v", err) + } + hs, err := sh.SetupHeadersForUpdate(dst, src) + if err != nil { + 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) + } + } + + if needsUpdateForDst { + dstAddress, err := dst.GetAddress() + if err != nil { + return nil, fmt.Errorf("failed to get relayer address on dst chain: %v", err) + } + hs, err := sh.SetupHeadersForUpdate(src, dst) + if err != nil { + 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) + } + } + + 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 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 { srcAttrs := []attribute.KeyValue{ attribute.Key("chain_id").String(src.ChainID()), attribute.Key("direction").String("src"), diff --git a/core/provers.go b/core/provers.go index 454bdfd9..ff706500 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 ChainInfoICS02Querier) (bool, error) } // ChainInfoICS02Querier is ChainInfo + ICS02Querier 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 913137bb..abc8162a 100644 --- a/core/service.go +++ b/core/service.go @@ -66,35 +66,55 @@ 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) 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 } - if err := srv.st.RelayAcknowledgements(srv.src, srv.dst, aseqs, srv.sh); err != nil { + + msgs := NewRelayMsgs() + + // update clients + 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 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 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 4b8312c0..46edae59 100644 --- a/core/strategies.go +++ b/core/strategies.go @@ -18,14 +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) (*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 diff --git a/proto/relayer/chains/tendermint/config/config.proto b/proto/relayer/chains/tendermint/config/config.proto index ee22b793..b3a03b98 100644 --- a/proto/relayer/chains/tendermint/config/config.proto +++ b/proto/relayer/chains/tendermint/config/config.proto @@ -19,4 +19,10 @@ message ChainConfig { message ProverConfig { string trusting_period = 1; + Fraction refresh_threshold_rate = 2; +} + +message Fraction { + uint64 numerator = 1; + uint64 denominator = 2; } diff --git a/provers/mock/prover.go b/provers/mock/prover.go index 4f126316..19fdc8b0 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.ChainInfoICS02Querier) (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 diff --git a/tests/cases/tm2tm/configs/demo/ibc-0.json b/tests/cases/tm2tm/configs/demo/ibc-0.json index e9058559..9f2b22e1 100644 --- a/tests/cases/tm2tm/configs/demo/ibc-0.json +++ b/tests/cases/tm2tm/configs/demo/ibc-0.json @@ -12,6 +12,10 @@ }, "prover": { "@type": "/relayer.chains.tendermint.config.ProverConfig", - "trusting_period": "336h" + "trusting_period": "336h", + "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 b072ec76..eda642d4 100644 --- a/tests/cases/tm2tm/configs/demo/ibc-1.json +++ b/tests/cases/tm2tm/configs/demo/ibc-1.json @@ -12,6 +12,10 @@ }, "prover": { "@type": "/relayer.chains.tendermint.config.ProverConfig", - "trusting_period": "336h" + "trusting_period": "336h", + "refresh_threshold_rate": { + "numerator": 2, + "denominator": 3 + } } } 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`