Remove address indexes

This commit is contained in:
lateminer
2018-10-11 22:02:52 +03:00
parent a059d578cd
commit b1bb30cb3a
33 changed files with 24 additions and 3280 deletions

View File

@@ -66,16 +66,11 @@ endif
if BUILD_BITCOIN_UTILS
bin_PROGRAMS += blackmore-cli blackmore-tx
if ENABLE_WALLET
bin_PROGRAMS += wallet-utility
endif
endif
.PHONY: FORCE check-symbols check-security
# bitcoin core #
BITCOIN_CORE_H = \
addressindex.h \
spentindex.h \
addrman.h \
amount.h \
arith_uint256.h \
@@ -407,14 +402,6 @@ blackmore_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
blackmore_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
blackmore_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
# wallet-utility binary #
if ENABLE_WALLET
wallet_utility_SOURCES = wallet-utility.cpp
wallet_utility_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAG)
wallet_utility_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
wallet_utility_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
endif
if TARGET_WINDOWS
blackmore_cli_SOURCES += bitcoin-cli-res.rc
endif
@@ -426,11 +413,6 @@ blackmore_cli_LDADD = \
$(LIBBITCOIN_CRYPTO)
blackmore_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
if ENABLE_WALLET
wallet_utility_LDADD = libbitcoin_wallet.a $(LIBBITCOIN_COMMON) $(LIBBITCOIN_CRYPTO) $(LIBSECP256K1) $(LIBBITCOIN_UTIL) $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS)
endif
#
# blackmore-tx binary #
blackmore_tx_SOURCES = bitcoin-tx.cpp

View File

@@ -17,9 +17,7 @@ EXTRA_DIST += \
test/data/txcreate2.hex \
test/data/txcreatedata1.hex \
test/data/txcreatedata2.hex \
test/data/txcreatesign.hex \
test/wallet-utility.py \
test/data/wallet.dat
test/data/txcreatesign.hex
JSON_TEST_FILES = \
test/data/script_valid.json \
@@ -73,7 +71,6 @@ BITCOIN_TESTS =\
test/sanity_tests.cpp \
test/scheduler_tests.cpp \
test/script_P2SH_tests.cpp \
test/script_P2PKH_tests.cpp \
test/scriptnum_tests.cpp \
test/serialize_tests.cpp \
test/sigopcount_tests.cpp \
@@ -137,10 +134,6 @@ bitcoin_test_clean : FORCE
check-local:
@echo "Running test/bitcoin-util-test.py..."
$(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(PYTHON) $(srcdir)/test/bitcoin-util-test.py
if ENABLE_WALLET
@echo "Running test/wallet-utility.py..."
$(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(PYTHON) $(srcdir)/test/wallet-utility.py
endif
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
if EMBEDDED_UNIVALUE
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check

View File

@@ -1,82 +0,0 @@
// 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_ADDRESSINDEX_H
#define BITCOIN_ADDRESSINDEX_H
#include "uint256.h"
#include "amount.h"
struct CMempoolAddressDelta
{
int64_t time;
CAmount amount;
uint256 prevhash;
unsigned int prevout;
CMempoolAddressDelta(int64_t t, CAmount a, uint256 hash, unsigned int out) {
time = t;
amount = a;
prevhash = hash;
prevout = out;
}
CMempoolAddressDelta(int64_t t, CAmount a) {
time = t;
amount = a;
prevhash.SetNull();
prevout = 0;
}
};
struct CMempoolAddressDeltaKey
{
int type;
uint160 addressBytes;
uint256 txhash;
unsigned int index;
int spending;
CMempoolAddressDeltaKey(int addressType, uint160 addressHash, uint256 hash, unsigned int i, int s) {
type = addressType;
addressBytes = addressHash;
txhash = hash;
index = i;
spending = s;
}
CMempoolAddressDeltaKey(int addressType, uint160 addressHash) {
type = addressType;
addressBytes = addressHash;
txhash.SetNull();
index = 0;
spending = 0;
}
};
struct CMempoolAddressDeltaKeyCompare
{
bool operator()(const CMempoolAddressDeltaKey& a, const CMempoolAddressDeltaKey& b) const {
if (a.type == b.type) {
if (a.addressBytes == b.addressBytes) {
if (a.txhash == b.txhash) {
if (a.index == b.index) {
return a.spending < b.spending;
} else {
return a.index < b.index;
}
} else {
return a.txhash < b.txhash;
}
} else {
return a.addressBytes < b.addressBytes;
}
} else {
return a.type < b.type;
}
}
};
#endif // BITCOIN_ADDRESSINDEX_H

View File

@@ -15,14 +15,14 @@
#include <memenv.h>
#include <stdint.h>
static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxOpenFiles)
static leveldb::Options GetOptions(size_t nCacheSize)
{
leveldb::Options options;
options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
options.filter_policy = leveldb::NewBloomFilterPolicy(10);
options.compression = compression ? leveldb::kSnappyCompression : leveldb::kNoCompression;
options.max_open_files = maxOpenFiles;
options.compression = leveldb::kNoCompression;
options.max_open_files = 64;
if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
// LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
// on corruption in later versions.
@@ -31,14 +31,14 @@ static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxO
return options;
}
CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate, bool compression, int maxOpenFiles)
CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
{
penv = NULL;
readoptions.verify_checksums = true;
iteroptions.verify_checksums = true;
iteroptions.fill_cache = false;
syncoptions.sync = true;
options = GetOptions(nCacheSize, compression, maxOpenFiles);
options = GetOptions(nCacheSize);
options.create_if_missing = true;
if (fMemory) {
penv = leveldb::NewMemEnv(leveldb::Env::Default());

View File

@@ -192,10 +192,8 @@ public:
* @param[in] fWipe If true, remove all existing data.
* @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
* with a zero'd byte array.
* @param[in] compression Enable snappy compression for the database
* @param[in] maxOpenFiles The maximum number of open files for the database
*/
CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false, bool compression = false, int maxOpenFiles = 64);
CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
~CDBWrapper();
template <typename K, typename V>

View File

@@ -331,10 +331,6 @@ std::string HelpMessage(HelpMessageMode mode)
#endif
strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), DEFAULT_TXINDEX));
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 += HelpMessageOpt("-timestampindex", strprintf(_("Maintain a timestamp index for block hashes, used to query blocks hashes by a range of timestamps (default: %u)"), DEFAULT_TIMESTAMPINDEX));
strUsage += HelpMessageOpt("-spentindex", strprintf(_("Maintain a full spent index, used to query the spending txid and input index for an outpoint (default: %u)"), DEFAULT_SPENTINDEX));
strUsage += HelpMessageGroup(_("Connection options:"));
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)"), DEFAULT_BANSCORE_THRESHOLD));
@@ -1221,33 +1217,18 @@ bool AppInit2(Config& config, boost::thread_group& threadGroup, CScheduler& sche
}
}
// block tree db settings
int dbMaxOpenFiles = GetArg("-dbmaxopenfiles", DEFAULT_DB_MAX_OPEN_FILES);
bool dbCompression = GetBoolArg("-dbcompression", DEFAULT_DB_COMPRESSION);
LogPrintf("Block index database configuration:\n");
LogPrintf("* Using %d max open files\n", dbMaxOpenFiles);
LogPrintf("* Compression is %s\n", dbCompression ? "enabled" : "disabled");
// cache size calculations
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
int64_t nBlockTreeDBCache = nTotalCache / 8;
if (GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX) || GetBoolArg("-spentindex", DEFAULT_SPENTINDEX)) {
// enable 3/4 of the cache if addressindex and/or spentindex is enabled
nBlockTreeDBCache = nTotalCache * 3 / 4;
} else {
if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB
}
}
if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", DEFAULT_TXINDEX))
nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB
nTotalCache -= nBlockTreeDBCache;
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
nTotalCache -= nCoinDBCache;
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
LogPrintf("Cache configuration:\n");
LogPrintf("* Max cache setting possible %.1fMiB\n", nMaxDbCache);
LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024));
@@ -1268,7 +1249,7 @@ bool AppInit2(Config& config, boost::thread_group& threadGroup, CScheduler& sche
delete pcoinscatcher;
delete pblocktree;
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex, dbCompression, dbMaxOpenFiles);
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState);
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
pcoinsTip = new CCoinsViewCache(pcoinscatcher);

View File

