github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/chunks/handle_check_manifest.go (about) 1 // Copyright 2021 The TrueBlocks Authors. All rights reserved. 2 // Use of this source code is governed by a license that can 3 // be found in the LICENSE file. 4 5 package chunksPkg 6 7 import ( 8 "fmt" 9 "strings" 10 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config" 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/manifest" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/version" 15 ) 16 17 type CompareState struct { 18 arrayA []string 19 arrayB []string 20 msg string 21 fail int 22 testMode bool 23 details bool 24 // msgB string 25 // failB int 26 } 27 28 // CheckManifest takes two arrays (either onDisc vs. LocalManifest, onDisc vs. RemoteManifest, 29 // or LocalManifest vs. RemoteManifest) and compares them for equality. If everything is up 30 // to date, all three arrays should be identical. Only the block ranges are in the arrays. 31 func (opts *ChunksOptions) CheckManifest(arrayA, arrayB []string, report *types.ReportCheck) error { 32 comp := CompareState{ 33 testMode: opts.Globals.TestMode, 34 details: opts.Globals.Verbose, 35 msg: "%s: The chunk is in the %s array but not the %s array%s", 36 fail: 3, 37 arrayA: arrayA, 38 arrayB: arrayB, 39 } 40 41 if err := comp.checkArrays(report); err != nil { 42 return err 43 } 44 45 comp.arrayA, comp.arrayB = comp.arrayB, comp.arrayA 46 comp.msg = "%s: The chunk is in the %s array but not the %s array%s" 47 comp.fail = 4 48 49 return comp.checkArrays(report) 50 } 51 52 func (comp *CompareState) checkArrays(report *types.ReportCheck) error { 53 marker := "" 54 if comp.testMode { 55 marker = " (testing)" 56 } 57 58 if !comp.testMode && len(comp.arrayA) != len(comp.arrayB) { 59 alreadyReported := false 60 for _, e := range report.MsgStrings { 61 if strings.Contains(e, "array lengths are different") { 62 alreadyReported = true 63 } 64 } 65 if !alreadyReported { 66 parts := strings.Split(report.Reason, " to ") 67 msg := fmt.Sprintf("array lengths are different: %s(%d) %s(%d)", parts[0], len(comp.arrayA), parts[1], len(comp.arrayB)) 68 report.MsgStrings = append(report.MsgStrings, msg) 69 } 70 } 71 72 theMap := make(map[string]bool, len(comp.arrayA)) 73 for _, item := range comp.arrayA { 74 theMap[item] = true 75 } 76 77 parts := strings.Split(report.Reason, " to ") 78 for testId, item := range comp.arrayB { 79 if testId > len(comp.arrayA)-1 { 80 continue 81 } 82 if !comp.testMode { 83 testId = -1 84 } 85 report.VisitedCnt++ 86 report.CheckedCnt++ 87 if !theMap[item] || testId == comp.fail { 88 if len(report.MsgStrings) < 4 || comp.details { 89 parts[0] = strings.ToLower(parts[0]) 90 parts[1] = strings.ToLower(parts[1]) 91 msg := fmt.Sprintf(comp.msg, item, parts[0], parts[1], marker) 92 report.MsgStrings = append(report.MsgStrings, msg) 93 } 94 } else { 95 report.PassedCnt++ 96 } 97 } 98 99 return nil 100 } 101 102 // CheckManContents spins through the manifest and makes sure all the 103 // bloom and index CIDs are present. It does not check that the CIDs are available. 104 func (opts *ChunksOptions) CheckManContents(man *manifest.Manifest, report *types.ReportCheck) error { 105 errs := []string{} 106 107 report.VisitedCnt += 3 108 report.CheckedCnt += 3 109 110 if !version.IsValidVersion(man.Version) { 111 errs = append(errs, "invalid version string "+opts.Tag) 112 } else { 113 report.PassedCnt++ 114 } 115 116 if opts.Globals.Chain != man.Chain { 117 errs = append(errs, "different chains: globals("+opts.Globals.Chain+") manifest ("+man.Chain+")") 118 } else { 119 report.PassedCnt++ 120 } 121 122 expectedSpec := config.SpecTags["trueblocks-core@v2.0.0-release"] 123 if expectedSpec != man.Specification.String() { 124 errs = append(errs, "invalid spec "+man.Specification.String()) 125 } else { 126 report.PassedCnt++ 127 } 128 129 for _, chunk := range man.Chunks { 130 report.VisitedCnt++ 131 report.CheckedCnt++ 132 if len(chunk.Range) == 0 { 133 errs = append(errs, "empty range") 134 } else { 135 report.PassedCnt++ 136 } 137 138 report.VisitedCnt++ 139 report.CheckedCnt++ 140 hasBloom := len(chunk.BloomHash) > 0 141 hasIndex := len(chunk.IndexHash) > 0 142 bloomSize := chunk.BloomSize > 0 143 indexSize := chunk.IndexSize > 0 144 if hasBloom && hasIndex && bloomSize && indexSize { 145 report.PassedCnt++ 146 } else { 147 if !hasBloom { 148 errs = append(errs, chunk.Range+" - missing bloom hash") 149 } 150 if !hasIndex { 151 errs = append(errs, chunk.Range+" - missing index hash") 152 } 153 if !bloomSize { 154 errs = append(errs, chunk.Range+" - missing bloom size") 155 } 156 if !indexSize { 157 errs = append(errs, chunk.Range+" - missing index size") 158 } 159 } 160 } 161 162 if len(errs) > 0 { 163 report.MsgStrings = append(report.MsgStrings, errs...) 164 } 165 166 return nil 167 }