Beispiel #1
0
// This function is called from the main thread (or from an UI)
func NetRouteInv(typ uint32, h *btc.Uint256, fromConn *OneConnection) (cnt uint) {
	common.CountSafe(fmt.Sprint("NetRouteInv", typ))

	// Prepare the inv
	inv := new([36]byte)
	binary.LittleEndian.PutUint32(inv[0:4], typ)
	copy(inv[4:36], h.Bytes())

	// Append it to PendingInvs in each open connection
	Mutex_net.Lock()
	for _, v := range OpenCons {
		if v != fromConn { // except the one that this inv came from
			v.Mutex.Lock()
			if v.Node.DoNotRelayTxs && typ == 1 {
				// This node does not want tx inv (it came with its version message)
				common.CountSafe("SendInvNoTxNode")
			} else {
				if fromConn == nil && v.InvsRecieved == 0 {
					// Do not broadcast own txs to nodes that never sent any invs to us
					common.CountSafe("SendInvOwnBlocked")
				} else if len(v.PendingInvs) < 500 {
					v.PendingInvs = append(v.PendingInvs, inv)
					cnt++
				} else {
					common.CountSafe("SendInvIgnored")
				}
			}
			v.Mutex.Unlock()
		}
	}
	Mutex_net.Unlock()
	return
}
Beispiel #2
0
// Download raw transaction from webbtc.com
func GetTxFromWebBTC(txid *btc.Uint256) (raw []byte) {
	url := "http://webbtc.com/tx/" + txid.String() + ".bin"
	r, er := http.Get(url)
	if er == nil && r.StatusCode == 200 {
		raw, _ = ioutil.ReadAll(r.Body)
		r.Body.Close()
	}
	return
}
Beispiel #3
0
// Adds a transaction to the rejected list or not, it it has been mined already
// Make sure to call it with locked TxMutex.
// Returns the OneTxRejected or nil if it has not been added.
func RejectTx(id *btc.Uint256, size int, why byte) *OneTxRejected {
	rec := new(OneTxRejected)
	rec.Id = id
	rec.Time = time.Now()
	rec.Size = uint32(size)
	rec.Reason = why
	TransactionsRejected[id.BIdx()] = rec
	return rec
}
Beispiel #4
0
func txChecker(h *btc.Uint256) bool {
	TxMutex.Lock()
	rec, ok := TransactionsToSend[h.BIdx()]
	TxMutex.Unlock()
	if ok && rec.Own != 0 {
		return false // Assume own txs as non-trusted
	}
	if ok {
		common.CountSafe("TxScrBoosted")
	} else {
		common.CountSafe("TxScrMissed")
	}
	return ok
}
Beispiel #5
0
// Return false if we do not want to receive a data fotr this tx
func NeedThisTx(id *btc.Uint256, cb func()) (res bool) {
	TxMutex.Lock()
	if _, present := TransactionsToSend[id.Hash]; present {
		//res = false
	} else if _, present := TransactionsRejected[id.BIdx()]; present {
		//res = false
	} else if _, present := TransactionsPending[id.Hash]; present {
		//res = false
	} else {
		res = true
		if cb != nil {
			cb()
		}
	}
	TxMutex.Unlock()
	return
}
Beispiel #6
0
func GetTx(txid *btc.Uint256, vout int) bool {
	r, er := http.Get("http://blockexplorer.com/rawtx/" + txid.String())
	if er == nil && r.StatusCode == 200 {
		defer r.Body.Close()
		c, _ := ioutil.ReadAll(r.Body)
		var txx onetx
		er = json.Unmarshal(c[:], &txx)
		if er == nil {
			tx := new(btc.Tx)
			tx.Version = txx.Ver
			tx.TxIn = make([]*btc.TxIn, len(txx.In))
			for i := range txx.In {
				tx.TxIn[i] = new(btc.TxIn)
				tx.TxIn[i].Input.Hash = btc.NewUint256FromString(txx.In[i].Prev_out.Hash).Hash
				tx.TxIn[i].Input.Vout = txx.In[i].Prev_out.N
				tx.TxIn[i].ScriptSig, _ = btc.DecodeScript(txx.In[i].ScriptSig)
				tx.TxIn[i].Sequence = 0xffffffff
			}
			tx.TxOut = make([]*btc.TxOut, len(txx.Out))
			for i := range txx.Out {
				tx.TxOut[i] = new(btc.TxOut)
				tx.TxOut[i].Value = btc.ParseValue(txx.Out[i].Value)
				tx.TxOut[i].Pk_script, _ = btc.DecodeScript(txx.Out[i].ScriptPubKey)
			}
			tx.Lock_time = txx.Lock_time
			rawtx := tx.Serialize()
			curid := btc.NewSha2Hash(rawtx)
			if !curid.Equal(txid) {
				fmt.Println("The downloaded transaction does not match its ID.")
				return false
			}
			ioutil.WriteFile("balance/"+curid.String()+".tx", rawtx, 0666)
			return true
		} else {
			fmt.Println("json.Unmarshal:", er.Error())
		}
	} else {
		if er != nil {
			fmt.Println("http.Get:", er.Error())
		} else {
			fmt.Println("StatusCode=", r.StatusCode)
		}
	}
	return false
}
Beispiel #7
0
// Return false if we do not want to receive a data for this tx
func NeedThisTx(id *btc.Uint256, cb func()) (res bool) {
	TxMutex.Lock()
	if _, present := TransactionsToSend[id.Hash]; present {
		//res = false
	} else if _, present := TransactionsRejected[id.BIdx()]; present {
		//res = false
	} else if _, present := TransactionsPending[id.Hash]; present {
		//res = false
	} else if txo, _ := common.BlockChain.Unspent.UnspentGet(&btc.TxPrevOut{Hash: id.Hash}); txo != nil {
		// This assumes that tx's out #0 has not been spent yet, which may not always be the case, but well...
		common.CountSafe("TxMinedRejected")
	} else {
		res = true
		if cb != nil {
			cb()
		}
	}
	TxMutex.Unlock()
	return
}
Beispiel #8
0
// Return false if we do not want to receive a data for this tx
func NeedThisTx(id *btc.Uint256, cb func()) (res bool) {
	TxMutex.Lock()
	if _, present := TransactionsToSend[id.Hash]; present {
		//res = false
	} else if _, present := TransactionsRejected[id.BIdx()]; present {
		//res = false
	} else if _, present := TransactionsPending[id.Hash]; present {
		//res = false
	} else if txo, _ := common.BlockChain.Unspent.UnspentGet(&btc.TxPrevOut{Hash: id.Hash}); txo != nil {
		//res = falseuint32()
		common.CountSafe("TxMinedRejected")
	} else {
		res = true
		if cb != nil {
			cb()
		}
	}
	TxMutex.Unlock()
	return
}
Beispiel #9
0
func TxMined(h *btc.Uint256) {
	TxMutex.Lock()
	if rec, ok := TransactionsToSend[h.Hash]; ok {
		common.CountSafe("TxMinedToSend")
		for i := range rec.Spent {
			delete(SpentOutputs, rec.Spent[i])
		}
		delete(TransactionsToSend, h.Hash)
	}
	if _, ok := TransactionsRejected[h.BIdx()]; ok {
		common.CountSafe("TxMinedRejected")
		deleteRejected(h.BIdx())
	}
	if _, ok := TransactionsPending[h.Hash]; ok {
		common.CountSafe("TxMinedPending")
		delete(TransactionsPending, h.Hash)
	}
	wtg := WaitingForInputs[h.BIdx()]
	TxMutex.Unlock()

	// Try to redo waiting txs
	if wtg != nil {
		common.CountSafe("TxMinedGotInput")
		RetryWaitingForInput(wtg)
	}
}
Beispiel #10
0
// Download raw transaction from blockr.io
func GetTxFromBlockrIo(txid *btc.Uint256) (raw []byte) {
	url := "http://btc.blockr.io/api/v1/tx/raw/" + txid.String()
	r, er := http.Get(url)
	if er == nil && r.StatusCode == 200 {
		defer r.Body.Close()
		c, _ := ioutil.ReadAll(r.Body)
		var txx struct {
			Status string
			Data   struct {
				Tx struct {
					Hex string
				}
			}
		}
		er = json.Unmarshal(c[:], &txx)
		if er == nil {
			raw, _ = hex.DecodeString(txx.Data.Tx.Hex)
		} else {
			println("er", er.Error())
		}
	}
	return
}
Beispiel #11
0
func SendInvToRandomPeer(typ uint32, h *btc.Uint256) {
	common.CountSafe(fmt.Sprint("NetSendOneInv", typ))

	// Prepare the inv
	inv := new([36]byte)
	binary.LittleEndian.PutUint32(inv[0:4], typ)
	copy(inv[4:36], h.Bytes())

	// Append it to PendingInvs in a random connection
	network.Mutex_net.Lock()
	idx := rand.Intn(len(network.OpenCons))
	var cnt int
	for _, v := range network.OpenCons {
		if idx == cnt {
			v.Mutex.Lock()
			v.PendingInvs = append(v.PendingInvs, inv)
			v.Mutex.Unlock()
			break
		}
		cnt++
	}
	network.Mutex_net.Unlock()
	return
}
Beispiel #12
0
// Download raw transaction from a web server (try one after another)
func GetTxFromWeb(txid *btc.Uint256) (raw []byte) {
	if raw != nil && txid.Equal(btc.NewSha2Hash(raw)) {
		//println("GetTxFromWebBTC - OK")
		return
	}

	raw = GetTxFromBlockrIo(txid)
	if raw != nil && txid.Equal(btc.NewSha2Hash(raw)) {
		//println("GetTxFromBlockrIo - OK")
		return
	}

	raw, _ = GetTxFromExplorer(txid)
	if raw != nil && txid.Equal(btc.NewSha2Hash(raw)) {
		//println("GetTxFromExplorer - OK")
		return
	}

	return
}
Beispiel #13
0
func main() {
	fmt.Println("Gocoin blockchain downloader version", btc.SourcesTag)
	parse_command_line()
	setup_runtime_vars()

	if !add_ip_str(SeedNode) {
		println("You need to specify IP address of a fast seed node.")
		println("For example run it like this: downloader -s 89.31.102.237")
		return
	}
	load_ips() // other seed nodes

	if len(GocoinHomeDir) > 0 && GocoinHomeDir[len(GocoinHomeDir)-1] != os.PathSeparator {
		GocoinHomeDir += string(os.PathSeparator)
	}
	if Testnet {
		GocoinHomeDir += "tstnet" + string(os.PathSeparator)
		Magic = [4]byte{0x0B, 0x11, 0x09, 0x07}
		DefaultTcpPort = 18333
		GenesisBlock = btc.NewUint256FromString("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")
		fmt.Println("Using testnet3")
	} else {
		GocoinHomeDir += "btcnet" + string(os.PathSeparator)
	}
	fmt.Println("GocoinHomeDir:", GocoinHomeDir)

	utils.LockDatabaseDir(GocoinHomeDir)
	defer utils.UnlockDatabaseDir()

	StartTime = time.Now()
	if open_blockchain() {
		fmt.Printf("Blockchain opening aborted\n")
		close_blockchain()
		return
	}
	fmt.Println("Blockchain open in", time.Now().Sub(StartTime))

	go do_usif()

	fmt.Println("Downloading headers from the seed peer", SeedNode)
	download_headers()
	if GlobalExit {
		close_blockchain()
		return
	}

	if DoThePings {
		fmt.Println("Tuning to other peers and trying to find the fastest ones.")
		fmt.Println("Execute command 'g' to continue to block chain download.")
		fmt.Println("Otherwise it will auto-continue after 15 minutes.")
		usif_prompt()
		do_pings()
		fmt.Println("Pings done.")
		usif_prompt()
	}

	var HighestTrustedBlock *btc.Uint256
	if LastTrustedBlock == "all" {
		HighestTrustedBlock = TheBlockChain.BlockTreeEnd.BlockHash
		fmt.Println("Assume all blocks trusted")
	} else if LastTrustedBlock == "auto" {
		if LastBlockHeight > 6 {
			ha := BlocksToGet[LastBlockHeight]
			HighestTrustedBlock = btc.NewUint256(ha[:])
			fmt.Println("Assume last trusted block as", HighestTrustedBlock.String())
		} else {
			fmt.Println("-t=auto ignored since LastBlockHeight is only", LastBlockHeight)
		}
	} else if LastTrustedBlock != "" {
		HighestTrustedBlock = btc.NewUint256FromString(LastTrustedBlock)
	}
	if HighestTrustedBlock != nil {
		for k, h := range BlocksToGet {
			if bytes.Equal(h[:], HighestTrustedBlock.Hash[:]) {
				TrustUpTo = k
				fmt.Println("All the blocks up to", TrustUpTo, "are assumed trusted")
				break
			}
		}
	} else {
		fmt.Println("None of the blocks is to be assumed trusted (it will be very slow).")
	}

	for n := TheBlockChain.BlockTreeEnd; n != nil && n.Height > TheBlockChain.BlockTreeEnd.Height-BSLEN; n = n.Parent {
		blocksize_update(int(n.BlockSize))
	}

	fmt.Println("Downloading blocks - BlocksToGet:", len(BlocksToGet), "  avg_size:", avg_block_size())
	usif_prompt()
	StartTime = time.Now()
	get_blocks()
	fmt.Println("Up to block", TheBlockChain.BlockTreeEnd.Height, "in", time.Now().Sub(StartTime).String())
	close_all_connections()

	close_blockchain()

	return
}
Beispiel #14
0
// Download (and re-assemble) raw transaction from blockexplorer.com
func GetTxFromExplorer(txid *btc.Uint256) ([]byte, []byte) {
	url := "http://blockexplorer.com/rawtx/" + txid.String()
	r, er := http.Get(url)
	if er == nil && r.StatusCode == 200 {
		defer r.Body.Close()
		c, _ := ioutil.ReadAll(r.Body)
		var txx onetx
		er = json.Unmarshal(c[:], &txx)
		if er == nil {
			// This part looks weird, but this is how I solved seq=FFFFFFFF, if the field not present:
			for i := range txx.In {
				txx.In[i].Sequence = 0xffffffff
			}
			json.Unmarshal(c[:], &txx)
			// ... end of the weird solution

			tx := new(btc.Tx)
			tx.Version = txx.Ver
			tx.TxIn = make([]*btc.TxIn, len(txx.In))
			for i := range txx.In {
				tx.TxIn[i] = new(btc.TxIn)
				tx.TxIn[i].Input.Hash = btc.NewUint256FromString(txx.In[i].Prev_out.Hash).Hash
				tx.TxIn[i].Input.Vout = txx.In[i].Prev_out.N
				if txx.In[i].Prev_out.N == 0xffffffff &&
					txx.In[i].Prev_out.Hash == "0000000000000000000000000000000000000000000000000000000000000000" {
					tx.TxIn[i].ScriptSig, _ = hex.DecodeString(txx.In[i].Coinbase)
				} else {
					tx.TxIn[i].ScriptSig, _ = btc.DecodeScript(txx.In[i].ScriptSig)
				}
				tx.TxIn[i].Sequence = txx.In[i].Sequence
			}
			tx.TxOut = make([]*btc.TxOut, len(txx.Out))
			for i := range txx.Out {
				am, er := btc.StringToSatoshis(txx.Out[i].Value)
				if er != nil {
					fmt.Println("Incorrect BTC amount", txx.Out[i].Value, er.Error())
					return nil, nil
				}
				tx.TxOut[i] = new(btc.TxOut)
				tx.TxOut[i].Value = am
				tx.TxOut[i].Pk_script, _ = btc.DecodeScript(txx.Out[i].ScriptPubKey)
			}
			tx.Lock_time = txx.Lock_time
			rawtx := tx.Serialize()
			if txx.Size != uint(len(rawtx)) {
				fmt.Printf("Transaction size mismatch: %d expexted, %d decoded\n", txx.Size, len(rawtx))
				return nil, rawtx
			}
			curid := btc.NewSha2Hash(rawtx)
			if !curid.Equal(txid) {
				fmt.Println("The downloaded transaction does not match its ID.", txid.String())
				return nil, rawtx
			}
			return rawtx, rawtx
		} else {
			fmt.Println("json.Unmarshal:", er.Error())
		}
	} else {
		if er != nil {
			fmt.Println("http.Get:", er.Error())
		} else {
			fmt.Println("StatusCode=", r.StatusCode)
		}
	}
	return nil, nil
}