@@ -75,9 +75,6 @@ int nScriptCheckThreads = 0;
bool fImporting = false;
bool fReindex = false;
bool fTxIndex = false;
bool fAddressIndex = false;
bool fTimestampIndex = false;
bool fSpentIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
@@ -1488,16 +1485,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
pool.addUnchecked(hash, entry, !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);
@@ -1523,55 +1510,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return res;
}
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes)
{
if (!fTimestampIndex)
return error("Timestamp index not enabled");
if (!pblocktree->ReadTimestampIndex(high, low, fActiveOnly, hashes))
return error("Unable to get hashes for timestamps");
return true;
}
bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
{
if (!fSpentIndex)
return false;
if (mempool.getSpentIndex(key, value))
return true;
if (!pblocktree->ReadSpentIndex(key, value))
return false;
return true;
}
bool GetAddressIndex(uint160 addressHash, int type,
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex, int start, int end)
{
if (!fAddressIndex)
return error("address index not enabled");
if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex, start, end))
return error("unable to get txids for address");
return true;
}
bool GetAddressUnspent(uint160 addressHash, int type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs)
{
if (!fAddressIndex)
return error("address index not enabled");
if (!pblocktree->ReadAddressUnspentIndex(addressHash, type, unspentOutputs))
return error("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, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow)
{
@@ -2317,55 +2255,11 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
return error("DisconnectBlock(): block and undo data inconsistent");
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex;
std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> > spentIndex;
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction &tx = block.vtx[i];
uint256 hash = tx.GetHash();
if (fAddressIndex) {
for (unsigned int k = tx.vout.size(); k-- > 0;) {
const CTxOut &out = tx.vout[k];
if (out.scriptPubKey.IsPayToScriptHash()) {
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
// undo receiving activity
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue));
// undo unspent index
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), hash, k), CAddressUnspentValue()));
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
// undo receiving activity
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue));
// undo unspent index
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), hash, k), CAddressUnspentValue()));
} else if(out.scriptPubKey.IsPayToPublicKey()){
uint160 uhashBytes = Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34);
// record receiving activity
addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, hash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, hash, k), CAddressUnspentValue()));
} else {
continue;
}
}
}
// Check that all outputs are available and match the outputs in the block itself
// exactly.
{
@@ -2395,49 +2289,6 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
const CTxInUndo &undo = txundo.vprevout[j];
if (!ApplyTxInUndo(undo, view, out))
fClean = false;
const CTxIn input = tx.vin[j];
if (fSpentIndex) {
// undo and delete the spent index
spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue()));
}
if (fAddressIndex) {
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
if (prevout.scriptPubKey.IsPayToScriptHash()) {
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
// undo spending activity
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
// restore unspent index
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight, tx.nTime)));
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
// undo spending activity
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
// restore unspent index
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight, tx.nTime)));
} else if(prevout.scriptPubKey.IsPayToPublicKey()){
uint160 uhashBytes = Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34);
// record receiving activity
addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
// record unspent output
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight, tx.nTime)));
} else {
continue;
}
}
}
}
}
@@ -2450,15 +2301,6 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
return true;
}
if (fAddressIndex) {
if (!pblocktree->EraseAddressIndex(addressIndex)) {
return AbortNode(state, "Failed to delete address index");
}
if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) {
return AbortNode(state, "Failed to write address unspent index");
}
}
return fClean;
}
@@ -2682,14 +2524,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex;
std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> > spentIndex;
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);
@@ -2703,48 +2541,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
REJECT_INVALID, "bad-txns-inputs-missingorspent");
if (fAddressIndex || fSpentIndex)
{
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 (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 if (prevout.scriptPubKey.IsPayToPublicKey()) {
hashBytes = Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34);
addressType = 1;
}
else {
hashBytes.SetNull();
addressType = 0;
}
if (fAddressIndex && addressType > 0) {
// record spending activity
addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
// 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)
{
// Add in sigops done by pay-to-script-hash inputs;
@@ -2769,46 +2565,6 @@ 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<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
// record receiving activity
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight, tx.nTime)));
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
// record receiving activity
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight, tx.nTime)));
} else if(out.scriptPubKey.IsPayToPublicKey()){
uint160 uhashBytes = Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34);
// record receiving activity
addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight, tx.nTime)));
} else {
continue;
}
}
}
CTxUndo undoDummy;
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
@@ -2870,41 +2626,6 @@ 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");
}
if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) {
return AbortNode(state, "Failed to write address unspent index");
}
}
if (fSpentIndex)
if (!pblocktree->UpdateSpentIndex(spentIndex))
return AbortNode(state, "Failed to write transaction index");
if (fTimestampIndex) {
unsigned int logicalTS = pindex->nTime;
unsigned int prevLogicalTS = 0;
// retrieve logical timestamp of the previous block
if (pindex->pprev)
if (!pblocktree->ReadTimestampBlockIndex(pindex->pprev->GetBlockHash(), prevLogicalTS))
LogPrintf("%s: Failed to read previous block's logical timestamp\n", __func__);
if (logicalTS <= prevLogicalTS) {
logicalTS = prevLogicalTS + 1;
LogPrintf("%s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d]\n", __func__, pindex->nTime, prevLogicalTS, logicalTS);
}
if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(logicalTS, pindex->GetBlockHash())))
return AbortNode(state, "Failed to write timestamp index");
if (!pblocktree->WriteTimestampBlockIndex(CTimestampBlockIndexKey(pindex->GetBlockHash()), CTimestampBlockIndexValue(logicalTS)))
return AbortNode(state, "Failed to write blockhash index");
}
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
@@ -4481,18 +4202,6 @@ 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");
// Check whether we have a timestamp index
pblocktree->ReadFlag("timestampindex", fTimestampIndex);
LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled");
// Check whether we have a spent index
pblocktree->ReadFlag("spentindex", fSpentIndex);
LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled");
// Load pointer to end of best chain
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
if (it == mapBlockIndex.end())
@@ -4658,18 +4367,6 @@ bool InitBlockIndex(const CChainParams& chainparams)
// Use the provided setting for -txindex in the new database
fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX);
pblocktree->WriteFlag("txindex", fTxIndex);
// Use the provided setting for -addressindex in the new database
fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX);
pblocktree->WriteFlag("addressindex", fAddressIndex);
// Use the provided setting for -timestampindex in the new database
fTimestampIndex = GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX);
pblocktree->WriteFlag("timestampindex", fTimestampIndex);
fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX);
pblocktree->WriteFlag("spentindex", fSpentIndex);
LogPrintf("Initializing databases...\n");
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)

View File

