Skip to content

Commit b72c5bd

Browse files
NateIsernclaude
andcommitted
feat: add address/spent/timestamp index + RPCs (Bitpay insight / PIVX)
Add the standard address-index feature so the daemon exposes the RPCs getaddressbalance, getaddressutxos, getaddresstxids, getaddressdeltas, getaddressmempool and getspentinfo, gated on -addressindex / -spentindex / -timestampindex (network-agnostic: works on mainnet, testnet and regtest). - addressindex.h / spentindex.h: key/value types (CAddressIndexKey, CAddressUnspentKey/Value, CSpentIndexKey/Value, CTimestampIndexKey, iterator keys, mempool delta types). Heights serialized big-endian for LevelDB key ordering. - serialize.h: ser_writedata*/ser_readdata* stream byte helpers (incl. *be). - txdb.[h|cpp]: DB prefixes (d/u/p/s/z) + Write/Erase/Read address index, Update/Read address-unspent, Update/Read spent index, Write/Read timestamp index. Read loops check the type byte before deserializing the key so a prefix scan that runs into a shorter-keyed family does not over-read. - main.[h|cpp]: globals fAddressIndex/fSpentIndex/fTimestampIndex; build index entries from each tx's vins (spends) and vouts (receives) in ConnectBlock and revert them symmetrically in DisconnectBlock (correct on reorg); GetAddressIndex / GetAddressUnspent / GetSpentIndex / GetTimestampIndex helpers; persist flags via the block tree db and require -reindex when they change; feed the mempool index from AcceptToMemoryPool. - txmempool.[h|cpp]: addressDeltaMap + addAddressIndex/getAddressIndex/ removeAddressIndex and the mempool spent index so getaddressmempool/getspentinfo see unconfirmed entries. - base58.[h|cpp]: CBitcoinAddress::GetIndexKey to turn an address into (hash,type). - rpcaddressindex.cpp + rpcserver.[h|cpp] table + rpcclient.cpp conversion table: the six RPCs, matching PIVX return shapes. - init.cpp: read the flags before block index load, add -reindex-required checks and help text. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7c44a3f commit b72c5bd

17 files changed

Lines changed: 1803 additions & 1 deletion

src/Makefile.am

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,12 @@ endif
7575
# faircoin core #
7676
BITCOIN_CORE_H = \
7777
activemasternode.h \
78+
addressindex.h \
7879
addrman.h \
7980
alert.h \
8081
allocators.h \
8182
amount.h \
83+
spentindex.h \
8284
base58.h \
8385
bip38.h \
8486
bloom.h \
@@ -197,6 +199,7 @@ libbitcoin_server_a_SOURCES = \
197199
noui.cpp \
198200
pow.cpp \
199201
rest.cpp \
202+
rpcaddressindex.cpp \
200203
rpcblockchain.cpp \
201204
rpcmasternode.cpp \
202205
rpcmasternode-budget.cpp \

