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 }