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  }