Bitcoin ABC 0.30.7
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 : nonce(GetRand<uint64_t>()), shorttxids(block.vtx.size() - 1),
23 prefilledtxn(1), header(block) {
25 // TODO: Use our mempool prior to block acceptance to predictively fill more
26 // than just the coinbase.
27 prefilledtxn[0] = {0, block.vtx[0]};
28 for (size_t i = 1; i < block.vtx.size(); i++) {
29 const CTransaction &tx = *block.vtx[i];
30 shorttxids[i - 1] = GetShortID(tx.GetHash());
31 }
32}
33
36 stream << header << nonce;
37 CSHA256 hasher;
38 hasher.Write((uint8_t *)&(*stream.begin()), stream.end() - stream.begin());
39 uint256 shorttxidhash;
40 hasher.Finalize(shorttxidhash.begin());
41 shorttxidk0 = shorttxidhash.GetUint64(0);
42 shorttxidk1 = shorttxidhash.GetUint64(1);
43}
44
45uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const TxHash &txhash) const {
46 static_assert(SHORTTXIDS_LENGTH == 6,
47 "shorttxids calculation assumes 6-byte shorttxids");
48 return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL;
49}
50
52 const CBlockHeaderAndShortTxIDs &cmpctblock,
53 const std::vector<std::pair<TxHash, CTransactionRef>> &extra_txns) {
54 if (cmpctblock.header.IsNull() ||
55 (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty())) {
57 }
58 if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() >
61 }
62
63 if (!header.IsNull() || shortidProcessor != nullptr) {
65 }
66
67 header = cmpctblock.header;
68
69 for (const auto &prefilledtxn : cmpctblock.prefilledtxn) {
70 if (prefilledtxn.tx->IsNull()) {
72 }
73 }
74 prefilled_count = cmpctblock.prefilledtxn.size();
75
76 // To determine the chance that the number of entries in a bucket exceeds N,
77 // we use the fact that the number of elements in a single bucket is
78 // binomially distributed (with n = the number of shorttxids S, and
79 // p = 1 / the number of buckets), that in the worst case the number of
80 // buckets is equal to S (due to std::unordered_map having a default load
81 // factor of 1.0), and that the chance for any bucket to exceed N elements
82 // is at most buckets * (the chance that any given bucket is above N
83 // elements). Thus:
84 // P(max_elements_per_bucket > N) <= S * (1 - cdf(binomial(n=S,p=1/S), N))
85 // If we assume blocks of up to 16000, allowing 12 elements per bucket
86 // should only fail once per ~1 million block transfers (per peer and
87 // connection).
88 // FIXME the value of 16000 txs in a block should be re-evaluated.
89 shortidProcessor = std::make_shared<TransactionShortIdProcessor>(
90 cmpctblock.prefilledtxn, cmpctblock.shorttxids, 12);
91
92 if (!shortidProcessor->isEvenlyDistributed() ||
93 shortidProcessor->hasShortIdCollision() ||
94 shortidProcessor->hasOutOfBoundIndex()) {
95 // TODO: in the shortid-collision case, we should instead request both
96 // transactions which collided. Falling back to full-block-request here
97 // is overkill.
98 return READ_STATUS_FAILED;
99 }
100
101 {
102 LOCK(pool->cs);
103 auto it = pool->mapTx.begin();
104 while (it != pool->mapTx.end()) {
105 uint64_t shortid = cmpctblock.GetShortID((*it)->GetTx().GetHash());
106
108 shortidProcessor->matchKnownItem(shortid, (*it)->GetSharedTx());
109 it++;
110
111 if (mempool_count == shortidProcessor->getShortIdCount()) {
112 break;
113 }
114 }
115 }
116
117 for (auto &extra_txn : extra_txns) {
118 uint64_t shortid = cmpctblock.GetShortID(extra_txn.first);
119
120 int count = shortidProcessor->matchKnownItem(shortid, extra_txn.second);
123
124 if (mempool_count == shortidProcessor->getShortIdCount()) {
125 break;
126 }
127 }
128
130 "Initialized PartiallyDownloadedBlock for block %s using a "
131 "cmpctblock of size %lu\n",
132 cmpctblock.header.GetHash().ToString(),
134
135 return READ_STATUS_OK;
136}
137
139 if (header.IsNull()) {
140 return false;
141 }
142 if (shortidProcessor == nullptr) {
143 return false;
144 }
145 return shortidProcessor->getItem(index) != nullptr;
146}
147
149 CBlock &block, const std::vector<CTransactionRef> &vtx_missing) {
150 if (header.IsNull()) {
151 return READ_STATUS_INVALID;
152 }
153 uint256 hash = header.GetHash();
154 block = header;
155 const size_t txnCount = shortidProcessor->getItemCount();
156 block.vtx.resize(txnCount);
157
158 size_t tx_missing_offset = 0;
159 for (size_t i = 0; i < txnCount; i++) {
160 auto &txn_available = shortidProcessor->getItem(i);
161 if (!txn_available) {
162 if (vtx_missing.size() <= tx_missing_offset) {
163 return READ_STATUS_INVALID;
164 }
165 block.vtx[i] = vtx_missing[tx_missing_offset++];
166 } else {
167 block.vtx[i] = txn_available;
168 }
169 }
170
171 // Make sure we can't call FillBlock again.
172 header.SetNull();
173 shortidProcessor.reset();
174
175 if (vtx_missing.size() != tx_missing_offset) {
176 return READ_STATUS_INVALID;
177 }
178
180 if (!CheckBlock(block, state, config->GetChainParams().GetConsensus(),
182 // TODO: We really want to just check merkle tree manually here, but
183 // that is expensive, and CheckBlock caches a block's "checked-status"
184 // (in the CBlock?). CBlock should be able to check its own merkle root
185 // and cache that check.
187 // Possible Short ID collision.
188 return READ_STATUS_FAILED;
189 }
191 }
192
194 "Successfully reconstructed block %s with %lu txn prefilled, %lu "
195 "txn from mempool (incl at least %lu from extra pool) and %lu txn "
196 "requested\n",
198 vtx_missing.size());
199 if (vtx_missing.size() < 5) {
200 for (const auto &tx : vtx_missing) {
202 "Reconstructed block %s required tx %s\n", hash.ToString(),
203 tx->GetId().ToString());
204 }
205 }
206
207 return READ_STATUS_OK;
208}
@ 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
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:92
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
const_iterator begin() const
Definition: streams.h:219
const_iterator end() const
Definition: streams.h:221
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:307
virtual uint64_t GetMaxBlockSize() const =0
virtual const CChainParams & GetChainParams() const =0
const CTxMemPool * pool
ReadStatus InitData(const CBlockHeaderAndShortTxIDs &cmpctblock, const std::vector< std::pair< TxHash, 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:238
@ CMPCTBLOCK
Definition: logging.h:52
bool CheckBlock(const CCheckpointData &data, int nHeight, const BlockHash &hash)
Returns true if block passes checkpoint checks.
Definition: checkpoints.cpp:11
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition: random.h:85
@ SER_NETWORK
Definition: serialize.h:152
size_t GetSerializeSize(const T &t, int nVersion=0)
Definition: serialize.h:1258
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256 &val)
Optimized SipHash-2-4 implementation for uint256.
Definition: siphash.cpp:99
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:79
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11