diff --git a/cmd/service.go b/cmd/service.go index 257582e1..ab0bb526 100644 --- a/cmd/service.go +++ b/cmd/service.go @@ -27,12 +27,16 @@ func serviceCmd(ctx *config.Context) *cobra.Command { func startCmd(ctx *config.Context) *cobra.Command { const ( - flagRelayInterval = "relay-interval" - flagPrometheusAddr = "prometheus-addr" + flagRelayInterval = "relay-interval" + flagPrometheusAddr = "prometheus-addr" + flagRelayOptimizeInterval = "relay-optimize-interval" + flagRelayOptimizeCount = "relay-optimize-count" ) const ( - defaultRelayInterval = 3 * time.Second - defaultPrometheusAddr = "localhost:2223" + defaultRelayInterval = 3 * time.Second + defaultPrometheusAddr = "localhost:2223" + defaultRelayOptimizeInterval = 10 * time.Second + defaultRelayOptimizeCount = 5 ) cmd := &cobra.Command{ @@ -60,10 +64,12 @@ func startCmd(ctx *config.Context) *cobra.Command { if err := st.SetupRelay(context.TODO(), c[src], c[dst]); err != nil { return err } - return core.StartService(context.Background(), st, c[src], c[dst], viper.GetDuration(flagRelayInterval)) + return core.StartService(context.Background(), st, c[src], c[dst], viper.GetDuration(flagRelayInterval), viper.GetDuration(flagRelayOptimizeInterval), viper.GetInt64(flagRelayOptimizeCount)) }, } cmd.Flags().Duration(flagRelayInterval, defaultRelayInterval, "time interval to perform relays") cmd.Flags().String(flagPrometheusAddr, defaultPrometheusAddr, "host address to which the prometheus exporter listens") + cmd.Flags().Duration(flagRelayOptimizeInterval, defaultRelayOptimizeInterval, "time interval to perform relays optimization") + cmd.Flags().Int64(flagRelayOptimizeCount, defaultRelayOptimizeCount, "number of packets to relays optimization") return cmd } diff --git a/core/service.go b/core/service.go index 913137bb..6820363c 100644 --- a/core/service.go +++ b/core/service.go @@ -7,32 +7,48 @@ import ( retry "github.com/avast/retry-go" ) +var currentTime = time.Now() + // StartService starts a relay service -func StartService(ctx context.Context, st StrategyI, src, dst *ProvableChain, relayInterval time.Duration) error { +func StartService( + ctx context.Context, + st StrategyI, + src, dst *ProvableChain, + relayInterval, relayOptimizeInterval time.Duration, + relayOptimizeCount int64) error { sh, err := NewSyncHeaders(src, dst) if err != nil { return err } - srv := NewRelayService(st, src, dst, sh, relayInterval) + srv := NewRelayService(st, src, dst, sh, relayInterval, relayOptimizeInterval, relayOptimizeCount) return srv.Start(ctx) } type RelayService struct { - src *ProvableChain - dst *ProvableChain - st StrategyI - sh SyncHeaders - interval time.Duration + src *ProvableChain + dst *ProvableChain + st StrategyI + sh SyncHeaders + interval time.Duration + optimizeInterval time.Duration + optimizeCount int64 } // NewRelayService returns a new service -func NewRelayService(st StrategyI, src, dst *ProvableChain, sh SyncHeaders, interval time.Duration) *RelayService { +func NewRelayService( + st StrategyI, + src, dst *ProvableChain, + sh SyncHeaders, + interval, optimizeInterval time.Duration, + optimizeCount int64) *RelayService { return &RelayService{ - src: src, - dst: dst, - st: st, - sh: sh, - interval: interval, + src: src, + dst: dst, + st: st, + sh: sh, + interval: interval, + optimizeInterval: optimizeInterval, + optimizeCount: optimizeCount, } } @@ -79,9 +95,12 @@ func (srv *RelayService) Serve(ctx context.Context) error { 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 + + if optimizeRelay(*pseqs, srv.optimizeInterval, srv.optimizeCount) { + 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 @@ -91,10 +110,29 @@ func (srv *RelayService) Serve(ctx context.Context) error { logger.Error("failed to get unrelayed acknowledgements", err) return err } - if err := srv.st.RelayAcknowledgements(srv.src, srv.dst, aseqs, srv.sh); err != nil { - logger.Error("failed to relay acknowledgements", err) - return err + if optimizeRelay(*pseqs, srv.optimizeInterval, srv.optimizeCount) { + if err := srv.st.RelayAcknowledgements(srv.src, srv.dst, aseqs, srv.sh); err != nil { + logger.Error("failed to relay acknowledgements", err) + return err + } } return nil } + +func optimizeRelay(pseqs RelayPackets, optimizeInterval time.Duration, optimizeCount int64) bool { + // time interval + elapseTime := time.Since(currentTime) + if elapseTime >= optimizeInterval { + currentTime = time.Now() + return true + } + // packet count + srcPacketCount := len(pseqs.Src) + dstPacketCount := len(pseqs.Dst) + if int64(srcPacketCount) >= optimizeCount || int64(dstPacketCount) >= optimizeCount { + return true + } + + return false +} diff --git a/tests/cases/tmmock2tmmock/Makefile b/tests/cases/tmmock2tmmock/Makefile index d1c56efe..29e90605 100644 --- a/tests/cases/tmmock2tmmock/Makefile +++ b/tests/cases/tmmock2tmmock/Makefile @@ -14,6 +14,10 @@ test: ./scripts/handshake ./scripts/test-tx +.PHONY: test-service +test-service: + ./scripts/test-service + .PHONY: network-down network-down: TAG=${DOCKER_TAG} $(DOCKER_COMPOSE) \ diff --git a/tests/cases/tmmock2tmmock/scripts/test-service b/tests/cases/tmmock2tmmock/scripts/test-service new file mode 100755 index 00000000..20d89005 --- /dev/null +++ b/tests/cases/tmmock2tmmock/scripts/test-service @@ -0,0 +1,114 @@ +#!/bin/bash + +: <<'END_COMMENT' +* relay-interval = 10s +* relay-optimize-interval = 15s +* relay-optimize-count = 3 + +- relay service [query = 0, time = 0] -> skip + - transfer + - + - + - finality + - query = 1 + - + - + - + - +- relay service [query = 1, time = 10] -> skip + - transfer + - + - + - finality + - query = 2 + - + - + - + - +- relay service [query = 2, time = 20] -> exec (time) + - transfer x 3 + - + - + - finality + - query 3 + - + - + - + - +- relay service [query = 3, time = 10] -> exec (count) +END_COMMENT + +set -eux + +SCRIPT_DIR=$(cd $(dirname $0); pwd) +RLY_BINARY=${SCRIPT_DIR}/../../../../build/yrly +RLY="${RLY_BINARY} --debug" + +TM_ADDRESS0=$(${RLY} tendermint keys show ibc0 testkey) +TM_ADDRESS1=$(${RLY} tendermint keys show ibc1 testkey) + +RETRY_COUNT=5 +RETRY_INTERVAL=1 + +${RLY} service start ibc01 --relay-interval 10s --relay-optimize-interval 15s --relay-optimize-count 3 & +RLY_PID=$! + +# transfer a token +${RLY} tx transfer ibc01 ibc0 ibc1 100samoleans ${TM_ADDRESS1} +sleep 3 # finality_delay + +# query unrelayed-packets 1 +unrelayed_packets=$(${RLY} query unrelayed-packets ibc01 | jq '.src | length') +if [ $unrelayed_packets -ne 1 ]; then + echo "unrelayed_packets: $unrelayed_packets" + kill $RLY_PID + exit 1 +fi + +sleep 7 # wait for relay-interval +echo "xxxxxxx relay service -> skip xxxxxx" + +# transfer a token +${RLY} tx transfer ibc01 ibc0 ibc1 100samoleans ${TM_ADDRESS1} +sleep 3 # finality_delay + +# query unrelayed-packets 2 +unrelayed_packets=$(${RLY} query unrelayed-packets ibc01 | jq '.src | length') +if [ $unrelayed_packets -ne 2 ]; then + echo "unrelayed_packets: $unrelayed_packets" + kill $RLY_PID + exit 1 +fi + +sleep 7 # wait for relay-interval +echo "xxxxxxx relay service -> exec - time xxxxxx" + +# transfer a token x 3 +${RLY} tx transfer ibc01 ibc0 ibc1 100samoleans ${TM_ADDRESS1} +${RLY} tx transfer ibc01 ibc0 ibc1 100samoleans ${TM_ADDRESS1} +${RLY} tx transfer ibc01 ibc0 ibc1 100samoleans ${TM_ADDRESS1} +sleep 3 # finality_delay + +# query unrelayed-packets 3 +unrelayed_packets=$(${RLY} query unrelayed-packets ibc01 | jq '.src | length') +if [ $unrelayed_packets -ne 3 ]; then + echo "unrelayed_packets: $unrelayed_packets" + kill $RLY_PID + exit 1 +fi + +sleep 7 # wait for relay-interval +echo "xxxxxxx relay service -> exec - count xxxxxx" + +# wait for relay service to execute +for i in `seq $RETRY_COUNT` +do + echo "[try:$i] waiting for sendPacket finalization ..." + sleep $RETRY_INTERVAL + unrelayed=$(${RLY} query unrelayed-packets ibc01 | jq '.src | length') + if [ $unrelayed -eq 0 ]; then + break + fi +done + +kill $RLY_PID