// 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 }
func get_blocks() { var bl *btc.Block DlStartTime = time.Now() BlocksMutex.Lock() BlocksComplete = TheBlockChain.BlockTreeEnd.Height CurrentBlockHeight := BlocksComplete + 1 BlocksMutex.Unlock() TheBlockChain.DoNotSync = true tickSec := time.Tick(time.Second) tickDrop := time.Tick(DROP_PEER_EVERY_SEC * time.Second) tickStat := time.Tick(6 * time.Second) for !GlobalExit() && CurrentBlockHeight <= LastBlockHeight { select { case <-tickSec: cc := open_connection_count() if cc > MaxNetworkConns { drop_slowest_peers() } else if cc < MaxNetworkConns { add_new_connections() } case <-tickStat: print_stats() usif_prompt() case <-tickDrop: if open_connection_count() >= MaxNetworkConns { drop_slowest_peers() } case bl = <-BlockQueue: bl.Trusted = CurrentBlockHeight <= TrustUpTo if OnlyStoreBlocks { TheBlockChain.Blocks.BlockAdd(CurrentBlockHeight, bl) } else { er, _, _ := TheBlockChain.CheckBlock(bl) if er != nil { fmt.Println("CheckBlock:", er.Error()) return } else { bl.LastKnownHeight = CurrentBlockHeight + uint32(len(BlockQueue)) TheBlockChain.AcceptBlock(bl) } } atomic.StoreUint32(&LastStoredBlock, CurrentBlockHeight) atomic.AddUint64(&DlBytesProcessed, uint64(len(bl.Raw))) CurrentBlockHeight++ case <-time.After(100 * time.Millisecond): COUNTER("IDLE") TheBlockChain.Unspent.Idle() } } TheBlockChain.Sync() }
func (ch *Chain) CommitBlock(bl *btc.Block, cur *BlockTreeNode) (e error) { cur.BlockSize = uint32(len(bl.Raw)) cur.TxCount = uint32(bl.TxCount) if ch.BlockTreeEnd == cur.Parent { // The head of out chain - apply the transactions var changes *BlockChanges changes, e = ch.ProcessBlockTransactions(bl, cur.Height, bl.LastKnownHeight) if e != nil { // ProcessBlockTransactions failed, so trash the block. println("ProcessBlockTransactionsA", cur.BlockHash.String(), cur.Height, e.Error()) ch.BlockIndexAccess.Lock() cur.Parent.delChild(cur) delete(ch.BlockIndex, cur.BlockHash.BIdx()) ch.BlockIndexAccess.Unlock() } else { cur.SigopsCost = bl.SigopsCost // 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: 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) if ch.BlockTreeEnd != cur { e = errors.New("CommitBlock: MoveToBlock failed") } } } return }
func import_blockchain(dir string) { BlockDatabase := blockdb.NewBlockDB(dir, Magic) chain := chain.NewChain(GocoinHomeDir, GenesisBlock, false) var bl *btc.Block var er error var dat []byte var totbytes, perbytes uint64 chain.DoNotSync = true fmt.Println("Be patient while importing Satoshi's database... ") start := time.Now().UnixNano() prv := start for { now := time.Now().UnixNano() if now-prv >= 10e9 { stat(now-start, now-prv, totbytes, perbytes, chain.BlockTreeEnd.Height) prv = now // show progress each 10 seconds perbytes = 0 } dat, er = BlockDatabase.FetchNextBlock() if dat == nil || er != nil { println("END of DB file") break } bl, er = btc.NewBlock(dat[:]) if er != nil { println("Block inconsistent:", er.Error()) break } bl.Trusted = Trust er, _, _ = chain.CheckBlock(bl) if er != nil { if er.Error() != "Genesis" { println("CheckBlock failed:", er.Error()) os.Exit(1) // Such a thing should not happen, so let's better abort here. } continue } er = chain.AcceptBlock(bl) if er != nil { println("AcceptBlock failed:", er.Error()) os.Exit(1) // Such a thing should not happen, so let's better abort here. } totbytes += uint64(len(bl.Raw)) perbytes += uint64(len(bl.Raw)) } stop := time.Now().UnixNano() stat(stop-start, stop-prv, totbytes, perbytes, chain.BlockTreeEnd.Height) fmt.Println("Satoshi's database import finished in", (stop-start)/1e9, "seconds") fmt.Println("Now saving the new database...") chain.Save() chain.Close() fmt.Println("Database saved. No more imports should be needed.") }
func get_blocks() { var bl *btc.Block BlocksInProgress = make(map[[32]byte]*one_bip) BlocksCached = make(map[uint32]*btc.Block) //fmt.Println("opening connections") DlStartTime = time.Now() BlocksComplete = TheBlockChain.BlockTreeEnd.Height BlocksIndex = BlocksComplete SetDoBlocks(true) ct := time.Now().Unix() lastdrop := ct laststat := ct TheBlockChain.DoNotSync = true var blks2do []*btc.Block for GetDoBlocks() { BlocksMutex.Lock() if BlocksComplete >= LastBlockHeight { BlocksMutex.Unlock() break } for { bl = BlocksCached[BlocksComplete+1] if bl == nil { break } BlocksComplete++ if BlocksComplete > BlocksIndex { BlocksIndex = BlocksComplete } bl.Trusted = BlocksComplete <= TrustUpTo if OnlyStoreBlocks { TheBlockChain.Blocks.BlockAdd(BlocksComplete, bl) } else { blks2do = append(blks2do, bl) } atomic.AddUint64(&DlBytesProcesses, uint64(len(bl.Raw))) delete(BlocksCached, BlocksComplete) BlocksCachedSize -= uint(len(bl.Raw)) } BlocksMutex.Unlock() if len(blks2do) > 0 { for idx := range blks2do { er, _, _ := TheBlockChain.CheckBlock(blks2do[idx]) if er != nil { fmt.Println(er.Error()) return } blks2do[idx].LastKnownHeight = BlocksComplete TheBlockChain.AcceptBlock(blks2do[idx]) } blks2do = nil } else { TheBlockChain.Unspent.Idle() COUNTER("IDLE") } time.Sleep(1e8) ct = time.Now().Unix() if open_connection_count() > MaxNetworkConns { drop_slowest_peers() } else { // drop slowest peers once for awhile occ := MaxNetworkConns if occ > 0 { occ = 1200 / occ // For 20 open connections: drop one per minute if occ < 3 { occ = 3 // .. drop not more often then once sper 3 seconds } if ct-lastdrop > int64(occ) { lastdrop = ct drop_slowest_peers() } } } add_new_connections() if ct-laststat >= 5 { laststat = ct print_stats() usif_prompt() } } }