Skip to content

Commit 55fa479

Browse files
author
Braydon Fuller
committed
main: spentindex for the mempool
1 parent 4c7dc87 commit 55fa479

File tree

7 files changed

+200
-79
lines changed

7 files changed

+200
-79
lines changed

qa/rpc-tests/spentindex.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,22 @@ def run_test(self):
9595
self.nodes[0].importprivkey(privkey)
9696
signed_tx2 = self.nodes[0].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8"))
9797
txid2 = self.nodes[0].sendrawtransaction(signed_tx2["hex"], True)
98+
99+
# Check the mempool index
100+
self.sync_all()
101+
txVerbose3 = self.nodes[1].getrawtransaction(txid2, 1)
102+
assert_equal(txVerbose3["vin"][0]["address"], address2)
103+
assert_equal(txVerbose3["vin"][0]["value"], Decimal(unspent[0]["amount"]))
104+
assert_equal(txVerbose3["vin"][0]["valueSat"], amount)
105+
106+
# Check the database index
98107
self.nodes[0].generate(1)
99108
self.sync_all()
100109

101-
txVerbose3 = self.nodes[3].getrawtransaction(txid2, 1)
102-
assert_equal(txVerbose3["vin"][0]["address"], address2)
103-
assert_equal(txVerbose2["vin"][0]["value"], Decimal(unspent[0]["amount"]))
104-
assert_equal(txVerbose2["vin"][0]["valueSat"], amount)
110+
txVerbose4 = self.nodes[3].getrawtransaction(txid2, 1)
111+
assert_equal(txVerbose4["vin"][0]["address"], address2)
112+
assert_equal(txVerbose4["vin"][0]["value"], Decimal(unspent[0]["amount"]))
113+
assert_equal(txVerbose4["vin"][0]["valueSat"], amount)
105114

106115
print "Passed\n"
107116

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ endif
8080
# bitcoin core #
8181
BITCOIN_CORE_H = \
8282
addressindex.h \
83+
spentindex.h \
8384
addrman.h \
8485
alert.h \
8586
amount.h \

src/main.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,10 +1415,17 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
14151415

14161416
// Store transaction in memory
14171417
pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
1418+
1419+
// Add memory address index
14181420
if (fAddressIndex) {
14191421
pool.addAddressIndex(entry, view);
14201422
}
14211423

