github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/when/handle_ts_check.go (about) 1 package whenPkg 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 8 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers" 9 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 10 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/progress" 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/tslib" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 14 ) 15 16 // HandleTimestampsCheck handles chifra when --timestamps --check 17 func (opts *WhenOptions) HandleTimestampsCheck(rCtx *output.RenderCtx) error { 18 chain := opts.Globals.Chain 19 20 cnt, err := tslib.NTimestamps(chain) 21 if err != nil { 22 return err 23 } 24 25 // For display only 26 skip := uint64(500) 27 if opts.Deep { 28 m, _ := opts.Conn.GetMetaData(opts.Globals.TestMode) 29 skip = uint64(m.Latest) / 500 30 } 31 count := uint64(cnt) 32 scanBar := progress.NewScanBar(count /* wanted */, (count / skip) /* freq */, count /* max */, (2. / 3.)) 33 34 blockNums, err := identifiers.GetBlockNumbers(chain, opts.BlockIds) 35 if err != nil { 36 return err 37 } 38 39 prev := types.NamedBlock{ 40 BlockNumber: base.NOPOSN, 41 Timestamp: base.NOPOSI, 42 } 43 44 if len(blockNums) > 0 { 45 for _, bn := range blockNums { 46 if bn < cnt { // ranges may include blocks after last block 47 if err = opts.checkOneBlock(scanBar, &prev, bn); err != nil { 48 return err 49 } 50 } 51 } 52 } else { 53 for bn := base.Blknum(0); bn < cnt; bn++ { 54 if err = opts.checkOneBlock(scanBar, &prev, bn); err != nil { 55 return err 56 } 57 } 58 } 59 60 return nil 61 } 62 63 func (opts *WhenOptions) checkOneBlock(scanBar *progress.ScanBar, prev *types.NamedBlock, bn base.Blknum) error { 64 chain := opts.Globals.Chain 65 66 // The i'th item in the timestamp array on disc 67 itemOnDisc, err := tslib.FromBn(chain, bn) 68 if err != nil { 69 return err 70 } 71 72 // This just simplifies the code below by removing the need to type cast 73 onDisc := types.NamedBlock{ 74 BlockNumber: base.Blknum(itemOnDisc.Bn), 75 Timestamp: base.Timestamp(itemOnDisc.Ts), 76 } 77 78 expected := types.LightBlock{BlockNumber: bn, Timestamp: onDisc.Timestamp} 79 if opts.Deep { 80 // If we're going deep, we need to query the node 81 expected, _ = opts.Conn.GetBlockHeaderByNumber(bn) 82 } 83 84 if prev.Timestamp != base.NOPOSI { 85 status := "Okay" 86 87 bnSequential := prev.BlockNumber < onDisc.BlockNumber 88 if !bnSequential { 89 msg := fmt.Sprintf("At block %d, block number %d is not one plus %d.%s", bn, onDisc.BlockNumber, prev.BlockNumber, clear) 90 logger.Error(msg) 91 status = "Error" 92 } 93 94 tsSequential := prev.Timestamp < onDisc.Timestamp 95 if !tsSequential { 96 msg := fmt.Sprintf("At block %d, timestamp %d does not increase over previous %d%s", bn, onDisc.Timestamp, prev.Timestamp, clear) 97 logger.Error(msg) 98 status = "Error" 99 } 100 101 deepTsCheck := !opts.Deep || (onDisc.Timestamp == expected.Timestamp) 102 if !deepTsCheck { 103 msg := fmt.Sprintf("At block %d, timestamp on disc %d does not agree with on chain %d%s", bn, onDisc.Timestamp, expected.Timestamp, clear) 104 logger.Error(msg) 105 status = "Error" 106 } 107 108 posOnDisc := bn == onDisc.BlockNumber 109 if opts.Deep { 110 posOnDisc = (bn == onDisc.BlockNumber && onDisc.BlockNumber == expected.BlockNumber) 111 } 112 if !posOnDisc { 113 msg := fmt.Sprintf("At block %d, onDisc block number %d does not match expected %d%s", bn, onDisc.BlockNumber, expected.BlockNumber, clear) 114 logger.Error(msg) 115 status = "Error" 116 } 117 118 if status == "Okay" { 119 scanBar.Report(opts.Globals.Writer, status, fmt.Sprintf(" bn: %d ts: %d", expected.BlockNumber, expected.Timestamp)) 120 } 121 } 122 123 *prev = onDisc 124 return nil 125 } 126 127 // TODO: There's got to be a better way 128 var clear = strings.Repeat(" ", 60)