Esempio n. 1
0
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)
	}
}
Esempio n. 2
0
// 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)
		}
	}
}
Esempio n. 3
0
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
}
Esempio n. 4
0
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)
}
Esempio n. 5
0
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)
}
Esempio n. 6
0
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")
		}
	}
}
Esempio n. 7
0
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
}
Esempio n. 8
0
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)
}
Esempio n. 9
0
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
}
Esempio n. 10
0
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)
	}
}
Esempio n. 11
0
// 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
}
Esempio n. 12
0
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
}
Esempio n. 13
0
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
}
Esempio n. 14
0
// 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
}
Esempio n. 15
0
// 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
			}
		}
	}
}
Esempio n. 16
0
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)
	}
}
Esempio n. 17
0
func getUnspIndex(po *btc.TxPrevOut) qdb.KeyType {
	return qdb.KeyType(binary.LittleEndian.Uint64(po.Hash[:8]) ^ uint64(po.Vout))
}
Esempio n. 18
0
func FullQdbRec(dat []byte) *QdbRec {
	return NewQdbRec(qdb.KeyType(binary.LittleEndian.Uint64(dat[:8])), dat[8:])
}
Esempio n. 19
0
func (p *PeerAddr) Save() {
	PeerDB.Put(qdb.KeyType(p.UniqID()), p.Bytes())
}
Esempio n. 20
0
func (db *unwindDb) del(height uint32) {
	db.tdb[height%NumberOfUnwindSubDBs].Del(qdb.KeyType(height))
}