1424+
// Add memory spent index
1425+
if (fSpentIndex) {
1426+
pool.addSpentIndex(entry, view);
1427+
}
1428+
14221429
// trim mempool and check if tx was trimmed
14231430
if (!fOverrideMempoolLimit) {
14241431
LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
@@ -1460,6 +1467,9 @@ bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
14601467
if (!fSpentIndex)
14611468
return false;
14621469

1470+
if (mempool.getSpentIndex(key, value))
1471+
return true;
1472+
14631473
if (!pblocktree->ReadSpentIndex(key, value))
14641474
return error("unable to get spent info");
14651475

src/main.h

Lines changed: 1 addition & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "script/script_error.h"
1818
#include "sync.h"
1919
#include "versionbits.h"
20+
#include "spentindex.h"
2021

2122
#include <algorithm>
2223
#include <exception>
@@ -293,81 +294,6 @@ struct CNodeStateStats {
293294
std::vector<int> vHeightInFlight;
294295
};
295296

296-
struct CSpentIndexKey {
297-
uint256 txid;
298-
unsigned int outputIndex;
299-
300-
ADD_SERIALIZE_METHODS;
301-
302-
template <typename Stream, typename Operation>
303-
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
304-
READWRITE(txid);
305-
READWRITE(outputIndex);
306-
}
307-
308-
CSpentIndexKey(uint256 t, unsigned int i) {
309-
txid = t;
310-
outputIndex = i;
311-
}
312-
313-
CSpentIndexKey() {
314-
SetNull();
315-
}
316-
317-
void SetNull() {
318-
txid.SetNull();
319-
outputIndex = 0;
320-
}
321-
322-
};
323-
324-
struct CSpentIndexValue {
325-
uint256 txid;
326-
unsigned int inputIndex;
327-
int blockHeight;
328-
CAmount satoshis;
329-
int addressType;
330-
uint160 addressHash;
331-
332-
ADD_SERIALIZE_METHODS;
333-
334-
template <typename Stream, typename Operation>
335-
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
336-
READWRITE(txid);
337-
READWRITE(inputIndex);
338-
READWRITE(blockHeight);
339-
READWRITE(satoshis);
340-
READWRITE(addressType);
341-
READWRITE(addressHash);
342-
}
343-
344-
CSpentIndexValue(uint256 t, unsigned int i, int h, CAmount s, int type, uint160 a) {
345-
txid = t;
346-
inputIndex = i;
347-
blockHeight = h;
348-
satoshis = s;
349-
addressType = type;
350-
addressHash = a;
351-
}
352-
353-
CSpentIndexValue() {
354-
SetNull();
355-
}
356-
357-
void SetNull() {
358-
txid.SetNull();
359-
inputIndex = 0;
360-
blockHeight = 0;
361-
satoshis = 0;
362-
addressType = 0;
363-
addressHash.SetNull();
364-
}
365-
366-
bool IsNull() const {
367-
return txid.IsNull();
368-
}
369-
};
370-
371297
struct CTimestampIndexIteratorKey {
372298
unsigned int timestamp;
373299

src/spentindex.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2015 The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#ifndef BITCOIN_SPENTINDEX_H
7+
#define BITCOIN_SPENTINDEX_H
8+
9+
#include "uint256.h"
10+
#include "amount.h"
11+
12+
struct CSpentIndexKey {
13+
uint256 txid;
14+
unsigned int outputIndex;
15+
16+
ADD_SERIALIZE_METHODS;
17+
18+
template <typename Stream, typename Operation>
19+
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
20+
READWRITE(txid);
21+
READWRITE(outputIndex);
22+
}
23+
24+
CSpentIndexKey(uint256 t, unsigned int i) {
25+
txid = t;
26+
outputIndex = i;
27+
}
28+
29+
CSpentIndexKey() {
30+
SetNull();
31+
}
32+
33+
void SetNull() {
34+
txid.SetNull();
35+
outputIndex = 0;
36+
}
37+
38+
};
39+
40+
struct CSpentIndexValue {
41+
uint256 txid;
42+
unsigned int inputIndex;
43+
int blockHeight;
44+
CAmount satoshis;
45+
int addressType;
46+
uint160 addressHash;
47+
48+
ADD_SERIALIZE_METHODS;
49+
50+
template <typename Stream, typename Operation>
51+
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
52+
READWRITE(txid);
53+
READWRITE(inputIndex);
54+
READWRITE(blockHeight);
55+
READWRITE(satoshis);
56+
READWRITE(addressType);
57+
READWRITE(addressHash);
58+
}
59+
60+
CSpentIndexValue(uint256 t, unsigned int i, int h, CAmount s, int type, uint160 a) {
61+
txid = t;
62+
inputIndex = i;
63+
blockHeight = h;
64+
satoshis = s;
65+
addressType = type;
66+
addressHash = a;
67+
}
68+
69+
CSpentIndexValue() {
70+
SetNull();
71+
}
72+
73+
void SetNull() {
74+
txid.SetNull();
75+
inputIndex = 0;
76+
blockHeight = 0;
77+
satoshis = 0;
78+
addressType = 0;
79+
addressHash.SetNull();
80+
}
81+
82+
bool IsNull() const {
83+
return txid.IsNull();
84+
}
85+
};
86+
87+
struct CSpentIndexKeyCompare
88+
{
89+
bool operator()(const CSpentIndexKey& a, const CSpentIndexKey& b) const {
90+
if (a.txid == b.txid) {
91+
return a.outputIndex < b.outputIndex;
92+
} else {
93+
return a.txid < b.txid;
94+
}
95+
}
96+
};
97+
98+
#endif // BITCOIN_SPENTINDEX_H

