upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rpc.cpp61
1 files changed, 48 insertions, 13 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp
index 41c0328..d73b09c 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -167,29 +167,64 @@ static bool RebuildJob()
167 CBlock block; 167 CBlock block;
168 block.vtx.push_back(txNew); 168 block.vtx.push_back(txNew);
169 169
170 // Fill the block the same way BitcoinMiner() does, because this is the
171 // same job: a block that gets mined and submitted for real.
172 //
173 // It used to differ in two ways, and both were bugs.
174 //
175 // One pass over mapTransactions is not enough. That map is keyed by
176 // hash, so it has no dependency order, and a transaction spending the
177 // still-unconfirmed output of another (change from a recent send, most
178 // commonly) fails ConnectInputs whenever its parent happens to sit
179 // later in map order. A single pass then drops it -- and because map
180 // order does not change between rebuilds, every later rebuild drops it
181 // again at the same point. Deterministic exclusion, not bad luck: if
182 // pool operators mine most of the blocks, a transaction of that shape
183 // can stay unconfirmed for as long as its parent does.
184 //
185 // Diagnosis and fix both come from Vic-Nas, who found it in his fork
186 // of this code and described it exactly. The fork has since been
187 // deleted, so this carries it back rather than losing it.
188 int64 nFees = 0;
170 { 189 {
171 CTxDB txdb("r"); 190 CTxDB txdb("r");
172 CRITICAL_BLOCK(cs_mapTransactions) 191 CRITICAL_BLOCK(cs_mapTransactions)
173 { 192 {
174 map<uint256, CTxIndex> pool; 193 map<uint256, CTxIndex> pool;
194 vector<char> vfAlreadyAdded(mapTransactions.size());
195 bool fFoundSomething = true;
175 unsigned int sz = 0; 196 unsigned int sz = 0;
176 for (auto& kv : mapTransactions) { 197 while (fFoundSomething && sz < MAX_SIZE / 2)
177 CTransaction& tx = kv.second; 198 {
178 if (tx.IsCoinBase() || !tx.IsFinal()) continue; 199 fFoundSomething = false;
179 int64 nFees = 0; 200 unsigned int n = 0;
180 map<uint256, CTxIndex> tmp(pool); 201 for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin();
181 if (!tx.ConnectInputs(txdb, tmp, CDiskTxPos(1,1,1), 0, nFees, 202 mi != mapTransactions.end(); ++mi, ++n)
182 false, true, tx.GetMinFee(block.vtx.size() < 100))) 203 {
183 continue; 204 if (vfAlreadyAdded[n])
184 pool = tmp; 205 continue;
185 block.vtx.push_back(tx); 206 CTransaction& tx = (*mi).second;
186 sz += ::GetSerializeSize(tx, SER_NETWORK); 207 if (tx.IsCoinBase() || !tx.IsFinal()) continue;
187 if (sz > MAX_SIZE / 2) break; 208 map<uint256, CTxIndex> tmp(pool);
209 if (!tx.ConnectInputs(txdb, tmp, CDiskTxPos(1,1,1), 0, nFees,
210 false, true, tx.GetMinFee(block.vtx.size() < 100)))
211 continue;
212 swap(pool, tmp);
213 block.vtx.push_back(tx);
214 sz += ::GetSerializeSize(tx, SER_NETWORK);
215 vfAlreadyAdded[n] = true;
216 fFoundSomething = true;
217 }
188 } 218 }
189 } 219 }
190 } 220 }
191 221
192 block.vtx[0].vout[0].nValue = block.GetBlockValue(pindexPrev->nHeight + 1, 0); 222 // And the fees actually go to the coinbase now. nFees was declared
223 // inside the scan loop, so every transaction reset it and the total was
224 // thrown away, while this line passed a hardcoded 0. A pool operator
225 // collected fees into a block and paid none of them to itself. Solo
226 // mining has always passed nFees here; only this builder did not.
227 block.vtx[0].vout[0].nValue = block.GetBlockValue(pindexPrev->nHeight + 1, nFees);
193 block.hashPrevBlock = pindexPrev->GetBlockHash(); 228 block.hashPrevBlock = pindexPrev->GetBlockHash();
194 block.hashMerkleRoot = block.BuildMerkleTree(); 229 block.hashMerkleRoot = block.BuildMerkleTree();
195 block.nTime = max((unsigned int)(pindexPrev->GetMedianTimePast() + 1), 230 block.nTime = max((unsigned int)(pindexPrev->GetMedianTimePast() + 1),