From 205830690b62100315101de8e177dc964cfc9c3f Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Sat, 5 Mar 2016 16:31:10 -0500 Subject: [PATCH] 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. --- src/init.cpp | 2 + src/main.cpp | 61 +++++++++ src/main.h | 38 ++++++ src/rpc/misc.cpp | 39 ++++++ src/rpcserver.h | 310 ++++++++++++++++++++++++++++++++++++++++++ src/script/script.cpp | 11 ++ src/script/script.h | 2 + src/txdb.cpp | 33 +++++ src/txdb.h | 3 + 9 files changed, 499 insertions(+) create mode 100644 src/rpcserver.h diff --git a/src/init.cpp b/src/init.cpp index de337c893..c90580f8f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -371,6 +371,8 @@ std::string HelpMessage(HelpMessageMode mode) #endif 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 += HelpMessageOpt("-addnode=", _("Add a node to connect to and attempt to keep the connection open")); strUsage += HelpMessageOpt("-banscore=", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100)); diff --git a/src/main.cpp b/src/main.cpp index 54928d3f1..d5dc33696 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,6 +67,7 @@ bool fExperimentalMode = false; bool fImporting = false; bool fReindex = false; bool fTxIndex = false; +bool fAddressIndex = false; bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = true; @@ -1582,6 +1583,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return true; } +bool GetAddressIndex(uint160 addressHash, int type, std::vector > &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 */ 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 > vPos; vPos.reserve(block.vtx.size()); blockundo.vtxundo.reserve(block.vtx.size() - 1); + std::vector > addressIndex; // Construct the incremental merkle tree at the current // 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++) { const CTransaction &tx = block.vtx[i]; + const uint256 txhash = tx.GetHash(); nInputs += tx.vin.size(); 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"), 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 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 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; // this is to prevent a "rogue miner" from creating // an incredibly-expensive-to-validate block. @@ -2516,6 +2546,24 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin 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 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 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; if (i > 0) { blockundo.vtxundo.push_back(CTxUndo()); @@ -2607,6 +2655,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!pblocktree->WriteTxIndex(vPos)) 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 view.SetBestBlock(pindex->GetBlockHash()); @@ -4093,6 +4145,10 @@ bool static LoadBlockIndexDB() pblocktree->ReadFlag("txindex", fTxIndex); 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 BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) { @@ -4426,6 +4482,11 @@ bool InitBlockIndex() { // Use the provided setting for -txindex in the new database fTxIndex = GetBoolArg("-txindex", false); 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"); // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) diff --git a/src/main.h b/src/main.h index 9481a6090..99f425b4e 100644 --- a/src/main.h +++ b/src/main.h @@ -99,6 +99,7 @@ static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60; /** Maximum length of reject messages. */ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; 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 BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE); @@ -268,6 +269,42 @@ struct CNodeStateStats { std::vector vHeightInFlight; }; +struct CAddressIndexKey { + uint160 hashBytes; + unsigned int type; + uint256 txhash; + size_t index; + + ADD_SERIALIZE_METHODS; + + template + 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 { unsigned int nTxOffset; // after header @@ -431,6 +468,7 @@ public: ScriptError GetScriptError() const { return error; } }; +bool GetAddressIndex(uint160 addressHash, int type, std::vector > &addressIndex); /** Functions for disk access for blocks */ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 589fbf5c6..03674e122 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -492,6 +492,9 @@ static const CRPCCommand commands[] = { "util", "createmultisig", &createmultisig, true }, { "util", "verifymessage", &verifymessage, true }, + /* Address index */ + { "addressindex", "getaddresstxids", &getaddresstxids, false }, /* insight explorer */ + /* Not shown in help */ { "hidden", "setmocktime", &setmocktime, true }, }; @@ -501,3 +504,39 @@ void RegisterMiscRPCCommands(CRPCTable &tableRPC) for (unsigned int vcidx = 0; vcidx < ARRAYLEN(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 > 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 >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + result.push_back(it->first.txhash.GetHex()); + + return result; + +} diff --git a/src/rpcserver.h b/src/rpcserver.h new file mode 100644 index 000000000..6263a1f98 --- /dev/null +++ b/src/rpcserver.h @@ -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 +#include +#include +#include +#include + +#include + +#include + +class AsyncRPCQueue; +class CRPCCommand; + +namespace RPCServer +{ + void OnStarted(boost::function slot); + void OnStopped(boost::function slot); + void OnPreCommand(boost::function slot); + void OnPostCommand(boost::function 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 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& 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& 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& 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 (if any). + */ +void RPCRunLater(const std::string& name, boost::function 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 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 ParseHexV(const UniValue& v, std::string strName); +extern std::vector 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 diff --git a/src/script/script.cpp b/src/script/script.cpp index d5234cae8..6ae1250eb 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -201,6 +201,17 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const 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 { // Extra-fast test for pay-to-script-hash CScripts: diff --git a/src/script/script.h b/src/script/script.h index 781a09773..21a99d6c8 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -565,6 +565,8 @@ public: */ unsigned int GetSigOpCount(const CScript& scriptSig) const; + bool IsPayToPublicKeyHash() const; + bool IsPayToScriptHash() const; /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ diff --git a/src/txdb.cpp b/src/txdb.cpp index 2bed1df47..bc52650c7 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -26,6 +26,7 @@ static const char DB_SAPLING_NULLIFIER = 'S'; static const char DB_COINS = 'c'; static const char DB_BLOCK_FILES = 'f'; static const char DB_TXINDEX = 't'; +static const char DB_ADDRESSINDEX = 'd'; static const char DB_BLOCK_INDEX = 'b'; static const char DB_BEST_BLOCK = 'B'; @@ -293,6 +294,38 @@ bool CBlockTreeDB::WriteTxIndex(const std::vector return WriteBatch(batch); } +bool CBlockTreeDB::WriteAddressIndex(const std::vector >&vect) { + CDBBatch batch(*this); + for (std::vector >::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 > &addressIndex) { + + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_ADDRESSINDEX, addressHash)); //TODO include type + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair 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) { return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0'); } diff --git a/src/txdb.h b/src/txdb.h index a415ad2bb..f57cb0773 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -17,6 +17,7 @@ class CBlockFileInfo; class CBlockIndex; struct CDiskTxPos; +struct CAddressIndexKey; class uint256; //! -dbcache default (MiB) @@ -70,6 +71,8 @@ public: bool ReadReindexing(bool &fReindex); bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); bool WriteTxIndex(const std::vector > &list); + bool WriteAddressIndex(const std::vector > &vect); + bool ReadAddressIndex(uint160 addressHash, int type, std::vector > &addressIndex); bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts();