func (db *UnspentDB) del(hash []byte, outs []bool) { if db.ch.CB.NotifyTxDel != nil { db.ch.CB.NotifyTxDel(hash, outs) } ind := qdb.KeyType(binary.LittleEndian.Uint64(hash[:8])) _db := db.dbN(int(hash[31]) % NumberOfUnspentSubDBs) v := _db.Get(ind) if v == nil { return // no such txid in UTXO (just ignorde delete request) } rec := NewQdbRec(ind, v) var anyout bool for i, rm := range outs { if rm { rec.Outs[i] = nil } else if rec.Outs[i] != nil { anyout = true } } if anyout { _db.Put(ind, rec.Bytes()) } else { _db.Del(ind) } }
func parse_addr(pl []byte) { b := bytes.NewBuffer(pl) cnt, _ := btc.ReadVLen(b) for i := 0; i < int(cnt); i++ { var buf [30]byte n, e := b.Read(buf[:]) if n != len(buf) || e != nil { COUNTER("ADER") break } a := peersdb.NewPeer(buf[:]) if !sys.ValidIp4(a.Ip4[:]) { COUNTER("ADNO") } else if time.Unix(int64(a.Time), 0).Before(time.Now().Add(time.Minute)) { if time.Now().Before(time.Unix(int64(a.Time), 0).Add(peersdb.ExpirePeerAfter)) { k := qdb.KeyType(a.UniqID()) v := peersdb.PeerDB.Get(k) if v != nil { a.Banned = peersdb.NewPeer(v[:]).Banned } peersdb.PeerDB.Put(k, a.Bytes()) } else { COUNTER("ADST") } } else { COUNTER("ADFU") } } }
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 (db *UnspentDB) commit(changes *BlockChanges) { // Now aplly the unspent changes for _, rec := range changes.AddList { ind := qdb.KeyType(binary.LittleEndian.Uint64(rec.TxID[:8])) if db.ch.CB.NotifyTxAdd != nil { db.ch.CB.NotifyTxAdd(rec) } db.dbN(int(rec.TxID[31])%NumberOfUnspentSubDBs).PutExt(ind, rec.Bytes(), 0) } for k, v := range changes.DeledTxs { db.del(k[:], v) } }
func NewPeerFromString(ipstr string, force_default_port bool) (p *PeerAddr, e error) { port := DefaultTcpPort() x := strings.Index(ipstr, ":") if x != -1 { if !force_default_port { v, er := strconv.ParseUint(ipstr[x+1:], 10, 32) if er != nil { e = er return } if v > 0xffff { e = errors.New("Port number too big") return } port = uint16(v) } ipstr = ipstr[:x] // remove port number } ip := net.ParseIP(ipstr) if ip != nil && len(ip) == 16 { if sys.IsIPBlocked(ip[12:16]) { e = errors.New(ipstr + " is blocked") return } p = NewEmptyPeer() copy(p.Ip4[:], ip[12:16]) p.Services = Services copy(p.Ip6[:], ip[:12]) p.Port = port if dbp := PeerDB.Get(qdb.KeyType(p.UniqID())); dbp != nil && NewPeer(dbp).Banned != 0 { e = errors.New(p.Ip() + " is banned") p = nil } else { p.Time = uint32(time.Now().Unix()) p.Save() } } else { e = errors.New("Error parsing IP '" + ipstr + "'") } return }
// Get ne unspent output func (db *UnspentDB) UnspentGet(po *btc.TxPrevOut) (res *btc.TxOut, e error) { ind := qdb.KeyType(binary.LittleEndian.Uint64(po.Hash[:8])) v := db.dbN(int(po.Hash[31]) % NumberOfUnspentSubDBs).Get(ind) if v == nil { e = errors.New("Unspent TX not found") return } rec := NewQdbRec(ind, v) if len(rec.Outs) < int(po.Vout) || rec.Outs[po.Vout] == nil { e = errors.New("Unspent VOut not found") return } res = new(btc.TxOut) res.VoutCount = uint32(len(rec.Outs)) res.WasCoinbase = rec.Coinbase res.BlockHeight = rec.InBlock res.Value = rec.Outs[po.Vout].Value res.Pk_script = rec.Outs[po.Vout].PKScr return }
// Parese network's "addr" message func (c *OneConnection) ParseAddr(pl []byte) { b := bytes.NewBuffer(pl) cnt, _ := btc.ReadVLen(b) for i := 0; i < int(cnt); i++ { var buf [30]byte n, e := b.Read(buf[:]) if n != len(buf) || e != nil { common.CountSafe("AddrError") c.DoS("AddrError") //println("ParseAddr:", n, e) break } a := peersdb.NewPeer(buf[:]) if !sys.ValidIp4(a.Ip4[:]) { //common.CountSafe("AddrLocal") if c.Misbehave("AddrLocal", 1) { break } //print(c.PeerAddr.Ip(), " ", c.Node.Agent, " ", c.Node.Version, " addr local ", a.String(), "\n> ") } else if time.Unix(int64(a.Time), 0).Before(time.Now().Add(time.Minute)) { if time.Now().Before(time.Unix(int64(a.Time), 0).Add(peersdb.ExpirePeerAfter)) { k := qdb.KeyType(a.UniqID()) v := peersdb.PeerDB.Get(k) if v != nil { a.Banned = peersdb.NewPeer(v[:]).Banned } peersdb.PeerDB.Put(k, a.Bytes()) } else { common.CountSafe("AddrStale") } } else { if c.Misbehave("AddrFuture", 50) { break } } } }
func (p *PeerAddr) Save() { PeerDB.Put(qdb.KeyType(p.UniqID()), p.Bytes()) }
func FullQdbRec(dat []byte) *QdbRec { return NewQdbRec(qdb.KeyType(binary.LittleEndian.Uint64(dat[:8])), dat[8:]) }