// Make sure to call with the mutex locked func (db *BlockDB) addToCache(h *btc.Uint256, bl []byte, str *btc.Block) (crec *BlckCachRec) { if db.cache == nil { return } crec = db.cache[h.BIdx()] if crec != nil { crec.Data = bl if str != nil { crec.Block = str } crec.LastUsed = time.Now() return } if len(db.cache) >= db.max_cached_blocks { var oldest_t time.Time var oldest_k [btc.Uint256IdxLen]byte for k, v := range db.cache { if oldest_t.IsZero() || v.LastUsed.Before(oldest_t) { oldest_t = v.LastUsed oldest_k = k } } delete(db.cache, oldest_k) } crec = &BlckCachRec{LastUsed: time.Now(), Data: bl, Block: str} db.cache[h.BIdx()] = crec return }
// 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 { if 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 { fmt.Println("btc.blockr.io StatusCode=", r.StatusCode) } } if er != nil { fmt.Println("btc.blockr.io:", er.Error()) } return }
func (c *OneConnection) SendCmpctBlk(hash *btc.Uint256) { crec := GetchBlockForBIP152(hash) if crec == nil { fmt.Println(c.ConnID, "cmpctblock not sent for", hash.String()) return } k0 := binary.LittleEndian.Uint64(crec.BIP152[8:16]) k1 := binary.LittleEndian.Uint64(crec.BIP152[16:24]) msg := new(bytes.Buffer) msg.Write(crec.Data[:80]) msg.Write(crec.BIP152[:8]) btc.WriteVlen(msg, uint64(len(crec.Block.Txs)-1)) // all except coinbase for i := 1; i < len(crec.Block.Txs); i++ { var lsb [8]byte var hasz *btc.Uint256 if c.Node.SendCmpctVer == 2 { hasz = crec.Block.Txs[i].WTxID() } else { hasz = crec.Block.Txs[i].Hash } binary.LittleEndian.PutUint64(lsb[:], siphash.Hash(k0, k1, hasz.Hash[:])) msg.Write(lsb[:6]) } msg.Write([]byte{1}) // one preffiled tx msg.Write([]byte{0}) // coinbase - index 0 if c.Node.SendCmpctVer == 2 { msg.Write(crec.Block.Txs[0].Raw) // coinbase - index 0 } else { crec.Block.Txs[0].WriteSerialized(msg) // coinbase - index 0 } c.SendRawMsg("cmpctblock", msg.Bytes()) }
// 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 }
// 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 }
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 }
// Download raw transaction from a web server (try one after another) func GetTxFromWeb(txid *btc.Uint256) (raw []byte) { raw = GetTxFromExplorer(txid) if raw != nil && txid.Equal(btc.NewSha2Hash(raw)) { println("GetTxFromExplorer - OK") return } raw = GetTxFromWebBTC(txid) 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 = GetTxFromBlockchainInfo(txid) if raw != nil && txid.Equal(btc.NewSha2Hash(raw)) { println("GetTxFromBlockchainInfo - OK") return } return }
func (db *BlockDB) BlockGetExt(hash *btc.Uint256) (cacherec *BlckCachRec, trusted bool, e error) { db.mutex.Lock() rec, ok := db.blockIndex[hash.BIdx()] if !ok { db.mutex.Unlock() e = errors.New("btc.Block not in the index") return } trusted = rec.trusted if db.cache != nil { if crec, hit := db.cache[hash.BIdx()]; hit { cacherec = crec crec.LastUsed = time.Now() db.mutex.Unlock() return } } db.mutex.Unlock() bl := make([]byte, rec.blen) // we will re-open the data file, to not spoil the writting pointer f, e := os.Open(db.dirname + "blockchain.dat") if e != nil { return } _, e = f.Seek(int64(rec.fpos), os.SEEK_SET) if e == nil { _, e = f.Read(bl[:]) } f.Close() if rec.compressed { if rec.snappied { bl, _ = snappy.Decode(nil, bl) } else { gz, _ := gzip.NewReader(bytes.NewReader(bl)) bl, _ = ioutil.ReadAll(gz) gz.Close() } } db.mutex.Lock() cacherec = db.addToCache(hash, bl, nil) db.mutex.Unlock() return }
// This function is called from the main thread (or from an UI) func NetRouteInvExt(typ uint32, h *btc.Uint256, fromConn *OneConnection, fee_spkb uint64) (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 send_inv := true v.Mutex.Lock() if typ == MSG_TX { if v.Node.DoNotRelayTxs { send_inv = false common.CountSafe("SendInvNoTxNode") } else if v.X.MinFeeSPKB > 0 && uint64(v.X.MinFeeSPKB) > fee_spkb { send_inv = false common.CountSafe("SendInvFeeTooLow") } /* This is to prevent sending own txs to "spying" peers: else if fromConn==nil && v.X.InvsRecieved==0 { send_inv = false common.CountSafe("SendInvOwnBlocked") } */ } if send_inv { if len(v.PendingInvs) < 500 { if typ, ok := v.InvDone.Map[hash2invid(inv[4:36])]; ok { common.CountSafe(fmt.Sprint("SendInvSame-", typ)) } else { v.PendingInvs = append(v.PendingInvs, inv) cnt++ } } else { common.CountSafe("SendInvFull") } } v.Mutex.Unlock() } } Mutex_net.Unlock() return }
// Download raw transaction from webbtc.com func GetTxFromWebBTC(txid *btc.Uint256) (raw []byte) { url := "https://webbtc.com/tx/" + txid.String() + ".bin" r, er := http.Get(url) if er == nil { if r.StatusCode == 200 { raw, _ = ioutil.ReadAll(r.Body) r.Body.Close() } else { fmt.Println("webbtc.com StatusCode=", r.StatusCode) } } if er != nil { fmt.Println("webbtc.com:", er.Error()) } return }
// Download (and re-assemble) raw transaction from blockexplorer.com func GetTxFromBlockchainInfo(txid *btc.Uint256) (rawtx []byte) { url := "https://blockchain.info/tx/" + txid.String() + "?format=hex" r, er := http.Get(url) if er == nil { if r.StatusCode == 200 { defer r.Body.Close() rawhex, _ := ioutil.ReadAll(r.Body) rawtx, er = hex.DecodeString(string(rawhex)) } else { fmt.Println("blockchain.info StatusCode=", r.StatusCode) } } if er != nil { fmt.Println("blockexplorer.com:", er.Error()) } return }
func (db *BlockDB) addToCache(h *btc.Uint256, bl []byte) { if rec, ok := db.cache[h.BIdx()]; ok { rec.used = time.Now() return } if uint(len(db.cache)) >= MaxCachedBlocks { var oldest_t time.Time var oldest_k [btc.Uint256IdxLen]byte for k, v := range db.cache { if oldest_t.IsZero() || v.used.Before(oldest_t) { oldest_t = v.used oldest_k = k } } delete(db.cache, oldest_k) } db.cache[h.BIdx()] = &cacheRecord{used: time.Now(), data: bl} }
// Get tx with given id from the balance folder, of from cache func tx_from_balance(txid *btc.Uint256, error_is_fatal bool) (tx *btc.Tx) { if tx = loadedTxs[txid.Hash]; tx != nil { return // we have it in cache already } fn := "balance/" + txid.String() + ".tx" buf, er := ioutil.ReadFile(fn) if er == nil && buf != nil { var th [32]byte btc.ShaHash(buf, th[:]) if txid.Hash == th { tx, _ = btc.NewTx(buf) if error_is_fatal && tx == nil { println("Transaction is corrupt:", txid.String()) cleanExit(1) } } else if error_is_fatal { println("Transaction file is corrupt:", txid.String()) cleanExit(1) } } else if error_is_fatal { println("Error reading transaction file:", fn) if er != nil { println(er.Error()) } cleanExit(1) } loadedTxs[txid.Hash] = tx // store it in the cache return }
func GetchBlockForBIP152(hash *btc.Uint256) (crec *chain.BlckCachRec) { crec, _, _ = common.BlockChain.Blocks.BlockGetExt(hash) if crec == nil { fmt.Println("BlockGetExt failed for", hash.String()) return } if crec.Block == nil { crec.Block, _ = btc.NewBlock(crec.Data) if crec.Block == nil { fmt.Println("SendCmpctBlk: btc.NewBlock() failed for", hash.String()) return } } if len(crec.Block.Txs) == 0 { if crec.Block.BuildTxList() != nil { fmt.Println("SendCmpctBlk: bl.BuildTxList() failed for", hash.String()) return } } if len(crec.BIP152) != 24 { crec.BIP152 = make([]byte, 24) copy(crec.BIP152[:8], crec.Data[48:56]) // set the nonce to 8 middle-bytes of block's merkle_root sha := sha256.New() sha.Write(crec.Data[:80]) sha.Write(crec.BIP152[:8]) copy(crec.BIP152[8:24], sha.Sum(nil)[0:16]) } return }
// Download (and re-assemble) raw transaction from blockexplorer.com func GetTxFromExplorer(txid *btc.Uint256) (rawtx []byte) { url := "http://blockexplorer.com/api/rawtx/" + txid.String() r, er := http.Get(url) if er == nil { if r.StatusCode == 200 { defer r.Body.Close() c, _ := ioutil.ReadAll(r.Body) var txx struct { Raw string `json:"rawtx"` } er = json.Unmarshal(c[:], &txx) if er == nil { rawtx, er = hex.DecodeString(txx.Raw) } } else { fmt.Println("blockexplorer.com StatusCode=", r.StatusCode) } } if er != nil { fmt.Println("blockexplorer.com:", er.Error()) } return }
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 }
// 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() if cnt == 0 { NetAlerts <- "WARNING: your tx has not been broadcasted to any peer" } return }
// 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.BIdx()]; present { //res = false } else if _, present := TransactionsRejected[id.BIdx()]; present { //res = false } else if _, present := TransactionsPending[id.BIdx()]; 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 }
func main() { if len(os.Args) < 2 { fmt.Println("Specify a path to folder containig blockchain.dat and blockchain.new") fmt.Println("Output bootstrap.dat file will be written in the current folder.") return } blks := chain.NewBlockDB(os.Args[1]) if blks == nil { return } fmt.Println("Loading block index...") bidx = make(map[[32]byte]*chain.BlockTreeNode, 300e3) blks.LoadBlockIndex(nil, walk) var tail, nd *chain.BlockTreeNode var genesis_block_hash *btc.Uint256 for _, v := range bidx { if v == tail { // skip root block (should be only one) continue } par_hash := btc.NewUint256(v.BlockHeader[4:36]) par, ok := bidx[par_hash.Hash] if !ok { genesis_block_hash = par_hash } else { v.Parent = par if tail == nil || v.Height > tail.Height { tail = v } } } if genesis_block_hash == nil { println("genesis_block_hash not found") return } var magic []byte gen_bin, _ := hex.DecodeString(GenesisBitcoin) tmp := btc.NewSha2Hash(gen_bin[:80]) if genesis_block_hash.Equal(tmp) { println("Bitcoin genesis block") magic = []byte{0xF9, 0xBE, 0xB4, 0xD9} } if magic == nil { gen_bin, _ := hex.DecodeString(GenesisTestnet) tmp = btc.NewSha2Hash(gen_bin[:80]) if genesis_block_hash.Equal(tmp) { println("Testnet3 genesis block") magic = []byte{0x0B, 0x11, 0x09, 0x07} } } if magic == nil { println("Unknow genesis block", genesis_block_hash.String()) println("Aborting since cannot figure out the magic bytes") return } var total_data, curr_data int64 for nd = tail; nd.Parent != nil; { nd.Parent.Childs = []*chain.BlockTreeNode{nd} total_data += int64(nd.BlockSize) nd = nd.Parent } fmt.Println("Writting bootstrap.dat, height", tail.Height, " magic", hex.EncodeToString(magic)) f, _ := os.Create("bootstrap.dat") f.Write(magic) binary.Write(f, binary.LittleEndian, uint32(len(gen_bin))) f.Write(gen_bin) for { bl, _, _ := blks.BlockGet(nd.BlockHash) f.Write(magic) binary.Write(f, binary.LittleEndian, uint32(len(bl))) f.Write(bl) curr_data += int64(nd.BlockSize) if (nd.Height & 0xfff) == 0 { fmt.Printf("\r%.1f%%...", 100*float64(curr_data)/float64(total_data)) } if len(nd.Childs) == 0 { break } nd = nd.Childs[0] } fmt.Println("\rDone ") }
// 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 }
func main() { fmt.Println("Gocoin blockchain downloader version", lib.Version) parse_command_line() setup_runtime_vars() 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} GenesisBlock = btc.NewUint256FromString("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943") fmt.Println("Using testnet3") } else { GocoinHomeDir += "btcnet" + string(os.PathSeparator) } fmt.Println("GocoinHomeDir:", GocoinHomeDir) sys.LockDatabaseDir(GocoinHomeDir) defer sys.UnlockDatabaseDir() peersdb.Testnet = Testnet peersdb.InitPeers(GocoinHomeDir) StartTime = time.Now() if open_blockchain() { fmt.Printf("Blockchain opening aborted\n") return } fmt.Println("Blockchain open in", time.Now().Sub(StartTime)) go do_usif() download_headers() if GlobalExit() { TheBlockChain.Close() return } var HighestTrustedBlock *btc.Uint256 if LastTrustedBlock == "all" { HighestTrustedBlock = TheBlockChain.BlockTreeEnd.BlockHash fmt.Println("Assume all blocks trusted") } else if LastTrustedBlock == "auto" { if LastBlockHeight > 6 { use := LastBlockHeight - 6 ha := BlocksToGet[use] HighestTrustedBlock = btc.NewUint256(ha[:]) fmt.Println("Assume last trusted block as", HighestTrustedBlock.String(), "at", use) } 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 break } } } else { fmt.Println("WARNING: The trusted block not found (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() peersdb.ClosePeerDB() StartTime = time.Now() fmt.Print("All blocks done - defrag unspent") qdb.SetDefragPercent(100) for { if !TheBlockChain.Unspent.Idle() { break } fmt.Print(".") } fmt.Println("\nDefrag unspent done in", time.Now().Sub(StartTime).String()) TheBlockChain.Close() return }
func main() { fmt.Println("Gocoin blockchain downloader version", lib.Version) 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) sys.LockDatabaseDir(GocoinHomeDir) defer sys.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 }
func blockReceived(bh *btc.Uint256) (ok bool) { MutexRcv.Lock() _, ok = ReceivedBlocks[bh.BIdx()] MutexRcv.Unlock() return }