| 4656 | }; |
| 4657 | |
| 4658 | bool ProcessGetUTXOs(const vector<COutPoint> &vOutPoints, bool fCheckMemPool, vector<unsigned char> *result, vector<CCoin> *resultCoins) |
| 4659 | { |
| 4660 | // Defined by BIP 64. |
| 4661 | // |
| 4662 | // Allows a peer to retrieve the CTxOut structures corresponding to the given COutPoints. |
| 4663 | // Note that this data is not authenticated by anything: this code could just invent any |
| 4664 | // old rubbish and hand it back, with the peer being unable to tell unless they are checking |
| 4665 | // the outpoints against some out of band data. |
| 4666 | // |
| 4667 | // Also the answer could change the moment after we give it. However some apps can tolerate |
| 4668 | // this, because they're only using the result as a hint or are willing to trust the results |
| 4669 | // based on something else. For example we may be a "trusted node" for the peer, or it may |
| 4670 | // be checking the results given by several nodes for consistency, it may |
| 4671 | // run the UTXOs returned against scriptSigs of transactions obtained elsewhere (after checking |
| 4672 | // for a standard script form), and because the height in which the UTXO was defined is provided |
| 4673 | // a client that has a map of heights to block headers (as SPV clients do, for recent blocks) |
| 4674 | // can request the creating block via hash. |
| 4675 | // |
| 4676 | // IMPORTANT: Clients expect ordering to be preserved! |
| 4677 | if (vOutPoints.size() > MAX_INV_SZ) |
| 4678 | return error("message getutxos size() = %u", vOutPoints.size()); |
| 4679 | |
| 4680 | LogPrint("net", "getutxos for %d queries %s mempool\n", vOutPoints.size(), fCheckMemPool ? "with" : "without"); |
| 4681 | |
| 4682 | // Due to the above check max space the bitmap can use is 50,000 / 8 == 6250 bytes. |
| 4683 | size_t bytes_used = vOutPoints.size() / 8; |
| 4684 | size_t max_bytes = SendBufferSize(); |
| 4685 | boost::dynamic_bitset<unsigned char> hits(vOutPoints.size()); |
| 4686 | { |
| 4687 | LOCK2(cs_main, mempool.cs); |
| 4688 | CCoinsViewMemPool cvMemPool(pcoinsTip, mempool); |
| 4689 | CCoinsView* baseView; |
| 4690 | if (fCheckMemPool) |
| 4691 | baseView = &cvMemPool; |
| 4692 | else |
| 4693 | baseView = pcoinsTip; |
| 4694 | CCoinsViewCache view(baseView); |
| 4695 | for (size_t i = 0; i < vOutPoints.size(); i++) |
| 4696 | { |
| 4697 | CCoins coins; |
| 4698 | uint256 hash = vOutPoints[i].hash; |
| 4699 | if (view.GetCoins(hash, coins)) |
| 4700 | { |
| 4701 | if (fCheckMemPool) |
| 4702 | mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool |
| 4703 | if (coins.IsAvailable(vOutPoints[i].n)) |
| 4704 | { |
| 4705 | hits[i] = true; |
| 4706 | // Safe to index into vout here because IsAvailable checked if it's off the end of the array, or if |
| 4707 | // n is valid but points to an already spent output (IsNull). |
| 4708 | CCoin coin; |
| 4709 | coin.nTxVer = coins.nVersion; |
| 4710 | coin.nHeight = coins.nHeight; |
| 4711 | coin.out = coins.vout.at(vOutPoints[i].n); |
| 4712 | assert(!coin.out.IsNull()); |
| 4713 | bytes_used += coin.GetSizeOf(); |
| 4714 | if (bytes_used > max_bytes) |
| 4715 | return false; |
no test coverage detected