// 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 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 }
// Make sure to call this function with ch.BlockIndexAccess locked func (ch *Chain) AcceptHeader(bl *btc.Block) (cur *BlockTreeNode) { 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 copy(cur.BlockHeader[:], bl.Raw[:80]) // Add this block to the block index prevblk.addChild(cur) ch.BlockIndex[cur.BlockHash.BIdx()] = cur 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 } // 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 } // Reject the block if it reaches into the chain deeper than our unwind buffer if prevblk != ch.BlockTreeEnd && int(ch.BlockTreeEnd.Height)-int(prevblk.Height+1) >= MovingCheckopintDepth { er = errors.New(fmt.Sprint("CheckBlock: btc.Block ", bl.Hash.String(), " hooks too deep into the chain: ", prevblk.Height+1, "/", 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", prevblk.Height+1, " exp:", gnwr) // Here is a "solution" for whatever shit there is in testnet3, that nobody can explain me: if !ch.testnet() || ((prevblk.Height+1)%2016) != 0 { er = errors.New("CheckBlock: incorrect proof of work") dos = true return } } if bl.Txs == nil { er = bl.BuildTxList() if er != nil { dos = true return } } if !bl.Trusted { // 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 for i := 0; i < len(bl.Txs); i++ { er = bl.Txs[i].CheckTransaction() if er != nil { er = errors.New("CheckBlock() : CheckTransaction failed: " + er.Error()) dos = true return } if !bl.Txs[i].IsFinal(prevblk.Height+1, bl.BlockTime()) { er = errors.New("CheckBlock() : Contains transaction that is not final") return } } } 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 }
func (ch *Chain) PreCheckBlock(bl *btc.Block) (er error, dos bool, maybelater bool) { // Size limits if len(bl.Raw) < 81 { er = errors.New("CheckBlock() : size limits failed - RPC_Result:bad-blk-length") dos = true return } if bl.Version() == 0 { er = errors.New("CheckBlock() : Block version 0 not allowed - RPC_Result:bad-version") dos = true return } // Check proof-of-work if !btc.CheckProofOfWork(bl.Hash, bl.Bits()) { er = errors.New("CheckBlock() : proof of work failed - RPC_Result:high-hash") 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 - RPC_Result:time-too-new") 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 - RPC_Result:duplicate") return } } prevblk, ok := ch.BlockIndex[btc.NewUint256(bl.ParentHash()).BIdx()] if !ok { er = errors.New("CheckBlock: " + bl.Hash.String() + " parent not found - RPC_Result:bad-prevblk") maybelater = true return } bl.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(bl.Height) >= MovingCheckopintDepth { er = errors.New(fmt.Sprint("CheckBlock: btc.Block ", bl.Hash.String(), " hooks too deep into the chain: ", bl.Height, "/", ch.BlockTreeEnd.Height, " ", btc.NewUint256(bl.ParentHash()).String(), " - RPC_Result:bad-prevblk")) return } // Check proof of work gnwr := ch.GetNextWorkRequired(prevblk, bl.BlockTime()) if bl.Bits() != gnwr { er = errors.New("CheckBlock: incorrect proof of work - RPC_Result:bad-diffbits") dos = true return } // Check timestamp against prev bl.MedianPastTime = prevblk.GetMedianTimePast() if bl.BlockTime() <= bl.MedianPastTime { er = errors.New("CheckBlock: block's timestamp is too early - RPC_Result:time-too-old") dos = true return } if bl.Version() < 2 && bl.Height >= ch.Consensus.BIP34Height || bl.Version() < 3 && bl.Height >= ch.Consensus.BIP66Height || bl.Version() < 4 && bl.Height >= ch.Consensus.BIP65Height { // bad block version erstr := fmt.Sprintf("0x%08x", bl.Version()) er = errors.New("CheckBlock() : Rejected Version=" + erstr + " blolck - RPC_Result:bad-version(" + erstr + ")") dos = true return } return }