github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/index/index.go (about)

     1  package index
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
     8  )
     9  
    10  const (
    11  	// HeaderWidth - size of Header Record
    12  	HeaderWidth = 44
    13  )
    14  
    15  // Index is one part of the two part Chunk (the other part is the Bloom)
    16  //
    17  // Each Index contains a HeaderRecord followed by two tables: the AddressTable and a related AppearanceTable.
    18  //
    19  // The HeaderRecord (44 bytes long) contains a four-byte magic number (`0xdeadbeef` -- to indicate we're reading
    20  // a file of the correct type), a 32-byte hash representing the file's version, and two 4-byte integers representing
    21  // the number of records in the AddressTable (nAddresses) and the number of records in the AppearanceTable (nAppearances)
    22  // respectively.
    23  //
    24  // The AddressTable has nAddresses records, one for each address that appears in any block between Start to End
    25  // inclusive. These addresses are found using the TrueBlocks Appearance Finder algorithm. Each AddressRecord consists
    26  // of a 20-byte address followed by two 4-byte integers representing the Offset into the AppearanceTable where
    27  // this address's list of appearances starts followed by the Count of appearance records for the given address.
    28  //
    29  // The AppearanceTable contains nAppeeances pairs of <blockNumber.transactionId> pairs arranged by the Offset
    30  // and Count pairs found in the corresponding AddressTable records.
    31  type Index struct {
    32  	File           *os.File
    33  	Header         indexHeader
    34  	Range          base.FileRange
    35  	AddrTableStart int64
    36  	AppTableStart  int64
    37  }
    38  
    39  // OpenIndex returns an Index with an opened file pointer to the given fileName. The HeaderRecord
    40  // for the chunk has been populated and the file position to the two tables are ready for use.
    41  func OpenIndex(fileName string, check bool) (Index, error) {
    42  	fileName = ToIndexPath(fileName)
    43  
    44  	blkRange, err := base.RangeFromFilenameE(fileName)
    45  	if err != nil {
    46  		return Index{}, err
    47  	}
    48  
    49  	indexChunk := Index{
    50  		AddrTableStart: HeaderWidth,
    51  		Range:          blkRange,
    52  	}
    53  	indexChunk.File, err = os.OpenFile(fileName, os.O_RDONLY, 0)
    54  	if err != nil {
    55  		return Index{}, err
    56  	}
    57  	// Note, we don't defer closing here since we want the file to stay opened. Caller must close it.
    58  	// defer idx.File.Close()
    59  
    60  	indexChunk.Header, err = indexChunk.readHeader(check)
    61  	if err != nil {
    62  		indexChunk.Close()
    63  		return Index{}, fmt.Errorf("%w: %s", err, fileName)
    64  	}
    65  
    66  	indexChunk.AppTableStart = int64(HeaderWidth + (indexChunk.Header.AddressCount * AddrRecordWidth))
    67  	return indexChunk, nil
    68  }
    69  
    70  // Close closes the Index's associated File pointer (if opened)
    71  func (chunk *Index) Close() error {
    72  	if chunk.File != nil {
    73  		chunk.File.Close()
    74  		chunk.File = nil
    75  	}
    76  	return nil
    77  }