Beispiel #1
0
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()
}
Beispiel #2
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.BlockSize = uint32(len(bl.Raw))
	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, bl.LastKnownHeight)
		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:
			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 #3
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 #4
0
func LocalAcceptBlock(bl *btc.Block, from *network.OneConnection) (e error) {
	sta := time.Now()
	e = common.BlockChain.AcceptBlock(bl)
	if e == nil {
		network.MutexRcv.Lock()
		network.ReceivedBlocks[bl.Hash.BIdx()].TmAccept = time.Now().Sub(sta)
		network.MutexRcv.Unlock()

		for i := 1; i < len(bl.Txs); i++ {
			network.TxMined(bl.Txs[i])
			/* dupa
			if msg:=contains_message(bl.Txs[i]); msg!=nil {
				for xx:=range msg {
					if msg[xx]<' ' || msg[xx]>127 {
						msg[xx] = '.'
					}
				}
				fmt.Println("TX", bl.Txs[i].Hash.String(), "says:", "'" + string(msg) + "'")
				textui.ShowPrompt()
			}
			*/
		}

		if int64(bl.BlockTime()) > time.Now().Add(-10*time.Minute).Unix() {
			// Freshly mined block - do the inv and beeps...
			common.Busy("NetRouteInv")
			network.NetRouteInv(2, bl.Hash, from)

			if common.CFG.Beeps.NewBlock {
				fmt.Println("\007Received block", common.BlockChain.BlockTreeEnd.Height)
				textui.ShowPrompt()
			}

			if common.CFG.Beeps.MinerID != "" {
				//_, rawtxlen := btc.NewTx(bl[bl.TxOffset:])
				if bytes.Contains(bl.Txs[0].Serialize(), []byte(common.CFG.Beeps.MinerID)) {
					fmt.Println("\007Mined by '"+common.CFG.Beeps.MinerID+"':", bl.Hash)
					textui.ShowPrompt()
				}
			}

			if common.CFG.Beeps.ActiveFork && common.Last.Block == common.BlockChain.BlockTreeEnd {
				// Last block has not changed, so it must have been an orphaned block
				bln := common.BlockChain.BlockIndex[bl.Hash.BIdx()]
				commonNode := common.Last.Block.FirstCommonParent(bln)
				forkDepth := bln.Height - commonNode.Height
				fmt.Println("Orphaned block:", bln.Height, bl.Hash.String(), bln.BlockSize>>10, "KB")
				if forkDepth > 1 {
					fmt.Println("\007\007\007WARNING: the fork is", forkDepth, "blocks deep")
				}
				textui.ShowPrompt()
			}

			if wallet.BalanceChanged && common.CFG.Beeps.NewBalance {
				fmt.Print("\007")
			}
		}

		common.Last.Mutex.Lock()
		common.Last.Time = time.Now()
		common.Last.Block = common.BlockChain.BlockTreeEnd
		common.Last.Mutex.Unlock()

		if wallet.BalanceChanged {
			wallet.BalanceChanged = false
			fmt.Println("Your balance has just changed")
			fmt.Print(wallet.DumpBalance(wallet.MyBalance, nil, false, true))
			textui.ShowPrompt()
		}
	} else {
		fmt.Println("Warning: AcceptBlock failed. If the block was valid, you may need to rebuild the unspent DB (-r)")
	}
	return
}
Beispiel #5
0
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.")
}
Beispiel #6
0
func (ch *Chain) CheckBlock(bl *btc.Block) (er error, dos bool, maybelater bool) {
	// Size limits
	if len(bl.Raw) < 81 || len(bl.Raw) > btc.MAX_BLOCK_SIZE {
		er = errors.New("CheckBlock() : size limits failed")
		dos = true
		return
	}

	if bl.Version() == 0 {
		er = errors.New("CheckBlock() : Block version 0 not allowed")
		dos = true
		return
	}

	// 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")
		dos = true
		return
	}

	if prv, pres := ch.BlockIndex[bl.Hash.BIdx()]; pres {
		if prv.Parent == nil {
			// This is genesis block
			er = errors.New("Genesis")
			return
		} else {
			er = errors.New("CheckBlock: " + bl.Hash.String() + " already in")
			return
		}
	}

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

	height := prevblk.Height + 1

	// Reject the block if it reaches into the chain deeper than our unwind buffer
	if prevblk != ch.BlockTreeEnd && int(ch.BlockTreeEnd.Height)-int(height) >= MovingCheckopintDepth {
		er = errors.New(fmt.Sprint("CheckBlock: btc.Block ", bl.Hash.String(),
			" hooks too deep into the chain: ", height, "/", ch.BlockTreeEnd.Height, " ",
			btc.NewUint256(bl.ParentHash()).String()))
		return
	}

	// Check proof of work
	gnwr := ch.GetNextWorkRequired(prevblk, bl.BlockTime())
	if bl.Bits() != gnwr {
		println("AcceptBlock() : incorrect proof of work ", bl.Bits, " at block", height, " exp:", gnwr)

		// Here is a "solution" for whatever shit there is in testnet3, that nobody can explain me:
		if !ch.testnet() || (height%2016) != 0 {
			er = errors.New("CheckBlock: incorrect proof of work")
			dos = true
			return
		}
	}

	// Count block versions within the Majority Window
	var majority_v2, majority_v3 uint
	n := prevblk
	for cnt := uint(0); cnt < ch.Consensus.Window && n != nil; cnt++ {
		ver := binary.LittleEndian.Uint32(n.BlockHeader[0:4])
		if ver >= 2 {
			majority_v2++
			if ver >= 3 {
				majority_v3++
			}
		}
		n = n.Parent
	}

	if bl.Version() < 2 && majority_v2 >= ch.Consensus.RejectBlock {
		er = errors.New("CheckBlock() : Rejected nVersion=1 block")
		dos = true
		return
	}

	if bl.Version() < 3 && majority_v3 >= ch.Consensus.RejectBlock {
		er = errors.New("CheckBlock() : Rejected nVersion=2 block")
		dos = true
		return
	}

	if bl.Txs == nil {
		er = bl.BuildTxList()
		if er != nil {
			dos = true
			return
		}
	}

	if !bl.Trusted {
		if bl.Version() >= 2 && majority_v2 >= ch.Consensus.EnforceUpgrade {
			var exp []byte
			if height >= 0x800000 {
				if height >= 0x80000000 {
					exp = []byte{5, byte(height), byte(height >> 8), byte(height >> 16), byte(height >> 24), 0}
				} else {
					exp = []byte{4, byte(height), byte(height >> 8), byte(height >> 16), byte(height >> 24)}
				}
			} else {
				exp = []byte{3, byte(height), byte(height >> 8), byte(height >> 16)}
			}
			if len(bl.Txs[0].TxIn[0].ScriptSig) < len(exp) || !bytes.Equal(exp, bl.Txs[0].TxIn[0].ScriptSig[:len(exp)]) {
				er = errors.New("CheckBlock() : Unexpected block number in coinbase: " + bl.Hash.String())
				dos = true
				return
			}
		}

		// This is a stupid check, but well, we need to be satoshi compatible
		if len(bl.Txs) == 0 || !bl.Txs[0].IsCoinBase() {
			er = errors.New("CheckBlock() : first tx is not coinbase: " + bl.Hash.String())
			dos = true
			return
		}

		// Check Merkle Root - that's importnant
		if !bytes.Equal(btc.GetMerkel(bl.Txs), bl.MerkleRoot()) {
			er = errors.New("CheckBlock() : Merkle Root mismatch")
			dos = true
			return
		}

		// Check transactions - this is the most time consuming task
		if !CheckTransactions(bl.Txs, height, bl.BlockTime()) {
			er = errors.New("CheckBlock() : CheckTransactions() failed")
			dos = true
			return
		}
	}

	if bl.BlockTime() >= BIP16SwitchTime {
		bl.VerifyFlags = script.VER_P2SH
	} else {
		bl.VerifyFlags = 0
	}

	if majority_v3 >= ch.Consensus.EnforceUpgrade {
		bl.VerifyFlags |= script.VER_DERSIG
	}

	return
}