main: start of address index
Adds a configuration option for addressindex to search for txids by address. Includes an additional rpc method for getting the txids for an address.
This commit is contained in:
parent
edd321609c
commit
205830690b
|
@ -371,6 +371,8 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||||
#endif
|
#endif
|
||||||
strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0));
|
strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0));
|
||||||
|
|
||||||
|
strUsage += HelpMessageOpt("-addressindex", strprintf(_("Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses (default: %u)"), DEFAULT_ADDRESSINDEX));
|
||||||
|
|
||||||
strUsage += HelpMessageGroup(_("Connection options:"));
|
strUsage += HelpMessageGroup(_("Connection options:"));
|
||||||
strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open"));
|
strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open"));
|
||||||
strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100));
|
strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100));
|
||||||
|
|
61
src/main.cpp
61
src/main.cpp
|
@ -67,6 +67,7 @@ bool fExperimentalMode = false;
|
||||||
bool fImporting = false;
|
bool fImporting = false;
|
||||||
bool fReindex = false;
|
bool fReindex = false;
|
||||||
bool fTxIndex = false;
|
bool fTxIndex = false;
|
||||||
|
bool fAddressIndex = false;
|
||||||
bool fHavePruned = false;
|
bool fHavePruned = false;
|
||||||
bool fPruneMode = false;
|
bool fPruneMode = false;
|
||||||
bool fIsBareMultisigStd = true;
|
bool fIsBareMultisigStd = true;
|
||||||
|
@ -1582,6 +1583,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetAddressIndex(uint160 addressHash, int type, std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex)
|
||||||
|
{
|
||||||
|
if (!fAddressIndex)
|
||||||
|
return error("%s: address index not enabled");
|
||||||
|
|
||||||
|
if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex))
|
||||||
|
return error("%s: unable to get txids for address");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
|
/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
|
||||||
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
|
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
|
||||||
{
|
{
|
||||||
|
@ -2447,6 +2459,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
|
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
|
||||||
vPos.reserve(block.vtx.size());
|
vPos.reserve(block.vtx.size());
|
||||||
blockundo.vtxundo.reserve(block.vtx.size() - 1);
|
blockundo.vtxundo.reserve(block.vtx.size() - 1);
|
||||||
|
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||||
|
|
||||||
// Construct the incremental merkle tree at the current
|
// Construct the incremental merkle tree at the current
|
||||||
// block position,
|
// block position,
|
||||||
|
@ -2477,6 +2490,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||||
{
|
{
|
||||||
const CTransaction &tx = block.vtx[i];
|
const CTransaction &tx = block.vtx[i];
|
||||||
|
const uint256 txhash = tx.GetHash();
|
||||||
|
|
||||||
nInputs += tx.vin.size();
|
nInputs += tx.vin.size();
|
||||||
nSigOps += GetLegacySigOpCount(tx);
|
nSigOps += GetLegacySigOpCount(tx);
|
||||||
|
@ -2495,6 +2509,22 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"),
|
return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"),
|
||||||
REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met");
|
REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met");
|
||||||
|
|
||||||
|
if (fAddressIndex)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < tx.vin.size(); j++) {
|
||||||
|
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
|
||||||
|
if (prevout.scriptPubKey.IsPayToScriptHash()) {
|
||||||
|
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
|
||||||
|
addressIndex.push_back(make_pair(CAddressIndexKey(uint160(hashBytes), 2, txhash, j), prevout.nValue * -1));
|
||||||
|
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||||
|
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
|
||||||
|
addressIndex.push_back(make_pair(CAddressIndexKey(uint160(hashBytes), 1, txhash, j), prevout.nValue * -1));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add in sigops done by pay-to-script-hash inputs;
|
// Add in sigops done by pay-to-script-hash inputs;
|
||||||
// this is to prevent a "rogue miner" from creating
|
// this is to prevent a "rogue miner" from creating
|
||||||
// an incredibly-expensive-to-validate block.
|
// an incredibly-expensive-to-validate block.
|
||||||
|
@ -2516,6 +2546,24 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
control.Add(vChecks);
|
control.Add(vChecks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fAddressIndex) {
|
||||||
|
for (unsigned int k = 0; k < tx.vout.size(); k++) {
|
||||||
|
const CTxOut &out = tx.vout[k];
|
||||||
|
|
||||||
|
if (out.scriptPubKey.IsPayToScriptHash()) {
|
||||||
|
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
|
||||||
|
addressIndex.push_back(make_pair(CAddressIndexKey(uint160(hashBytes), 2, txhash, k), out.nValue));
|
||||||
|
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||||
|
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
|
||||||
|
addressIndex.push_back(make_pair(CAddressIndexKey(uint160(hashBytes), 1, txhash, k), out.nValue));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CTxUndo undoDummy;
|
CTxUndo undoDummy;
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
blockundo.vtxundo.push_back(CTxUndo());
|
blockundo.vtxundo.push_back(CTxUndo());
|
||||||
|
@ -2607,6 +2655,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
if (!pblocktree->WriteTxIndex(vPos))
|
if (!pblocktree->WriteTxIndex(vPos))
|
||||||
return AbortNode(state, "Failed to write transaction index");
|
return AbortNode(state, "Failed to write transaction index");
|
||||||
|
|
||||||
|
if (fAddressIndex)
|
||||||
|
if (!pblocktree->WriteAddressIndex(addressIndex))
|
||||||
|
return AbortNode(state, "Failed to write address index");
|
||||||
|
|
||||||
// add this block to the view's block chain
|
// add this block to the view's block chain
|
||||||
view.SetBestBlock(pindex->GetBlockHash());
|
view.SetBestBlock(pindex->GetBlockHash());
|
||||||
|
|
||||||
|
@ -4093,6 +4145,10 @@ bool static LoadBlockIndexDB()
|
||||||
pblocktree->ReadFlag("txindex", fTxIndex);
|
pblocktree->ReadFlag("txindex", fTxIndex);
|
||||||
LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled");
|
LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
// Check whether we have an address index
|
||||||
|
pblocktree->ReadFlag("addressindex", fAddressIndex);
|
||||||
|
LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled");
|
||||||
|
|
||||||
// Fill in-memory data
|
// Fill in-memory data
|
||||||
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
|
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
|
||||||
{
|
{
|
||||||
|
@ -4426,6 +4482,11 @@ bool InitBlockIndex() {
|
||||||
// Use the provided setting for -txindex in the new database
|
// Use the provided setting for -txindex in the new database
|
||||||
fTxIndex = GetBoolArg("-txindex", false);
|
fTxIndex = GetBoolArg("-txindex", false);
|
||||||
pblocktree->WriteFlag("txindex", fTxIndex);
|
pblocktree->WriteFlag("txindex", fTxIndex);
|
||||||
|
|
||||||
|
// Use the provided setting for -addressindex in the new database
|
||||||
|
fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX);
|
||||||
|
pblocktree->WriteFlag("addressindex", fAddressIndex);
|
||||||
|
|
||||||
LogPrintf("Initializing databases...\n");
|
LogPrintf("Initializing databases...\n");
|
||||||
|
|
||||||
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
|
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
|
||||||
|
|
38
src/main.h
38
src/main.h
|
@ -99,6 +99,7 @@ static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
|
||||||
/** Maximum length of reject messages. */
|
/** Maximum length of reject messages. */
|
||||||
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
|
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
|
||||||
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
|
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
|
||||||
|
static const bool DEFAULT_ADDRESSINDEX = false;
|
||||||
|
|
||||||
// Sanity check the magic numbers when we change them
|
// Sanity check the magic numbers when we change them
|
||||||
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE);
|
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE);
|
||||||
|
@ -268,6 +269,42 @@ struct CNodeStateStats {
|
||||||
std::vector<int> vHeightInFlight;
|
std::vector<int> vHeightInFlight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CAddressIndexKey {
|
||||||
|
uint160 hashBytes;
|
||||||
|
unsigned int type;
|
||||||
|
uint256 txhash;
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||||
|
READWRITE(hashBytes);
|
||||||
|
READWRITE(type);
|
||||||
|
READWRITE(txhash);
|
||||||
|
READWRITE(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAddressIndexKey(uint160 addressHash, unsigned int addressType, uint256 txid, size_t txindex) {
|
||||||
|
hashBytes = addressHash;
|
||||||
|
type = addressType;
|
||||||
|
txhash = txid;
|
||||||
|
index = txindex;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAddressIndexKey() {
|
||||||
|
SetNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetNull() {
|
||||||
|
hashBytes.SetNull();
|
||||||
|
type = 0;
|
||||||
|
txhash.SetNull();
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct CDiskTxPos : public CDiskBlockPos
|
struct CDiskTxPos : public CDiskBlockPos
|
||||||
{
|
{
|
||||||
unsigned int nTxOffset; // after header
|
unsigned int nTxOffset; // after header
|
||||||
|
@ -431,6 +468,7 @@ public:
|
||||||
ScriptError GetScriptError() const { return error; }
|
ScriptError GetScriptError() const { return error; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool GetAddressIndex(uint160 addressHash, int type, std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex);
|
||||||
|
|
||||||
/** Functions for disk access for blocks */
|
/** Functions for disk access for blocks */
|
||||||
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
|
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
|
||||||
|
|
|
@ -492,6 +492,9 @@ static const CRPCCommand commands[] =
|
||||||
{ "util", "createmultisig", &createmultisig, true },
|
{ "util", "createmultisig", &createmultisig, true },
|
||||||
{ "util", "verifymessage", &verifymessage, true },
|
{ "util", "verifymessage", &verifymessage, true },
|
||||||
|
|
||||||
|
/* Address index */
|
||||||
|
{ "addressindex", "getaddresstxids", &getaddresstxids, false }, /* insight explorer */
|
||||||
|
|
||||||
/* Not shown in help */
|
/* Not shown in help */
|
||||||
{ "hidden", "setmocktime", &setmocktime, true },
|
{ "hidden", "setmocktime", &setmocktime, true },
|
||||||
};
|
};
|
||||||
|
@ -501,3 +504,39 @@ void RegisterMiscRPCCommands(CRPCTable &tableRPC)
|
||||||
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
|
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
|
||||||
tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
|
tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue getaddresstxids(const UniValue& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (fHelp || params.size() != 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"getaddresstxids\n"
|
||||||
|
"\nReturns the txids for an address (requires addressindex to be enabled).\n"
|
||||||
|
"\nResult\n"
|
||||||
|
"[\n"
|
||||||
|
" \"transactionid\" (string) The transaction id\n"
|
||||||
|
" ,...\n"
|
||||||
|
"]\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
CBitcoinAddress address(params[0].get_str());
|
||||||
|
if (!address.IsValid())
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||||
|
|
||||||
|
CKeyID keyID;
|
||||||
|
address.GetKeyID(keyID);
|
||||||
|
|
||||||
|
int type = 1; // TODO
|
||||||
|
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||||
|
|
||||||
|
LOCK(cs_main);
|
||||||
|
|
||||||
|
if (!GetAddressIndex(keyID, type, addressIndex))
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
|
||||||
|
|
||||||
|
UniValue result(UniValue::VARR);
|
||||||
|
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||||
|
result.push_back(it->first.txhash.GetHex());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,310 @@
|
||||||
|
// Copyright (c) 2010 Satoshi Nakamoto
|
||||||
|
// Copyright (c) 2009-2014 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_RPCSERVER_H
|
||||||
|
#define BITCOIN_RPCSERVER_H
|
||||||
|
|
||||||
|
#include "amount.h"
|
||||||
|
#include "rpcprotocol.h"
|
||||||
|
#include "uint256.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
#include <univalue.h>
|
||||||
|
|
||||||
|
class AsyncRPCQueue;
|
||||||
|
class CRPCCommand;
|
||||||
|
|
||||||
|
namespace RPCServer
|
||||||
|
{
|
||||||
|
void OnStarted(boost::function<void ()> slot);
|
||||||
|
void OnStopped(boost::function<void ()> slot);
|
||||||
|
void OnPreCommand(boost::function<void (const CRPCCommand&)> slot);
|
||||||
|
void OnPostCommand(boost::function<void (const CRPCCommand&)> slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CBlockIndex;
|
||||||
|
class CNetAddr;
|
||||||
|
|
||||||
|
class JSONRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UniValue id;
|
||||||
|
std::string strMethod;
|
||||||
|
UniValue params;
|
||||||
|
|
||||||
|
JSONRequest() { id = NullUniValue; }
|
||||||
|
void parse(const UniValue& valRequest);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Query whether RPC is running */
|
||||||
|
bool IsRPCRunning();
|
||||||
|
|
||||||
|
/** Get the async queue*/
|
||||||
|
std::shared_ptr<AsyncRPCQueue> getAsyncRPCQueue();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the RPC warmup status. When this is done, all RPC calls will error out
|
||||||
|
* immediately with RPC_IN_WARMUP.
|
||||||
|
*/
|
||||||
|
void SetRPCWarmupStatus(const std::string& newStatus);
|
||||||
|
/* Mark warmup as done. RPC calls will be processed from now on. */
|
||||||
|
void SetRPCWarmupFinished();
|
||||||
|
|
||||||
|
/* returns the current warmup state. */
|
||||||
|
bool RPCIsInWarmup(std::string *statusOut);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
|
||||||
|
* the right number of arguments are passed, just that any passed are the correct type.
|
||||||
|
* Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type));
|
||||||
|
*/
|
||||||
|
void RPCTypeCheck(const UniValue& params,
|
||||||
|
const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check for expected keys/value types in an Object.
|
||||||
|
Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type));
|
||||||
|
*/
|
||||||
|
void RPCTypeCheckObj(const UniValue& o,
|
||||||
|
const std::map<std::string, UniValue::VType>& typesExpected, bool fAllowNull=false);
|
||||||
|
|
||||||
|
/** Opaque base class for timers returned by NewTimerFunc.
|
||||||
|
* This provides no methods at the moment, but makes sure that delete
|
||||||
|
* cleans up the whole state.
|
||||||
|
*/
|
||||||
|
class RPCTimerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~RPCTimerBase() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RPC timer "driver".
|
||||||
|
*/
|
||||||
|
class RPCTimerInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~RPCTimerInterface() {}
|
||||||
|
/** Implementation name */
|
||||||
|
virtual const char *Name() = 0;
|
||||||
|
/** Factory function for timers.
|
||||||
|
* RPC will call the function to create a timer that will call func in *millis* milliseconds.
|
||||||
|
* @note As the RPC mechanism is backend-neutral, it can use different implementations of timers.
|
||||||
|
* This is needed to cope with the case in which there is no HTTP server, but
|
||||||
|
* only GUI RPC console, and to break the dependency of rpcserver on httprpc.
|
||||||
|
*/
|
||||||
|
virtual RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Register factory function for timers */
|
||||||
|
void RPCRegisterTimerInterface(RPCTimerInterface *iface);
|
||||||
|
/** Unregister factory function for timers */
|
||||||
|
void RPCUnregisterTimerInterface(RPCTimerInterface *iface);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run func nSeconds from now.
|
||||||
|
* Overrides previous timer <name> (if any).
|
||||||
|
*/
|
||||||
|
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds);
|
||||||
|
|
||||||
|
typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
class CRPCCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string category;
|
||||||
|
std::string name;
|
||||||
|
rpcfn_type actor;
|
||||||
|
bool okSafeMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitcoin RPC command dispatcher.
|
||||||
|
*/
|
||||||
|
class CRPCTable
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::map<std::string, const CRPCCommand*> mapCommands;
|
||||||
|
public:
|
||||||
|
CRPCTable();
|
||||||
|
const CRPCCommand* operator[](const std::string& name) const;
|
||||||
|
std::string help(const std::string& name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a method.
|
||||||
|
* @param method Method to execute
|
||||||
|
* @param params UniValue Array of arguments (JSON objects)
|
||||||
|
* @returns Result of the call.
|
||||||
|
* @throws an exception (UniValue) when an error happens.
|
||||||
|
*/
|
||||||
|
UniValue execute(const std::string &method, const UniValue ¶ms) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const CRPCTable tableRPC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities: convert hex-encoded Values
|
||||||
|
* (throws error if not hex).
|
||||||
|
*/
|
||||||
|
extern uint256 ParseHashV(const UniValue& v, std::string strName);
|
||||||
|
extern uint256 ParseHashO(const UniValue& o, std::string strKey);
|
||||||
|
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
|
||||||
|
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
|
||||||
|
|
||||||
|
extern int64_t nWalletUnlockTime;
|
||||||
|
extern CAmount AmountFromValue(const UniValue& value);
|
||||||
|
extern UniValue ValueFromAmount(const CAmount& amount);
|
||||||
|
extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
|
||||||
|
extern double GetNetworkDifficulty(const CBlockIndex* blockindex = NULL);
|
||||||
|
extern std::string HelpRequiringPassphrase();
|
||||||
|
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
|
||||||
|
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
|
||||||
|
|
||||||
|
extern void EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp
|
||||||
|
extern UniValue getaddresstxids(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
extern UniValue getpeerinfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue ping(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue addnode(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue disconnectnode(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getnettotals(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue setban(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue listbanned(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue clearbanned(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern UniValue importprivkey(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue importaddress(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue dumpwallet(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue importwallet(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp
|
||||||
|
extern UniValue setgenerate(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue generate(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getlocalsolps(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getnetworksolps(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getnetworkhashps(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getmininginfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue prioritisetransaction(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getblocktemplate(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue submitblock(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue estimatefee(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue estimatepriority(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue getaccountaddress(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue setaccount(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getaccount(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue sendtoaddress(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue signmessage(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue verifymessage(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getbalance(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue movecmd(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue sendfrom(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue sendmany(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue addmultisigaddress(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue createmultisig(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue listtransactions(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue listaddressgroupings(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue listaccounts(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue listsinceblock(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue gettransaction(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue backupwallet(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue keypoolrefill(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue walletpassphrase(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue walletpassphrasechange(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue walletlock(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue encryptwallet(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue validateaddress(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getinfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getwalletinfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getblockchaininfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getnetworkinfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getdeprecationinfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue setmocktime(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue resendwallettransactions(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue zc_benchmark(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue zc_raw_keygen(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue zc_raw_receive(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rcprawtransaction.cpp
|
||||||
|
extern UniValue listunspent(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue lockunspent(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue listlockunspent(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue createrawtransaction(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue decoderawtransaction(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue decodescript(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue fundrawtransaction(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue signrawtransaction(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue sendrawtransaction(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue gettxoutproof(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue verifytxoutproof(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp
|
||||||
|
extern UniValue getbestblockhash(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getdifficulty(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue settxfee(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getrawmempool(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getblockhash(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getblockheader(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getblock(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue gettxout(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue verifychain(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getchaintips(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue invalidateblock(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue reconsiderblock(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
extern UniValue getblocksubsidy(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
|
extern UniValue z_exportkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern UniValue z_importkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern UniValue z_importviewingkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern UniValue z_getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_listaddresses(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_exportwallet(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern UniValue z_importwallet(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_listunspent(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_getbalance(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_gettotalbalance(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_mergetoaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_sendmany(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_shieldcoinbase(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_getoperationresult(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_listoperationids(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_validateaddress(const UniValue& params, bool fHelp); // in rpcmisc.cpp
|
||||||
|
extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp
|
||||||
|
extern UniValue z_validatepaymentdisclosure(const UniValue ¶ms, bool fHelp); // in rpcdisclosure.cpp
|
||||||
|
|
||||||
|
bool StartRPC();
|
||||||
|
void InterruptRPC();
|
||||||
|
void StopRPC();
|
||||||
|
std::string JSONRPCExecBatch(const UniValue& vReq);
|
||||||
|
|
||||||
|
#endif // BITCOIN_RPCSERVER_H
|
|
@ -201,6 +201,17 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
|
||||||
return subscript.GetSigOpCount(true);
|
return subscript.GetSigOpCount(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CScript::IsPayToPublicKeyHash() const
|
||||||
|
{
|
||||||
|
// Extra-fast test for pay-to-pubkey-hash CScripts:
|
||||||
|
return (this->size() == 25 &&
|
||||||
|
(*this)[0] == OP_DUP &&
|
||||||
|
(*this)[1] == OP_HASH160 &&
|
||||||
|
(*this)[2] == 0x14 &&
|
||||||
|
(*this)[23] == OP_EQUALVERIFY &&
|
||||||
|
(*this)[24] == OP_CHECKSIG);
|
||||||
|
}
|
||||||
|
|
||||||
bool CScript::IsPayToScriptHash() const
|
bool CScript::IsPayToScriptHash() const
|
||||||
{
|
{
|
||||||
// Extra-fast test for pay-to-script-hash CScripts:
|
// Extra-fast test for pay-to-script-hash CScripts:
|
||||||
|
|
|
@ -565,6 +565,8 @@ public:
|
||||||
*/
|
*/
|
||||||
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
||||||
|
|
||||||
|
bool IsPayToPublicKeyHash() const;
|
||||||
|
|
||||||
bool IsPayToScriptHash() const;
|
bool IsPayToScriptHash() const;
|
||||||
|
|
||||||
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
||||||
|
|
33
src/txdb.cpp
33
src/txdb.cpp
|
@ -26,6 +26,7 @@ static const char DB_SAPLING_NULLIFIER = 'S';
|
||||||
static const char DB_COINS = 'c';
|
static const char DB_COINS = 'c';
|
||||||
static const char DB_BLOCK_FILES = 'f';
|
static const char DB_BLOCK_FILES = 'f';
|
||||||
static const char DB_TXINDEX = 't';
|
static const char DB_TXINDEX = 't';
|
||||||
|
static const char DB_ADDRESSINDEX = 'd';
|
||||||
static const char DB_BLOCK_INDEX = 'b';
|
static const char DB_BLOCK_INDEX = 'b';
|
||||||
|
|
||||||
static const char DB_BEST_BLOCK = 'B';
|
static const char DB_BEST_BLOCK = 'B';
|
||||||
|
@ -293,6 +294,38 @@ bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos>
|
||||||
return WriteBatch(batch);
|
return WriteBatch(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CBlockTreeDB::WriteAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount > >&vect) {
|
||||||
|
CDBBatch batch(*this);
|
||||||
|
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
|
||||||
|
batch.Write(make_pair(DB_ADDRESSINDEX, it->first), it->second);
|
||||||
|
return WriteBatch(batch);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex) {
|
||||||
|
|
||||||
|
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
|
||||||
|
|
||||||
|
pcursor->Seek(make_pair(DB_ADDRESSINDEX, addressHash)); //TODO include type
|
||||||
|
|
||||||
|
while (pcursor->Valid()) {
|
||||||
|
boost::this_thread::interruption_point();
|
||||||
|
std::pair<char,CAddressIndexKey> key;
|
||||||
|
if (pcursor->GetKey(key) && key.first == DB_ADDRESSINDEX && key.second.hashBytes == addressHash) {
|
||||||
|
CAmount nValue;
|
||||||
|
if (pcursor->GetValue(nValue)) {
|
||||||
|
addressIndex.push_back(make_pair(key.second, nValue));
|
||||||
|
pcursor->Next();
|
||||||
|
} else {
|
||||||
|
return error("failed to get address index value");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
|
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
|
||||||
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
|
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
class CBlockFileInfo;
|
class CBlockFileInfo;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
struct CDiskTxPos;
|
struct CDiskTxPos;
|
||||||
|
struct CAddressIndexKey;
|
||||||
class uint256;
|
class uint256;
|
||||||
|
|
||||||
//! -dbcache default (MiB)
|
//! -dbcache default (MiB)
|
||||||
|
@ -70,6 +71,8 @@ public:
|
||||||
bool ReadReindexing(bool &fReindex);
|
bool ReadReindexing(bool &fReindex);
|
||||||
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
|
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
|
||||||
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
|
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
|
||||||
|
bool WriteAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount> > &vect);
|
||||||
|
bool ReadAddressIndex(uint160 addressHash, int type, std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex);
|
||||||
bool WriteFlag(const std::string &name, bool fValue);
|
bool WriteFlag(const std::string &name, bool fValue);
|
||||||
bool ReadFlag(const std::string &name, bool &fValue);
|
bool ReadFlag(const std::string &name, bool &fValue);
|
||||||
bool LoadBlockIndexGuts();
|
bool LoadBlockIndexGuts();
|
||||||
|
|
Loading…
Reference in New Issue