github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/others/blockdb/blockdb.go (about) 1 /* 2 This package is suposed to help importin Satoshi's bitcoin 3 client blockchain into Gocoin's bitcoin client. 4 */ 5 package blockdb 6 7 import ( 8 "fmt" 9 "os" 10 "bytes" 11 "errors" 12 ) 13 14 15 type BlockDB struct { 16 dir string 17 magic [4]byte 18 f *os.File 19 currfileidx uint32 20 } 21 22 23 func NewBlockDB(dir string, magic [4]byte) (res *BlockDB) { 24 f, e := os.Open(idx2fname(dir, 0)) 25 if e != nil { 26 panic(e.Error()) 27 } 28 res = new(BlockDB) 29 res.dir = dir 30 res.magic = magic 31 res.f = f 32 return 33 } 34 35 36 func idx2fname(dir string, fidx uint32) string { 37 if fidx == 0xffffffff { 38 return "blk99999.dat" 39 } 40 return fmt.Sprintf("%s/blk%05d.dat", dir, fidx) 41 } 42 43 44 func readBlockFromFile(f *os.File, mag []byte) (res []byte, e error) { 45 var buf [4]byte 46 _, e = f.Read(buf[:]) 47 if e != nil { 48 return 49 } 50 51 if !bytes.Equal(buf[:], mag[:]) { 52 e = errors.New(fmt.Sprintf("BlockDB: Unexpected magic: %02x%02x%02x%02x", 53 buf[0], buf[1], buf[2], buf[3])) 54 return 55 } 56 57 _, e = f.Read(buf[:]) 58 if e != nil { 59 return 60 } 61 le := uint32(lsb2uint(buf[:])) 62 if le<81 { 63 e = errors.New(fmt.Sprintf("Incorrect block size %d", le)) 64 return 65 } 66 67 res = make([]byte, le) 68 _, e = f.Read(res[:]) 69 if e!=nil { 70 return 71 } 72 73 return 74 } 75 76 77 func (db *BlockDB)readOneBlock() (res []byte, e error) { 78 fpos, _ := db.f.Seek(0, 1) 79 res, e = readBlockFromFile(db.f, db.magic[:]) 80 if e != nil { 81 db.f.Seek(int64(fpos), os.SEEK_SET) // restore the original position 82 return 83 } 84 return 85 } 86 87 func (db *BlockDB) FetchNextBlock() (bl []byte, e error) { 88 if db.f == nil { 89 println("DB file not open - this should never happen") 90 os.Exit(1) 91 } 92 bl, e = db.readOneBlock() 93 if e != nil { 94 f, e2 := os.Open(idx2fname(db.dir, db.currfileidx+1)) 95 if e2 == nil { 96 db.currfileidx++ 97 db.f.Close() 98 db.f = f 99 bl, e = db.readOneBlock() 100 } 101 } 102 return 103 } 104 105 func lsb2uint(lt []byte) (res uint64) { 106 for i:=0; i<len(lt); i++ { 107 res |= (uint64(lt[i]) << uint(i*8)) 108 } 109 return 110 }