@@ -17,7 +17,6 @@
#include "script/script_error.h"
#include "sync.h"
#include "versionbits.h"
#include "spentindex.h"
#include <algorithm>
#include <exception>
@@ -118,11 +117,6 @@ static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = true;
static const bool DEFAULT_ADDRESSINDEX = false;
static const bool DEFAULT_TIMESTAMPINDEX = false;
static const bool DEFAULT_SPENTINDEX = false;
static const unsigned int DEFAULT_DB_MAX_OPEN_FILES = 1000;
static const bool DEFAULT_DB_COMPRESSION = true;
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
static const bool DEFAULT_TESTSAFEMODE = false;
@@ -308,343 +302,6 @@ struct CNodeStateStats {
std::vector<int> vHeightInFlight;
};
struct CTimestampIndexIteratorKey {
unsigned int timestamp;
size_t GetSerializeSize(int nType, int nVersion) const {
return 4;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
ser_writedata32be(s, timestamp);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
timestamp = ser_readdata32be(s);
}
CTimestampIndexIteratorKey(unsigned int time) {
timestamp = time;
}
CTimestampIndexIteratorKey() {
SetNull();
}
void SetNull() {
timestamp = 0;
}
};
struct CTimestampIndexKey {
unsigned int timestamp;
uint256 blockHash;
size_t GetSerializeSize(int nType, int nVersion) const {
return 36;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
ser_writedata32be(s, timestamp);
blockHash.Serialize(s, nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
timestamp = ser_readdata32be(s);
blockHash.Unserialize(s, nType, nVersion);
}
CTimestampIndexKey(unsigned int time, uint256 hash) {
timestamp = time;
blockHash = hash;
}
CTimestampIndexKey() {
SetNull();
}
void SetNull() {
timestamp = 0;
blockHash.SetNull();
}
};
struct CTimestampBlockIndexKey {
uint256 blockHash;
size_t GetSerializeSize(int nType, int nVersion) const {
return 32;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
blockHash.Serialize(s, nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
blockHash.Unserialize(s, nType, nVersion);
}
CTimestampBlockIndexKey(uint256 hash) {
blockHash = hash;
}
CTimestampBlockIndexKey() {
SetNull();
}
void SetNull() {
blockHash.SetNull();
}
};
struct CTimestampBlockIndexValue {
unsigned int ltimestamp;
size_t GetSerializeSize(int nType, int nVersion) const {
return 4;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
ser_writedata32be(s, ltimestamp);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
ltimestamp = ser_readdata32be(s);
}
CTimestampBlockIndexValue (unsigned int time) {
ltimestamp = time;
}
CTimestampBlockIndexValue() {
SetNull();
}
void SetNull() {
ltimestamp = 0;
}
};
struct CAddressUnspentKey {
unsigned int type;
uint160 hashBytes;
uint256 txhash;
size_t index;
size_t GetSerializeSize(int nType, int nVersion) const {
return 57;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
ser_writedata8(s, type);
hashBytes.Serialize(s, nType, nVersion);
txhash.Serialize(s, nType, nVersion);
ser_writedata32(s, index);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
type = ser_readdata8(s);
hashBytes.Unserialize(s, nType, nVersion);
txhash.Unserialize(s, nType, nVersion);
index = ser_readdata32(s);
}
CAddressUnspentKey(unsigned int addressType, uint160 addressHash, uint256 txid, size_t indexValue) {
type = addressType;
hashBytes = addressHash;
txhash = txid;
index = indexValue;
}
CAddressUnspentKey() {
SetNull();
}
void SetNull() {
type = 0;
hashBytes.SetNull();
txhash.SetNull();
index = 0;
}
};
struct CAddressUnspentValue {
CAmount satoshis;
CScript script;
int blockHeight;
uint64_t nTime;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(satoshis);
READWRITE(*(CScriptBase*)(&script));
READWRITE(blockHeight);
READWRITE(nTime);
}
CAddressUnspentValue(CAmount sats, CScript scriptPubKey, int height, uint64_t nTimeVal) {
satoshis = sats;
script = scriptPubKey;
blockHeight = height;
nTime = nTimeVal;
}
CAddressUnspentValue() {
SetNull();
}
void SetNull() {
satoshis = -1;
script.clear();
blockHeight = 0;
nTime = 0;
}
bool IsNull() const {
return (satoshis == -1);
}
};
struct CAddressIndexKey {
unsigned int type;
uint160 hashBytes;
int blockHeight;
unsigned int txindex;
uint256 txhash;
size_t index;
bool spending;
size_t GetSerializeSize(int nType, int nVersion) const {
return 66;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
ser_writedata8(s, type);
hashBytes.Serialize(s, nType, nVersion);
// Heights are stored big-endian for key sorting in LevelDB
ser_writedata32be(s, blockHeight);
ser_writedata32be(s, txindex);
txhash.Serialize(s, nType, nVersion);
ser_writedata32(s, index);
char f = spending;
ser_writedata8(s, f);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
type = ser_readdata8(s);
hashBytes.Unserialize(s, nType, nVersion);
blockHeight = ser_readdata32be(s);
txindex = ser_readdata32be(s);
txhash.Unserialize(s, nType, nVersion);
index = ser_readdata32(s);
char f = ser_readdata8(s);
spending = f;
}
CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex,
uint256 txid, size_t indexValue, bool isSpending) {
type = addressType;
hashBytes = addressHash;
blockHeight = height;
txindex = blockindex;
txhash = txid;
index = indexValue;
spending = isSpending;
}
CAddressIndexKey() {
SetNull();
}
void SetNull() {
type = 0;
hashBytes.SetNull();
blockHeight = 0;
txindex = 0;
txhash.SetNull();
index = 0;
spending = false;
}
};
struct CAddressIndexIteratorKey {
unsigned int type;
uint160 hashBytes;
size_t GetSerializeSize(int nType, int nVersion) const {
return 21;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
ser_writedata8(s, type);
hashBytes.Serialize(s, nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
type = ser_readdata8(s);
hashBytes.Unserialize(s, nType, nVersion);
}
CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash) {
type = addressType;
hashBytes = addressHash;
}
CAddressIndexIteratorKey() {
SetNull();
}
void SetNull() {
type = 0;
hashBytes.SetNull();
}
};
struct CAddressIndexIteratorHeightKey {
unsigned int type;
uint160 hashBytes;
int blockHeight;
size_t GetSerializeSize(int nType, int nVersion) const {
return 25;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
ser_writedata8(s, type);
hashBytes.Serialize(s, nType, nVersion);
ser_writedata32be(s, blockHeight);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
type = ser_readdata8(s);
hashBytes.Unserialize(s, nType, nVersion);
blockHeight = ser_readdata32be(s);
}
CAddressIndexIteratorHeightKey(unsigned int addressType, uint160 addressHash, int height) {
type = addressType;
hashBytes = addressHash;
blockHeight = height;
}
CAddressIndexIteratorHeightKey() {
SetNull();
}
void SetNull() {
type = 0;
hashBytes.SetNull();
blockHeight = 0;
}
};
struct CDiskTxPos : public CDiskBlockPos
{
unsigned int nTxOffset; // after header
@@ -777,14 +434,6 @@ public:
ScriptError GetScriptError() const { return error; }
};
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes);
bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
bool GetAddressIndex(uint160 addressHash, int type,
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
int start = 0, int end = 0);
bool GetAddressUnspent(uint160 addressHash, int type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs);
/** Functions for disk access for blocks */
bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams);

View File

@@ -14,10 +14,6 @@
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "rpc/server.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "script/standard.h"
#include "streams.h"
#include "sync.h"
#include "txmempool.h"
@@ -98,112 +94,6 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
return result;
}
UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
{
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", blockindex->GetBlockHash().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", EncodeDestination(CKeyID(spentInfo.addressHash))));
} else if (spentInfo.addressType == 2) {
delta.push_back(Pair("address", EncodeDestination(CScriptID(spentInfo.addressHash))));
} 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", EncodeDestination(CScriptID(uint160(hashBytes)))));
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
delta.push_back(Pair("address", EncodeDestination(CKeyID(uint160(hashBytes)))));
} 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->GetPastTimeLimit()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
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;
}
double GetPoSKernelPS()
{
int nPoSInterval = 72;
@@ -450,102 +340,6 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
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, Params().GetConsensus()))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
return blockToDeltasJSON(block, pblockindex);
}
UniValue getblockhashes(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 2)
throw runtime_error(
"getblockhashes timestamp\n"
"\nReturns array of hashes of blocks within the timestamp range provided.\n"
"\nArguments:\n"
"1. high (numeric, required) The newer block timestamp\n"
"2. low (numeric, required) The older block timestamp\n"
"3. options (string, required) A json object\n"
" {\n"
" \"noOrphans\":true (boolean) will only include blocks on the main chain\n"
" \"logicalTimes\":true (boolean) will include logical timestamps with hashes\n"
" }\n"
"\nResult:\n"
"[\n"
" \"hash\" (string) The block hash\n"
"]\n"
"[\n"
" {\n"
" \"blockhash\": (string) The block hash\n"
" \"logicalts\": (numeric) The logical timestamp\n"
" }\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli("getblockhashes", "1231614698 1231024505")
+ HelpExampleRpc("getblockhashes", "1231614698, 1231024505")
+ HelpExampleCli("getblockhashes", "1231614698 1231024505 '{\"noOrphans\":false, \"logicalTimes\":true}'")
);
unsigned int high = params[0].get_int();
unsigned int low = params[1].get_int();
bool fActiveOnly = false;
bool fLogicalTS = false;
if (params.size() > 2) {
if (params[2].isObject()) {
UniValue noOrphans = find_value(params[2].get_obj(), "noOrphans");
UniValue returnLogical = find_value(params[2].get_obj(), "logicalTimes");
if (noOrphans.isBool())
fActiveOnly = noOrphans.get_bool();
if (returnLogical.isBool())
fLogicalTS = returnLogical.get_bool();
}
}
std::vector<std::pair<uint256, unsigned int> > blockHashes;
if (fActiveOnly)
LOCK(cs_main);
if (!GetTimestampIndex(high, low, fActiveOnly, blockHashes)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for block hashes");
}
UniValue result(UniValue::VARR);
for (std::vector<std::pair<uint256, unsigned int> >::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) {
if (fLogicalTS) {
UniValue item(UniValue::VOBJ);
item.push_back(Pair("blockhash", it->first.GetHex()));
item.push_back(Pair("logicalts", (int)it->second));
result.push_back(item);
} else {
result.push_back(it->first.GetHex());
}
}
return result;
}
UniValue getblockhash(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@@ -1283,8 +1077,6 @@ static const CRPCCommand commands[] =
{ "blockchain", "getbestblockhash", &getbestblockhash, true },
{ "blockchain", "getblockcount", &getblockcount, true },
{ "blockchain", "getblock", &getblock, true },
{ "blockchain", "getblockdeltas", &getblockdeltas, false },
{ "blockchain", "getblockhashes", &getblockhashes, true },
{ "blockchain", "getblockhash", &getblockhash, true },
{ "blockchain", "getblockheader", &getblockheader, true },
{ "blockchain", "getchaintips", &getchaintips, true },

View File

@@ -102,15 +102,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "prioritisetransaction", 2 },
{ "setban", 2 },
{ "setban", 3 },
{ "getblockhashes", 0 },
{ "getblockhashes", 1 },
{ "getblockhashes", 2 },
{ "getspentinfo", 0},
{ "getaddresstxids", 0},
{ "getaddressbalance", 0},
{ "getaddressdeltas", 0},
{ "getaddressutxos", 0},
{ "getaddressmempool", 0},
};
class CRPCConvertTable