src/txmempool.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,71 @@ bool CTxMemPool::removeAddressIndex(const uint256 txhash)
496496
return true;
497497
}
498498

499+
void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view)
500+
{
501+
LOCK(cs);
502+
503+
const CTransaction& tx = entry.GetTx();
504+
std::vector<CSpentIndexKey> inserted;
505+
506+
uint256 txhash = tx.GetHash();
507+
for (unsigned int j = 0; j < tx.vin.size(); j++) {
508+
const CTxIn input = tx.vin[j];
509+
const CTxOut &prevout = view.GetOutputFor(input);
510+
uint160 addressHash;
511+
int addressType;
512+
513+
if (prevout.scriptPubKey.IsPayToScriptHash()) {
514+
addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
515+
addressType = 2;
516+
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
517+
addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
518+
addressType = 1;
519+
} else {
520+
addressHash.SetNull();
521+
addressType = 0;
522+
}
523+
524+
CSpentIndexKey key = CSpentIndexKey(input.prevout.hash, input.prevout.n);
525+
CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, addressType, addressHash);
526+
527+
mapSpent.insert(make_pair(key, value));
528+
inserted.push_back(key);
529+
530+
}
531+
532+
mapSpentInserted.insert(make_pair(txhash, inserted));
533+
}
534+
535+
bool CTxMemPool::getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
536+
{
537+
LOCK(cs);
538+
mapSpentIndex::iterator it;
539+
540+
it = mapSpent.find(key);
541+
if (it != mapSpent.end()) {
542+
value = it->second;
543+
return true;
544+
}
545+
return false;
546+
}
547+
548+
bool CTxMemPool::removeSpentIndex(const uint256 txhash)
549+
{
550+
LOCK(cs);
551+
mapSpentIndexInserted::iterator it = mapSpentInserted.find(txhash);
552+
553+
if (it != mapSpentInserted.end()) {
554+
std::vector<CSpentIndexKey> keys = (*it).second;
555+
for (std::vector<CSpentIndexKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) {
556+
mapSpent.erase(*mit);
557+
}
558+
mapSpentInserted.erase(it);
559+
}
560+
561+
return true;
562+
}
563+
499564
void CTxMemPool::removeUnchecked(txiter it)
500565
{
501566
const uint256 hash = it->GetTx().GetHash();
@@ -510,6 +575,7 @@ void CTxMemPool::removeUnchecked(txiter it)
510575
nTransactionsUpdated++;
511576
minerPolicyEstimator->removeTx(hash);
512577
removeAddressIndex(hash);
578+
removeSpentIndex(hash);
513579
}
514580

515581
// Calculates descendants of entry that are not already in setDescendants, and adds to

src/txmempool.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <set>
1111

1212
#include "addressindex.h"
13+
#include "spentindex.h"
1314
#include "amount.h"
1415
#include "coins.h"
1516
#include "primitives/transaction.h"
@@ -426,6 +427,12 @@ class CTxMemPool
426427
typedef std::map<uint256, std::vector<CMempoolAddressDeltaKey> > addressDeltaMapInserted;
427428
addressDeltaMapInserted mapAddressInserted;
428429

430+
typedef std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare> mapSpentIndex;
431+
mapSpentIndex mapSpent;
432+
433+
typedef std::map<uint256, std::vector<CSpentIndexKey> > mapSpentIndexInserted;
434+
mapSpentIndexInserted mapSpentInserted;
435+
429436
void UpdateParent(txiter entry, txiter parent, bool add);
430437
void UpdateChild(txiter entry, txiter child, bool add);
431438

@@ -462,6 +469,10 @@ class CTxMemPool
462469
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results);
463470
bool removeAddressIndex(const uint256 txhash);
464471

472+
void addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
473+
bool getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
474+
bool removeSpentIndex(const uint256 txhash);
475+
465476
void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
466477
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
467478
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);

0 commit comments

Comments
 (0)