Beispiel #1
0
func (c *OneConnection) SendInvs() (res bool) {
	b_txs := new(bytes.Buffer)
	b_blk := new(bytes.Buffer)
	var c_blk []*btc.Uint256

	c.Mutex.Lock()
	if len(c.PendingInvs) > 0 {
		for i := range c.PendingInvs {
			var inv_sent_otherwise bool
			typ := binary.LittleEndian.Uint32((*c.PendingInvs[i])[:4])
			c.InvStore(typ, (*c.PendingInvs[i])[4:36])
			if typ == MSG_BLOCK {
				if c.Node.SendCmpctVer >= 1 && c.Node.HighBandwidth {
					c_blk = append(c_blk, btc.NewUint256((*c.PendingInvs[i])[4:]))
					inv_sent_otherwise = true
				} else if c.Node.SendHeaders {
					// convert block inv to block header
					common.BlockChain.BlockIndexAccess.Lock()
					bl := common.BlockChain.BlockIndex[btc.NewUint256((*c.PendingInvs[i])[4:]).BIdx()]
					if bl != nil {
						b_blk.Write(bl.BlockHeader[:])
						b_blk.Write([]byte{0}) // 0 txs
					}
					common.BlockChain.BlockIndexAccess.Unlock()
					inv_sent_otherwise = true
				}
			}

			if !inv_sent_otherwise {
				b_txs.Write((*c.PendingInvs[i])[:])
			}
		}
		res = true
	}
	c.PendingInvs = nil
	c.Mutex.Unlock()

	if len(c_blk) > 0 {
		for _, h := range c_blk {
			c.SendCmpctBlk(h)
		}
	}

	if b_blk.Len() > 0 {
		common.CountSafe("InvSentAsHeader")
		b := new(bytes.Buffer)
		btc.WriteVlen(b, uint64(b_blk.Len()/81))
		c.SendRawMsg("headers", append(b.Bytes(), b_blk.Bytes()...))
		//println("sent block's header(s)", b_blk.Len(), uint64(b_blk.Len()/81))
	}

	if b_txs.Len() > 0 {
		b := new(bytes.Buffer)
		btc.WriteVlen(b, uint64(b_txs.Len()/36))
		c.SendRawMsg("inv", append(b.Bytes(), b_txs.Bytes()...))
	}

	return
}
Beispiel #2
0
func (c *OneConnection) GetBlockData(h []byte) {
	var b [1 + 4 + 32]byte
	b[0] = 1 // One inv
	b[1] = 2 // Block
	copy(b[5:37], h[:32])
	if common.DebugLevel > 1 {
		println("GetBlockData", btc.NewUint256(h).String())
	}
	bh := btc.NewUint256(h)
	c.Mutex.Lock()
	c.GetBlockInProgress[bh.BIdx()] = &oneBlockDl{hash: bh, start: time.Now()}
	c.Mutex.Unlock()
	c.SendRawMsg("getdata", b[:])
}
Beispiel #3
0
func init() {
	rd, _ := hex.DecodeString("0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000")
	dummy_tx, _ := btc.NewTx(rd)
	dummy_tx.Size = uint32(len(rd))
	ha := btc.Sha2Sum(rd)
	dummy_tx.Hash = btc.NewUint256(ha[:])
}
Beispiel #4
0
func execute_test_tx(t *testing.T, tv *testvector) bool {
	if len(tv.inps) == 0 {
		t.Error("Vector has no inputs")
		return false
	}
	rd, er := hex.DecodeString(tv.tx)
	if er != nil {
		t.Error(er.Error())
		return false
	}
	tx, _ := btc.NewTx(rd)
	if tx == nil {
		t.Error("Canot decode tx")
		return false
	}
	tx.Size = uint32(len(rd))
	ha := btc.Sha2Sum(rd)
	tx.Hash = btc.NewUint256(ha[:])

	if skip_broken_tests(tx) {
		return false
	}

	if !tx.IsCoinBase() {
		for i := range tx.TxIn {
			if tx.TxIn[i].Input.IsNull() {
				return false
			}
		}
	}

	oks := 0
	for i := range tx.TxIn {
		var j int
		for j = range tv.inps {
			if bytes.Equal(tx.TxIn[i].Input.Hash[:], tv.inps[j].txid.Hash[:]) &&
				tx.TxIn[i].Input.Vout == uint32(tv.inps[j].vout) {
				break
			}
		}
		if j >= len(tv.inps) {
			t.Error("Matching input not found")
			continue
		}

		pk, er := btc.DecodeScript(tv.inps[j].pkscr)
		if er != nil {
			t.Error(er.Error())
			continue
		}
		var ss []byte
		if tv.inps[j].vout >= 0 {
			ss = tx.TxIn[i].ScriptSig
		}
		if VerifyTxScript(ss, pk, i, tx, tv.ver_flags) {
			oks++
		}
	}
	return oks == len(tx.TxIn)
}
Beispiel #5
0
func xml_balance(w http.ResponseWriter, r *http.Request) {
	if !ipchecker(r) {
		return
	}

	w.Header()["Content-Type"] = []string{"text/xml"}
	w.Write([]byte("<unspent>"))

	wallet.BalanceMutex.Lock()
	for i := range wallet.MyBalance {
		w.Write([]byte("<output>"))
		fmt.Fprint(w, "<txid>", btc.NewUint256(wallet.MyBalance[i].TxPrevOut.Hash[:]).String(), "</txid>")
		fmt.Fprint(w, "<vout>", wallet.MyBalance[i].TxPrevOut.Vout, "</vout>")
		fmt.Fprint(w, "<value>", wallet.MyBalance[i].Value, "</value>")
		fmt.Fprint(w, "<inblock>", wallet.MyBalance[i].MinedAt, "</inblock>")
		fmt.Fprint(w, "<blocktime>", get_block_time(wallet.MyBalance[i].MinedAt), "</blocktime>")
		fmt.Fprint(w, "<addr>", wallet.MyBalance[i].DestAddr(), "</addr>")
		fmt.Fprint(w, "<addrorg>", wallet.MyBalance[i].BtcAddr.String(), "</addrorg>")
		fmt.Fprint(w, "<wallet>", html.EscapeString(wallet.MyBalance[i].BtcAddr.Extra.Wallet), "</wallet>")
		fmt.Fprint(w, "<label>", html.EscapeString(wallet.MyBalance[i].BtcAddr.Extra.Label), "</label>")
		fmt.Fprint(w, "<virgin>", fmt.Sprint(wallet.MyBalance[i].BtcAddr.Extra.Virgin), "</virgin>")
		w.Write([]byte("</output>"))
	}
	wallet.BalanceMutex.Unlock()
	w.Write([]byte("</unspent>"))
}
Beispiel #6
0
func output_tx_xml(w http.ResponseWriter, id string) {
	txid := btc.NewUint256FromString(id)
	w.Write([]byte("<tx>"))
	fmt.Fprint(w, "<id>", id, "</id>")
	if t2s, ok := network.TransactionsToSend[txid.BIdx()]; ok {
		w.Write([]byte("<status>OK</status>"))
		w.Write([]byte(fmt.Sprint("<len>", len(t2s.Data), "</len>")))
		tx := t2s.Tx
		w.Write([]byte("<inputs>"))
		for i := range tx.TxIn {
			w.Write([]byte("<input>"))
			var po *btc.TxOut
			inpid := btc.NewUint256(tx.TxIn[i].Input.Hash[:])
			if txinmem, ok := network.TransactionsToSend[inpid.BIdx()]; ok {
				if int(tx.TxIn[i].Input.Vout) < len(txinmem.TxOut) {
					po = txinmem.TxOut[tx.TxIn[i].Input.Vout]
				}
			} else {
				po, _ = common.BlockChain.Unspent.UnspentGet(&tx.TxIn[i].Input)
			}
			if po != nil {
				ok := script.VerifyTxScript(tx.TxIn[i].ScriptSig, po.Pk_script, i, tx, script.VER_P2SH|script.VER_DERSIG)
				if !ok {
					w.Write([]byte("<status>Script FAILED</status>"))
				} else {
					w.Write([]byte("<status>OK</status>"))
				}
				fmt.Fprint(w, "<value>", po.Value, "</value>")
				ads := "???"
				if ad := btc.NewAddrFromPkScript(po.Pk_script, common.Testnet); ad != nil {
					ads = ad.String()
				}
				fmt.Fprint(w, "<addr>", ads, "</addr>")
				fmt.Fprint(w, "<block>", po.BlockHeight, "</block>")
			} else {
				w.Write([]byte("<status>UNKNOWN INPUT</status>"))
			}
			w.Write([]byte("</input>"))
		}
		w.Write([]byte("</inputs>"))

		w.Write([]byte("<outputs>"))
		for i := range tx.TxOut {
			w.Write([]byte("<output>"))
			fmt.Fprint(w, "<value>", tx.TxOut[i].Value, "</value>")
			adr := btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, common.Testnet)
			if adr != nil {
				fmt.Fprint(w, "<addr>", adr.String(), "</addr>")
			} else {
				fmt.Fprint(w, "<addr>", "scr:"+hex.EncodeToString(tx.TxOut[i].Pk_script), "</addr>")
			}
			w.Write([]byte("</output>"))
		}
		w.Write([]byte("</outputs>"))
	} else {
		w.Write([]byte("<status>Not found</status>"))
	}
	w.Write([]byte("</tx>"))
}
Beispiel #7
0
func DecodeTx(tx *btc.Tx) (s string, missinginp bool, totinp, totout uint64, e error) {
	s += fmt.Sprintln("Transaction details (for your information):")
	s += fmt.Sprintln(len(tx.TxIn), "Input(s):")
	for i := range tx.TxIn {
		s += fmt.Sprintf(" %3d %s", i, tx.TxIn[i].Input.String())
		var po *btc.TxOut

		inpid := btc.NewUint256(tx.TxIn[i].Input.Hash[:])
		if txinmem, ok := network.TransactionsToSend[inpid.BIdx()]; ok {
			s += fmt.Sprint(" mempool")
			if int(tx.TxIn[i].Input.Vout) >= len(txinmem.TxOut) {
				s += fmt.Sprintf(" - Vout TOO BIG (%d/%d)!", int(tx.TxIn[i].Input.Vout), len(txinmem.TxOut))
			} else {
				po = txinmem.TxOut[tx.TxIn[i].Input.Vout]
			}
		} else {
			po, _ = common.BlockChain.Unspent.UnspentGet(&tx.TxIn[i].Input)
			if po != nil {
				s += fmt.Sprintf("%8d", po.BlockHeight)
			}
		}
		if po != nil {
			ok := script.VerifyTxScript(tx.TxIn[i].ScriptSig, po.Pk_script, i, tx, true)
			if !ok {
				s += fmt.Sprintln("\nERROR: The transacion does not have a valid signature.")
				e = errors.New("Invalid signature")
				return
			}
			totinp += po.Value

			ads := "???"
			if ad := btc.NewAddrFromPkScript(po.Pk_script, common.Testnet); ad != nil {
				ads = ad.String()
			}
			s += fmt.Sprintf(" %15.8f BTC @ %s\n", float64(po.Value)/1e8, ads)
		} else {
			s += fmt.Sprintln(" - UNKNOWN INPUT")
			missinginp = true
		}
	}
	s += fmt.Sprintln(len(tx.TxOut), "Output(s):")
	for i := range tx.TxOut {
		totout += tx.TxOut[i].Value
		adr := btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, common.Testnet)
		if adr != nil {
			s += fmt.Sprintf(" %15.8f BTC to adr %s\n", float64(tx.TxOut[i].Value)/1e8, adr.String())
		} else {
			s += fmt.Sprintf(" %15.8f BTC to scr %s\n", float64(tx.TxOut[i].Value)/1e8, hex.EncodeToString(tx.TxOut[i].Pk_script))
		}
	}
	if missinginp {
		s += fmt.Sprintln("WARNING: There are missing inputs and we cannot calc input BTC amount.")
		s += fmt.Sprintln("If there is somethign wrong with this transaction, you can loose money...")
	} else {
		s += fmt.Sprintf("All OK: %.8f BTC in -> %.8f BTC out, with %.8f BTC fee\n", float64(totinp)/1e8,
			float64(totout)/1e8, float64(totinp-totout)/1e8)
	}
	return
}
Beispiel #8
0
// This function either appends a new block at the end of the existing chain
// in which case it also applies all the transactions to the unspent database.
// If the block does is not the heighest, it is added to the chain, but maked
// as an orphan - its transaction will be verified only if the chain would swap
// to its branch later on.
func (ch *Chain) AcceptBlock(bl *btc.Block) (e error) {

	prevblk, ok := ch.BlockIndex[btc.NewUint256(bl.ParentHash()).BIdx()]
	if !ok {
		panic("This should not happen")
	}

	// create new BlockTreeNode
	cur := new(BlockTreeNode)
	cur.BlockHash = bl.Hash
	cur.Parent = prevblk
	cur.Height = prevblk.Height + 1
	cur.TxCount = uint32(bl.TxCount)
	copy(cur.BlockHeader[:], bl.Raw[:80])

	// Add this block to the block index
	ch.BlockIndexAccess.Lock()
	prevblk.addChild(cur)
	ch.BlockIndex[cur.BlockHash.BIdx()] = cur
	ch.BlockIndexAccess.Unlock()

	if ch.BlockTreeEnd == prevblk {
		// The head of out chain - apply the transactions
		var changes *BlockChanges
		changes, e = ch.ProcessBlockTransactions(bl, cur.Height)
		if e != nil {
			// ProcessBlockTransactions failed, so trash the block.
			println("ProcessBlockTransactions ", cur.BlockHash.String(), cur.Height, e.Error())
			ch.BlockIndexAccess.Lock()
			cur.Parent.delChild(cur)
			delete(ch.BlockIndex, cur.BlockHash.BIdx())
			ch.BlockIndexAccess.Unlock()
		} else {
			// ProcessBlockTransactions succeeded, so save the block as "trusted".
			bl.Trusted = true
			ch.Blocks.BlockAdd(cur.Height, bl)
			// Apply the block's trabnsactions to the unspent database:
			changes.LastKnownHeight = bl.LastKnownHeight
			ch.Unspent.CommitBlockTxs(changes, bl.Hash.Hash[:])
			if !ch.DoNotSync {
				ch.Blocks.Sync()
			}
			ch.BlockTreeEnd = cur // Advance the head
		}
	} else {
		// The block's parent is not the current head of the chain...

		// Save the block, though do not makt it as "trusted" just yet
		ch.Blocks.BlockAdd(cur.Height, bl)

		// If it has a bigger height than the current head,
		// ... move the coin state into a new branch.
		if cur.Height > ch.BlockTreeEnd.Height {
			ch.MoveToBlock(cur)
		}
	}

	return
}
Beispiel #9
0
func (db *BlockDB) BlockInvalid(hash []byte) {
	idx := btc.NewUint256(hash).BIdx()
	db.mutex.Lock()
	cur, ok := db.blockIndex[idx]
	if !ok {
		db.mutex.Unlock()
		println("BlockInvalid: no such block")
		return
	}
	println("mark", btc.NewUint256(hash).String(), "as invalid")
	if cur.trusted {
		panic("if it is trusted - how can be invalid?")
	}
	db.setBlockFlag(cur, BLOCK_INVALID)
	delete(db.blockIndex, idx)
	db.mutex.Unlock()
}
Beispiel #10
0
func print_record(sl []byte) {
	bh := btc.NewSha2Hash(sl[56:136])
	fmt.Print("Block ", bh.String(), " Height ", binary.LittleEndian.Uint32(sl[36:40]))
	fmt.Println()
	fmt.Println("  ...", binary.LittleEndian.Uint32(sl[48:52]), " Bytes @ ",
		binary.LittleEndian.Uint64(sl[40:48]), " in dat file")
	hdr := sl[56:136]
	fmt.Println("   ->", btc.NewUint256(hdr[4:36]).String())
}
Beispiel #11
0
// Handle tx-inv notifications
func (c *OneConnection) TxInvNotify(hash []byte) {
	if NeedThisTx(btc.NewUint256(hash), nil) {
		var b [1 + 4 + 32]byte
		b[0] = 1 // One inv
		b[1] = 1 // Tx
		copy(b[5:37], hash)
		c.SendRawMsg("getdata", b[:])
	}
}
Beispiel #12
0
func (db *BlockDB) BlockInvalid(hash []byte) {
	idx := btc.NewUint256(hash).BIdx()
	db.mutex.Lock()
	cur, ok := db.blockIndex[idx]
	if !ok {
		db.mutex.Unlock()
		println("BlockInvalid: no such block", btc.NewUint256(hash).String())
		return
	}
	if cur.trusted {
		println("Looks like your UTXO database is corrupt")
		println("To rebuild it, remove folder: " + db.dirname + "unspent4")
		panic("Trusted block cannot be invalid")
	}
	//println("mark", btc.NewUint256(hash).String(), "as invalid")
	db.setBlockFlag(cur, BLOCK_INVALID)
	delete(db.blockIndex, idx)
	db.mutex.Unlock()
}
Beispiel #13
0
// Call it only from the Chain thread
func DumpBalance(mybal chain.AllUnspentTx, utxt *os.File, details, update_balance bool) (s string) {
	var sum uint64
	BalanceMutex.Lock()
	for i := range mybal {
		sum += mybal[i].Value

		if details {
			if i < 100 {
				s += fmt.Sprintf("%7d %s\n", 1+common.Last.Block.Height-mybal[i].MinedAt,
					mybal[i].String())
			} else if i == 100 {
				s += fmt.Sprintln("List of unspent outputs truncated to 100 records")
			}
		}

		// update the balance/ folder
		if utxt != nil {
			po, e := common.BlockChain.Unspent.UnspentGet(&mybal[i].TxPrevOut)
			if e != nil {
				println("UnspentGet:", e.Error())
				println("This should not happen - please, report a bug.")
				println("You can probably fix it by launching the client with -rescan")
				os.Exit(1)
			}

			txid := btc.NewUint256(mybal[i].TxPrevOut.Hash[:])

			// Store the unspent line in balance/unspent.txt
			fmt.Fprintln(utxt, mybal[i].UnspentTextLine())

			// store the entire transactiojn in balance/<txid>.tx
			fn := "balance/" + txid.String()[:64] + ".tx"
			txf, _ := os.Open(fn)
			if txf == nil {
				// Do it only once per txid
				txf, _ = os.Create(fn)
				if txf == nil {
					println("Cannot create ", fn)
					os.Exit(1)
				}
				GetRawTransaction(po.BlockHeight, txid, txf)
			}
			txf.Close()
		}
	}
	if update_balance {
		LastBalance = sum
	}
	BalanceMutex.Unlock()
	s += fmt.Sprintf("Total balance: %.8f BTC in %d unspent outputs\n", float64(sum)/1e8, len(mybal))
	if utxt != nil {
		utxt.Close()
	}
	return
}
Beispiel #14
0
// Loads block index from the disk
func (ch *Chain) loadBlockIndex() {
	ch.BlockIndex = make(map[[btc.Uint256IdxLen]byte]*BlockTreeNode, BlockMapInitLen)
	ch.BlockTreeRoot = new(BlockTreeNode)
	ch.BlockTreeRoot.BlockHash = ch.Genesis
	ch.RebuildGenesisHeader()
	ch.BlockIndex[ch.Genesis.BIdx()] = ch.BlockTreeRoot

	ch.Blocks.LoadBlockIndex(ch, nextBlock)
	tlb := ch.Unspent.LastBlockHash
	//println("Building tree from", len(ch.BlockIndex), "nodes")
	for k, v := range ch.BlockIndex {
		if AbortNow {
			return
		}
		if v == ch.BlockTreeRoot {
			// skip root block (should be only one)
			continue
		}

		par, ok := ch.BlockIndex[btc.NewUint256(v.BlockHeader[4:36]).BIdx()]
		if !ok {
			println("ERROR: Block", v.Height, v.BlockHash.String(), "has no Parent")
			println("...", btc.NewUint256(v.BlockHeader[4:36]).String(), "- removing it from blocksDB")
			delete(ch.BlockIndex, k)
			continue
		}
		v.Parent = par
		v.Parent.addChild(v)
	}
	if tlb == nil {
		//println("No last block - full rescan will be needed")
		ch.BlockTreeEnd = ch.BlockTreeRoot
		return
	} else {
		//println("Last Block Hash:", btc.NewUint256(tlb).String())
		var ok bool
		ch.BlockTreeEnd, ok = ch.BlockIndex[btc.NewUint256(tlb).BIdx()]
		if !ok {
			panic("Last btc.Block Hash not found")
		}
	}
}
Beispiel #15
0
func (c *OneConnection) ProcessGetBlockTxn(pl []byte) {
	if len(pl) < 34 {
		println(c.ConnID, "GetBlockTxnShort")
		c.DoS("GetBlockTxnShort")
		return
	}
	hash := btc.NewUint256(pl[:32])
	crec := GetchBlockForBIP152(hash)
	if crec == nil {
		fmt.Println(c.ConnID, "GetBlockTxn aborting for", hash.String())
		return
	}

	req := bytes.NewReader(pl[32:])
	indexes_length, _ := btc.ReadVLen(req)
	if indexes_length == 0 {
		println(c.ConnID, "GetBlockTxnEmpty")
		c.DoS("GetBlockTxnEmpty")
		return
	}

	var exp_idx uint64
	msg := new(bytes.Buffer)

	msg.Write(hash.Hash[:])
	btc.WriteVlen(msg, indexes_length)

	for {
		idx, er := btc.ReadVLen(req)
		if er != nil {
			println(c.ConnID, "GetBlockTxnERR")
			c.DoS("GetBlockTxnERR")
			return
		}
		idx += exp_idx
		if int(idx) >= len(crec.Block.Txs) {
			println(c.ConnID, "GetBlockTxnIdx+")
			c.DoS("GetBlockTxnIdx+")
			return
		}
		if c.Node.SendCmpctVer == 2 {
			msg.Write(crec.Block.Txs[idx].Raw) // coinbase - index 0
		} else {
			crec.Block.Txs[idx].WriteSerialized(msg) // coinbase - index 0
		}
		if indexes_length == 1 {
			break
		}
		indexes_length--
		exp_idx = idx + 1
	}

	c.SendRawMsg("blocktxn", msg.Bytes())
}
Beispiel #16
0
func send_all_tx(par string) {
	network.TxMutex.Lock()
	for k, v := range network.TransactionsToSend {
		if v.Own != 0 {
			cnt := network.NetRouteInv(1, btc.NewUint256(k[:]), nil)
			v.Invsentcnt += cnt
			fmt.Println("INV for TxID", v.Hash.String(), "sent to", cnt, "node(s)")
		}
	}
	network.TxMutex.Unlock()
}
Beispiel #17
0
func baned_txs(par string) {
	fmt.Println("Rejected transactions:")
	cnt := 0
	network.TxMutex.Lock()
	for k, v := range network.TransactionsRejected {
		cnt++
		fmt.Println("", cnt, btc.NewUint256(k[:]).String(), "-", v.Size, "bytes",
			"-", v.Reason, "-", time.Now().Sub(v.Time).String(), "ago")
	}
	network.TxMutex.Unlock()
}
Beispiel #18
0
func chkblock(bl *btc.Block) (er error) {
	// Check timestamp (must not be higher than now +2 hours)
	if int64(bl.BlockTime()) > time.Now().Unix()+2*60*60 {
		er = errors.New("CheckBlock() : block timestamp too far in the future")
		return
	}

	MemBlockChainMutex.Lock()
	if prv, pres := MemBlockChain.BlockIndex[bl.Hash.BIdx()]; pres {
		MemBlockChainMutex.Unlock()
		if prv.Parent == nil {
			// This is genesis block
			er = errors.New("Genesis")
			return
		} else {
			return
		}
	}

	prevblk, ok := MemBlockChain.BlockIndex[btc.NewUint256(bl.ParentHash()).BIdx()]
	if !ok {
		er = errors.New("CheckBlock: " + bl.Hash.String() + " parent not found")
		return
	}

	// Check proof of work
	gnwr := MemBlockChain.GetNextWorkRequired(prevblk, bl.BlockTime())
	if bl.Bits() != gnwr {
		if !Testnet || ((prevblk.Height+1)%2016) != 0 {
			MemBlockChainMutex.Unlock()
			er = errors.New(fmt.Sprint("CheckBlock: Incorrect proof of work at block", prevblk.Height+1))
			return
		}
	}

	cur := new(chain.BlockTreeNode)
	cur.BlockHash = bl.Hash
	cur.Parent = prevblk
	cur.Height = prevblk.Height + 1
	cur.TxCount = uint32(bl.TxCount)
	copy(cur.BlockHeader[:], bl.Raw[:80])
	prevblk.Childs = append(prevblk.Childs, cur)
	MemBlockChain.BlockIndex[cur.BlockHash.BIdx()] = cur
	MemBlockChainMutex.Unlock()

	LastBlock.Mutex.Lock()
	if cur.Height > LastBlock.node.Height {
		LastBlock.node = cur
	}
	LastBlock.Mutex.Unlock()

	return
}
Beispiel #19
0
// Loads block index from the disk
func (ch *Chain) loadBlockIndex() {
	ch.BlockIndex = make(map[[btc.Uint256IdxLen]byte]*BlockTreeNode, BlockMapInitLen)
	ch.BlockTreeRoot = new(BlockTreeNode)
	ch.BlockTreeRoot.BlockHash = ch.Genesis
	ch.BlockIndex[ch.Genesis.BIdx()] = ch.BlockTreeRoot

	ch.Blocks.LoadBlockIndex(ch, nextBlock)
	tlb := ch.Unspent.GetLastBlockHash()
	//println("Building tree from", len(ch.BlockIndex), "nodes")
	for _, v := range ch.BlockIndex {
		if AbortNow {
			return
		}
		if v == ch.BlockTreeRoot {
			// skip root block (should be only one)
			continue
		}

		par, ok := ch.BlockIndex[btc.NewUint256(v.BlockHeader[4:36]).BIdx()]
		if !ok {
			panic(v.BlockHash.String() + " has no Parent " + btc.NewUint256(v.BlockHeader[4:36]).String())
		}
		/*if par.Height+1 != v.Height {
			panic("height mismatch")
		}*/
		v.Parent = par
		v.Parent.addChild(v)
	}
	if tlb == nil {
		//println("No last block - full rescan will be needed")
		ch.BlockTreeEnd = ch.BlockTreeRoot
		return
	} else {
		var ok bool
		ch.BlockTreeEnd, ok = ch.BlockIndex[btc.NewUint256(tlb).BIdx()]
		if !ok {
			panic("Last btc.Block Hash not found")
		}
	}
}
Beispiel #20
0
// Handle tx-inv notifications
func (c *OneConnection) TxInvNotify(hash []byte) {
	if NeedThisTx(btc.NewUint256(hash), nil) {
		var b [1 + 4 + 32]byte
		b[0] = 1 // One inv
		if (c.Node.Services & SERVICE_SEGWIT) != 0 {
			binary.LittleEndian.PutUint32(b[1:5], MSG_WITNESS_TX) // SegWit Tx
			//println(c.ConnID, "getdata", btc.NewUint256(hash).String())
		} else {
			b[1] = 1 // Tx
		}
		copy(b[5:37], hash)
		c.SendRawMsg("getdata", b[:])
	}
}
Beispiel #21
0
func nextBlock(ch *Chain, hash, header []byte, height, blen, txs uint32) {
	bh := btc.NewUint256(hash[:])
	if _, ok := ch.BlockIndex[bh.BIdx()]; ok {
		println("nextBlock:", bh.String(), "- already in")
		return
	}
	v := new(BlockTreeNode)
	v.BlockHash = bh
	v.Height = height
	v.BlockSize = blen
	v.TxCount = txs
	copy(v.BlockHeader[:], header)
	ch.BlockIndex[v.BlockHash.BIdx()] = v
}
Beispiel #22
0
// Read VLen followed by the number of locators
// parse the payload of getblocks and getheaders messages
func parseLocatorsPayload(pl []byte) (h2get []*btc.Uint256, hashstop *btc.Uint256, er error) {
	var cnt uint64
	var h [32]byte
	var ver uint32

	b := bytes.NewReader(pl)

	// version
	if er = binary.Read(b, binary.LittleEndian, &ver); er != nil {
		return
	}

	// hash count
	cnt, er = btc.ReadVLen(b)
	if er != nil {
		return
	}

	// block locator hashes
	if cnt > 0 {
		h2get = make([]*btc.Uint256, cnt)
		for i := 0; i < int(cnt); i++ {
			if _, er = b.Read(h[:]); er != nil {
				return
			}
			h2get[i] = btc.NewUint256(h[:])
		}
	}

	// hash_stop
	if _, er = b.Read(h[:]); er != nil {
		return
	}
	hashstop = btc.NewUint256(h[:])

	return
}
Beispiel #23
0
func (db *unwindDb) stats() (s string) {
	var cnt int
	var totdatasize uint64
	for i := range db.tdb {
		cnt += db.dbH(i).Count()
		db.dbH(i).Browse(func(k qdb.KeyType, v []byte) uint32 {
			totdatasize += uint64(len(v))
			return 0
		})
	}
	s = fmt.Sprintf("UNWIND: len:%d  last:%d  defrags:%d/%d  TotalData:%dMB\n",
		cnt, db.lastBlockHeight, db.defragCount, db.defragIndex, totdatasize>>20)
	s += "Last block: " + btc.NewUint256(db.lastBlockHash[:]).String() + "\n"
	return
}
Beispiel #24
0
func walk(ch *chain.Chain, hash, hdr []byte, height, blen, txs uint32) {
	bh := btc.NewUint256(hash)
	if _, ok := bidx[bh.Hash]; ok {
		println("walk: ", bh.String(), "already in")
		return
	}
	v := new(chain.BlockTreeNode)
	v.BlockHash = bh
	v.Height = height
	v.BlockSize = blen
	v.TxCount = txs
	copy(v.BlockHeader[:], hdr)
	bidx[bh.Hash] = v
	cnt++
}
Beispiel #25
0
func (db *BlockDB) BlockTrusted(hash []byte) {
	idx := btc.NewUint256(hash).BIdx()
	db.mutex.Lock()
	cur, ok := db.blockIndex[idx]
	if !ok {
		db.mutex.Unlock()
		println("BlockTrusted: no such block")
		return
	}
	if !cur.trusted {
		//fmt.Println("mark", btc.NewUint256(hash).String(), "as trusted")
		db.setBlockFlag(cur, BLOCK_TRUSTED)
	}
	db.mutex.Unlock()
}
Beispiel #26
0
// Return DB statistics
func (db *UnspentDB) GetStats() (s string) {
	var tot, outcnt, sum, sumcb, stealth_uns, stealth_tot uint64
	var mincnt, maxcnt, totdatasize, unspendable uint64
	for i := range db.tdb {
		dbcnt := uint64(db.DbN(i).Count())
		if i == 0 {
			mincnt, maxcnt = dbcnt, dbcnt
		} else if dbcnt < mincnt {
			mincnt = dbcnt
		} else if dbcnt > maxcnt {
			maxcnt = dbcnt
		}
		tot += dbcnt
		db.DbN(i).Browse(func(k qdb.KeyType, v []byte) uint32 {
			totdatasize += uint64(len(v) + 8)
			rec := NewQdbRecStatic(k, v)
			for idx, r := range rec.Outs {
				if r != nil {
					outcnt++
					sum += r.Value
					if rec.Coinbase {
						sumcb += r.Value
					}
					if len(r.PKScr) > 0 && r.PKScr[0] == 0x6a {
						unspendable++
					}
					if r.IsStealthIdx() && idx+1 < len(rec.Outs) {
						if rec.Outs[idx+1] != nil {
							stealth_uns++
						}
						stealth_tot++
					}
				}
			}
			return 0
		})
	}
	s = fmt.Sprintf("UNSPENT: %.8f BTC in %d outs from %d txs. %.8f BTC in coinbase.\n",
		float64(sum)/1e8, outcnt, tot, float64(sumcb)/1e8)
	s += fmt.Sprintf(" Defrags:%d  Recs/db : %d..%d   TotalData:%.1fMB  MaxTxOutCnt:%d \n",
		db.defragCount, mincnt, maxcnt, float64(totdatasize)/1e6, len(rec_outs))
	s += fmt.Sprintf(" Last Block : %s @ %d\n", btc.NewUint256(db.LastBlockHash).String(),
		db.LastBlockHeight)
	s += fmt.Sprintf(" Number of unspendable outputs: %d.  Number of stealth indexes: %d / %d spent\n",
		unspendable, stealth_uns, stealth_tot)
	return
}
Beispiel #27
0
func (c *OneConnection) ProcessInv(pl []byte) {
	if len(pl) < 37 {
		//println(c.PeerAddr.Ip(), "inv payload too short", len(pl))
		c.DoS("InvEmpty")
		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
}
Beispiel #28
0
// Called from network threads
func blockWanted(h []byte) (yes bool) {
	idx := btc.NewUint256(h).BIdx()
	MutexRcv.Lock()
	_, ok := ReceivedBlocks[idx]
	MutexRcv.Unlock()
	if !ok {
		if atomic.LoadUint32(&common.CFG.Net.MaxBlockAtOnce) == 0 || !blocksLimitReached(idx) {
			yes = true
			common.CountSafe("BlockWanted")
		} else {
			common.CountSafe("BlockInProgress")
		}
	} else {
		common.CountSafe("BlockUnwanted")
	}
	return
}
Beispiel #29
0
func (c *one_net_conn) ping_idle() {
	c.ping.Lock()
	if c.ping.inProgress {
		if time.Now().After(c.ping.timeSent.Add(PING_TIMEOUT)) {
			c.store_ping_result()
			c.ping.Unlock()
			//fmt.Println(c.peerip, "ping timeout", c.ping.seq)
		} else {
			c.ping.Unlock()
			time.Sleep(time.Millisecond)
		}
	} else if c.ping.now {
		//fmt.Println("ping", c.peerip, c.ping.seq)
		c.ping.inProgress = true
		c.ping.timeSent = time.Now()
		c.ping.now = false
		if false {
			rand.Read(c.ping.pattern[:])
			c.ping.Unlock()
			c.sendmsg("ping", c.ping.pattern[:])
		} else {
			b := new(bytes.Buffer)
			btc.WriteVlen(b, PING_FETCH_BLOCKS)
			BlocksMutex.Lock()
			for i := uint32(1); ; i++ {
				binary.Write(b, binary.LittleEndian, uint32(2))
				btg := BlocksToGet[i]
				b.Write(btg[:])
				if i == PING_FETCH_BLOCKS {
					c.ping.lastBlock = btc.NewUint256(btg[:])
					break
				}
			}
			BlocksMutex.Unlock()
			c.ping.bytes = 0
			c.ping.Unlock()
			c.sendmsg("getdata", b.Bytes())
			//fmt.Println("ping sent", c.ping.lastBlock.String())
		}
	} else {
		c.ping.Unlock()
		time.Sleep(10 * time.Millisecond)
	}
}
Beispiel #30
0
// Make sure to call this function with ch.BlockIndexAccess locked
func (ch *Chain) AcceptHeader(bl *btc.Block) (cur *BlockTreeNode) {
	prevblk, ok := ch.BlockIndex[btc.NewUint256(bl.ParentHash()).BIdx()]
	if !ok {
		panic("This should not happen")
	}

	// create new BlockTreeNode
	cur = new(BlockTreeNode)
	cur.BlockHash = bl.Hash
	cur.Parent = prevblk
	cur.Height = prevblk.Height + 1
	copy(cur.BlockHeader[:], bl.Raw[:80])

	// Add this block to the block index
	prevblk.addChild(cur)
	ch.BlockIndex[cur.BlockHash.BIdx()] = cur

	return
}