View File

@@ -12,7 +12,6 @@
#include "netbase.h"
#include "rpc/server.h"
#include "timedata.h"
#include "txmempool.h"
#include "util.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
@@ -467,534 +466,6 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
return NullUniValue;
}
bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address)
{
if (type == 2) {
address = EncodeDestination(CScriptID(hash));
} else if (type == 1) {
address = EncodeDestination(CKeyID(hash));
} else {
return false;
}
return true;
}
bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint160, int> > &addresses)
{
if (params[0].isStr()) {
CTxDestination dest = DecodeDestination(params[0].get_str());
uint160 hashBytes;
int type = 0;
if (IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
addresses.push_back(std::make_pair(hashBytes, type));
} else if (params[0].isObject()) {
UniValue addressValues = find_value(params[0].get_obj(), "addresses");
if (!addressValues.isArray()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Addresses is expected to be an array");
}
std::vector<UniValue> values = addressValues.getValues();
for (std::vector<UniValue>::iterator it = values.begin(); it != values.end(); ++it) {
CTxDestination dest = DecodeDestination(it->get_str());
uint160 hashBytes;
int type = 0;
if (IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
addresses.push_back(std::make_pair(hashBytes, type));
}
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
return true;
}
bool heightSort(std::pair<CAddressUnspentKey, CAddressUnspentValue> a,
std::pair<CAddressUnspentKey, CAddressUnspentValue> b) {
return a.second.blockHeight < b.second.blockHeight;
}
bool timestampSort(std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> a,
std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> b) {
return a.second.time < b.second.time;
}
UniValue getaddressmempool(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getaddressmempool\n"
"\nReturns all mempool deltas for an address (requires addressindex to be enabled).\n"
"\nArguments:\n"
"{\n"
" \"addresses\"\n"
" [\n"
" \"address\" (string) The base58check encoded address\n"
" ,...\n"
" ]\n"
"}\n"
"\nResult:\n"
"[\n"
" {\n"
" \"address\" (string) The base58check encoded address\n"
" \"txid\" (string) The related txid\n"
" \"index\" (number) The related input or output index\n"
" \"satoshis\" (number) The difference of satoshis\n"
" \"timestamp\" (number) The time the transaction entered the mempool (seconds)\n"
" \"prevtxid\" (string) The previous txid (if spending)\n"
" \"prevout\" (string) The previous transaction output index (if spending)\n"
" }\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli("getaddressmempool", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
+ HelpExampleRpc("getaddressmempool", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
);
std::vector<std::pair<uint160, int> > addresses;
if (!getAddressesFromParams(params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > indexes;
if (!mempool.getAddressIndex(addresses, indexes)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
std::sort(indexes.begin(), indexes.end(), timestampSort);
UniValue result(UniValue::VARR);
for (std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> >::iterator it = indexes.begin();
it != indexes.end(); it++) {
std::string address;
if (!getAddressFromIndex(it->first.type, it->first.addressBytes, address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
}
UniValue delta(UniValue::VOBJ);
delta.push_back(Pair("address", address));
delta.push_back(Pair("txid", it->first.txhash.GetHex()));
delta.push_back(Pair("index", (int)it->first.index));
delta.push_back(Pair("satoshis", it->second.amount));
delta.push_back(Pair("timestamp", it->second.time));
if (it->second.amount < 0) {
delta.push_back(Pair("prevtxid", it->second.prevhash.GetHex()));
delta.push_back(Pair("prevout", (int)it->second.prevout));
}
result.push_back(delta);
}
return result;
}
UniValue getaddressutxos(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getaddressutxos\n"
"\nReturns all unspent outputs for an address (requires addressindex to be enabled).\n"
"\nArguments:\n"
"{\n"
" \"addresses\"\n"
" [\n"
" \"address\" (string) The base58check encoded address\n"
" ,...\n"
" ],\n"
" \"chainInfo\" (boolean) Include chain info with results\n"
"}\n"
"\nResult\n"
"[\n"
" {\n"
" \"address\" (string) The address base58check encoded\n"
" \"txid\" (string) The output txid\n"
" \"height\" (number) The block height\n"
" \"outputIndex\" (number) The output index\n"
" \"script\" (strin) The script hex encoded\n"
" \"satoshis\" (number) The number of satoshis of the output\n"
" }\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli("getaddressutxos", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
+ HelpExampleRpc("getaddressutxos", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
);
bool includeChainInfo = false;
if (params[0].isObject()) {
UniValue chainInfo = find_value(params[0].get_obj(), "chainInfo");
if (chainInfo.isBool()) {
includeChainInfo = chainInfo.get_bool();
}
}
std::vector<std::pair<uint160, int> > addresses;
if (!getAddressesFromParams(params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
if (!GetAddressUnspent((*it).first, (*it).second, unspentOutputs)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
}
std::sort(unspentOutputs.begin(), unspentOutputs.end(), heightSort);
UniValue utxos(UniValue::VARR);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) {
UniValue output(UniValue::VOBJ);
std::string address;
if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
}
output.push_back(Pair("address", address));
output.push_back(Pair("txid", it->first.txhash.GetHex()));
output.push_back(Pair("outputIndex", (int)it->first.index));
output.push_back(Pair("script", HexStr(it->second.script.begin(), it->second.script.end())));
output.push_back(Pair("satoshis", it->second.satoshis));
output.push_back(Pair("height", it->second.blockHeight));
output.push_back(Pair("txtime", it->second.nTime));
utxos.push_back(output);
}
if (includeChainInfo) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("utxos", utxos));
LOCK(cs_main);
result.push_back(Pair("hash", chainActive.Tip()->GetBlockHash().GetHex()));
result.push_back(Pair("height", (int)chainActive.Height()));
return result;
} else {
return utxos;
}
}
UniValue getaddressdeltas(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1 || !params[0].isObject())
throw runtime_error(
"getaddressdeltas\n"
"\nReturns all changes for an address (requires addressindex to be enabled).\n"
"\nArguments:\n"
"{\n"
" \"addresses\"\n"
" [\n"
" \"address\" (string) The base58check encoded address\n"
" ,...\n"
" ]\n"
" \"start\" (number) The start block height\n"
" \"end\" (number) The end block height\n"
" \"chainInfo\" (boolean) Include chain info in results, only applies if start and end specified\n"
"}\n"
"\nResult:\n"
"[\n"
" {\n"
" \"satoshis\" (number) The difference of satoshis\n"
" \"txid\" (string) The related txid\n"
" \"index\" (number) The related input or output index\n"
" \"height\" (number) The block height\n"
" \"address\" (string) The base58check encoded address\n"
" }\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli("getaddressdeltas", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
+ HelpExampleRpc("getaddressdeltas", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
);
UniValue startValue = find_value(params[0].get_obj(), "start");
UniValue endValue = find_value(params[0].get_obj(), "end");
UniValue chainInfo = find_value(params[0].get_obj(), "chainInfo");
bool includeChainInfo = false;
if (chainInfo.isBool()) {
includeChainInfo = chainInfo.get_bool();
}
int start = 0;
int end = 0;
if (startValue.isNum() && endValue.isNum()) {
start = startValue.get_int();
end = endValue.get_int();
if (start <= 0 || end <= 0) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start and end is expected to be greater than zero");
}
if (end < start) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "End value is expected to be greater than start");
}
}
std::vector<std::pair<uint160, int> > addresses;
if (!getAddressesFromParams(params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
if (start > 0 && end > 0) {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
} else {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
}
}
UniValue deltas(UniValue::VARR);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) {
std::string address;
if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
}
UniValue delta(UniValue::VOBJ);
delta.push_back(Pair("satoshis", it->second));
delta.push_back(Pair("txid", it->first.txhash.GetHex()));
delta.push_back(Pair("index", (int)it->first.index));
delta.push_back(Pair("blockindex", (int)it->first.txindex));
delta.push_back(Pair("height", it->first.blockHeight));
delta.push_back(Pair("address", address));
deltas.push_back(delta);
}
UniValue result(UniValue::VOBJ);
if (includeChainInfo && start > 0 && end > 0) {
LOCK(cs_main);
if (start > chainActive.Height() || end > chainActive.Height()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start or end is outside chain range");
}
CBlockIndex* startIndex = chainActive[start];
CBlockIndex* endIndex = chainActive[end];
UniValue startInfo(UniValue::VOBJ);
UniValue endInfo(UniValue::VOBJ);
startInfo.push_back(Pair("hash", startIndex->GetBlockHash().GetHex()));
startInfo.push_back(Pair("height", start));
endInfo.push_back(Pair("hash", endIndex->GetBlockHash().GetHex()));
endInfo.push_back(Pair("height", end));
result.push_back(Pair("deltas", deltas));
result.push_back(Pair("start", startInfo));
result.push_back(Pair("end", endInfo));
return result;
} else {
return deltas;
}
}
UniValue getaddressbalance(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getaddressbalance\n"
"\nReturns the balance for an address(es) (requires addressindex to be enabled).\n"
"\nArguments:\n"
"{\n"
" \"addresses\"\n"
" [\n"
" \"address\" (string) The base58check encoded address\n"
" ,...\n"
" ]\n"
"}\n"
"\nResult:\n"
"{\n"
" \"balance\" (string) The current balance in satoshis\n"
" \"received\" (string) The total number of satoshis received (including change)\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getaddressbalance", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
+ HelpExampleRpc("getaddressbalance", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
);
std::vector<std::pair<uint160, int> > addresses;
if (!getAddressesFromParams(params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
}
CAmount balance = 0;
CAmount received = 0;
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) {
if (it->second > 0) {
received += it->second;
}
balance += it->second;
}
UniValue result(UniValue::VOBJ);
result.push_back(Pair("balance", balance));
result.push_back(Pair("received", received));
return result;
}
UniValue getaddresstxids(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getaddresstxids\n"
"\nReturns the txids for an address(es) (requires addressindex to be enabled).\n"
"\nArguments:\n"
"{\n"
" \"addresses\"\n"
" [\n"
" \"address\" (string) The base58check encoded address\n"
" ,...\n"
" ]\n"
" \"start\" (number) The start block height\n"
" \"end\" (number) The end block height\n"
"}\n"
"\nResult:\n"
"[\n"
" \"transactionid\" (string) The transaction id\n"
" ,...\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli("getaddresstxids", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'")
+ HelpExampleRpc("getaddresstxids", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}")
);
std::vector<std::pair<uint160, int> > addresses;
if (!getAddressesFromParams(params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
int start = 0;
int end = 0;
if (params[0].isObject()) {
UniValue startValue = find_value(params[0].get_obj(), "start");
UniValue endValue = find_value(params[0].get_obj(), "end");
if (startValue.isNum() && endValue.isNum()) {
start = startValue.get_int();
end = endValue.get_int();
}
}
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
if (start > 0 && end > 0) {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
} else {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
}
}
std::set<std::pair<int, std::string> > txids;
UniValue result(UniValue::VARR);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) {
int height = it->first.blockHeight;
std::string txid = it->first.txhash.GetHex();
if (addresses.size() > 1) {
txids.insert(std::make_pair(height, txid));
} else {
if (txids.insert(std::make_pair(height, txid)).second) {
result.push_back(txid);
}
}
}
if (addresses.size() > 1) {
for (std::set<std::pair<int, std::string> >::const_iterator it=txids.begin(); it!=txids.end(); it++) {
result.push_back(it->second);
}
}
return result;
}
UniValue getspentinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1 || !params[0].isObject())
throw runtime_error(
"getspentinfo\n"
"\nReturns the txid and index where an output is spent.\n"
"\nArguments:\n"
"{\n"
" \"txid\" (string) The hex string of the txid\n"
" \"index\" (number) The start block height\n"
"}\n"
"\nResult:\n"
"{\n"
" \"txid\" (string) The transaction id\n"
" \"index\" (number) The spending input index\n"
" ,...\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getspentinfo", "'{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}'")
+ HelpExampleRpc("getspentinfo", "{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}")
);
UniValue txidValue = find_value(params[0].get_obj(), "txid");
UniValue indexValue = find_value(params[0].get_obj(), "index");
if (!txidValue.isStr() || !indexValue.isNum()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid txid or index");
}
uint256 txid = ParseHashV(txidValue, "txid");
int outputIndex = indexValue.get_int();
CSpentIndexKey key(txid, outputIndex);
CSpentIndexValue value;
if (!GetSpentIndex(key, value)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to get spent info");
}
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txid", value.txid.GetHex()));
obj.push_back(Pair("index", (int)value.inputIndex));
obj.push_back(Pair("height", value.blockHeight));
return obj;
}
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
@@ -1003,14 +474,6 @@ static const CRPCCommand commands[] =
{ "util", "createmultisig", &createmultisig, true },
{ "util", "verifymessage", &verifymessage, true },
{ "util", "signmessagewithprivkey", &signmessagewithprivkey, true },
{ "util", "getspentinfo", &getspentinfo, false },
/* Address index */
{ "addressindex", "getaddressmempool", &getaddressmempool, true },
{ "addressindex", "getaddressutxos", &getaddressutxos, false },
{ "addressindex", "getaddressdeltas", &getaddressdeltas, false },
{ "addressindex", "getaddresstxids", &getaddresstxids, false },
{ "addressindex", "getaddressbalance", &getaddressbalance, false },
/* Not shown in help */
{ "hidden", "setmocktime", &setmocktime, true },

