Add method to get address deltas from a block
This commit is contained in:
parent
ec4c4a37f6
commit
1a07bc991a
|
@ -104,7 +104,7 @@ class SpentIndexTest(BitcoinTestFramework):
|
||||||
assert_equal(txVerbose3["vin"][0]["valueSat"], amount)
|
assert_equal(txVerbose3["vin"][0]["valueSat"], amount)
|
||||||
|
|
||||||
# Check the database index
|
# Check the database index
|
||||||
self.nodes[0].generate(1)
|
block_hash = self.nodes[0].generate(1)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
txVerbose4 = self.nodes[3].getrawtransaction(txid2, 1)
|
txVerbose4 = self.nodes[3].getrawtransaction(txid2, 1)
|
||||||
|
@ -112,6 +112,26 @@ class SpentIndexTest(BitcoinTestFramework):
|
||||||
assert_equal(txVerbose4["vin"][0]["value"], Decimal(unspent[0]["amount"]))
|
assert_equal(txVerbose4["vin"][0]["value"], Decimal(unspent[0]["amount"]))
|
||||||
assert_equal(txVerbose4["vin"][0]["valueSat"], amount)
|
assert_equal(txVerbose4["vin"][0]["valueSat"], amount)
|
||||||
|
|
||||||
|
|
||||||
|
# Check block deltas
|
||||||
|
print "Testing getblockdeltas..."
|
||||||
|
|
||||||
|
block = self.nodes[3].getblockdeltas(block_hash[0])
|
||||||
|
assert_equal(len(block["deltas"]), 2)
|
||||||
|
assert_equal(block["deltas"][0]["index"], 0)
|
||||||
|
assert_equal(len(block["deltas"][0]["inputs"]), 0)
|
||||||
|
assert_equal(len(block["deltas"][0]["outputs"]), 0)
|
||||||
|
assert_equal(block["deltas"][1]["index"], 1)
|
||||||
|
assert_equal(block["deltas"][1]["txid"], txid2)
|
||||||
|
assert_equal(block["deltas"][1]["inputs"][0]["index"], 0)
|
||||||
|
assert_equal(block["deltas"][1]["inputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW")
|
||||||
|
assert_equal(block["deltas"][1]["inputs"][0]["satoshis"], amount * -1)
|
||||||
|
assert_equal(block["deltas"][1]["inputs"][0]["prevtxid"], txid)
|
||||||
|
assert_equal(block["deltas"][1]["inputs"][0]["prevout"], 0)
|
||||||
|
assert_equal(block["deltas"][1]["outputs"][0]["index"], 0)
|
||||||
|
assert_equal(block["deltas"][1]["outputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW")
|
||||||
|
assert_equal(block["deltas"][1]["outputs"][0]["satoshis"], amount)
|
||||||
|
|
||||||
print "Passed\n"
|
print "Passed\n"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
|
#include "base58.h"
|
||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
|
@ -125,6 +126,112 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
|
||||||
|
{
|
||||||
|
UniValue result(UniValue::VOBJ);
|
||||||
|
result.push_back(Pair("hash", block.GetHash().GetHex()));
|
||||||
|
int confirmations = -1;
|
||||||
|
// Only report confirmations if the block is on the main chain
|
||||||
|
if (chainActive.Contains(blockindex)) {
|
||||||
|
confirmations = chainActive.Height() - blockindex->nHeight + 1;
|
||||||
|
} else {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block is an orphan");
|
||||||
|
}
|
||||||
|
result.push_back(Pair("confirmations", confirmations));
|
||||||
|
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
|
||||||
|
result.push_back(Pair("height", blockindex->nHeight));
|
||||||
|
result.push_back(Pair("version", block.nVersion));
|
||||||
|
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
|
||||||
|
|
||||||
|
UniValue deltas(UniValue::VARR);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < block.vtx.size(); i++) {
|
||||||
|
const CTransaction &tx = block.vtx[i];
|
||||||
|
const uint256 txhash = tx.GetHash();
|
||||||
|
|
||||||
|
UniValue entry(UniValue::VOBJ);
|
||||||
|
entry.push_back(Pair("txid", txhash.GetHex()));
|
||||||
|
entry.push_back(Pair("index", (int)i));
|
||||||
|
|
||||||
|
UniValue inputs(UniValue::VARR);
|
||||||
|
|
||||||
|
if (!tx.IsCoinBase()) {
|
||||||
|
|
||||||
|
for (size_t j = 0; j < tx.vin.size(); j++) {
|
||||||
|
const CTxIn input = tx.vin[j];
|
||||||
|
|
||||||
|
UniValue delta(UniValue::VOBJ);
|
||||||
|
|
||||||
|
CSpentIndexValue spentInfo;
|
||||||
|
CSpentIndexKey spentKey(input.prevout.hash, input.prevout.n);
|
||||||
|
|
||||||
|
if (GetSpentIndex(spentKey, spentInfo)) {
|
||||||
|
if (spentInfo.addressType == 1) {
|
||||||
|
delta.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
|
||||||
|
} else if (spentInfo.addressType == 2) {
|
||||||
|
delta.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
delta.push_back(Pair("satoshis", -1 * spentInfo.satoshis));
|
||||||
|
delta.push_back(Pair("index", (int)j));
|
||||||
|
delta.push_back(Pair("prevtxid", input.prevout.hash.GetHex()));
|
||||||
|
delta.push_back(Pair("prevout", (int)input.prevout.n));
|
||||||
|
|
||||||
|
inputs.push_back(delta);
|
||||||
|
} else {
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Spent information not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.push_back(Pair("inputs", inputs));
|
||||||
|
|
||||||
|
UniValue outputs(UniValue::VARR);
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < tx.vout.size(); k++) {
|
||||||
|
const CTxOut &out = tx.vout[k];
|
||||||
|
|
||||||
|
UniValue delta(UniValue::VOBJ);
|
||||||
|
|
||||||
|
if (out.scriptPubKey.IsPayToScriptHash()) {
|
||||||
|
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
|
||||||
|
delta.push_back(Pair("address", CBitcoinAddress(CScriptID(uint160(hashBytes))).ToString()));
|
||||||
|
|
||||||
|
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||||
|
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
|
||||||
|
delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString()));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
delta.push_back(Pair("satoshis", out.nValue));
|
||||||
|
delta.push_back(Pair("index", (int)k));
|
||||||
|
|
||||||
|
outputs.push_back(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.push_back(Pair("outputs", outputs));
|
||||||
|
deltas.push_back(entry);
|
||||||
|
|
||||||
|
}
|
||||||
|
result.push_back(Pair("deltas", deltas));
|
||||||
|
result.push_back(Pair("time", block.GetBlockTime()));
|
||||||
|
result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
|
||||||
|
result.push_back(Pair("nonce", block.nNonce.GetHex()));
|
||||||
|
result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
|
||||||
|
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
|
||||||
|
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
|
||||||
|
|
||||||
|
if (blockindex->pprev)
|
||||||
|
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
|
||||||
|
CBlockIndex *pnext = chainActive.Next(blockindex);
|
||||||
|
if (pnext)
|
||||||
|
result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
|
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
|
||||||
{
|
{
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
|
@ -313,6 +420,29 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
|
||||||
return mempoolToJSON(fVerbose);
|
return mempoolToJSON(fVerbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue getblockdeltas(const UniValue& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (fHelp || params.size() != 1)
|
||||||
|
throw runtime_error("");
|
||||||
|
|
||||||
|
std::string strHash = params[0].get_str();
|
||||||
|
uint256 hash(uint256S(strHash));
|
||||||
|
|
||||||
|
if (mapBlockIndex.count(hash) == 0)
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
|
||||||
|
|
||||||
|
CBlock block;
|
||||||
|
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||||
|
|
||||||
|
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
|
||||||
|
|
||||||
|
if(!ReadBlockFromDisk(block, pblockindex))
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
|
||||||
|
|
||||||
|
return blockToDeltasJSON(block, pblockindex);
|
||||||
|
}
|
||||||
|
|
||||||
UniValue getblockhashes(const UniValue& params, bool fHelp)
|
UniValue getblockhashes(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() != 2)
|
if (fHelp || params.size() != 2)
|
||||||
|
|
|
@ -273,6 +273,7 @@ extern UniValue settxfee(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
|
extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getrawmempool(const UniValue& params, bool fHelp);
|
extern UniValue getrawmempool(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getblockhashes(const UniValue& params, bool fHelp);
|
extern UniValue getblockhashes(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getblockdeltas(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getblockhash(const UniValue& params, bool fHelp);
|
extern UniValue getblockhash(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getblockheader(const UniValue& params, bool fHelp);
|
extern UniValue getblockheader(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getblock(const UniValue& params, bool fHelp);
|
extern UniValue getblock(const UniValue& params, bool fHelp);
|
||||||
|
|
Loading…
Reference in New Issue