Bitcoin ABC 0.32.6
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 <random.h>
15#include <streams.h>
16#include <txmempool.h>
17#include <validation.h>
18
19#include <unordered_map>
20
22 const uint64_t nonce)
23 : nonce(nonce), shorttxids(block.vtx.size() - 1), prefilledtxn(1),
24 header(block) {
26 // TODO: Use our mempool prior to block acceptance to predictively fill more
27 // than just the coinbase.
28 prefilledtxn[0] = {0, block.vtx[0]};
29 for (size_t i = 1; i < block.vtx.size(); i++) {
30 const CTransaction &tx = *block.vtx[i];
31 shorttxids[i - 1] = GetShortID(tx.GetHash());
32 }
33}
34
36 DataStream stream{};
37 stream << header << nonce;
38 CSHA256 hasher;
39 hasher.Write((uint8_t *)&(*stream.begin()), stream.end() - stream.begin());
40 uint256 shorttxidhash;
41 hasher.Finalize(shorttxidhash.begin());
42 shorttxidk0 = shorttxidhash.GetUint64(0);
43 shorttxidk1 = shorttxidhash.GetUint64(1);
44}
45
46uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const TxHash &txhash) const {
47 static_assert(SHORTTXIDS_LENGTH == 6,
48 "shorttxids calculation assumes 6-byte shorttxids");
49 return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL;
50}
51
53 const CBlockHeaderAndShortTxIDs &cmpctblock,
54 const std::vector<CTransactionRef> &extra_txns) {
55 if (cmpctblock.header.IsNull() ||
56 (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty())) {
58 }
59 if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() >
62 }
63
64 if (!header.IsNull() || shortidProcessor != nullptr) {
66 }
67
68 header = cmpctblock.header;
69
70 for (const auto &prefilledtxn : cmpctblock.prefilledtxn) {
71 if (prefilledtxn.tx->IsNull()) {
73 }
74 }
75 prefilled_count = cmpctblock.prefilledtxn.size();
76
77 // To determine the chance that the number of entries in a bucket exceeds N,
78 // we use the fact that the number of elements in a single bucket is
79 // binomially distributed (with n = the number of shorttxids S, and
80 // p = 1 / the number of buckets), that in the worst case the number of
81 // buckets is equal to S (due to std::unordered_map having a default load
82 // factor of 1.0), and that the chance for any bucket to exceed N elements
83 // is at most buckets * (the chance that any given bucket is above N
84 // elements). Thus:
85 // P(max_elements_per_bucket > N) <= S * (1 - cdf(binomial(n=S,p=1/S), N))
86 // If we assume blocks of up to 16000, allowing 12 elements per bucket
87 // should only fail once per ~1 million block transfers (per peer and
88 // connection).
89 // FIXME the value of 16000 txs in a block should be re-evaluated.
90 shortidProcessor = std::make_shared<TransactionShortIdProcessor>(
91 cmpctblock.prefilledtxn, cmpctblock.shorttxids, 12);
92
93 if (!shortidProcessor->isEvenlyDistributed() ||
94 shortidProcessor->hasShortIdCollision() ||
95 shortidProcessor->hasOutOfBoundIndex()) {
96 // TODO: in the shortid-collision case, we should instead request both
97 // transactions which collided. Falling back to full-block-request here
98 // is overkill.
99 return READ_STATUS_FAILED;
100 }
101
102 {
103 LOCK(pool->cs);
104 auto it = pool->mapTx.begin();
105 while (it != pool->mapTx.end()) {
106 uint64_t shortid = cmpctblock.GetShortID((*it)->GetTx().GetHash());
107
109 shortidProcessor->matchKnownItem(shortid, (*it)->GetSharedTx());
110 it++;
111
112 if (mempool_count == shortidProcessor->getShortIdCount()) {
113 break;
114 }
115 }
116 }
117
118 for (auto &extra_txn : extra_txns) {
119 if (extra_txn == nullptr) {
120 continue;
121 }
122 uint64_t shortid = cmpctblock.GetShortID(extra_txn->GetHash());
123
124 int count = shortidProcessor->matchKnownItem(shortid, extra_txn);
127
128 if (mempool_count == shortidProcessor->getShortIdCount()) {
129 break;
130 }
131 }
132
134 "Initialized PartiallyDownloadedBlock for block %s using a "
135 "cmpctblock of size %lu\n",
136 cmpctblock.header.GetHash().ToString(),
137 GetSerializeSize(cmpctblock));
138
139 return READ_STATUS_OK;
140}
141
143 if (header.IsNull()) {
144 return false;
145 }
146 if (shortidProcessor == nullptr) {
147 return false;
148 }
149 return shortidProcessor->getItem(index) != nullptr;
150}
151
153 CBlock &block, const std::vector<CTransactionRef> &vtx_missing) {
154 if (header.IsNull()) {
155 return READ_STATUS_INVALID;
156 }
157 uint256 hash = header.GetHash();
158 block = header;
159 const size_t txnCount = shortidProcessor->getItemCount();
160 block.vtx.resize(txnCount);
161
162 size_t tx_missing_offset = 0;
163 for (size_t i = 0; i < txnCount; i++) {
164 auto &txn_available = shortidProcessor->getItem(i);
165 if (!txn_available) {
166 if (vtx_missing.size() <= tx_missing_offset) {
167 return READ_STATUS_INVALID;
168 }
169 block.vtx[i] = vtx_missing[tx_missing_offset++];
170 } else {
171 block.vtx[i] = txn_available;
172 }
173 }
174
175 // Make sure we can't call FillBlock again.
176 header.SetNull();
177 shortidProcessor.reset();
178
179 if (vtx_missing.size() != tx_missing_offset) {
180 return READ_STATUS_INVALID;
181 }
182
184 if (!CheckBlock(block, state, config->GetChainParams().GetConsensus(),
186 // TODO: We really want to just check merkle tree manually here, but
187 // that is expensive, and CheckBlock caches a block's "checked-status"
188 // (in the CBlock?). CBlock should be able to check its own merkle root
189 // and cache that check.
191 // Possible Short ID collision.
192 return READ_STATUS_FAILED;
193 }
195 }
196
198 "Successfully reconstructed block %s with %lu txn prefilled, %lu "
199 "txn from mempool (incl at least %lu from extra pool) and %lu txn "
200 "requested\n",
202 vtx_missing.size());
203 if (vtx_missing.size() < 5) {
204 for (const auto &tx : vtx_missing) {
206 "Reconstructed block %s required tx %s\n", hash.ToString(),
207 tx->GetId().ToString());
208 }
209 }
210
211 return READ_STATUS_OK;
212}
@ READ_STATUS_OK
@ READ_STATUS_INVALID
@ READ_STATUS_CHECKBLOCK_FAILED
@ READ_STATUS_FAILED
enum ReadStatus_t ReadStatus
uint64_t GetShortID(const TxHash &txhash) const
void FillShortTxIDSelector() const
CBlockHeaderAndShortTxIDs()
Dummy for deserialization.
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:317
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
uint8_t * begin()
Definition: uint256.h:85
std::string ToString() const
Definition: uint256.h:80
uint64_t GetUint64(int pos) const
Definition: uint256.h:95
256-bit opaque blob.
Definition: uint256.h:129
@ BLOCK_MUTATED
the block's data didn't match the data committed to by the PoW
#define LogPrint(category,...)
Definition: logging.h:452
@ 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:1262
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:22
#define LOCK(cs)
Definition: sync.h:306
static int count
Definition: tests.c:31
#define MIN_TRANSACTION_SIZE
Definition: validation.h:86