View File

@@ -63,91 +63,9 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud
out.push_back(Pair("addresses", a));
}
void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& entry,
int nHeight = 0, int nConfirmations = 0, int nBlockTime = 0)
{
uint256 txid = tx.GetHash();
entry.push_back(Pair("txid", txid.GetHex()));
entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
entry.push_back(Pair("version", tx.nVersion));
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
UniValue vin(UniValue::VARR);
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
UniValue in(UniValue::VOBJ);
if (tx.IsCoinBase())
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
else {
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
UniValue o(UniValue::VOBJ);
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", EncodeDestination(CKeyID(spentInfo.addressHash))));
} else if (spentInfo.addressType == 2) {
in.push_back(Pair("address", EncodeDestination(CScriptID(spentInfo.addressHash))));
}
}
}
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
vin.push_back(in);
}
entry.push_back(Pair("vin", vin));
UniValue vout(UniValue::VARR);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
const CTxOut& txout = tx.vout[i];
UniValue out(UniValue::VOBJ);
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
out.push_back(Pair("valueSat", txout.nValue));
out.push_back(Pair("n", (int64_t)i));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
out.push_back(Pair("scriptPubKey", o));
// Add spent information if spentindex is enabled
CSpentIndexValue spentInfo;
CSpentIndexKey spentKey(txid, i);
if (GetSpentIndex(spentKey, spentInfo)) {
out.push_back(Pair("spentTxId", spentInfo.txid.GetHex()));
out.push_back(Pair("spentIndex", (int)spentInfo.inputIndex));
out.push_back(Pair("spentHeight", spentInfo.blockHeight));
}
vout.push_back(out);
}
entry.push_back(Pair("vout", vout));
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
if (nConfirmations > 0) {
entry.push_back(Pair("height", nHeight));
entry.push_back(Pair("confirmations", nConfirmations));
entry.push_back(Pair("time", nBlockTime));
entry.push_back(Pair("blocktime", nBlockTime));
} else {
entry.push_back(Pair("height", -1));
entry.push_back(Pair("confirmations", 0));
}
}
}
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
uint256 txid = tx.GetHash();
entry.push_back(Pair("txid", txid.GetHex()));
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
entry.push_back(Pair("version", tx.nVersion));
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
@@ -175,7 +93,6 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
const CTxOut& txout = tx.vout[i];
UniValue out(UniValue::VOBJ);
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
out.push_back(Pair("valueSat", txout.nValue));
out.push_back(Pair("n", (int64_t)i));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
@@ -190,14 +107,12 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
entry.push_back(Pair("height", pindex->nHeight));
entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
entry.push_back(Pair("time", pindex->GetBlockTime()));
entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
} else {
entry.push_back(Pair("height", -1));
entry.push_back(Pair("confirmations", 0));
}
else
entry.push_back(Pair("confirmations", 0));
}
}
}
@@ -269,6 +184,8 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
);
LOCK(cs_main);
uint256 hash = ParseHashV(params[0], "parameter 1");
bool fVerbose = false;
@@ -276,31 +193,9 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
fVerbose = (params[1].get_int() != 0);
CTransaction tx;
uint256 hashBlock;
int nHeight = 0;
int nConfirmations = 0;
int nBlockTime = 0;
{
LOCK(cs_main);
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
nHeight = pindex->nHeight;
nConfirmations = 1 + chainActive.Height() - pindex->nHeight;
nBlockTime = pindex->GetBlockTime();
} else {
nHeight = -1;
nConfirmations = 0;
nBlockTime = pindex->GetBlockTime();
}
}
}
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
string strHex = EncodeHexTx(tx);
@@ -309,8 +204,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", strHex));
TxToJSONExpanded(tx, hashBlock, result, nHeight, nConfirmations, nBlockTime);
TxToJSON(tx, hashBlock, result);
return result;
}

