// checkProofOfWork ensures the block header bits which indicate the target // difficulty is in min/max range and that the block hash is less than the // target difficulty as claimed. func checkProofOfWork(block *btcutil.Block, powLimit *big.Int) error { // The target difficulty must be larger than zero. target := CompactToBig(block.MsgBlock().Header.Bits) if target.Sign() <= 0 { str := fmt.Sprintf("block target difficulty of %064x is too low", target) return RuleError(str) } // The target difficulty must be less than the maximum allowed. if target.Cmp(powLimit) > 0 { str := fmt.Sprintf("block target difficulty of %064x is "+ "higher than max of %064x", target, powLimit) return RuleError(str) } // The block hash must be less than the claimed target. blockHash, err := block.Sha() if err != nil { return err } hashNum := ShaHashToBig(blockHash) if hashNum.Cmp(target) > 0 { str := fmt.Sprintf("block hash of %064x is higher than "+ "expected max of %064x", hashNum, target) return RuleError(str) } return nil }
// connectBlock handles connecting the passed node/block to the end of the main // (best) chain. func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block) error { // Make sure it's extending the end of the best chain. prevHash := &block.MsgBlock().Header.PrevBlock if b.bestChain != nil && !prevHash.IsEqual(b.bestChain.hash) { return fmt.Errorf("connectBlock must be called with a block " + "that extends the main chain") } // Insert the block into the database which houses the main chain. _, err := b.db.InsertBlock(block) if err != nil { return err } // Add the new node to the memory main chain indices for faster // lookups. node.inMainChain = true b.index[*node.hash] = node b.depNodes[*prevHash] = append(b.depNodes[*prevHash], node) // This node is now the end of the best chain. b.bestChain = node // Notify the caller that the block was connected to the main chain. // The caller would typically want to react with actions such as // updating wallets. b.sendNotification(NTBlockConnected, block) return nil }
// Process block takes care of sorting out transactions with exodus output. // At this point it doesn't matter whether the Txs are valid or not. Validation // is done at the proper handlers. func (s *MastercoinServer) ProcessBlock(block *btcutil.Block) error { // Gather transactions from this block which had an exodus output txPack := &TxPack{ txs: mscutil.GetExodusTransactions(block), time: block.MsgBlock().Header.Timestamp.Unix(), height: block.Height(), } if len(txPack.txs) > 0 { /* TODO: We want to start persisting raw data here var buffer bytes.Buffer enc := gob.NewEncoder(&buffer) err := enc.Encode(txPack) if err != nil { mscutil.Logger.Fatal(err) } dec := gob.NewDecoder(&buffer) var pack TxPack err = dec.Decode(&pack) if err != nil { mscutil.Logger.Fatal(err) } */ // Queue the slice of transactions for further processing by the // message parser. _ = s.msgParser.ProcessTransactions(txPack) // mscutil.Logger.Println(messages) } return nil }
// disconnectTransactions updates the passed map by undoing transaction and // spend information for all transactions in the passed block. Only // transactions in the passed map are updated. func disconnectTransactions(txStore TxStore, block *btcutil.Block) error { // Loop through all of the transactions in the block to see if any of // them are ones that need to be undone based on the transaction store. for _, tx := range block.Transactions() { // Clear this transaction from the transaction store if needed. // Only clear it rather than deleting it because the transaction // connect code relies on its presence to decide whether or not // to update the store and any transactions which exist on both // sides of a fork would otherwise not be updated. if txD, exists := txStore[*tx.Sha()]; exists { txD.Tx = nil txD.BlockHeight = 0 txD.Spent = nil txD.Err = btcdb.ErrTxShaMissing } // Unspend the origin transaction output. for _, txIn := range tx.MsgTx().TxIn { originHash := &txIn.PreviousOutPoint.Hash originIndex := txIn.PreviousOutPoint.Index originTx, exists := txStore[*originHash] if exists && originTx.Tx != nil && originTx.Err == nil { if originIndex > uint32(len(originTx.Spent)) { continue } originTx.Spent[originIndex] = false } } } return nil }
// connectTransactions updates the passed map by applying transaction and // spend information for all the transactions in the passed block. Only // transactions in the passed map are updated. func connectTransactions(txStore TxStore, block *btcutil.Block) error { // Loop through all of the transactions in the block to see if any of // them are ones we need to update and spend based on the results map. for _, tx := range block.Transactions() { // Update the transaction store with the transaction information // if it's one of the requested transactions. msgTx := tx.MsgTx() if txD, exists := txStore[*tx.Sha()]; exists { txD.Tx = tx txD.BlockHeight = block.Height() txD.Spent = make([]bool, len(msgTx.TxOut)) txD.Err = nil } // Spend the origin transaction output. for _, txIn := range msgTx.TxIn { originHash := &txIn.PreviousOutPoint.Hash originIndex := txIn.PreviousOutPoint.Index if originTx, exists := txStore[*originHash]; exists { if originIndex > uint32(len(originTx.Spent)) { continue } originTx.Spent[originIndex] = true } } } return nil }
// Process block takes care of sorting out transactions with exodus output. // At this point it doesn't matter whether the Txs are valid or not. Validation // is done at the proper handlers. func (s *MastercoinServer) ProcessBlock(block *btcutil.Block) error { // Gather transactions from this block which had an exodus output txPack := &mscutil.TxPack{ Txs: mscutil.GetExodusTransactions(block), Time: block.MsgBlock().Header.Timestamp.Unix(), Height: block.Height(), } // Update Exodus Vesting // // balance = ((1-(0.5 ** time_difference)) * 5631623576222 .round(8) if len(txPack.Txs) > 0 { serializedData, err := txPack.Serialize() if err != nil { return err } s.db.CreateTxPack(txPack.Height, serializedData) mscutil.Logger.Println("Mastercoin data found at block with height:", txPack.Height) // Queue the slice of transactions for further processing by the // message parser. _ = s.msgParser.ProcessTransactions(txPack) } return nil }
// checkProofOfWork ensures the block header bits which indicate the target // difficulty is in min/max range and that the block hash is less than the // target difficulty as claimed. // // // The flags modify the behavior of this function as follows: // - BFNoPoWCheck: The check to ensure the block hash is less than the target // difficulty is not performed. func checkProofOfWork(block *btcutil.Block, powLimit *big.Int, flags BehaviorFlags) error { // The target difficulty must be larger than zero. target := CompactToBig(block.MsgBlock().Header.Bits) if target.Sign() <= 0 { str := fmt.Sprintf("block target difficulty of %064x is too low", target) return ruleError(ErrUnexpectedDifficulty, str) } // The target difficulty must be less than the maximum allowed. if target.Cmp(powLimit) > 0 { str := fmt.Sprintf("block target difficulty of %064x is "+ "higher than max of %064x", target, powLimit) return ruleError(ErrUnexpectedDifficulty, str) } // The block hash must be less than the claimed target unless the flag // to avoid proof of work checks is set. if flags&BFNoPoWCheck != BFNoPoWCheck { // The block hash must be less than the claimed target. blockHash, err := block.Sha() if err != nil { return err } hashNum := ShaHashToBig(blockHash) if hashNum.Cmp(target) > 0 { str := fmt.Sprintf("block hash of %064x is higher than "+ "expected max of %064x", hashNum, target) return ruleError(ErrHighHash, str) } } return nil }
// NotifyBlockConnected creates and marshalls a JSON message to notify // of a new block connected to the main chain. The notification is sent // to each connected wallet. func (s *rpcServer) NotifyBlockConnected(block *btcutil.Block) { hash, err := block.Sha() if err != nil { rpcsLog.Error("Bad block; connected block notification dropped.") return } // TODO: remove int32 type conversion. ntfn := btcws.NewBlockConnectedNtfn(hash.String(), int32(block.Height())) mntfn, _ := json.Marshal(ntfn) s.ws.walletNotificationMaster <- mntfn // Inform any interested parties about txs mined in this block. s.ws.Lock() for _, tx := range block.Transactions() { if clist, ok := s.ws.minedTxNotifications[*tx.Sha()]; ok { var enext *list.Element for e := clist.Front(); e != nil; e = enext { enext = e.Next() c := e.Value.(walletChan) // TODO: remove int32 type conversion after // the int64 -> int32 switch is made. ntfn := btcws.NewTxMinedNtfn(tx.Sha().String(), hash.String(), int32(block.Height()), block.MsgBlock().Header.Timestamp.Unix(), tx.Index()) mntfn, _ := json.Marshal(ntfn) c <- mntfn s.ws.removeMinedTxRequest(c, tx.Sha()) } } } s.ws.Unlock() }
// NotifyBlockTXs creates and marshals a JSON message to notify wallets // of new transactions (with both spent and unspent outputs) for a watched // address. func (s *rpcServer) NotifyBlockTXs(db btcdb.Db, block *btcutil.Block) { // Build a map of in-flight transactions to see if any of the inputs in // this block are referencing other transactions earlier in this block. txInFlight := map[btcwire.ShaHash]int{} transactions := block.Transactions() spent := make([][]bool, len(transactions)) for i, tx := range transactions { spent[i] = make([]bool, len(tx.MsgTx().TxOut)) txInFlight[*tx.Sha()] = i } // The newBlockNotifyCheckTxOut current needs spent data. This can // this can ultimately be optimized out by making sure the notifications // are in order. For now, just create the spent data. for i, tx := range transactions[1:] { for _, txIn := range tx.MsgTx().TxIn { originHash := &txIn.PreviousOutpoint.Hash if inFlightIndex, ok := txInFlight[*originHash]; ok && i >= inFlightIndex { prevIndex := txIn.PreviousOutpoint.Index spent[inFlightIndex][prevIndex] = true } } } for i, tx := range transactions { go s.newBlockNotifyCheckTxIn(tx) go s.newBlockNotifyCheckTxOut(block, tx, spent[i]) } }
// newBlockNotifyCheckTxOut is a helper function to iterate through // each transaction output of a new block and perform any checks and // notify listening frontends when necessary. func (s *rpcServer) newBlockNotifyCheckTxOut(block *btcutil.Block, tx *btcutil.Tx, spent []bool) { for wltNtfn, cxt := range s.ws.requests.m { for i, txout := range tx.MsgTx().TxOut { _, txaddrhash, err := btcscript.ScriptToAddrHash(txout.PkScript) if err != nil { log.Debug("Error getting payment address from tx; dropping any Tx notifications.") break } for addr, id := range cxt.txRequests { if !bytes.Equal(addr[:], txaddrhash) { continue } blkhash, err := block.Sha() if err != nil { log.Error("Error getting block sha; dropping Tx notification.") break } txaddr, err := btcutil.EncodeAddress(txaddrhash, s.server.btcnet) if err != nil { log.Error("Error encoding address; dropping Tx notification.") break } reply := &btcjson.Reply{ Result: struct { Sender string `json:"sender"` Receiver string `json:"receiver"` BlockHash string `json:"blockhash"` Height int64 `json:"height"` TxHash string `json:"txhash"` Index uint32 `json:"index"` Amount int64 `json:"amount"` PkScript string `json:"pkscript"` Spent bool `json:"spent"` }{ Sender: "Unknown", // TODO(jrick) Receiver: txaddr, BlockHash: blkhash.String(), Height: block.Height(), TxHash: tx.Sha().String(), Index: uint32(i), Amount: txout.Value, PkScript: btcutil.Base58Encode(txout.PkScript), Spent: spent[i], }, Error: nil, Id: &id, } replyBytes, err := json.Marshal(reply) if err != nil { log.Errorf("RPCS: Unable to marshal tx notification: %v", err) continue } wltNtfn <- replyBytes } } } }
// NotifyBlockDisconnected creates and marshals a JSON message to notify // of a new block disconnected from the main chain. The notification is sent // to each connected wallet. func (s *rpcServer) NotifyBlockDisconnected(block *btcutil.Block) { hash, err := block.Sha() if err != nil { rpcsLog.Error("Bad block; connected block notification dropped.") return } // TODO: remove int32 type conversion. ntfn := btcws.NewBlockDisconnectedNtfn(hash.String(), int32(block.Height())) mntfn, _ := json.Marshal(ntfn) s.ws.walletNotificationMaster <- mntfn }
// DropAfterBlockBySha will remove any blocks from the database after // the given block. func (db *LevelDb) DropAfterBlockBySha(sha *btcwire.ShaHash) (rerr error) { db.dbLock.Lock() defer db.dbLock.Unlock() defer func() { if rerr == nil { rerr = db.processBatches() } else { db.lBatch().Reset() } }() startheight := db.nextBlock - 1 keepidx, err := db.getBlkLoc(sha) if err != nil { // should the error here be normalized ? log.Tracef("block loc failed %v ", sha) return err } for height := startheight; height > keepidx; height = height - 1 { var blk *btcutil.Block blksha, buf, err := db.getBlkByHeight(height) if err != nil { return err } blk, err = btcutil.NewBlockFromBytes(buf) if err != nil { return err } for _, tx := range blk.MsgBlock().Transactions { err = db.unSpend(tx) if err != nil { return err } } // rather than iterate the list of tx backward, do it twice. for _, tx := range blk.Transactions() { var txUo txUpdateObj txUo.delete = true db.txUpdateMap[*tx.Sha()] = &txUo } db.lBatch().Delete(shaBlkToKey(blksha)) db.lBatch().Delete(int64ToKey(height)) } db.nextBlock = keepidx + 1 return nil }
// NotifyBlockDisconnected creates and marshals a JSON message to notify // of a new block disconnected from the main chain. The notification is sent // to each connected wallet. func (s *rpcServer) NotifyBlockDisconnected(block *btcutil.Block) { hash, err := block.Sha() if err != nil { rpcsLog.Error("Bad block; connected block notification dropped") return } // TODO: remove int32 type conversion. ntfn := btcws.NewBlockDisconnectedNtfn(hash.String(), int32(block.Height())) for ntfnChan, rc := range s.ws.connections { if rc.blockUpdates { ntfnChan <- ntfn } } }
// addOrphanBlock adds the passed block (which is already determined to be // an orphan prior calling this function) to the orphan pool. It lazily cleans // up any expired blocks so a separate cleanup poller doesn't need to be run. // It also imposes a maximum limit on the number of outstanding orphan // blocks and will remove the oldest received orphan block if the limit is // exceeded. func (b *BlockChain) addOrphanBlock(block *btcutil.Block) { // Remove expired orphan blocks. for _, oBlock := range b.orphans { if time.Now().After(oBlock.expiration) { b.removeOrphanBlock(oBlock) continue } // Update the oldest orphan block pointer so it can be discarded // in case the orphan pool fills up. if b.oldestOrphan == nil || oBlock.expiration.Before(b.oldestOrphan.expiration) { b.oldestOrphan = oBlock } } // Limit orphan blocks to prevent memory exhaustion. if len(b.orphans)+1 > maxOrphanBlocks { // Remove the oldest orphan to make room for the new one. b.removeOrphanBlock(b.oldestOrphan) b.oldestOrphan = nil } // Get the block sha. It is safe to ignore the error here since any // errors would've been caught prior to calling this function. blockSha, _ := block.Sha() // Protect concurrent access. This is intentionally done here instead // of near the top since removeOrphanBlock does its own locking and // the range iterator is not invalidated by removing map entries. b.orphanLock.Lock() b.orphanLock.Unlock() // Insert the block into the orphan map with an expiration time // 1 hour from now. expiration := time.Now().Add(time.Hour) oBlock := &orphanBlock{ block: block, expiration: expiration, } b.orphans[*blockSha] = oBlock // Add to previous hash lookup index for faster dependency lookups. prevHash := &block.MsgBlock().Header.PrevBlock b.prevOrphans[*prevHash] = append(b.prevOrphans[*prevHash], oBlock) return }
// SubmitBlockAsync returns an instance of a type that can be used to get the // result of the RPC at some future time by invoking the Receive function on the // returned instance. // // See SubmitBlock for the blocking version and more details. func (c *Client) SubmitBlockAsync(block *btcutil.Block, options *btcjson.SubmitBlockOptions) FutureSubmitBlockResult { blockHex := "" if block != nil { blockBytes, err := block.Bytes() if err != nil { return newFutureError(err) } blockHex = hex.EncodeToString(blockBytes) } id := c.NextID() cmd, err := btcjson.NewSubmitBlockCmd(id, blockHex, options) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) }
// checkBIP0030 ensures blocks do not contain duplicate transactions which // 'overwrite' older transactions that are not fully spent. This prevents an // attack where a coinbase and all of its dependent transactions could be // duplicated to effectively revert the overwritten transactions to a single // confirmation thereby making them vulnerable to a double spend. // // For more details, see https://en.bitcoin.it/wiki/BIP_0030 and // http://r6.ca/blog/20120206T005236Z.html. func (b *BlockChain) checkBIP0030(node *blockNode, block *btcutil.Block) error { // Attempt to fetch duplicate transactions for all of the transactions // in this block from the point of view of the parent node. fetchList, err := block.TxShas() if err != nil { return nil } fetchSet := make(map[btcwire.ShaHash]bool) for _, txHash := range fetchList { fetchSet[*txHash] = true } txResults, err := b.fetchTxStore(node, fetchSet) if err != nil { return err } // Examine the resulting data about the requested transactions. for _, txD := range txResults { switch txD.Err { // A duplicate transaction was not found. This is the most // common case. case btcdb.TxShaMissing: continue // A duplicate transaction was found. This is only allowed if // the duplicate transaction is fully spent. case nil: if !isTransactionSpent(txD) { str := fmt.Sprintf("tried to overwrite "+ "transaction %v at block height %d "+ "that is not fully spent", txD.Hash, txD.BlockHeight) return RuleError(str) } // Some other unexpected error occurred. Return it now. default: return txD.Err } } return nil }
// NotifyBlockDisconnected creates and marshals a JSON message to notify // of a new block disconnected from the main chain. The notification is sent // to each connected wallet. func (s *rpcServer) NotifyBlockDisconnected(block *btcutil.Block) { var id interface{} = "btcd:blockdisconnected" hash, err := block.Sha() if err != nil { log.Error("Bad block; connected block notification dropped.") return } ntfn := btcjson.Reply{ Result: struct { Hash string `json:"hash"` Height int64 `json:"height"` }{ Hash: hash.String(), Height: block.Height(), }, Id: &id, } m, _ := json.Marshal(ntfn) s.ws.walletNotificationMaster <- m }
// getPrevNodeFromBlock returns a block node for the block previous to the // passed block (the passed block's parent). When it is already in the memory // block chain, it simply returns it. Otherwise, it loads the previous block // from the block database, creates a new block node from it, and returns it. // The returned node will be nil if the genesis block is passed. func (b *BlockChain) getPrevNodeFromBlock(block *btcutil.Block) (*blockNode, error) { // Genesis block. prevHash := &block.MsgBlock().Header.PrevBlock if prevHash.IsEqual(zeroHash) { return nil, nil } // Return the existing previous block node if it's already there. if bn, ok := b.index[*prevHash]; ok { return bn, nil } // Dynamically load the previous block from the block database, create // a new block node for it, and update the memory chain accordingly. prevBlockNode, err := b.loadBlockNode(prevHash) if err != nil { return nil, err } return prevBlockNode, nil }
// logBlockHeight logs a new block height as an information message to show // progress to the user. In order to prevent spam, it limits logging to one // message every 10 seconds with duration and totals included. func (b *blockManager) logBlockHeight(block *btcutil.Block) { b.receivedLogBlocks++ b.receivedLogTx += int64(len(block.MsgBlock().Transactions)) now := time.Now() duration := now.Sub(b.lastBlockLogTime) if duration < time.Second*10 { return } // Truncate the duration to 10s of milliseconds. durationMillis := int64(duration / time.Millisecond) tDuration := 10 * time.Millisecond * time.Duration(durationMillis/10) // Log information about new block height. blockStr := "blocks" if b.receivedLogBlocks == 1 { blockStr = "block" } txStr := "transactions" if b.receivedLogTx == 1 { txStr = "transaction" } bmgrLog.Infof("Processed %d %s in the last %s (%d %s, height %d, %s)", b.receivedLogBlocks, blockStr, tDuration, b.receivedLogTx, txStr, block.Height(), block.MsgBlock().Header.Timestamp) b.receivedLogBlocks = 0 b.receivedLogTx = 0 b.lastBlockLogTime = now }
func GetExodusTransactions(block *btcutil.Block) []*btcutil.Tx { var txs []*btcutil.Tx for _, tx := range block.Transactions() { mtx := tx.MsgTx() for _, txOut := range mtx.TxOut { // Extract the address from the script pub key addrs, _ := GetAddrs(txOut.PkScript) // Check each output address and if there's an address going to the exodus address // we add it to tx slice for _, addr := range addrs { if addr.Addr == ExodusAddress { txs = append(txs, tx) // Continue, we don't care if there are more exodus addresses continue } } } } return txs }
// BuildMerkleTreeStore creates a merkle tree from block, stores it using a // linear array, and returns a slice of the backing array. A linear array was // chosen as opposed to an actual tree structure since it uses about half as // much memory. The following describes a merkle tree and how it is stored in // a linear array. // // A merkle tree is a tree in which every non-leaf node is the hash of its // children nodes. A diagram depicting how this works for bitcoin transactions // where h(x) is a double sha256 follows: // // root = h1234 = h(h12 + h34) // / \ // h12 = h(h1 + h2) h34 = h(h3 + h4) // / \ / \ // h1 = h(tx1) h2 = h(tx2) h3 = h(tx3) h4 = h(tx4) // // The above stored as a linear array is as follows: // // [h1 h2 h3 h4 h12 h34 root] // // As the above shows, the merkle root is always the last element in the array. // // The number of inputs is not always a power of two which results in a // balanced tree structure as above. In that case, parent nodes with no // children are also zero and parent nodes with only a single left node // are calculated by concatenating the left node with itself before hashing. // Since this function uses nodes that are pointers to the hashes, empty nodes // will be nil. func BuildMerkleTreeStore(block *btcutil.Block) []*btcwire.ShaHash { // Calculate how many entries are required to hold the binary merkle // tree as a linear array and create an array of that size. nextPoT := nextPowerOfTwo(len(block.Transactions())) arraySize := nextPoT*2 - 1 merkles := make([]*btcwire.ShaHash, arraySize) // Create the base transaction shas and populate the array with them. for i, tx := range block.Transactions() { merkles[i] = tx.Sha() } // Start the array offset after the last transaction and adjusted to the // next power of two. offset := nextPoT for i := 0; i < arraySize-1; i += 2 { switch { // When there is no left child node, the parent is nil too. case merkles[i] == nil: merkles[offset] = nil // When there is no right child, the parent is generated by // hashing the concatenation of the left child with itself. case merkles[i+1] == nil: newSha := hashMerkleBranches(merkles[i], merkles[i]) merkles[offset] = newSha // The normal case sets the parent node to the double sha256 // of the concatentation of the left and right children. default: newSha := hashMerkleBranches(merkles[i], merkles[i+1]) merkles[offset] = newSha } offset++ } return merkles }
// createTxRawResult converts the passed transaction and associated parameters // to a raw transaction JSON object. func createTxRawResult(net btcwire.BitcoinNet, txSha string, mtx *btcwire.MsgTx, blk *btcutil.Block, maxidx int64, blksha *btcwire.ShaHash) (*btcjson.TxRawResult, error) { mtxHex, err := messageToHex(mtx) if err != nil { return nil, err } vin, err := createVinList(mtx) if err != nil { return nil, err } vout, err := createVoutList(mtx, net) if err != nil { return nil, err } txReply := &btcjson.TxRawResult{ Hex: mtxHex, Txid: txSha, Vout: vout, Vin: vin, Version: mtx.Version, LockTime: mtx.LockTime, } if blk != nil { blockHeader := &blk.MsgBlock().Header idx := blk.Height() // This is not a typo, they are identical in bitcoind as well. txReply.Time = blockHeader.Timestamp.Unix() txReply.Blocktime = blockHeader.Timestamp.Unix() txReply.BlockHash = blksha.String() txReply.Confirmations = uint64(1 + maxidx - idx) } return txReply, nil }
// NotifyForTxOuts iterates through all outputs of a tx, performing any // necessary notifications for wallets. If a non-nil block is passed, // additional block information is passed with the notifications. func (s *rpcServer) NotifyForTxOuts(tx *btcutil.Tx, block *btcutil.Block) { // Nothing to do if nobody is listening for transaction notifications. if len(s.ws.txNotifications) == 0 { return } for i, txout := range tx.MsgTx().TxOut { _, addrs, _, err := btcscript.ExtractPkScriptAddrs( txout.PkScript, s.server.btcnet) if err != nil { continue } for _, addr := range addrs { // Only support pay-to-pubkey-hash right now. if _, ok := addr.(*btcutil.AddressPubKeyHash); !ok { continue } encodedAddr := addr.EncodeAddress() if idlist, ok := s.ws.txNotifications[encodedAddr]; ok { for e := idlist.Front(); e != nil; e = e.Next() { n := e.Value.(ntfnChan) ntfn := &btcws.ProcessedTxNtfn{ Receiver: encodedAddr, TxID: tx.Sha().String(), TxOutIndex: uint32(i), Amount: txout.Value, PkScript: hex.EncodeToString(txout.PkScript), // TODO(jrick): hardcoding unspent is WRONG and needs // to be either calculated from other block txs, or dropped. Spent: false, } if block != nil { blkhash, err := block.Sha() if err != nil { rpcsLog.Error("Error getting block sha; dropping Tx notification") break } ntfn.BlockHeight = int32(block.Height()) ntfn.BlockHash = blkhash.String() ntfn.BlockIndex = tx.Index() ntfn.BlockTime = block.MsgBlock().Header.Timestamp.Unix() } else { ntfn.BlockHeight = -1 ntfn.BlockIndex = -1 } n <- ntfn } } } } }
// CheckConnectBlock performs several checks to confirm connecting the passed // block to the main chain does not violate any rules. An example of some of // the checks performed are ensuring connecting the block would not cause any // duplicate transaction hashes for old transactions that aren't already fully // spent, double spends, exceeding the maximum allowed signature operations // per block, invalid values in relation to the expected block subisidy, or // fail transaction script validation. // // This function is NOT safe for concurrent access. func (b *BlockChain) CheckConnectBlock(block *btcutil.Block) error { prevNode := b.bestChain blockSha, _ := block.Sha() newNode := newBlockNode(&block.MsgBlock().Header, blockSha, block.Height()) if prevNode != nil { newNode.parent = prevNode newNode.workSum.Add(prevNode.workSum, newNode.workSum) } return b.checkConnectBlock(newNode, block) }
// NotifyBlockConnected creates and marshalls a JSON message to notify // of a new block connected to the main chain. The notification is sent // to each connected wallet. func (s *rpcServer) NotifyBlockConnected(block *btcutil.Block) { s.ws.walletListeners.RLock() for wltNtfn := range s.ws.walletListeners.m { // Create notification with basic information filled in. // This data is the same for every connected wallet. hash, err := block.Sha() if err != nil { log.Error("Bad block; connected block notification dropped.") return } ntfnResult := struct { Hash string `json:"hash"` Height int64 `json:"height"` MinedTXs []string `json:"minedtxs"` }{ Hash: hash.String(), Height: block.Height(), } // Fill in additional wallet-specific notifications. If there // is no request context for this wallet, no need to give this // wallet any extra notifications. if cxt := s.ws.requests.m[wltNtfn]; cxt != nil { // Create list of all txs created by this wallet that appear in this // block. minedTxShas := make([]string, 0, len(cxt.minedTxRequests)) // TxShas does not return a non-nil error. txShaList, _ := block.TxShas() txList := s.server.db.FetchTxByShaList(txShaList) for _, txReply := range txList { if txReply.Err != nil { continue } if _, ok := cxt.minedTxRequests[*txReply.Sha]; ok { minedTxShas = append(minedTxShas, txReply.Sha.String()) s.ws.requests.RemoveMinedTxRequest(wltNtfn, txReply.Sha) } } ntfnResult.MinedTXs = minedTxShas } var id interface{} = "btcd:blockconnected" ntfn := btcjson.Reply{ Result: ntfnResult, Id: &id, } m, _ := json.Marshal(ntfn) wltNtfn <- m } s.ws.walletListeners.RUnlock() }
// NewMerkleBlock returns a new *btcwire.MsgMerkleBlock and an array of the matched // transaction hashes based on the passed block and filter. func NewMerkleBlock(block *btcutil.Block, filter *Filter) (*btcwire.MsgMerkleBlock, []*btcwire.ShaHash) { numTx := uint32(len(block.Transactions())) mBlock := merkleBlock{ numTx: numTx, allHashes: make([]*btcwire.ShaHash, 0, numTx), matchedBits: make([]byte, 0, numTx), } // Find and keep track of any transactions that match the filter. var matchedHashes []*btcwire.ShaHash for _, tx := range block.Transactions() { if filter.MatchTxAndUpdate(tx) { mBlock.matchedBits = append(mBlock.matchedBits, 0x01) matchedHashes = append(matchedHashes, tx.Sha()) } else { mBlock.matchedBits = append(mBlock.matchedBits, 0x00) } mBlock.allHashes = append(mBlock.allHashes, tx.Sha()) } // Calculate the number of merkle branches (height) in the tree. height := uint32(0) for mBlock.calcTreeWidth(height) > 1 { height++ } // Build the depth-first partial merkle tree. mBlock.traverseAndBuild(height, 0) // Create and return the merkle block. msgMerkleBlock := btcwire.MsgMerkleBlock{ Header: block.MsgBlock().Header, Transactions: uint32(mBlock.numTx), Hashes: make([]*btcwire.ShaHash, 0, len(mBlock.finalHashes)), Flags: make([]byte, (len(mBlock.bits)+7)/8), } for _, sha := range mBlock.finalHashes { msgMerkleBlock.AddTxHash(sha) } for i := uint32(0); i < uint32(len(mBlock.bits)); i++ { msgMerkleBlock.Flags[i/8] |= mBlock.bits[i] << (i % 8) } return &msgMerkleBlock, matchedHashes }
// submitBlock submits the passed block to network after ensuring it passes all // of the consensus validation rules. func (m *CPUMiner) submitBlock(block *btcutil.Block) bool { m.submitBlockLock.Lock() defer m.submitBlockLock.Unlock() // Ensure the block is not stale since a new block could have shown up // while the solution was being found. Typically that condition is // detected and all work on the stale block is halted to start work on // a new block, but the check only happens periodically, so it is // possible a block was found and submitted in between. latestHash, _ := m.server.blockManager.chainState.Best() msgBlock := block.MsgBlock() if !msgBlock.Header.PrevBlock.IsEqual(latestHash) { minrLog.Debugf("Block submitted via CPU miner with previous "+ "block %s is stale", msgBlock.Header.PrevBlock) return false } // Process this block using the same rules as blocks coming from other // nodes. This will in turn relay it to the network like normal. isOrphan, err := m.server.blockManager.ProcessBlock(block) if err != nil { // Anything other than a rule violation is an unexpected error, // so log that error as an internal error. if _, ok := err.(btcchain.RuleError); !ok { minrLog.Errorf("Unexpected error while processing "+ "block submitted via CPU miner: %v", err) return false } minrLog.Debugf("Block submitted via CPU miner rejected: %v", err) return false } if isOrphan { minrLog.Debugf("Block submitted via CPU miner is an orphan") return false } // The block was accepted. blockSha, _ := block.Sha() coinbaseTx := block.MsgBlock().Transactions[0].TxOut[0] minrLog.Infof("Block submitted via CPU miner accepted (hash %s, "+ "amount %v)", blockSha, btcutil.Amount(coinbaseTx.Value)) return true }
func MakeBlock(block *btcutil.Block, previous *Block) *Block { transactions := make([]ads.ADS, 0) for _, transaction := range block.Transactions() { t := &Transaction{ MsgTx: *transaction.MsgTx(), } t.SetCachedHash(sha.Hash(*transaction.Sha())) transactions = append(transactions, t) } b := &Block{ Header: block.MsgBlock().Header, Previous: previous, Transactions: transactions, } hash, _ := block.Sha() b.SetCachedHash(sha.Hash(*hash)) return b }
// checkBlockScripts executes and validates the scripts for all transactions in // the passed block. func checkBlockScripts(block *btcutil.Block, txStore TxStore) error { // Setup the script validation flags. Blocks created after the BIP0016 // activation time need to have the pay-to-script-hash checks enabled. var flags btcscript.ScriptFlags if block.MsgBlock().Header.Timestamp.After(btcscript.Bip16Activation) { flags |= btcscript.ScriptBip16 } // Collect all of the transaction inputs and required information for // validation for all transactions in the block into a single slice. numInputs := 0 for _, tx := range block.Transactions() { numInputs += len(tx.MsgTx().TxIn) } txValItems := make([]*txValidateItem, 0, numInputs) for _, tx := range block.Transactions() { for txInIdx, txIn := range tx.MsgTx().TxIn { // Skip coinbases. if txIn.PreviousOutpoint.Index == math.MaxUint32 { continue } txVI := &txValidateItem{ txInIndex: txInIdx, txIn: txIn, tx: tx, } txValItems = append(txValItems, txVI) } } // Validate all of the inputs. validator := newTxValidator(txStore, flags) if err := validator.Validate(txValItems); err != nil { return err } return nil }
// IsCheckpointCandidate returns whether or not the passed block is a good // checkpoint candidate. // // The factors used to determine a good checkpoint are: // - The block must be in the main chain // - The block must be at least 'CheckpointConfirmations' blocks prior to the // current end of the main chain // - The timestamps for the blocks before and after the checkpoint must have // timestamps which are also before and after the checkpoint, respectively // (due to the median time allowance this is not always the case) // - The block must not contain any strange transaction such as those with // nonstandard scripts func (b *BlockChain) IsCheckpointCandidate(block *btcutil.Block) (bool, error) { // Checkpoints must be enabled. if b.noCheckpoints { return false, fmt.Errorf("checkpoints are disabled") } blockHash, err := block.Sha() if err != nil { return false, err } // A checkpoint must be in the main chain. if !b.db.ExistsSha(blockHash) { return false, nil } // A checkpoint must be at least CheckpointConfirmations blocks before // the end of the main chain. blockHeight := block.Height() _, mainChainHeight, err := b.db.NewestSha() if err != nil { return false, err } if blockHeight > (mainChainHeight - CheckpointConfirmations) { return false, nil } // Get the previous block. prevHash := &block.MsgBlock().Header.PrevBlock prevBlock, err := b.db.FetchBlockBySha(prevHash) if err != nil { return false, err } // Get the next block. nextHash, err := b.db.FetchBlockShaByHeight(blockHeight + 1) if err != nil { return false, err } nextBlock, err := b.db.FetchBlockBySha(nextHash) if err != nil { return false, err } // A checkpoint must have timestamps for the block and the blocks on // either side of it in order (due to the median time allowance this is // not always the case). prevTime := prevBlock.MsgBlock().Header.Timestamp curTime := block.MsgBlock().Header.Timestamp nextTime := nextBlock.MsgBlock().Header.Timestamp if prevTime.After(curTime) || nextTime.Before(curTime) { return false, nil } // A checkpoint must have transactions that only contain standard // scripts. for _, tx := range block.Transactions() { if isNonstandardTransaction(tx) { return false, nil } } return true, nil }