github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/ledger/context.go (about) 1 package ledger 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 9 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 10 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 11 ) 12 13 type ledgerContextKey string 14 15 // ledgerContext is a struct to hold the context of a reconciliation (i.e., its 16 // previous and next blocks and whether they are different) 17 type ledgerContext struct { 18 PrevBlock base.Blknum 19 CurBlock base.Blknum 20 NextBlock base.Blknum 21 ReconType types.ReconType 22 } 23 24 func newLedgerContext(prev, cur, next base.Blknum, isFirst, isLast, reversed bool) *ledgerContext { 25 _ = reversed // Silences unused parameter warning 26 27 if prev > cur || cur > next { 28 return &ledgerContext{ 29 ReconType: types.Invalid, 30 } 31 } 32 33 reconType := types.Invalid 34 if cur == 0 { 35 reconType = types.Genesis 36 } else { 37 prevDiff := prev != cur 38 nextDiff := cur != next 39 if prevDiff && nextDiff { 40 reconType = types.DiffDiff 41 } else if !prevDiff && !nextDiff { 42 reconType = types.SameSame 43 } else if prevDiff { 44 reconType = types.DiffSame 45 } else if nextDiff { 46 reconType = types.SameDiff 47 } else { 48 reconType = types.Invalid 49 logger.Panic("should not happen") 50 } 51 } 52 53 if isFirst { 54 reconType |= types.First 55 } 56 57 if isLast { 58 reconType |= types.Last 59 } 60 61 return &ledgerContext{ 62 PrevBlock: prev, 63 CurBlock: cur, 64 NextBlock: next, 65 ReconType: reconType, 66 // Reversed: reversed, 67 } 68 } 69 70 func (c *ledgerContext) Prev() base.Blknum { 71 return c.PrevBlock 72 } 73 74 func (c *ledgerContext) Cur() base.Blknum { 75 return c.CurBlock 76 } 77 78 func (c *ledgerContext) Next() base.Blknum { 79 return c.NextBlock 80 } 81 82 func (l *Ledger) ctxKey(bn base.Blknum, txid base.Txnum) ledgerContextKey { 83 // TODO: Is having the context per asset necessary? Can we use Locator? 84 // return fmt.Sprintf("%s-%09d-%05d", l.AccountFor.Hex(), bn, txid) 85 return ledgerContextKey(fmt.Sprintf("%09d-%05d", bn, txid)) 86 } 87 88 const maxTestingBlock = 17000000 89 90 // SetContexts visits the list of appearances and notes the block numbers of the next and previous 91 // appearance's and if they are the same or different. Because balances are only available per block, 92 // we must know this information to be able to calculate the correct post-tx balance. 93 func (l *Ledger) SetContexts(chain string, apps []types.Appearance) error { 94 for i := 0; i < len(apps); i++ { 95 cur := base.Blknum(apps[i].BlockNumber) 96 prev := base.Blknum(apps[base.Max(1, i)-1].BlockNumber) 97 next := base.Blknum(apps[base.Min(i+1, len(apps)-1)].BlockNumber) 98 key := l.ctxKey(base.Blknum(apps[i].BlockNumber), base.Txnum(apps[i].TransactionIndex)) 99 l.Contexts[key] = newLedgerContext(base.Blknum(prev), base.Blknum(cur), base.Blknum(next), i == 0, i == (len(apps)-1), l.Reversed) 100 } 101 l.debugContext() 102 return nil 103 } 104 105 func (l *Ledger) debugContext() { 106 if !l.TestMode { 107 return 108 } 109 110 keys := make([]ledgerContextKey, 0, len(l.Contexts)) 111 for key := range l.Contexts { 112 keys = append(keys, key) 113 } 114 115 sort.Slice(keys, func(i, j int) bool { 116 return string(keys[i]) < string(keys[j]) 117 }) 118 119 logger.Info(strings.Repeat("-", 60)) 120 logger.Info(fmt.Sprintf("Contexts (%d)", len(keys))) 121 for _, key := range keys { 122 c := l.Contexts[key] 123 if c.CurBlock > maxTestingBlock { 124 continue 125 } 126 msg := "" 127 rr := c.ReconType &^ (types.First | types.Last) 128 switch rr { 129 case types.Genesis: 130 msg = fmt.Sprintf(" %s", c.ReconType.String()+"-diff") 131 case types.DiffDiff: 132 msg = fmt.Sprintf(" %s", c.ReconType.String()) 133 case types.SameSame: 134 msg = fmt.Sprintf(" %s", c.ReconType.String()) 135 case types.DiffSame: 136 msg = fmt.Sprintf(" %s", c.ReconType.String()) 137 case types.SameDiff: 138 msg = fmt.Sprintf(" %s", c.ReconType.String()) 139 default: 140 msg = fmt.Sprintf(" %s should not happen!", c.ReconType.String()) 141 } 142 logger.Info(fmt.Sprintf("%s: % 10d % 10d % 11d%s", key, c.PrevBlock, c.CurBlock, c.NextBlock, msg)) 143 } 144 }