View File

@@ -201,17 +201,6 @@ 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:
@@ -221,13 +210,11 @@ bool CScript::IsPayToScriptHash() const
(*this)[22] == OP_EQUAL);
}
bool CScript::IsPayToPublicKey() const
{
// Extra-fast test for pay-to-pubkey CScripts:
return (this->size() == 35 &&
(*this)[0] == 0x21 &&
(*this)[0] == 0x21 &&
(*this)[34] == OP_CHECKSIG);
}

View File

@@ -633,10 +633,7 @@ public:
*/
unsigned int GetSigOpCount(const CScript& scriptSig) const;
bool IsPayToPublicKeyHash() const;
bool IsPayToScriptHash() const;
bool IsPayToPublicKey() const;
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */

View File

@@ -91,11 +91,6 @@ template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
obj = htole32(obj);
s.write((char*)&obj, 4);
}
template<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj)
{
obj = htobe32(obj);
s.write((char*)&obj, 4);
}
template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)
{
obj = htole64(obj);
@@ -119,12 +114,6 @@ template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
s.read((char*)&obj, 4);
return le32toh(obj);
}
template<typename Stream> inline uint32_t ser_readdata32be(Stream &s)
{
uint32_t obj;
s.read((char*)&obj, 4);
return be32toh(obj);
}
template<typename Stream> inline uint64_t ser_readdata64(Stream &s)
{
uint64_t obj;

View File

@@ -1,98 +0,0 @@
// 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

Binary file not shown.

View File

@@ -47,49 +47,6 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
}
}
BOOST_AUTO_TEST_CASE(dbwrapper_compression)
{
// Perform tests both with compression and without
for (int i = 0; i < 2; i++) {
bool compression = (bool)i;
path ph = temp_directory_path() / unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, false, compression);
char key = 'k';
uint256 in = GetRandHash();
uint256 res;
BOOST_CHECK(dbw.Write(key, in));
BOOST_CHECK(dbw.Read(key, res));
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
}
}
BOOST_AUTO_TEST_CASE(dbwrapper_maxopenfiles_64)
{
path ph = temp_directory_path() / unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, false, false, 64);
char key = 'k';
uint256 in = GetRandHash();
uint256 res;
BOOST_CHECK(dbw.Write(key, in));
BOOST_CHECK(dbw.Read(key, res));
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
}
BOOST_AUTO_TEST_CASE(dbwrapper_maxopenfiles_1000)
{
path ph = temp_directory_path() / unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, false, false, 1000);
char key = 'k';
uint256 in = GetRandHash();
uint256 res;
BOOST_CHECK(dbw.Write(key, in));
BOOST_CHECK(dbw.Read(key, res));
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
}
// Test batch operations
BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{

View File

@@ -1,59 +0,0 @@
// Copyright (c) 2012-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.
#include "script/script.h"
#include "test/test_bitcoin.h"
#include <boost/test/unit_test.hpp>
using namespace std;
BOOST_FIXTURE_TEST_SUITE(script_P2PKH_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(IsPayToPublicKeyHash)
{
// Test CScript::IsPayToPublicKeyHash()
uint160 dummy;
CScript p2pkh;
p2pkh << OP_DUP << OP_HASH160 << ToByteVector(dummy) << OP_EQUALVERIFY << OP_CHECKSIG;
BOOST_CHECK(p2pkh.IsPayToPublicKeyHash());
static const unsigned char direct[] = {
OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG
};
BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToPublicKeyHash());
static const unsigned char notp2pkh1[] = {
OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_CHECKSIG
};
BOOST_CHECK(!CScript(notp2pkh1, notp2pkh1+sizeof(notp2pkh1)).IsPayToPublicKeyHash());
static const unsigned char p2sh[] = {
OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL
};
BOOST_CHECK(!CScript(p2sh, p2sh+sizeof(p2sh)).IsPayToPublicKeyHash());
static const unsigned char extra[] = {
OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_CHECKSIG
};
BOOST_CHECK(!CScript(extra, extra+sizeof(extra)).IsPayToPublicKeyHash());
static const unsigned char missing[] = {
OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUALVERIFY, OP_CHECKSIG, OP_RETURN
};
BOOST_CHECK(!CScript(missing, missing+sizeof(missing)).IsPayToPublicKeyHash());
static const unsigned char missing2[] = {
OP_DUP, OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
BOOST_CHECK(!CScript(missing2, missing2+sizeof(missing)).IsPayToPublicKeyHash());
static const unsigned char tooshort[] = {
OP_DUP, OP_HASH160, 2, 0,0, OP_EQUALVERIFY, OP_CHECKSIG
};
BOOST_CHECK(!CScript(tooshort, tooshort+sizeof(direct)).IsPayToPublicKeyHash());
}
BOOST_AUTO_TEST_SUITE_END()

View File

@@ -1,61 +0,0 @@
#!/usr/bin/python
# Copyright 2014 BitPay, Inc.
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import subprocess
import os
import json
import sys
import buildenv
import shutil
def assert_equal(thing1, thing2):
if thing1 != thing2:
raise AssertionError("%s != %s"%(str(thing1),str(thing2)))
if __name__ == '__main__':
datadir = os.environ["srcdir"] + "/test/data"
execprog = './wallet-utility' + buildenv.exeext
execargs = '-datadir=' + datadir
execrun = execprog + ' ' + execargs
proc = subprocess.Popen(execrun, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
try:
outs = proc.communicate()
except OSError:
print("OSError, Failed to execute " + execprog)
sys.exit(1)
output = json.loads(outs[0])
assert_equal(output[0], "13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av")
assert_equal(output[1], "1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8")
assert_equal(output[2], "13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F")
execargs = '-datadir=' + datadir + ' -dumppass'
execrun = execprog + ' ' + execargs
proc = subprocess.Popen(execrun, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
try:
outs = proc.communicate()
except OSError:
print("OSError, Failed to execute " + execprog)
sys.exit(1)
output = json.loads(outs[0])
assert_equal(output[0]['addr'], "13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av")
assert_equal(output[0]['pkey'], "5Jz5BWE2WQxp1hGqDZeisQFV1mRFR2AVBAgiXCbNcZyXNjD9aUd")
assert_equal(output[1]['addr'], "1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8")
assert_equal(output[1]['pkey'], "5HsX2b3v2GjngYQ5ZM4mLp2b2apw6aMNVaPELV1YmpiYR1S4jzc")
assert_equal(output[2]['addr'], "13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F")
assert_equal(output[2]['pkey'], "5KCWAs1wX2ESiL4PfDR8XYVSSETHFd2jaRGxt1QdanBFTit4XcH")
if os.path.exists(datadir + '/database'):
if os.path.isdir(datadir + '/database'):
shutil.rmtree(datadir + '/database')
if os.path.exists(datadir + '/db.log'):
os.remove(datadir + '/db.log')
sys.exit(0)

View File

@@ -21,11 +21,6 @@ using namespace std;
static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_TXINDEX = 't';
static const char DB_ADDRESSINDEX = 'a';
static const char DB_ADDRESSUNSPENTINDEX = 'u';
static const char DB_TIMESTAMPINDEX = 's';
static const char DB_BLOCKHASHINDEX = 'z';
static const char DB_SPENTINDEX = 'p';
static const char DB_BLOCK_INDEX = 'b';
static const char DB_BEST_BLOCK = 'B';
@@ -34,7 +29,7 @@ static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true, false, 64)
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true)
{
}
@@ -76,7 +71,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
return db.WriteBatch(batch);
}
CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe, bool compression, int maxOpenFiles) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe, false, compression, maxOpenFiles) {
CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe, false) {
}
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
@@ -166,156 +161,6 @@ bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos>
return WriteBatch(batch);
}
bool CBlockTreeDB::ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) {
return Read(make_pair(DB_SPENTINDEX, key), value);
}
bool CBlockTreeDB::UpdateSpentIndex(const std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> >&vect) {
CDBBatch batch(*this);
for (std::vector<std::pair<CSpentIndexKey,CSpentIndexValue> >::const_iterator it=vect.begin(); it!=vect.end(); it++) {
if (it->second.IsNull()) {
batch.Erase(make_pair(DB_SPENTINDEX, it->first));
} else {
batch.Write(make_pair(DB_SPENTINDEX, it->first), it->second);
}
}
return WriteBatch(batch);
}
bool CBlockTreeDB::UpdateAddressUnspentIndex(const std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue > >&vect) {
CDBBatch batch(*this);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=vect.begin(); it!=vect.end(); it++) {
if (it->second.IsNull()) {
batch.Erase(make_pair(DB_ADDRESSUNSPENTINDEX, it->first));
} else {
batch.Write(make_pair(DB_ADDRESSUNSPENTINDEX, it->first), it->second);
}
}
return WriteBatch(batch);
}
bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, int type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs) {
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
pcursor->Seek(make_pair(DB_ADDRESSUNSPENTINDEX, CAddressIndexIteratorKey(type, addressHash)));
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
std::pair<char,CAddressUnspentKey> key;
if (pcursor->GetKey(key) && key.first == DB_ADDRESSUNSPENTINDEX && key.second.hashBytes == addressHash) {
CAddressUnspentValue nValue;
if (pcursor->GetValue(nValue)) {
unspentOutputs.push_back(make_pair(key.second, nValue));
pcursor->Next();
} else {
return error("failed to get address unspent value");
}
} else {
break;
}
}
return true;
}
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::EraseAddressIndex(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.Erase(make_pair(DB_ADDRESSINDEX, it->first));
return WriteBatch(batch);
}
bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
int start, int end) {
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
if (start > 0 && end > 0) {
pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorHeightKey(type, addressHash, start)));
} else {
pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorKey(type, addressHash)));
}
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) {
if (end > 0 && key.second.blockHeight > end) {
break;
}
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::WriteTimestampIndex(const CTimestampIndexKey &timestampIndex) {
CDBBatch batch(*this);
batch.Write(make_pair(DB_TIMESTAMPINDEX, timestampIndex), 0);
return WriteBatch(batch);
}
bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes) {
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
pcursor->Seek(make_pair(DB_TIMESTAMPINDEX, CTimestampIndexIteratorKey(low)));
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
std::pair<char, CTimestampIndexKey> key;
if (pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp < high) {
if (fActiveOnly) {
if (blockOnchainActive(key.second.blockHash)) {
hashes.push_back(std::make_pair(key.second.blockHash, key.second.timestamp));
}
} else {
hashes.push_back(std::make_pair(key.second.blockHash, key.second.timestamp));
}
pcursor->Next();
} else {
break;
}
}
return true;
}
bool CBlockTreeDB::WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, const CTimestampBlockIndexValue &logicalts) {
CDBBatch batch(*this);
batch.Write(make_pair(DB_BLOCKHASHINDEX, blockhashIndex), logicalts);
return WriteBatch(batch);
}
bool CBlockTreeDB::ReadTimestampBlockIndex(const uint256 &hash, unsigned int &ltimestamp) {
CTimestampBlockIndexValue(lts);
if (!Read(std::make_pair(DB_BLOCKHASHINDEX, hash), lts))
return false;
ltimestamp = lts.ltimestamp;
return true;
}
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
}
@@ -328,16 +173,6 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
return true;
}
bool CBlockTreeDB::blockOnchainActive(const uint256 &hash) {
CBlockIndex* pblockindex = mapBlockIndex[hash];
if (!chainActive.Contains(pblockindex)) {
return false;
}
return true;
}
bool CBlockTreeDB::LoadBlockIndexGuts()
{
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());

