diff --git a/cmd/check_construction.go b/cmd/check_construction.go index 09c15af7..6f4ded15 100644 --- a/cmd/check_construction.go +++ b/cmd/check_construction.go @@ -131,6 +131,10 @@ func runCheckConstructionCmd(cmd *cobra.Command, args []string) { return constructionTester.WatchEndConditions(ctx) }) + g.Go(func() error { + return tester.LogMemoryLoop(ctx) + }) + sigListeners := []context.CancelFunc{cancel} go handleSignals(&sigListeners) diff --git a/cmd/check_data.go b/cmd/check_data.go index 774ee652..9f7b3744 100644 --- a/cmd/check_data.go +++ b/cmd/check_data.go @@ -141,6 +141,14 @@ func runCheckDataCmd(cmd *cobra.Command, args []string) { return dataTester.WatchEndConditions(ctx) }) + g.Go(func() error { + return tester.LogMemoryLoop(ctx) + }) + + g.Go(func() error { + return dataTester.StartProgressLogger(ctx) + }) + sigListeners := []context.CancelFunc{cancel} go handleSignals(&sigListeners) diff --git a/cmd/root.go b/cmd/root.go index c03681ec..33c1fd18 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -132,6 +132,6 @@ var versionCmd = &cobra.Command{ Use: "version", Short: "Print rosetta-cli version", Run: func(cmd *cobra.Command, args []string) { - fmt.Println("v0.5.4") + fmt.Println("v0.5.5") }, } diff --git a/go.mod b/go.mod index 796d8f2c..823653ef 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/coinbase/rosetta-cli go 1.13 require ( - github.com/coinbase/rosetta-sdk-go v0.4.6 + github.com/coinbase/rosetta-sdk-go v0.4.8 github.com/fatih/color v1.9.0 github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c diff --git a/go.sum b/go.sum index ff156c1c..a2849f95 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,7 @@ github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= @@ -155,6 +156,10 @@ github.com/coinbase/rosetta-sdk-go v0.4.5 h1:5Z+25mm/J1SStzSdTp5e8dlEMtCZRBZdOaT github.com/coinbase/rosetta-sdk-go v0.4.5/go.mod h1:Luv0AhzZH81eul2hYZ3w0hBGwmFPiexwbntYxihEZck= github.com/coinbase/rosetta-sdk-go v0.4.6 h1:zX2SLmBF1oFbK0c4QCMwkwcHN9VjenFfIt0Dr8k8JGY= github.com/coinbase/rosetta-sdk-go v0.4.6/go.mod h1:Luv0AhzZH81eul2hYZ3w0hBGwmFPiexwbntYxihEZck= +github.com/coinbase/rosetta-sdk-go v0.4.7 h1:5KFc0CgLMkKamX++hYUFvE58a5/tCn0wSqpcTnDhRhY= +github.com/coinbase/rosetta-sdk-go v0.4.7/go.mod h1:8d4iN4VSGvLUzl+jRQlvYSLyS9TeY0QZebneWouizqU= +github.com/coinbase/rosetta-sdk-go v0.4.8 h1:+E1TM4q1c5/x/jE9FPI1IZIbNvUWy4tRRgDPLnKzUV4= +github.com/coinbase/rosetta-sdk-go v0.4.8/go.mod h1:8d4iN4VSGvLUzl+jRQlvYSLyS9TeY0QZebneWouizqU= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -198,6 +203,7 @@ github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbT github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -207,6 +213,8 @@ github.com/ethereum/go-ethereum v1.9.20 h1:kk/J5OIoaoz3DRrCXznz3RGi212mHHXwzXlY/ github.com/ethereum/go-ethereum v1.9.20/go.mod h1:JSSTypSMTkGZtAdAChH2wP5dZEvPGh3nUTuDpH+hNrg= github.com/ethereum/go-ethereum v1.9.21 h1:8qRlhzrItnmUGdVlBzZLI2Tb46S0RdSNjFwICo781ws= github.com/ethereum/go-ethereum v1.9.21/go.mod h1:RXAVzbGrSGmDkDnHymruTAIEjUR3E4TX0EOpaj702sI= +github.com/ethereum/go-ethereum v1.9.22 h1:/Fea9n2EWJuNJ9oahMq9luqjRBcbW7QWdThbcJl13ek= +github.com/ethereum/go-ethereum v1.9.22/go.mod h1:FQjK3ZwD8C5DYn7ukTmFee36rq1dOMESiUfXr5RUc1w= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -249,6 +257,7 @@ github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26 h1:lMm2hD9Fy0ynom5 github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/addlicense v0.0.0-20200817051935-6f4cd4aacc89 h1:oTppmscIAQ2Y1tcsMDcTLR3z4MN/96/pvIsBSLGl7o8= github.com/google/addlicense v0.0.0-20200817051935-6f4cd4aacc89/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA= +github.com/google/addlicense v0.0.0-20200827091314-d1655b921368 h1:Ds6gDZHoviaQM7r7oMx/cG2qwZc3l5u7cg6gTkxOZNE= github.com/google/addlicense v0.0.0-20200827091314-d1655b921368/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -260,6 +269,7 @@ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20181127221834-b4f47329b966/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -480,11 +490,19 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -560,11 +578,13 @@ golang.org/x/tools v0.0.0-20181127232545-e782529d0ddd/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191024220359-3d91e92cde03 h1:4gtJXHJ9ud0q8MNSDxJsRU/WH+afypbe4Vk4zq+8qow= golang.org/x/tools v0.0.0-20191024220359-3d91e92cde03/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729181040-64cdafbe085c/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 2d65bf82..343b7b60 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -110,17 +110,6 @@ func (l *Logger) LogDataStats(ctx context.Context) error { return nil } - elapsedTime, err := l.CounterStorage.Get(ctx, TimeElapsedCounter) - if err != nil { - return fmt.Errorf("%w cannot get elapsed time", err) - } - - if elapsedTime.Sign() == 0 { // wait for at least some elapsed time - return nil - } - - blocksPerSecond := new(big.Int).Div(blocks, elapsedTime) - orphans, err := l.CounterStorage.Get(ctx, storage.OrphanCounter) if err != nil { return fmt.Errorf("%w cannot get orphan counter", err) @@ -147,10 +136,9 @@ func (l *Logger) LogDataStats(ctx context.Context) error { } statsMessage := fmt.Sprintf( - "[STATS] Blocks: %s (Orphaned: %s, Rate: %s/sec) Transactions: %s Operations: %s", + "[STATS] Blocks: %s (Orphaned: %s) Transactions: %s Operations: %s", blocks.String(), orphans.String(), - blocksPerSecond.String(), txs.String(), ops.String(), ) @@ -181,6 +169,54 @@ func (l *Logger) LogDataStats(ctx context.Context) error { return nil } +// LogTipEstimate logs information about the remaining blocks to sync. +func (l *Logger) LogTipEstimate(ctx context.Context, tipIndex int64) error { + blocks, err := l.CounterStorage.Get(ctx, storage.BlockCounter) + if err != nil { + return fmt.Errorf("%w cannot get block counter", err) + } + + if blocks.Sign() == 0 { // wait for at least 1 block to be processed + return nil + } + + orphans, err := l.CounterStorage.Get(ctx, storage.OrphanCounter) + if err != nil { + return fmt.Errorf("%w cannot get orphan counter", err) + } + + adjustedBlocks := blocks.Int64() - orphans.Int64() + if tipIndex-adjustedBlocks <= 0 { // return if no blocks to sync + return nil + } + + elapsedTime, err := l.CounterStorage.Get(ctx, TimeElapsedCounter) + if err != nil { + return fmt.Errorf("%w cannot get elapsed time", err) + } + + if elapsedTime.Sign() == 0 { // wait for at least some elapsed time + return nil + } + + blocksPerSecond := new(big.Float).Quo(new(big.Float).SetInt64(adjustedBlocks), new(big.Float).SetInt(elapsedTime)) + blocksPerSecondFloat, _ := blocksPerSecond.Float64() + blocksSynced := new(big.Float).Quo(new(big.Float).SetInt64(adjustedBlocks), new(big.Float).SetInt64(tipIndex)) + blocksSyncedFloat, _ := blocksSynced.Float64() + + statsMessage := fmt.Sprintf( + "[PROGRESS] Blocks Synced: %d/%d (Completed: %f%%, Rate: %f/second) Time Remaining: %s", + adjustedBlocks, + tipIndex, + blocksSyncedFloat*utils.OneHundred, + blocksPerSecondFloat, + utils.TimeToTip(blocksPerSecondFloat, adjustedBlocks, tipIndex), + ) + + color.Cyan(statsMessage) + return nil +} + // LogConstructionStats logs all construction values in CounterStorage. func (l *Logger) LogConstructionStats(ctx context.Context, inflightTransactions int) error { transactionsCreated, err := l.CounterStorage.Get(ctx, storage.TransactionsCreatedCounter) @@ -227,6 +263,20 @@ func (l *Logger) LogConstructionStats(ctx context.Context, inflightTransactions return nil } +// LogMemoryStats logs memory usage information. +func LogMemoryStats(ctx context.Context) { + memUsage := utils.MonitorMemoryUsage(ctx, -1) + statsMessage := fmt.Sprintf( + "[MEMORY] Heap: %fMB Stack: %fMB System: %fMB GCs: %d", + memUsage.Heap, + memUsage.Stack, + memUsage.System, + memUsage.GarbageCollections, + ) + + color.Cyan(statsMessage) +} + // AddBlockStream writes the next processed block to the end of the // blockStreamFile output file. func (l *Logger) AddBlockStream( diff --git a/pkg/tester/construction.go b/pkg/tester/construction.go index 20289fae..75ac867a 100644 --- a/pkg/tester/construction.go +++ b/pkg/tester/construction.go @@ -44,6 +44,7 @@ const ( constructionCmdName = "check-construction" endConditionsCheckInterval = 10 * time.Second + tipWaitInterval = 10 * time.Second ) // ConstructionTester coordinates the `check:construction` test. @@ -283,6 +284,47 @@ func (t *ConstructionTester) StartPeriodicLogger( } } +func (t *ConstructionTester) checkTip(ctx context.Context) (int64, error) { + status, fetchErr := t.onlineFetcher.NetworkStatusRetry(ctx, t.network, nil) + if fetchErr != nil { + return -1, fmt.Errorf("%w: unable to fetch network status", fetchErr.Err) + } + + // If a block has yet to be synced, start syncing from tip. + if utils.AtTip(t.config.TipDelay, status.CurrentBlockTimestamp) { + return status.CurrentBlockIdentifier.Index, nil + } + + return -1, nil +} + +// waitForTip loops until the Rosetta implementation is at tip. +func (t *ConstructionTester) waitForTip(ctx context.Context) (int64, error) { + tc := time.NewTicker(tipWaitInterval) + defer tc.Stop() + + for { + // Don't wait any time before first tick if at tip. + tipIndex, err := t.checkTip(ctx) + if err != nil { + return -1, err + } + + if tipIndex != -1 { + return tipIndex, nil + } + + log.Println("waiting for implementation to reach tip before testing...") + + select { + case <-ctx.Done(): + return -1, ctx.Err() + case <-tc.C: + continue + } + } +} + // StartSyncer uses the tester's stateful syncer // to compute balance changes and track transactions // for confirmation on-chain. @@ -293,14 +335,12 @@ func (t *ConstructionTester) StartSyncer( startIndex := int64(-1) _, err := t.blockStorage.GetHeadBlockIdentifier(ctx) if errors.Is(err, storage.ErrHeadBlockNotFound) { - // If a block has yet to be synced, start syncing from tip. - // TODO: make configurable - status, fetchErr := t.onlineFetcher.NetworkStatusRetry(ctx, t.network, nil) - if fetchErr != nil { - return fmt.Errorf("%w: unable to fetch network status", fetchErr.Err) + // If no head block exists, ensure we are at tip before starting. Otherwise, + // we will unnecessarily sync tons of blocks before reaching any that matter. + startIndex, err = t.waitForTip(ctx) + if err != nil { + return fmt.Errorf("%w: unable to wait for tip", err) } - - startIndex = status.CurrentBlockIdentifier.Index } else if err != nil { return fmt.Errorf("%w: unable to get last block synced", err) } diff --git a/pkg/tester/construction_results.go b/pkg/tester/construction_results.go index 55ff54b0..00b26c77 100644 --- a/pkg/tester/construction_results.go +++ b/pkg/tester/construction_results.go @@ -240,8 +240,10 @@ func ExitConstruction( counterStorage, jobStorage, ) - results.Print() - results.Output(config.Construction.ResultsOutputFile) + if results != nil { + results.Print() + results.Output(config.Construction.ResultsOutputFile) + } os.Exit(status) } diff --git a/pkg/tester/data.go b/pkg/tester/data.go index 8387f72d..1eab0aa9 100644 --- a/pkg/tester/data.go +++ b/pkg/tester/data.go @@ -355,6 +355,24 @@ func (t *DataTester) StartPeriodicLogger( // Print stats one last time before exiting _ = t.logger.LogDataStats(ctx) + return ctx.Err() + case <-tc.C: + _ = t.logger.LogDataStats(ctx) + } + } +} + +// StartProgressLogger priunts out periodic +// estimates of sync duration if we are behind tip. +func (t *DataTester) StartProgressLogger( + ctx context.Context, +) error { + tc := time.NewTicker(PeriodicLoggingFrequency) + defer tc.Stop() + + for { + select { + case <-ctx.Done(): return ctx.Err() case <-tc.C: // Update the elapsed time in counter storage so that @@ -364,7 +382,14 @@ func (t *DataTester) StartPeriodicLogger( logger.TimeElapsedCounter, big.NewInt(periodicLoggingSeconds), ) - _ = t.logger.LogDataStats(ctx) + + status, fetchErr := t.fetcher.NetworkStatusRetry(ctx, t.network, nil) + if fetchErr != nil { + log.Printf("%v: unable to get network status\n", fetchErr.Err) + continue + } + + _ = t.logger.LogTipEstimate(ctx, status.CurrentBlockIdentifier.Index) } } } diff --git a/pkg/tester/data_results.go b/pkg/tester/data_results.go index 06252dad..09b8d4ce 100644 --- a/pkg/tester/data_results.go +++ b/pkg/tester/data_results.go @@ -471,8 +471,10 @@ func ExitData( endCondition, endConditionDetail, ) - results.Print() - results.Output(config.Data.ResultsOutputFile) + if results != nil { + results.Print() + results.Output(config.Data.ResultsOutputFile) + } os.Exit(status) } diff --git a/pkg/tester/general.go b/pkg/tester/general.go new file mode 100644 index 00000000..ae636ca1 --- /dev/null +++ b/pkg/tester/general.go @@ -0,0 +1,46 @@ +// Copyright 2020 Coinbase, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tester + +import ( + "context" + "time" + + "github.com/coinbase/rosetta-cli/pkg/logger" +) + +const ( + // MemoryLoggingFrequency is the frequency that memory + // usage stats are logged to the terminal. + MemoryLoggingFrequency = 10 * time.Second +) + +// LogMemoryLoop runs a loop that logs memory usage. +func LogMemoryLoop( + ctx context.Context, +) error { + ticker := time.NewTicker(MemoryLoggingFrequency) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + logger.LogMemoryStats(ctx) + return ctx.Err() + case <-ticker.C: + logger.LogMemoryStats(ctx) + } + } +}