Skip to content

Commit

Permalink
main: spentindex for the mempool
Browse files Browse the repository at this point in the history
  • Loading branch information
Braydon Fuller committed May 16, 2016
1 parent 5e54311 commit c5b1b04
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 79 deletions.
17 changes: 13 additions & 4 deletions qa/rpc-tests/spentindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,22 @@ def run_test(self):
self.nodes[0].importprivkey(privkey)
signed_tx2 = self.nodes[0].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8"))
txid2 = self.nodes[0].sendrawtransaction(signed_tx2["hex"], True)

# Check the mempool index
self.sync_all()
txVerbose3 = self.nodes[1].getrawtransaction(txid2, 1)
assert_equal(txVerbose3["vin"][0]["address"], address2)
assert_equal(txVerbose3["vin"][0]["value"], Decimal(unspent[0]["amount"]))
assert_equal(txVerbose3["vin"][0]["valueSat"], amount)

# Check the database index
self.nodes[0].generate(1)
self.sync_all()

txVerbose3 = self.nodes[3].getrawtransaction(txid2, 1)
assert_equal(txVerbose3["vin"][0]["address"], address2)
assert_equal(txVerbose2["vin"][0]["value"], Decimal(unspent[0]["amount"]))
assert_equal(txVerbose2["vin"][0]["valueSat"], amount)
txVerbose4 = self.nodes[3].getrawtransaction(txid2, 1)
assert_equal(txVerbose4["vin"][0]["address"], address2)
assert_equal(txVerbose4["vin"][0]["value"], Decimal(unspent[0]["amount"]))
assert_equal(txVerbose4["vin"][0]["valueSat"], amount)

print "Passed\n"

Expand Down
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ endif
# bitcoin core #
BITCOIN_CORE_H = \
addressindex.h \
spentindex.h \
addrman.h \
alert.h \
amount.h \
Expand Down
10 changes: 10 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1209,10 +1209,17 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C

// Store transaction in memory
pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());

// Add memory address index
if (fAddressIndex) {
pool.addAddressIndex(entry, view);
}

// Add memory spent index
if (fSpentIndex) {
pool.addSpentIndex(entry, view);
}

// trim mempool and check if tx was trimmed
if (!fOverrideMempoolLimit) {
LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
Expand Down Expand Up @@ -1254,6 +1261,9 @@ bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
if (!fSpentIndex)
return false;

if (mempool.getSpentIndex(key, value))
return true;

if (!pblocktree->ReadSpentIndex(key, value))
return error("unable to get spent info");

Expand Down
76 changes: 1 addition & 75 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "net.h"
#include "script/script_error.h"
#include "sync.h"
#include "spentindex.h"

#include <algorithm>
#include <exception>
Expand Down Expand Up @@ -284,81 +285,6 @@ struct CNodeStateStats {
std::vector<int> vHeightInFlight;
};

struct CSpentIndexKey {
uint256 txid;
unsigned int outputIndex;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(txid);
READWRITE(outputIndex);
}

CSpentIndexKey(uint256 t, unsigned int i) {
txid = t;
outputIndex = i;
}

CSpentIndexKey() {
SetNull();
}

void SetNull() {
txid.SetNull();
outputIndex = 0;
}

};

struct CSpentIndexValue {
uint256 txid;
unsigned int inputIndex;
int blockHeight;
CAmount satoshis;
int addressType;
uint160 addressHash;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(txid);
READWRITE(inputIndex);
READWRITE(blockHeight);
READWRITE(satoshis);
READWRITE(addressType);
READWRITE(addressHash);
}

CSpentIndexValue(uint256 t, unsigned int i, int h, CAmount s, int type, uint160 a) {
txid = t;
inputIndex = i;
blockHeight = h;
satoshis = s;
addressType = type;
addressHash = a;
}

CSpentIndexValue() {
SetNull();
}

void SetNull() {
txid.SetNull();
inputIndex = 0;
blockHeight = 0;
satoshis = 0;
addressType = 0;
addressHash.SetNull();
}

bool IsNull() const {
return txid.IsNull();
}
};

struct CTimestampIndexIteratorKey {
unsigned int timestamp;

Expand Down
98 changes: 98 additions & 0 deletions src/spentindex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_SPENTINDEX_H
#define BITCOIN_SPENTINDEX_H

#include "uint256.h"
#include "amount.h"

struct CSpentIndexKey {
uint256 txid;
unsigned int outputIndex;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(txid);
READWRITE(outputIndex);
}

CSpentIndexKey(uint256 t, unsigned int i) {
txid = t;
outputIndex = i;
}

CSpentIndexKey() {
SetNull();
}

void SetNull() {
txid.SetNull();
outputIndex = 0;
}

};