View File

@@ -17,17 +17,6 @@
class CBlockFileInfo;
class CBlockIndex;
struct CDiskTxPos;
struct CAddressUnspentKey;
struct CAddressUnspentValue;
struct CAddressIndexKey;
struct CAddressIndexIteratorKey;
struct CAddressIndexIteratorHeightKey;
struct CTimestampIndexKey;
struct CTimestampIndexIteratorKey;
struct CTimestampBlockIndexKey;
struct CTimestampBlockIndexValue;
struct CSpentIndexKey;
struct CSpentIndexValue;
class uint256;
//! -dbcache default (MiB)
@@ -80,7 +69,7 @@ private:
class CBlockTreeDB : public CDBWrapper
{
public:
CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool compression = true, int maxOpenFiles = 1000);
CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
private:
CBlockTreeDB(const CBlockTreeDB&);
void operator=(const CBlockTreeDB&);
@@ -92,24 +81,9 @@ public:
bool ReadReindexing(bool &fReindex);
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
bool UpdateSpentIndex(const std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> >&vect);
bool UpdateAddressUnspentIndex(const std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue > >&vect);
bool ReadAddressUnspentIndex(uint160 addressHash, int type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &vect);
bool WriteAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount> > &vect);
bool EraseAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount> > &vect);
bool ReadAddressIndex(uint160 addressHash, int type,
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
int start = 0, int end = 0);
bool WriteTimestampIndex(const CTimestampIndexKey &timestampIndex);
bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &vect);
bool WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, const CTimestampBlockIndexValue &logicalts);
bool ReadTimestampBlockIndex(const uint256 &hash, unsigned int &logicalTS);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
bool LoadBlockIndexGuts();
bool blockOnchainActive(const uint256 &hash);
};
#endif // BITCOIN_TXDB_H

View File

@@ -441,145 +441,6 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
return true;
}
void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view)
{
LOCK(cs);
const CTransaction& tx = entry.GetTx();
std::vector<CMempoolAddressDeltaKey> inserted;
uint256 txhash = tx.GetHash();
for (unsigned int j = 0; j < tx.vin.size(); j++) {
const CTxIn input = tx.vin[j];
const CTxOut &prevout = view.GetOutputFor(input);
if (prevout.scriptPubKey.IsPayToScriptHash()) {
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, j, 1);
CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n);
mapAddress.insert(make_pair(key, delta));
inserted.push_back(key);
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, j, 1);
CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n);
mapAddress.insert(make_pair(key, delta));
inserted.push_back(key);
}
}
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);
CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, k, 0);
mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
inserted.push_back(key);
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
std::pair<addressDeltaMap::iterator,bool> ret;
CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, k, 0);
mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
inserted.push_back(key);
}
}
mapAddressInserted.insert(make_pair(txhash, inserted));
}
bool CTxMemPool::getAddressIndex(std::vector<std::pair<uint160, int> > &addresses,
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results)
{
LOCK(cs);
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
addressDeltaMap::iterator ait = mapAddress.lower_bound(CMempoolAddressDeltaKey((*it).second, (*it).first));
while (ait != mapAddress.end() && (*ait).first.addressBytes == (*it).first && (*ait).first.type == (*it).second) {
results.push_back(*ait);
ait++;
}
}
return true;
}
bool CTxMemPool::removeAddressIndex(const uint256 txhash)
{
LOCK(cs);
addressDeltaMapInserted::iterator it = mapAddressInserted.find(txhash);
if (it != mapAddressInserted.end()) {
std::vector<CMempoolAddressDeltaKey> keys = (*it).second;
for (std::vector<CMempoolAddressDeltaKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) {
mapAddress.erase(*mit);
}
mapAddressInserted.erase(it);
}
return true;
}
void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view)
{
LOCK(cs);
const CTransaction& tx = entry.GetTx();
std::vector<CSpentIndexKey> inserted;
uint256 txhash = tx.GetHash();
for (unsigned int j = 0; j < tx.vin.size(); j++) {
const CTxIn input = tx.vin[j];
const CTxOut &prevout = view.GetOutputFor(input);
uint160 addressHash;
int addressType;
if (prevout.scriptPubKey.IsPayToScriptHash()) {
addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
addressType = 2;
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
addressType = 1;
} else {
addressHash.SetNull();
addressType = 0;
}
CSpentIndexKey key = CSpentIndexKey(input.prevout.hash, input.prevout.n);
CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, addressType, addressHash);
mapSpent.insert(make_pair(key, value));
inserted.push_back(key);
}
mapSpentInserted.insert(make_pair(txhash, inserted));
}
bool CTxMemPool::getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
{
LOCK(cs);
mapSpentIndex::iterator it;
it = mapSpent.find(key);
if (it != mapSpent.end()) {
value = it->second;
return true;
}
return false;
}
bool CTxMemPool::removeSpentIndex(const uint256 txhash)
{
LOCK(cs);
mapSpentIndexInserted::iterator it = mapSpentInserted.find(txhash);
if (it != mapSpentInserted.end()) {
std::vector<CSpentIndexKey> keys = (*it).second;
for (std::vector<CSpentIndexKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) {
mapSpent.erase(*mit);
}
mapSpentInserted.erase(it);
}
return true;
}
void CTxMemPool::removeUnchecked(txiter it)
{
const uint256 hash = it->GetTx().GetHash();
@@ -593,8 +454,6 @@ void CTxMemPool::removeUnchecked(txiter it)
mapTx.erase(it);
nTransactionsUpdated++;
minerPolicyEstimator->removeTx(hash);
removeAddressIndex(hash);
removeSpentIndex(hash);
}
// Calculates descendants of entry that are not already in setDescendants, and adds to

