func (db *UnspentDB) UndoBlockTxs(bl *btc.Block, newhash []byte) { for _, tx := range bl.Txs { lst := make([]bool, len(tx.TxOut)) for i := range lst { lst[i] = true } db.del(tx.Hash.Hash[:], lst) } fn := fmt.Sprint(db.dir, db.LastBlockHeight) var addback []*QdbRec if _, er := os.Stat(fn); er != nil { fn += ".tmp" } dat, er := ioutil.ReadFile(fn) if er != nil { panic(er.Error()) } off := 32 // ship the block hash for off < len(dat) { le, n := btc.VLen(dat[off:]) off += n qr := FullQdbRec(dat[off : off+le]) off += le addback = append(addback, qr) } for _, tx := range addback { if db.ch.CB.NotifyTxAdd != nil { db.ch.CB.NotifyTxAdd(tx) } ind := qdb.KeyType(binary.LittleEndian.Uint64(tx.TxID[:8])) _db := db.dbN(int(tx.TxID[31]) % NumberOfUnspentSubDBs) v := _db.Get(ind) if v != nil { oldrec := NewQdbRec(ind, v) for a := range tx.Outs { if tx.Outs[a] == nil { tx.Outs[a] = oldrec.Outs[a] } } } _db.PutExt(ind, tx.Bytes(), 0) } os.Remove(fn) db.LastBlockHeight-- copy(db.LastBlockHash, newhash) }
func (c *OneConnection) ProcessInv(pl []byte) { if len(pl) < 37 { println(c.PeerAddr.Ip(), "inv payload too short", len(pl)) return } c.InvsRecieved++ cnt, of := btc.VLen(pl) if len(pl) != of+36*cnt { println("inv payload length mismatch", len(pl), of, cnt) } var blinv2ask []byte for i := 0; i < cnt; i++ { typ := binary.LittleEndian.Uint32(pl[of : of+4]) common.CountSafe(fmt.Sprint("InvGot", typ)) if typ == 2 { if blockWanted(pl[of+4 : of+36]) { blinv2ask = append(blinv2ask, pl[of+4:of+36]...) } } else if typ == 1 { if common.CFG.TXPool.Enabled { c.TxInvNotify(pl[of+4 : of+36]) } } of += 36 } if len(blinv2ask) > 0 { bu := new(bytes.Buffer) btc.WriteVlen(bu, uint64(len(blinv2ask)/32)) for i := 0; i < len(blinv2ask); i += 32 { bh := btc.NewUint256(blinv2ask[i : i+32]) c.Mutex.Lock() c.GetBlockInProgress[bh.BIdx()] = &oneBlockDl{hash: bh, start: time.Now()} c.Mutex.Unlock() binary.Write(bu, binary.LittleEndian, uint32(2)) bu.Write(bh.Hash[:]) } c.SendRawMsg("getdata", bu.Bytes()) } return }
func NewQdbRecStatic(key qdb.KeyType, dat []byte) *QdbRec { var off, n, i int var u64, idx uint64 binary.LittleEndian.PutUint64(sta_rec.TxID[:8], uint64(key)) copy(sta_rec.TxID[8:], dat[:24]) off = 24 u64, n = btc.VULe(dat[off:]) off += n sta_rec.InBlock = uint32(u64) u64, n = btc.VULe(dat[off:]) off += n sta_rec.Coinbase = (u64 & 1) != 0 u64 >>= 1 if len(rec_outs) < int(u64) { rec_outs = make([]*QdbTxOut, u64) rec_pool = make([]QdbTxOut, u64) } sta_rec.Outs = rec_outs[:u64] for i := range sta_rec.Outs { sta_rec.Outs[i] = nil } for off < len(dat) { idx, n = btc.VULe(dat[off:]) off += n sta_rec.Outs[idx] = &rec_pool[idx] u64, n = btc.VULe(dat[off:]) off += n sta_rec.Outs[idx].Value = uint64(u64) i, n = btc.VLen(dat[off:]) off += n sta_rec.Outs[idx].PKScr = dat[off : off+i] off += i } return &sta_rec }
func (c *OneConnection) HandleVersion(pl []byte) error { if len(pl) >= 80 /*Up to, includiong, the nonce */ { c.Mutex.Lock() c.Node.Version = binary.LittleEndian.Uint32(pl[0:4]) if bytes.Equal(pl[72:80], nonce[:]) { c.Mutex.Unlock() return errors.New("Connecting to ourselves") } if c.Node.Version < MIN_PROTO_VERSION { c.Mutex.Unlock() return errors.New("Client version too low") } c.Node.Services = binary.LittleEndian.Uint64(pl[4:12]) c.Node.Timestamp = binary.LittleEndian.Uint64(pl[12:20]) c.Mutex.Unlock() if sys.ValidIp4(pl[40:44]) { ExternalIpMutex.Lock() c.Node.ReportedIp4 = binary.BigEndian.Uint32(pl[40:44]) ExternalIp4[c.Node.ReportedIp4] = [2]uint{ExternalIp4[c.Node.ReportedIp4][0] + 1, uint(time.Now().Unix())} ExternalIpMutex.Unlock() } if len(pl) >= 86 { c.Mutex.Lock() le, of := btc.VLen(pl[80:]) of += 80 c.Node.Agent = string(pl[of : of+le]) of += le if len(pl) >= of+4 { c.Node.Height = binary.LittleEndian.Uint32(pl[of : of+4]) of += 4 if len(pl) > of && pl[of] == 0 { c.Node.DoNotRelayTxs = true } } c.Mutex.Unlock() } } else { return errors.New("version message too short") } c.SendRawMsg("verack", []byte{}) return nil }
func NewQdbRec(key qdb.KeyType, dat []byte) *QdbRec { var off, n, i int var u64, idx uint64 var rec QdbRec binary.LittleEndian.PutUint64(rec.TxID[:8], uint64(key)) copy(rec.TxID[8:], dat[:24]) off = 24 u64, n = btc.VULe(dat[off:]) off += n rec.InBlock = uint32(u64) u64, n = btc.VULe(dat[off:]) off += n rec.Coinbase = (u64 & 1) != 0 rec.Outs = make([]*QdbTxOut, u64>>1) for off < len(dat) { idx, n = btc.VULe(dat[off:]) off += n rec.Outs[idx] = new(QdbTxOut) u64, n = btc.VULe(dat[off:]) off += n rec.Outs[idx].Value = uint64(u64) i, n = btc.VLen(dat[off:]) off += n rec.Outs[idx].PKScr = dat[off : off+i] off += i } return &rec }
// TODO: at some point this function will become obsolete func BlockDBConvertIndexFile(dir string) { f, _ := os.Open(dir + "blockchain.idx") if f == nil { if fi, _ := os.Stat(dir + "blockchain_backup.idx"); fi != nil && fi.Size() > 0 { fmt.Println("If you don't plan to go back to a version prior 0.9.8, delete this file:\n", dir+"blockchain_backup.idx") } return // nothing to convert } fmt.Println("Converting btc.Block Database to the new format - please be patient!") id, _ := ioutil.ReadAll(f) f.Close() fmt.Println(len(id)/92, "blocks in the index") f, _ = os.Open(dir + "blockchain.dat") if f == nil { panic("blockchain.dat not found") } defer f.Close() var ( datlen, sofar, sf2, tmp int64 fl, le, he uint32 po uint64 buf [2 * 1024 * 1024]byte // pre-allocate two 2MB buffers blk []byte ) if fi, _ := f.Stat(); fi != nil { datlen = fi.Size() } else { panic("Stat() failed on blockchain.dat") } nidx := new(bytes.Buffer) for i := 0; i+92 <= len(id); i += 92 { fl = binary.LittleEndian.Uint32(id[i : i+4]) he = binary.LittleEndian.Uint32(id[i+68 : i+72]) po = binary.LittleEndian.Uint64(id[i+80 : i+88]) le = binary.LittleEndian.Uint32(id[i+88 : i+92]) f.Seek(int64(po), os.SEEK_SET) if _, er := f.Read(buf[:le]); er != nil { panic(er.Error()) } if (fl & BLOCK_COMPRSD) != 0 { if (fl & BLOCK_SNAPPED) != 0 { blk, _ = snappy.Decode(nil, buf[:le]) } else { gz, _ := gzip.NewReader(bytes.NewReader(buf[:le])) blk, _ = ioutil.ReadAll(gz) gz.Close() } } else { blk = buf[:le] } tx_n, _ := btc.VLen(blk[80:]) binary.Write(nidx, binary.LittleEndian, fl) nidx.Write(id[i+4 : i+36]) binary.Write(nidx, binary.LittleEndian, he) binary.Write(nidx, binary.LittleEndian, po) binary.Write(nidx, binary.LittleEndian, le) binary.Write(nidx, binary.LittleEndian, uint32(tx_n)) nidx.Write(blk[:80]) sf2 += int64(len(blk)) tmp = sofar + int64(le) if ((tmp ^ sofar) >> 20) != 0 { fmt.Printf("\r%d / %d MB processed so far (%d) ", tmp>>20, datlen>>20, sf2>>20) } sofar = tmp } fmt.Println() fmt.Println("Almost there - just save the new index file... don't you dare to stop now!") ioutil.WriteFile(dir+"blockchain.new", nidx.Bytes(), 0666) os.Rename(dir+"blockchain.idx", dir+"blockchain_backup.idx") fmt.Println("The old index backed up at blockchain_backup.dat") fmt.Println("Conversion done and will not be neded again, unless you downgrade.") }