Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

indexes: add satoshis and address to spent index value #11

Merged
merged 3 commits into from
May 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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