View File

@@ -9,8 +9,6 @@
#include <list>
#include <set>
#include "addressindex.h"
#include "spentindex.h"
#include "amount.h"
#include "coins.h"
#include "primitives/transaction.h"
@@ -476,18 +474,6 @@ private:
typedef std::map<txiter, TxLinks, CompareIteratorByHash> txlinksMap;
txlinksMap mapLinks;
typedef std::map<CMempoolAddressDeltaKey, CMempoolAddressDelta, CMempoolAddressDeltaKeyCompare> addressDeltaMap;
addressDeltaMap mapAddress;
typedef std::map<uint256, std::vector<CMempoolAddressDeltaKey> > addressDeltaMapInserted;
addressDeltaMapInserted mapAddressInserted;
typedef std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare> mapSpentIndex;
mapSpentIndex mapSpent;
typedef std::map<uint256, std::vector<CSpentIndexKey> > mapSpentIndexInserted;
mapSpentIndexInserted mapSpentInserted;
void UpdateParent(txiter entry, txiter parent, bool add);
void UpdateChild(txiter entry, txiter child, bool add);
@@ -519,15 +505,6 @@ public:
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true);
void addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
bool getAddressIndex(std::vector<std::pair<uint160, int> > &addresses,
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results);
bool removeAddressIndex(const uint256 txhash);
void addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
bool getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
bool removeSpentIndex(const uint256 txhash);
void removeRecursive(const CTransaction &tx, std::list<CTransaction>& removed);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);

View File

@@ -1,340 +0,0 @@
#include <iostream>
#include <string>
// Include local headers
#include "wallet/walletdb.h"
#include "util.h"
#include "base58.h"
#include "dstencode.h"
#include "wallet/crypter.h"
#include <boost/foreach.hpp>
void show_help()
{
std::cout <<
"This program outputs Bitcoin addresses and private keys from a wallet.dat file" << std::endl
<< std::endl
<< "Usage and options: "
<< std::endl
<< " -datadir=<directory> to tell the program where your wallet is"
<< std::endl
<< " -wallet=<name> (Optional) if your wallet is not named wallet.dat"
<< std::endl
<< " -regtest or -testnet (Optional) dumps addresses from regtest/testnet"
<< std::endl
<< " -dumppass (Optional)if you want to extract private keys associated with addresses"
<< std::endl
<< " -pass=<walletpassphrase> if you have encrypted private keys stored in your wallet"
<< std::endl;
}
class WalletUtilityDB : public CDB
{
private:
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID;
SecureString mPass;
std::vector<CKeyingMaterial> vMKeys;
public:
WalletUtilityDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose)
{
nMasterKeyMaxID = 0;
mPass.reserve(100);
}
std::string getAddress(CDataStream ssKey);
std::string getKey(CDataStream ssKey, CDataStream ssValue);
std::string getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass);
bool updateMasterKeys(CDataStream ssKey, CDataStream ssValue);
bool parseKeys(bool dumppriv, std::string masterPass);
bool DecryptSecret(const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
bool Unlock();
bool DecryptKey(const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key);
};
/*
* Address from a public key in base58
*/
std::string WalletUtilityDB::getAddress(CDataStream ssKey)
{
CPubKey vchPubKey;
ssKey >> vchPubKey;
CKeyID id = vchPubKey.GetID();
std::string strAddr = EncodeDestination(id);
return strAddr;
}
/*
* Non encrypted private key in WIF
*/
std::string WalletUtilityDB::getKey(CDataStream ssKey, CDataStream ssValue)
{
std::string strKey;
CPubKey vchPubKey;
ssKey >> vchPubKey;
CPrivKey pkey;
CKey key;
ssValue >> pkey;
if (key.Load(pkey, vchPubKey, true))
strKey = CBitcoinSecret(key).ToString();
return strKey;
}
bool WalletUtilityDB::DecryptSecret(const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
BOOST_FOREACH(const CKeyingMaterial vMKey, vMKeys)
{
if(!cKeyCrypter.SetKey(vMKey, chIV))
continue;
if (cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)))
return true;
}
return false;
}
bool WalletUtilityDB::Unlock()
{
CCrypter crypter;
CKeyingMaterial vMasterKey;
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(mPass, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
continue; // try another master key
vMKeys.push_back(vMasterKey);
}
return true;
}
bool WalletUtilityDB::DecryptKey(const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
{
CKeyingMaterial vchSecret;
if(!DecryptSecret(vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false;
if (vchSecret.size() != 32)
return false;
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
return true;
}
/*
* Encrypted private key in WIF format
*/
std::string WalletUtilityDB::getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass)
{
mPass = masterPass.c_str();
CPubKey vchPubKey;
ssKey >> vchPubKey;
CKey key;
std::vector<unsigned char> vKey;
ssValue >> vKey;
if (!Unlock())
return "";
if(!DecryptKey(vKey, vchPubKey, key))
return "";
std::string strKey = CBitcoinSecret(key).ToString();
return strKey;
}
/*
* Master key derivation
*/
bool WalletUtilityDB::updateMasterKeys(CDataStream ssKey, CDataStream ssValue)
{
unsigned int nID;
ssKey >> nID;
CMasterKey kMasterKey;
ssValue >> kMasterKey;
if (mapMasterKeys.count(nID) != 0)
{
std::cout << "Error reading wallet database: duplicate CMasterKey id " << nID << std::endl;
return false;
}
mapMasterKeys[nID] = kMasterKey;
if (nMasterKeyMaxID < nID)
nMasterKeyMaxID = nID;
return true;
}
/*
* Look at all the records and parse keys for addresses and private keys
*/
bool WalletUtilityDB::parseKeys(bool dumppriv, std::string masterPass)
{
DBErrors result = DB_LOAD_OK;
std::string strType;
bool first = true;
try {
Dbc* pcursor = GetCursor();
if (!pcursor)
{
LogPrintf("Error getting wallet database cursor\n");
result = DB_CORRUPT;
}
if (dumppriv)
{
while (result == DB_LOAD_OK && true)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int result = ReadAtCursor(pcursor, ssKey, ssValue);
if (result == DB_NOTFOUND) {
break;
}
else if (result != 0)
{
LogPrintf("Error reading next record from wallet database\n");
result = DB_CORRUPT;
break;
}
ssKey >> strType;
if (strType == "mkey")
{
updateMasterKeys(ssKey, ssValue);
}
}
pcursor->close();
pcursor = GetCursor();
}
while (result == DB_LOAD_OK && true)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = ReadAtCursor(pcursor, ssKey, ssValue);
if (ret == DB_NOTFOUND)
{
std::cout << " ]" << std::endl;
first = true;
break;
}
else if (ret != DB_LOAD_OK)
{
LogPrintf("Error reading next record from wallet database\n");
result = DB_CORRUPT;
break;
}
ssKey >> strType;
if (strType == "key" || strType == "ckey")
{
std::string strAddr = getAddress(ssKey);
std::string strKey = "";
if (dumppriv && strType == "key")
strKey = getKey(ssKey, ssValue);
if (dumppriv && strType == "ckey")
{
if (masterPass == "")
{
std::cout << "Encrypted wallet, please provide a password. See help below" << std::endl;
show_help();
result = DB_LOAD_FAIL;
break;
}
strKey = getCryptedKey(ssKey, ssValue, masterPass);
}
if (strAddr != "")
{
if (first)
std::cout << "[ ";
else
std::cout << ", ";
}
if (dumppriv)
{
std::cout << "{\"addr\" : \"" + strAddr + "\", "
<< "\"pkey\" : \"" + strKey + "\"}"
<< std::flush;
}
else
{
std::cout << "\"" + strAddr + "\"";
}
first = false;
}
}
pcursor->close();
} catch (DbException &e) {
std::cout << "DBException caught " << e.get_errno() << std::endl;
} catch (std::exception &e) {
std::cout << "Exception caught " << std::endl;
}
if (result == DB_LOAD_OK)
return true;
else
return false;
}
int main(int argc, char* argv[])
{
ParseParameters(argc, argv);
std::string walletFile = GetArg("-wallet", "wallet.dat");
std::string masterPass = GetArg("-pass", "");
bool fDumpPass = GetBoolArg("-dumppass", false);
bool help = GetBoolArg("-h", false);
bool result = false;
if (help)
{
show_help();
return 0;
}
try {
SelectParams(ChainNameFromCommandLine());
result = WalletUtilityDB(walletFile, "r").parseKeys(fDumpPass, masterPass);
}
catch (const std::exception& e) {
std::cout << "Error opening wallet file " << walletFile << std::endl;
std::cout << e.what() << std::endl;
}
if (result)
return 0;
else
return -1;
}