func (db *UnspentDB) del(hash []byte, outs []bool) { 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) if db.ch.CB.NotifyTxDel != nil { db.ch.CB.NotifyTxDel(rec, outs) } 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) } }
// 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[:]) { c.Misbehave("AddrLocal", 2) } 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 { c.Misbehave("AddrFuture", 5) } } }
func NewIncomingPeer(ipstr string) (p *onePeer, e error) { x := strings.Index(ipstr, ":") if x != -1 { ipstr = ipstr[:x] // remove port number } ip := net.ParseIP(ipstr) if ip != nil && len(ip) == 16 { if common.IsIPBlocked(ip[12:16]) { e = errors.New(ipstr + " is blocked") return } p = NewEmptyPeer() copy(p.Ip4[:], ip[12:16]) p.Services = common.Services copy(p.Ip6[:], ip[:12]) p.Port = common.DefaultTcpPort 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 }
func (db *unspentDb) del(idx *btc.TxPrevOut) { if db.ch.CB.NotifyTx != nil { db.ch.CB.NotifyTx(idx, nil) } key := qdb.KeyType(idx.UIdx()) db.dbN(int(idx.Hash[31]) % NumberOfUnspentSubDBs).Del(key) }
func (db *unspentDb) add(idx *btc.TxPrevOut, Val_Pk *btc.TxOut) { v := make([]byte, SCR_OFFS+len(Val_Pk.Pk_script)) copy(v[0:32], idx.Hash[:]) binary.LittleEndian.PutUint32(v[32:36], idx.Vout) binary.LittleEndian.PutUint64(v[36:44], Val_Pk.Value) binary.LittleEndian.PutUint32(v[44:48], Val_Pk.BlockHeight) copy(v[SCR_OFFS:], Val_Pk.Pk_script) k := qdb.KeyType(idx.UIdx()) var flgz uint32 dbN := db.dbN(int(idx.Hash[31]) % NumberOfUnspentSubDBs) if stealthIndex(v) { if db.ch.CB.NotifyStealthTx != nil { db.ch.CB.NotifyStealthTx(dbN, k, NewWalkRecord(v)) } flgz = qdb.YES_CACHE | qdb.YES_BROWSE } else { if db.ch.CB.NotifyTx != nil { db.ch.CB.NotifyTx(idx, Val_Pk) } if Val_Pk.Value < MinBrowsableOutValue { flgz = qdb.NO_CACHE | qdb.NO_BROWSE } else if NocacheBlocksBelow == -1 { flgz = qdb.NO_CACHE | qdb.NO_BROWSE } } dbN.PutExt(k, v, flgz) }
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 (ur *OneAllAddrInp) GetRec() (rec *chain.QdbRec, vout uint32) { ind := qdb.KeyType(binary.LittleEndian.Uint64(ur[1:9])) v := common.BlockChain.Unspent.DbN(int(ur[0])).Get(ind) if v != nil { vout = binary.LittleEndian.Uint32(ur[9:13]) rec = chain.NewQdbRec(ind, v) } return }
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 *unwindDb) undo(height uint32, unsp *unspentDb) { if height != db.lastBlockHeight { panic("Unexpected height") } v := db.dbH(int(height) % NumberOfUnwindSubDBs).Get(qdb.KeyType(height)) if v == nil { panic("Unwind data not found") } unwindFromReader(bytes.NewReader(v[32:]), unsp) db.del(height) db.lastBlockHeight-- v = db.dbH(int(db.lastBlockHeight) % NumberOfUnwindSubDBs).Get(qdb.KeyType(db.lastBlockHeight)) if v == nil { panic("Parent data not found") } copy(db.lastBlockHash[:], v[:32]) return }
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) } }
// It is assumed that you call this function only after rec.IsStealthIdx() was true func CheckStealthRec(db *qdb.DB, k qdb.KeyType, rec *chain.OneWalkRecord, addr *btc.BtcAddr, d []byte, inbrowse bool) (fl uint32, uo *chain.OneUnspentTx) { sth_scr := rec.Script() sa := addr.StealthAddr if sa.CheckNonce(sth_scr[3:]) { vo := rec.VOut() // get the spending output var spend_v []byte if inbrowse { spend_v = db.GetNoMutex(qdb.KeyType(uint64(k) ^ uint64(vo) ^ uint64(vo+1))) } else { spend_v = db.Get(qdb.KeyType(uint64(k) ^ uint64(vo) ^ uint64(vo+1))) } if spend_v != nil { rec = chain.NewWalkRecord(spend_v) if rec.IsP2KH() { var h160 [20]byte c := btc.StealthDH(sth_scr[7:40], d) spen_exp := btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(rec.Script()[3:23], h160[:]) { adr := btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo = rec.ToUnspent(adr) adr.StealthAddr = sa adr.Extra = addr.Extra uo.StealthC = c } } else { fl = chain.WALK_NOMORE } } else { fl = chain.WALK_NOMORE } } return }
func (db *unspentDb) get(po *btc.TxPrevOut) (res *btc.TxOut, e error) { ind := qdb.KeyType(po.UIdx()) val := db.dbN(int(po.Hash[31]) % NumberOfUnspentSubDBs).Get(ind) if val == nil { e = errors.New("Unspent not found") return } if len(val) < SCR_OFFS { panic(fmt.Sprint("unspent record too short:", len(val))) } res = new(btc.TxOut) res.Value = binary.LittleEndian.Uint64(val[36:44]) res.BlockHeight = binary.LittleEndian.Uint32(val[44:48]) res.Pk_script = make([]byte, len(val)-SCR_OFFS) copy(res.Pk_script, val[SCR_OFFS:]) return }
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 } a.Time = uint32(time.Now().Add(-5 * time.Minute).Unix()) // add new peers as not just alive peersdb.PeerDB.Put(k, a.Bytes()) } else { common.CountSafe("AddrStale") } } else { if c.Misbehave("AddrFuture", 50) { break } } } }
func (db *unwindDb) commit(changes *BlockChanges, blhash []byte) { if db.lastBlockHeight+1 != changes.Height { println(db.lastBlockHeight+1, changes.Height) panic("Unexpected height") } db.lastBlockHeight++ copy(db.lastBlockHash[:], blhash[0:32]) f := new(bytes.Buffer) f.Write(blhash[0:32]) // cast uin32 to int to properly discover negative diffs: if int(changes.LastKnownHeight)-int(changes.Height) < UnwindBufferMaxHistory { for k, _ := range changes.AddedTxs { writeSpent(f, &k, nil) } for k, v := range changes.DeledTxs { writeSpent(f, &k, v) } } db.dbH(int(changes.Height)%NumberOfUnwindSubDBs).PutExt(qdb.KeyType(changes.Height), f.Bytes(), qdb.NO_CACHE) if changes.Height >= UnwindBufferMaxHistory { db.del(changes.Height - UnwindBufferMaxHistory) } }
func getUnspIndex(po *btc.TxPrevOut) qdb.KeyType { return qdb.KeyType(binary.LittleEndian.Uint64(po.Hash[:8]) ^ uint64(po.Vout)) }
func FullQdbRec(dat []byte) *QdbRec { return NewQdbRec(qdb.KeyType(binary.LittleEndian.Uint64(dat[:8])), dat[8:]) }
func (p *PeerAddr) Save() { PeerDB.Put(qdb.KeyType(p.UniqID()), p.Bytes()) }
func (db *unwindDb) del(height uint32) { db.tdb[height%NumberOfUnwindSubDBs].Del(qdb.KeyType(height)) }