Bitcoin ABC 0.34.2
P2P Digital Currency
blockencodings.cpp
Go to the documentation of this file.
1// Copyright (c) 2016 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <blockencodings.h>
6
7#include <chainparams.h>
8#include <common/system.h>
9#include <config.h>
10#include <consensus/consensus.h>
12#include <crypto/sha256.h>
13#include <crypto/siphash.h>
14#include <logging.h>
15#include <random.h>
16#include <streams.h>
17#include <txmempool.h>
18#include <validation.h>
19
20#include <unordered_map>
21
23 const uint64_t nonce)
24 : nonce(nonce), shorttxids(block.vtx.size() - 1), prefilledtxn(1),
25 header(block) {
27 // TODO: Use our mempool prior to block acceptance to predictively fill more
28 // than just the coinbase.
29 prefilledtxn[0] = {0, block.vtx[0]};
30 for (size_t i = 1; i < block.vtx.size(); i++) {
31 const CTransaction &tx = *block.vtx[i];
32 shorttxids[i - 1] = GetShortID(tx.GetHash());
33 }
34}
35
37 DataStream stream{};
38 stream << header << nonce;
39 CSHA256 hasher;
40 hasher.Write((uint8_t *)&(*stream.begin()), stream.end() - stream.begin());
41 uint256 shorttxidhash;
42 hasher.Finalize(shorttxidhash.begin());
43 shorttxidk0 = shorttxidhash.GetUint64(0);
44 shorttxidk1 = shorttxidhash.GetUint64(1);
45}
46
47uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const TxHash &txhash) const {
48 static_assert(SHORTTXIDS_LENGTH == 6,
49 "shorttxids calculation assumes 6-byte shorttxids");
50 return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL;
51}
52
54 const CBlockHeaderAndShortTxIDs &cmpctblock,
55 const std::vector<CTransactionRef> &extra_txns) {
56 if (cmpctblock.header.IsNull() ||
57 (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty())) {
59 }
60 if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() >
63 }
64
65 if (!header.IsNull() || shortidProcessor != nullptr) {
67 }
68
69 header = cmpctblock.header;
70
71 for (const auto &prefilledtxn : cmpctblock.prefilledtxn) {
72 if (prefilledtxn.tx->IsNull()) {
74 }
75 }
76 prefilled_count = cmpctblock.prefilledtxn.size();
77
78 // To determine the chance that the number of entries in a bucket exceeds N,
79 // we use the fact that the number of elements in a single bucket is
80 // binomially distributed (with n = the number of shorttxids S, and
81 // p = 1 / the number of buckets), that in the worst case the number of
82 // buckets is equal to S (due to std::unordered_map having a default load
83 // factor of 1.0), and that the chance for any bucket to exceed N elements
84 // is at most buckets * (the chance that any given bucket is above N
85 // elements). Thus:
86 // P(max_elements_per_bucket > N) <= S * (1 - cdf(binomial(n=S,p=1/S), N))
87 // If we assume blocks of up to 16000, allowing 12 elements per bucket
88 // should only fail once per ~1 million block transfers (per peer and
89 // connection).
90 // FIXME the value of 16000 txs in a block should be re-evaluated.
91 shortidProcessor = std::make_shared<TransactionShortIdProcessor>(
92 cmpctblock.prefilledtxn, cmpctblock.shorttxids, 12);
93
94 if (!shortidProcessor->isEvenlyDistributed() ||
95 shortidProcessor->hasShortIdCollision() ||
96 shortidProcessor->hasOutOfBoundIndex()) {
97 // TODO: in the shortid-collision case, we should instead request both
98 // transactions which collided. Falling back to full-block-request here
99 // is overkill.
100 return READ_STATUS_FAILED;
101 }
102
103 {
104 LOCK(pool->cs);
105 auto it = pool->mapTx.begin();
106 while (it != pool->mapTx.end()) {
107 uint64_t shortid = cmpctblock.GetShortID((*it)->GetTx().GetHash());
108
110 shortidProcessor->matchKnownItem(shortid, (*it)->GetSharedTx());
111 it++;
112
113 if (mempool_count == shortidProcessor->getShortIdCount()) {
114 break;
115 }
116 }
117 }
118
119 for (auto &extra_txn : extra_txns) {
120 if (extra_txn == nullptr) {
121 continue;
122 }
123 uint64_t shortid = cmpctblock.GetShortID(extra_txn->GetHash());
124
125 int count = shortidProcessor->matchKnownItem(shortid, extra_txn);
128
129 if (mempool_count == shortidProcessor->getShortIdCount()) {
130 break;
131 }
132 }
133
135 "Initialized PartiallyDownloadedBlock for block %s using a "
136 "cmpctblock of size %lu\n",
137 cmpctblock.header.GetHash().ToString(),
138 GetSerializeSize(cmpctblock));
139
140 return READ_STATUS_OK;
141}
142
144 if (header.IsNull()) {
145 return false;
146 }
147 if (shortidProcessor == nullptr) {
148 return false;
149 }
150 return shortidProcessor->getItem(index) != nullptr;
151}
152
154 CBlock &block, const std::vector<CTransactionRef> &vtx_missing) {
155 if (header.IsNull()) {
156 return READ_STATUS_INVALID;
157 }
158 uint256 hash = header.GetHash();
159 block = header;
160 const size_t txnCount = shortidProcessor->getItemCount();
161 block.vtx.resize(txnCount);
162
163 size_t tx_missing_offset = 0;
164 for (size_t i = 0; i < txnCount; i++) {
165 auto &txn_available = shortidProcessor->getItem(i);
166 if (!txn_available) {
167 if (vtx_missing.size() <= tx_missing_offset) {
168 return READ_STATUS_INVALID;
169 }
170 block.vtx[i] = vtx_missing[tx_missing_offset++];
171 } else {
172 block.vtx[i] = txn_available;
173 }
174 }
175
176 // Make sure we can't call FillBlock again.
177 header.SetNull();
178 shortidProcessor.reset();
179
180 if (vtx_missing.size() != tx_missing_offset) {
181 return READ_STATUS_INVALID;
182 }
183
185 if (!CheckBlock(block, state, config->GetChainParams().GetConsensus(),
187 // TODO: We really want to just check merkle tree manually here, but
188 // that is expensive, and CheckBlock caches a block's "checked-status"
189 // (in the CBlock?). CBlock should be able to check its own merkle root
190 // and cache that check.
192 // Possible Short ID collision.
193 return READ_STATUS_FAILED;
194 }
196 }
197
199 "Successfully reconstructed block %s with %lu txn prefilled, %lu "
200 "txn from mempool (incl at least %lu from extra pool) and %lu txn "
201 "requested\n",
203 vtx_missing.size());
204 if (vtx_missing.size() < 5) {
205 for (const auto &tx : vtx_missing) {
207 "Reconstructed block %s required tx %s\n", hash.ToString(),
208 tx->GetId().ToString());
209 }
210 }
211
212 return READ_STATUS_OK;
213}
@ READ_STATUS_OK
@ READ_STATUS_INVALID
@ READ_STATUS_CHECKBLOCK_FAILED
@ READ_STATUS_FAILED
enum ReadStatus_t ReadStatus
uint64_t GetShortID(const TxHash &txhash) const
CBlockHeaderAndShortTxIDs()=default
Dummy for deserialization.
void FillShortTxIDSelector() const
std::vector< PrefilledTransaction > prefilledtxn
static constexpr int SHORTTXIDS_LENGTH
std::vector< uint64_t > shorttxids
BlockHash GetHash() const
Definition: block.cpp:11
void SetNull()
Definition: block.h:40
bool IsNull() const
Definition: block.h:49
Definition: block.h:60
std::vector< CTransactionRef > vtx
Definition: block.h:63
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:98
A hasher class for SHA-256.
Definition: sha256.h:13
CSHA256 & Write(const uint8_t *data, size_t len)
Definition: sha256.cpp:819
void Finalize(uint8_t hash[OUTPUT_SIZE])
Definition: sha256.cpp:844
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:316
virtual uint64_t GetMaxBlockSize() const =0
virtual const CChainParams & GetChainParams() const =0
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:118
const CTxMemPool * pool
ReadStatus InitData(const CBlockHeaderAndShortTxIDs &cmpctblock, const std::vector< CTransactionRef > &extra_txn)
bool IsTxAvailable(size_t index) const
ReadStatus FillBlock(CBlock &block, const std::vector< CTransactionRef > &vtx_missing)
std::shared_ptr< TransactionShortIdProcessor > shortidProcessor
Result GetResult() const
Definition: validation.h:122
constexpr uint64_t GetUint64(int pos) const
Definition: uint256.h:130
constexpr uint8_t * begin()
Definition: uint256.h:122
std::string ToString() const
Definition: uint256.h:117
256-bit opaque blob.
Definition: uint256.h:199
@ BLOCK_MUTATED
the block's data didn't match the data committed to by the PoW
#define LogDebug(category,...)
Definition: logging.h:446
@ CMPCTBLOCK
Definition: logging.h:81
bool CheckBlock(const CCheckpointData &data, int nHeight, const BlockHash &hash)
Returns true if block passes checkpoint checks.
Definition: checkpoints.cpp:11
size_t GetSerializeSize(const T &t)
Definition: serialize.h:1264
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256 &val)
Optimized SipHash-2-4 implementation for uint256.
Definition: siphash.cpp:100
A TxHash is the double sha256 hash of the full transaction data.
Definition: txid.h:26
#define LOCK(cs)
Definition: sync.h:295
static int count
#define MIN_TRANSACTION_SIZE
Definition: validation.h:82