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 }
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 }
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 }