Skip to content

Commit ca9da76

Browse files
committed
Merge pull request #11 from braydonf/0.12-bitcore-spent
indexes: add satoshis and address to spent index value
2 parents dbbb3f9 + c5b1b04 commit ca9da76

File tree

8 files changed

+262
-89
lines changed

8 files changed

+262
-89
lines changed

qa/rpc-tests/spentindex.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,56 @@ def run_test(self):
6262
self.nodes[0].generate(1)
6363
self.sync_all()
6464

65+
print "Testing getspentinfo method..."
66+
6567
# Check that the spentinfo works standalone
6668
info = self.nodes[1].getspentinfo({"txid": unspent[0]["txid"], "index": unspent[0]["vout"]})
6769
assert_equal(info["txid"], txid)
6870
assert_equal(info["index"], 0)
6971
assert_equal(info["height"], 106)
7072

73+
print "Testing getrawtransaction method..."
74+
7175
# Check that verbose raw transaction includes spent info
7276
txVerbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1)
7377
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentTxId"], txid)
7478
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentIndex"], 0)
7579
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentHeight"], 106)
7680

81+
# Check that verbose raw transaction includes input values
82+
txVerbose2 = self.nodes[3].getrawtransaction(txid, 1)
83+
assert_equal(txVerbose2["vin"][0]["value"], Decimal(unspent[0]["amount"]))
84+
assert_equal(txVerbose2["vin"][0]["valueSat"], amount)
85+
86+
# Check that verbose raw transaction includes address values and input values
87+
privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG"
88+
address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW"
89+
addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex")
90+
scriptPubKey2 = CScript([OP_DUP, OP_HASH160, addressHash2, OP_EQUALVERIFY, OP_CHECKSIG])
91+
tx2 = CTransaction()
92+
tx2.vin = [CTxIn(COutPoint(int(txid, 16), 0))]
93+
tx2.vout = [CTxOut(amount, scriptPubKey2)]
94+
tx.rehash()
95+
self.nodes[0].importprivkey(privkey)
96+
signed_tx2 = self.nodes[0].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8"))
97+
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
107+
self.nodes[0].generate(1)
108+
self.sync_all()
109+
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)
114+
77115
print "Passed\n"
78116

79117

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: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,10 +1209,17 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
12091209

12101210
// Store transaction in memory
12111211
pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
1212+
1213+
// Add memory address index
12121214
if (fAddressIndex) {
12131215
pool.addAddressIndex(entry, view);
12141216
}
12151217

1218+
// Add memory spent index
1219+
if (fSpentIndex) {
1220+
pool.addSpentIndex(entry, view);
1221+
}
1222+
12161223
// trim mempool and check if tx was trimmed
12171224
if (!fOverrideMempoolLimit) {
12181225
LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
@@ -1254,6 +1261,9 @@ bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
12541261
if (!fSpentIndex)
12551262
return false;
12561263

1264+
if (mempool.getSpentIndex(key, value))
1265+
return true;
1266+
12571267
if (!pblocktree->ReadSpentIndex(key, value))
12581268
return error("unable to get spent info");
12591269

@@ -2220,39 +2230,36 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
22202230
for (size_t j = 0; j < tx.vin.size(); j++) {
22212231

22222232
const CTxIn input = tx.vin[j];
2233+
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
2234+
uint160 hashBytes;
2235+
int addressType;
22232236

2224-
if (fSpentIndex) {
2225-
// add the spent index to determine the txid and input that spent an output
2226-
spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight)));
2237+
if (prevout.scriptPubKey.IsPayToScriptHash()) {
2238+
hashBytes = uint160(vector <unsigned char>(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
2239+
addressType = 2;
2240+
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
2241+
hashBytes = uint160(vector <unsigned char>(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
2242+
addressType = 1;
2243+
} else {
2244+
hashBytes.SetNull();
2245+
addressType = 0;
22272246
}
22282247

2229-
if (fAddressIndex) {
2230-
2231-
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
2248+
if (fAddressIndex && addressType > 0) {
2249+
// record spending activity
2250+
addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
22322251

2233-
if (prevout.scriptPubKey.IsPayToScriptHash()) {
2234-
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
2235-
2236-
// record spending activity
2237-
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
2238-
2239-
// remove address from unspent index
2240-
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
2241-
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
2242-
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
2243-
2244-
// record spending activity
2245-
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
2246-
2247-
// remove address from unspent index
2248-
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
2249-
2250-
} else {
2251-
continue;
2252-
}
2252+
// remove address from unspent index
2253+
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
22532254
}
22542255

2256+
if (fSpentIndex) {
2257+
// add the spent index to determine the txid and input that spent an output
2258+
// and to find the amount and address from an input
2259+
spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes)));
2260+
}
22552261
}
2262+
22562263
}
22572264

22582265
if (fStrictPayToScriptHash)

src/main.h

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "net.h"
1717
#include "script/script_error.h"
1818
#include "sync.h"
19+
#include "spentindex.h"
1920

2021
#include <algorithm>
2122
#include <exception>
@@ -284,69 +285,6 @@ struct CNodeStateStats {
284285
std::vector<int> vHeightInFlight;
285286
};
286287

287-
struct CSpentIndexKey {
288-
uint256 txid;
289-
unsigned int outputIndex;
290-
291-
ADD_SERIALIZE_METHODS;
292-
293-
template <typename Stream, typename Operation>
294-
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
295-
READWRITE(txid);
296-
READWRITE(outputIndex);
297-
}
298-
299-
CSpentIndexKey(uint256 t, unsigned int i) {
300-
txid = t;
301-
outputIndex = i;
302-
}
303-
304-
CSpentIndexKey() {
305-
SetNull();
306-
}
307-
308-
void SetNull() {
309-
txid.SetNull();
310-
outputIndex = 0;
311-
}
312-
313-
};
314-
315-
struct CSpentIndexValue {
316-
uint256 txid;
317-
unsigned int inputIndex;
318-
int blockHeight;
319-
320-
ADD_SERIALIZE_METHODS;
321-
322-
template <typename Stream, typename Operation>
323-
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
324-
READWRITE(txid);
325-
READWRITE(inputIndex);
326-
READWRITE(blockHeight);
327-
}
328-
329-
CSpentIndexValue(uint256 t, unsigned int i, int h) {
330-
txid = t;
331-
inputIndex = i;
332-
blockHeight = h;
333-
}
334-
335-
CSpentIndexValue() {
336-
SetNull();
337-
}
338-
339-
void SetNull() {
340-
txid.SetNull();
341-
inputIndex = 0;
342-
blockHeight = 0;
343-
}
344-
345-
bool IsNull() const {
346-
return txid.IsNull();
347-
}
348-
};
349-
350288
struct CTimestampIndexIteratorKey {
351289
unsigned int timestamp;
352290

src/rpcrawtransaction.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
7878
o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true)));
7979
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
8080
in.push_back(Pair("scriptSig", o));
81+
82+
// Add address and value info if spentindex enabled
83+
CSpentIndexValue spentInfo;
84+
CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n);
85+
if (GetSpentIndex(spentKey, spentInfo)) {
86+
in.push_back(Pair("value", ValueFromAmount(spentInfo.satoshis)));
87+
in.push_back(Pair("valueSat", spentInfo.satoshis));
88+
if (spentInfo.addressType == 1) {
89+
in.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
90+
} else if (spentInfo.addressType == 2) {
91+
in.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
92+
}
93+
}
94+
8195
}
8296
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
8397
vin.push_back(in);

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

0 commit comments

Comments
 (0)