Skip to content

Commit

Permalink
Merge pull request #11 from braydonf/0.12-bitcore-spent
Browse files Browse the repository at this point in the history
indexes: add satoshis and address to spent index value
  • Loading branch information
kleetus committed May 17, 2016
2 parents dbbb3f9 + c5b1b04 commit ca9da76
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 89 deletions.
38 changes: 38 additions & 0 deletions qa/rpc-tests/spentindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,56 @@ def run_test(self):
self.nodes[0].generate(1)
self.sync_all()

print "Testing getspentinfo method..."

# Check that the spentinfo works standalone
info = self.nodes[1].getspentinfo({"txid": unspent[0]["txid"], "index": unspent[0]["vout"]})
assert_equal(info["txid"], txid)
assert_equal(info["index"], 0)
assert_equal(info["height"], 106)

print "Testing getrawtransaction method..."

# Check that verbose raw transaction includes spent info
txVerbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1)
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentTxId"], txid)
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentIndex"], 0)
assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentHeight"], 106)

# Check that verbose raw transaction includes input values
txVerbose2 = self.nodes[3].getrawtransaction(txid, 1)
assert_equal(txVerbose2["vin"][0]["value"], Decimal(unspent[0]["amount"]))
assert_equal(txVerbose2["vin"][0]["valueSat"], amount)

# Check that verbose raw transaction includes address values and input values
privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG"
address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW"
addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex")
scriptPubKey2 = CScript([OP_DUP, OP_HASH160, addressHash2, OP_EQUALVERIFY, OP_CHECKSIG])
tx2 = CTransaction()
tx2.vin = [CTxIn(COutPoint(int(txid, 16), 0))]
tx2.vout = [CTxOut(amount, scriptPubKey2)]
tx.rehash()
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()

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
59 changes: 33 additions & 26 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 Expand Up @@ -2220,39 +2230,36 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
for (size_t j = 0; j < tx.vin.size(); j++) {

const CTxIn input = tx.vin[j];
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
uint160 hashBytes;
int addressType;

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

if (fAddressIndex) {

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

if (prevout.scriptPubKey.IsPayToScriptHash()) {
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);

// record spending activity
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));

// remove address from unspent index
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);

// record spending activity
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));

// remove address from unspent index
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue()));

} else {
continue;
}
// remove address from unspent index
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
}

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

}

if (fStrictPayToScriptHash)
Expand Down
64 changes: 1 addition & 63 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,69 +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;

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);
}

CSpentIndexValue(uint256 t, unsigned int i, int h) {
txid = t;
inputIndex = i;
blockHeight = h;
}

CSpentIndexValue() {
SetNull();
}

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

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

struct CTimestampIndexIteratorKey {
unsigned int timestamp;

Expand Down
14 changes: 14 additions & 0 deletions src/rpcrawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true)));
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in.push_back(Pair("scriptSig", o));

// Add address and value info if spentindex enabled
CSpentIndexValue spentInfo;
CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n);
if (GetSpentIndex(spentKey, spentInfo)) {
in.push_back(Pair("value", ValueFromAmount(spentInfo.satoshis)));
in.push_back(Pair("valueSat", spentInfo.satoshis));
if (spentInfo.addressType == 1) {
in.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
} else if (spentInfo.addressType == 2) {
in.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
}
}

}
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
vin.push_back(in);
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
Loading

0 comments on commit ca9da76

Please sign in to comment.