struct CSpentIndexValue {
uint256 txid;
unsigned int inputIndex;
int blockHeight;
CAmount satoshis;
int addressType;
uint160 addressHash;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(txid);
READWRITE(inputIndex);
READWRITE(blockHeight);
READWRITE(satoshis);
READWRITE(addressType);
READWRITE(addressHash);
}

CSpentIndexValue(uint256 t, unsigned int i, int h, CAmount s, int type, uint160 a) {
txid = t;
inputIndex = i;
blockHeight = h;
satoshis = s;
addressType = type;
addressHash = a;
}

CSpentIndexValue() {
SetNull();
}

void SetNull() {
txid.SetNull();
inputIndex = 0;
blockHeight = 0;
satoshis = 0;
addressType = 0;
addressHash.SetNull();
}

bool IsNull() const {
return txid.IsNull();
}
};

struct CSpentIndexKeyCompare
{
bool operator()(const CSpentIndexKey& a, const CSpentIndexKey& b) const {
if (a.txid == b.txid) {
return a.outputIndex < b.outputIndex;
} else {
return a.txid < b.txid;
}
}
};

#endif // BITCOIN_SPENTINDEX_H
66 changes: 66 additions & 0 deletions src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,71 @@ bool CTxMemPool::removeAddressIndex(const uint256 txhash)
return true;
}

void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view)
{
LOCK(cs);

const CTransaction& tx = entry.GetTx();
std::vector<CSpentIndexKey> inserted;

uint256 txhash = tx.GetHash();
for (unsigned int j = 0; j < tx.vin.size(); j++) {
const CTxIn input = tx.vin[j];
const CTxOut &prevout = view.GetOutputFor(input);
uint160 addressHash;
int addressType;

if (prevout.scriptPubKey.IsPayToScriptHash()) {
addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
addressType = 2;
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
addressType = 1;
} else {
addressHash.SetNull();
addressType = 0;
}

CSpentIndexKey key = CSpentIndexKey(input.prevout.hash, input.prevout.n);
CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, addressType, addressHash);

mapSpent.insert(make_pair(key, value));
inserted.push_back(key);

}

mapSpentInserted.insert(make_pair(txhash, inserted));
}

bool CTxMemPool::getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
{
LOCK(cs);
mapSpentIndex::iterator it;

it = mapSpent.find(key);
if (it != mapSpent.end()) {
value = it->second;
return true;
}
return false;
}

bool CTxMemPool::removeSpentIndex(const uint256 txhash)
{
LOCK(cs);
mapSpentIndexInserted::iterator it = mapSpentInserted.find(txhash);

if (it != mapSpentInserted.end()) {
std::vector<CSpentIndexKey> keys = (*it).second;
for (std::vector<CSpentIndexKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) {
mapSpent.erase(*mit);
}
mapSpentInserted.erase(it);
}

return true;
}

void CTxMemPool::removeUnchecked(txiter it)
{
const uint256 hash = it->GetTx().GetHash();
Expand All @@ -505,6 +570,7 @@ void CTxMemPool::removeUnchecked(txiter it)
nTransactionsUpdated++;
minerPolicyEstimator->removeTx(hash);
removeAddressIndex(hash);
removeSpentIndex(hash);
}

// Calculates descendants of entry that are not already in setDescendants, and adds to
Expand Down
11 changes: 11 additions & 0 deletions src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <set>

#include "addressindex.h"
#include "spentindex.h"
#include "amount.h"
#include "coins.h"
#include "primitives/transaction.h"
Expand Down Expand Up @@ -396,6 +397,12 @@ class CTxMemPool
typedef std::map<uint256, std::vector<CMempoolAddressDeltaKey> > addressDeltaMapInserted;
addressDeltaMapInserted mapAddressInserted;

typedef std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare> mapSpentIndex;
mapSpentIndex mapSpent;

typedef std::map<uint256, std::vector<CSpentIndexKey> > mapSpentIndexInserted;
mapSpentIndexInserted mapSpentInserted;

void UpdateParent(txiter entry, txiter parent, bool add);
void UpdateChild(txiter entry, txiter child, bool add);

Expand Down Expand Up @@ -432,6 +439,10 @@ class CTxMemPool
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results);
bool removeAddressIndex(const uint256 txhash);

void addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
bool getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
bool removeSpentIndex(const uint256 txhash);

void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);
Expand Down

0 comments on commit c5b1b04

Please sign in to comment.