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  }