src/addressindex.h

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2014 The Bitcoin developers
3+
// Copyright (c) 2017 The Bitcore developers
4+
// Distributed under the MIT software license, see the accompanying
5+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
6+
7+
#ifndef BITCOIN_ADDRESSINDEX_H
8+
#define BITCOIN_ADDRESSINDEX_H
9+
10+
#include "amount.h"
11+
#include "script/script.h"
12+
#include "serialize.h"
13+
#include "uint256.h"
14+
15+
#include <utility>
16+
#include <vector>
17+
18+
struct CAddressUnspentKey {
19+
unsigned int type;
20+
uint160 hashBytes;
21+
uint256 txhash;
22+
size_t index;
23+
24+
size_t GetSerializeSize(int nType, int nVersion) const
25+
{
26+
return 57;
27+
}
28+
template <typename Stream>
29+
void Serialize(Stream& s, int nType, int nVersion) const
30+
{
31+
ser_writedata8(s, type);
32+
hashBytes.Serialize(s, nType, nVersion);
33+
txhash.Serialize(s, nType, nVersion);
34+
ser_writedata32(s, index);
35+
}
36+
template <typename Stream>
37+
void Unserialize(Stream& s, int nType, int nVersion)
38+
{
39+
type = ser_readdata8(s);
40+
hashBytes.Unserialize(s, nType, nVersion);
41+
txhash.Unserialize(s, nType, nVersion);
42+
index = ser_readdata32(s);
43+
}
44+
45+
CAddressUnspentKey(unsigned int addressType, uint160 addressHash, uint256 txid, size_t indexValue)
46+
{
47+
type = addressType;
48+
hashBytes = addressHash;
49+
txhash = txid;
50+
index = indexValue;
51+
}
52+
53+
CAddressUnspentKey()
54+
{
55+
SetNull();
56+
}
57+
58+
void SetNull()
59+
{
60+
type = 0;
61+
hashBytes.SetNull();
62+
txhash.SetNull();
63+
index = 0;
64+
}
65+
};
66+
67+
struct CAddressUnspentValue {
68+
CAmount satoshis;
69+
CScript script;
70+
int blockHeight;
71+
72+
ADD_SERIALIZE_METHODS;
73+
74+
template <typename Stream, typename Operation>
75+
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
76+
{
77+
READWRITE(satoshis);
78+
READWRITE(script);
79+
READWRITE(blockHeight);
80+
}
81+
82+
CAddressUnspentValue(CAmount sats, CScript scriptPubKey, int height)
83+
{
84+
satoshis = sats;
85+
script = scriptPubKey;
86+
blockHeight = height;
87+
}
88+
89+
CAddressUnspentValue()
90+
{
91+
SetNull();
92+
}
93+
94+
void SetNull()
95+
{
96+
satoshis = -1;
97+
script.clear();
98+
blockHeight = 0;
99+
}
100+
101+
bool IsNull() const
102+
{
103+
return (satoshis == -1);
104+
}
105+
};
106+
107+
struct CAddressIndexKey {
108+
unsigned int type;
109+
uint160 hashBytes;
110+
int blockHeight;
111+
unsigned int txindex;
112+
uint256 txhash;
113+
size_t index;
114+
bool spending;
115+
116+
size_t GetSerializeSize(int nType, int nVersion) const
117+
{
118+
return 66;
119+
}
120+
template <typename Stream>
121+
void Serialize(Stream& s, int nType, int nVersion) const
122+
{
123+
ser_writedata8(s, type);
124+
hashBytes.Serialize(s, nType, nVersion);
125+
// Heights are stored big-endian for key sorting in LevelDB
126+
ser_writedata32be(s, blockHeight);
127+
ser_writedata32be(s, txindex);
128+
txhash.Serialize(s, nType, nVersion);
129+
ser_writedata32(s, index);
130+
char f = spending;
131+
ser_writedata8(s, f);
132+
}
133+
template <typename Stream>
134+
void Unserialize(Stream& s, int nType, int nVersion)
135+
{
136+
type = ser_readdata8(s);
137+
hashBytes.Unserialize(s, nType, nVersion);
138+
blockHeight = ser_readdata32be(s);
139+
txindex = ser_readdata32be(s);
140+
txhash.Unserialize(s, nType, nVersion);
141+
index = ser_readdata32(s);
142+
char f = ser_readdata8(s);
143+
spending = f;
144+
}
145+
146+
CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex,
147+
uint256 txid, size_t indexValue, bool isSpending)
148+
{
149+
type = addressType;
150+
hashBytes = addressHash;
151+
blockHeight = height;
152+
txindex = blockindex;
153+
txhash = txid;
154+
index = indexValue;
155+
spending = isSpending;
156+
}
157+
158+
CAddressIndexKey()
159+
{
160+
SetNull();
161+
}
162+
163+
void SetNull()
164+
{
165+
type = 0;
166+
hashBytes.SetNull();
167+
blockHeight = 0;
168+
txindex = 0;
169+
txhash.SetNull();
170+
index = 0;
171+
spending = false;
172+
}
173+
};
174+
175+
struct CAddressIndexIteratorKey {
176+
unsigned int type;
177+
uint160 hashBytes;
178+
179+
size_t GetSerializeSize(int nType, int nVersion) const
180+
{
181+
return 21;
182+
}
183+
template <typename Stream>
184+
void Serialize(Stream& s, int nType, int nVersion) const
185+
{
186+
ser_writedata8(s, type);
187+
hashBytes.Serialize(s, nType, nVersion);
188+
}
189+
template <typename Stream>
190+
void Unserialize(Stream& s, int nType, int nVersion)
191+
{
192+
type = ser_readdata8(s);
193+
hashBytes.Unserialize(s, nType, nVersion);
194+
}
195+
196+
CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash)
197+
{
198+
type = addressType;
199+
hashBytes = addressHash;
200+
}
201+
202+
CAddressIndexIteratorKey()
203+
{
204+
SetNull();
205+
}
206+
207+
void SetNull()
208+
{
209+
type = 0;
210+
hashBytes.SetNull();
211+
}
212+
};
213+
214+
struct CAddressIndexIteratorHeightKey {
215+
unsigned int type;
216+
uint160 hashBytes;
217+
int blockHeight;
218+
219+
size_t GetSerializeSize(int nType, int nVersion) const
220+
{
221+
return 25;
222+
}
223+
template <typename Stream>
224+
void Serialize(Stream& s, int nType, int nVersion) const
225+
{
226+
ser_writedata8(s, type);
227+
hashBytes.Serialize(s, nType, nVersion);
228+
ser_writedata32be(s, blockHeight);
229+
}
230+
template <typename Stream>
231+
void Unserialize(Stream& s, int nType, int nVersion)
232+
{
233+
type = ser_readdata8(s);
234+
hashBytes.Unserialize(s, nType, nVersion);
235+
blockHeight = ser_readdata32be(s);
236+
}
237+
238+
CAddressIndexIteratorHeightKey(unsigned int addressType, uint160 addressHash, int height)
239+
{
240+
type = addressType;
241+
hashBytes = addressHash;
242+
blockHeight = height;
243+
}
244+
245+
CAddressIndexIteratorHeightKey()
246+
{
247+
SetNull();
248+
}
249+
250+
void SetNull()
251+
{
252+
type = 0;
253+
hashBytes.SetNull();
254+
blockHeight = 0;
255+
}
256+
};
257+
258+
struct CTimestampIndexIteratorKey {
259+
unsigned int timestamp;
260+
261+
size_t GetSerializeSize(int nType, int nVersion) const
262+
{
263+
return 4;
264+
}
265+
template <typename Stream>
266+
void Serialize(Stream& s, int nType, int nVersion) const
267+
{
268+
ser_writedata32be(s, timestamp);
269+
}
270+
template <typename Stream>
271+
void Unserialize(Stream& s, int nType, int nVersion)
272+
{
273+
timestamp = ser_readdata32be(s);
274+
}
275+
276+
CTimestampIndexIteratorKey(unsigned int time)
277+
{
278+
timestamp = time;
279+
}
280+
281+
CTimestampIndexIteratorKey()
282+
{
283+
SetNull();
284+
}
285+
286+
void SetNull()
287+
{
288+
timestamp = 0;
289+
}
290+
};
291+
292+
struct CTimestampIndexKey {
293+
unsigned int timestamp;
294+
uint256 blockHash;
295+
296+
size_t GetSerializeSize(int nType, int nVersion) const
297+
{
298+
return 36;
299+
}
300+
template <typename Stream>
301+
void Serialize(Stream& s, int nType, int nVersion) const
302+
{
303+
ser_writedata32be(s, timestamp);
304+
blockHash.Serialize(s, nType, nVersion);
305+
}
306+
template <typename Stream>
307+
void Unserialize(Stream& s, int nType, int nVersion)
308+
{
309+
timestamp = ser_readdata32be(s);
310+
blockHash.Unserialize(s, nType, nVersion);
311+
}
312+
313+
CTimestampIndexKey(unsigned int time, uint256 hash)
314+
{
315+
timestamp = time;
316+
blockHash = hash;
317+
}
318+
319+
CTimestampIndexKey()
320+
{
321+
SetNull();
322+
}
323+
324+
void SetNull()
325+
{
326+
timestamp = 0;
327+
blockHash.SetNull();
328+
}
329+
};
330+
331+
#endif // BITCOIN_ADDRESSINDEX_H

src/base58.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,23 @@ bool CBitcoinAddress::IsScript() const
293293
return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
294294
}
295295

296+
bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const
297+
{
298+
if (!IsValid()) {
299+
return false;
300+
} else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) {
301+
memcpy(&hashBytes, &vchData[0], 20);
302+
type = 1;
303+
return true;
304+
} else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) {
305+
memcpy(&hashBytes, &vchData[0], 20);
306+
type = 2;
307+
return true;
308+
}
309+
310+
return false;
311+
}
312+
296313
void CBitcoinSecret::SetKey(const CKey& vchSecret)
297314
{
298315
assert(vchSecret.IsValid());

src/base58.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ class CBitcoinAddress : public CBase58Data
122122

123123
CTxDestination Get() const;
124124
bool GetKeyID(CKeyID& keyID) const;
125+
bool GetIndexKey(uint160& hashBytes, int& type) const;
125126
bool IsScript() const;
126127
};
127128

0 commit comments

Comments
 (0)