Example #1
0
// 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()
}
Example #2
0
// 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
}