Merge pull request #5577 from kwvg/bitcore_idx

refactor: cleanup {address,spent}index, remove platform-specific types, split out timestamp index
This commit is contained in:
PastaPastaPasta 2023-09-26 20:56:48 -05:00 committed by GitHub
commit 2958aacf5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 599 additions and 633 deletions

View File

@ -297,6 +297,7 @@ BITCOIN_CORE_H = \
support/events.h \
support/lockedpool.h \
sync.h \
timestampindex.h \
threadsafety.h \
threadinterrupt.h \
timedata.h \
@ -385,6 +386,7 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrdb.cpp \
addressindex.cpp \
addrman.cpp \
banman.cpp \
batchedlogger.cpp \

43
src/addressindex.cpp Normal file
View File

@ -0,0 +1,43 @@
// Copyright (c) 2016 BitPay, Inc.
// Copyright (c) 2023 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <addressindex.h>
#include <key_io.h>
#include <hash.h>
#include <script/script.h>
template <typename T1>
inline std::vector<uint8_t> TrimScriptP2PKH(const T1& input) {
return std::vector<uint8_t>(input.begin() + 3, input.begin() + 23);
};
template <typename T1>
inline std::vector<uint8_t> TrimScriptP2SH(const T1& input) {
return std::vector<uint8_t>(input.begin() + 2, input.begin() + 22);
};
template <typename T1>
inline std::vector<uint8_t> TrimScriptP2PK(const T1& input) {
return std::vector<uint8_t>(input.begin() + 1, input.end() - 1);
};
bool AddressBytesFromScript(const CScript& script, AddressType& address_type, uint160& address_bytes) {
if (script.IsPayToScriptHash()) {
address_type = AddressType::P2SH;
address_bytes = uint160(TrimScriptP2SH(script));
} else if (script.IsPayToPublicKeyHash()) {
address_type = AddressType::P2PK_OR_P2PKH;
address_bytes = uint160(TrimScriptP2PKH(script));
} else if (script.IsPayToPublicKey()) {
address_type = AddressType::P2PK_OR_P2PKH;
address_bytes = Hash160(TrimScriptP2PK(script));
} else {
address_type = AddressType::UNKNOWN;
address_bytes.SetNull();
return false;
}
return true;
}

View File

@ -1,84 +1,219 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2016 BitPay, Inc.
// Copyright (c) 2023 The Dash 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>
#include <serialize.h>
#include <uint256.h>
#include <util/underlying.h>
#include <chrono>
#include <tuple>
class CScript;
enum class AddressType : uint8_t {
P2PK_OR_P2PKH = 1,
P2SH = 2,
UNKNOWN = 0
};
template<> struct is_serializable_enum<AddressType> : std::true_type {};
struct CMempoolAddressDelta
{
std::chrono::seconds time;
CAmount amount;
uint256 prevhash;
unsigned int prevout;
public:
std::chrono::seconds m_time;
CAmount m_amount;
uint256 m_prev_hash;
uint32_t m_prev_out{0};
CMempoolAddressDelta(std::chrono::seconds t, CAmount a, uint256 hash, unsigned int out) {
time = t;
amount = a;
prevhash = hash;
prevout = out;
}
public:
CMempoolAddressDelta(std::chrono::seconds time, CAmount amount, uint256 prev_hash, uint32_t prev_out) :
m_time{time}, m_amount{amount}, m_prev_hash{prev_hash}, m_prev_out{prev_out} {}
CMempoolAddressDelta(std::chrono::seconds t, CAmount a) {
time = t;
amount = a;
prevhash.SetNull();
prevout = 0;
}
CMempoolAddressDelta(std::chrono::seconds time, CAmount amount) :
m_time{time}, m_amount{amount} {}
};
struct CMempoolAddressDeltaKey
{
int type;
uint160 addressBytes;
uint256 txhash;
unsigned int index;
int spending;
public:
AddressType m_address_type{AddressType::UNKNOWN};
uint160 m_address_bytes;
uint256 m_tx_hash;
uint32_t m_tx_index{0};
bool m_tx_spent{false};
CMempoolAddressDeltaKey(int addressType, uint160 addressHash, uint256 hash, unsigned int i, int s) {
type = addressType;
addressBytes = addressHash;
txhash = hash;
index = i;
spending = s;
}
public:
CMempoolAddressDeltaKey(AddressType address_type, uint160 address_bytes, uint256 tx_hash, uint32_t tx_index, bool tx_spent) :
m_address_type{address_type},
m_address_bytes{address_bytes},
m_tx_hash{tx_hash},
m_tx_index{tx_index},
m_tx_spent{tx_spent} {};
CMempoolAddressDeltaKey(int addressType, uint160 addressHash) {
type = addressType;
addressBytes = addressHash;
txhash.SetNull();
index = 0;
spending = 0;
}
CMempoolAddressDeltaKey(AddressType address_type, uint160 address_bytes) :
m_address_type{address_type},
m_address_bytes{address_bytes} {};
};
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;
}
auto to_tuple = [](const CMempoolAddressDeltaKey& obj) {
return std::tie(obj.m_address_type, obj.m_address_bytes, obj.m_tx_hash, obj.m_tx_index, obj.m_tx_spent);
};
return to_tuple(a) < to_tuple(b);
}
};
struct CAddressIndexKey {
public:
AddressType m_address_type{AddressType::UNKNOWN};
uint160 m_address_bytes;
int32_t m_block_height{0};
uint32_t m_block_tx_pos{0};
uint256 m_tx_hash;
uint32_t m_tx_index{0};
bool m_tx_spent{false};
public:
CAddressIndexKey() {
SetNull();
}
CAddressIndexKey(AddressType address_type, uint160 address_bytes, int32_t block_height, uint32_t block_tx_pos, uint256 tx_hash,
uint32_t tx_index, bool tx_spent) :
m_address_type{address_type},
m_address_bytes{address_bytes},
m_block_height{block_height},
m_block_tx_pos{block_tx_pos},
m_tx_hash{tx_hash},
m_tx_index{tx_index},
m_tx_spent{tx_spent} {};
void SetNull() {
m_address_type = AddressType::UNKNOWN;
m_address_bytes.SetNull();
m_block_height = 0;
m_block_tx_pos = 0;
m_tx_hash.SetNull();
m_tx_index = 0;
m_tx_spent = false;
}
public:
size_t GetSerializeSize(int nType, int nVersion) const {
return 66;
}
template<typename Stream>
void Serialize(Stream& s) const {
ser_writedata8(s, ToUnderlying(m_address_type));
m_address_bytes.Serialize(s);
// Heights are stored big-endian for key sorting in LevelDB
ser_writedata32be(s, m_block_height);
ser_writedata32be(s, m_block_tx_pos);
m_tx_hash.Serialize(s);
ser_writedata32(s, m_tx_index);
ser_writedata8(s, static_cast<uint8_t>(m_tx_spent));
}
template<typename Stream>
void Unserialize(Stream& s) {
m_address_type = static_cast<AddressType>(ser_readdata8(s));
m_address_bytes.Unserialize(s);
m_block_height = ser_readdata32be(s);
m_block_tx_pos = ser_readdata32be(s);
m_tx_hash.Unserialize(s);
m_tx_index = ser_readdata32(s);
m_tx_spent = static_cast<bool>(ser_readdata8(s));
}
};
struct CAddressIndexIteratorKey {
public:
AddressType m_address_type{AddressType::UNKNOWN};
uint160 m_address_bytes;
public:
CAddressIndexIteratorKey() {
SetNull();
}
CAddressIndexIteratorKey(AddressType address_type, uint160 address_bytes) :
m_address_type{address_type}, m_address_bytes{address_bytes} {};
void SetNull() {
m_address_type = AddressType::UNKNOWN;
m_address_bytes.SetNull();
}
public:
size_t GetSerializeSize(int nType, int nVersion) const {
return 21;
}
template<typename Stream>
void Serialize(Stream& s) const {
ser_writedata8(s, ToUnderlying(m_address_type));
m_address_bytes.Serialize(s);
}
template<typename Stream>
void Unserialize(Stream& s) {
m_address_type = static_cast<AddressType>(ser_readdata8(s));
m_address_bytes.Unserialize(s);
}
};
struct CAddressIndexIteratorHeightKey {
public:
AddressType m_address_type{AddressType::UNKNOWN};
uint160 m_address_bytes;
int32_t m_block_height{0};
public:
CAddressIndexIteratorHeightKey() {
SetNull();
}
CAddressIndexIteratorHeightKey(AddressType address_type, uint160 address_bytes, int32_t block_height) :
m_address_type{address_type}, m_address_bytes{address_bytes}, m_block_height{block_height} {};
void SetNull() {
m_address_type = AddressType::UNKNOWN;
m_address_bytes.SetNull();
m_block_height = 0;
}
public:
size_t GetSerializeSize(int nType, int nVersion) const {
return 25;
}
template<typename Stream>
void Serialize(Stream& s) const {
ser_writedata8(s, ToUnderlying(m_address_type));
m_address_bytes.Serialize(s);
ser_writedata32be(s, m_block_height);
}
template<typename Stream>
void Unserialize(Stream& s) {
m_address_type = static_cast<AddressType>(ser_readdata8(s));
m_address_bytes.Unserialize(s);
m_block_height = ser_readdata32be(s);
}
};
bool AddressBytesFromScript(const CScript& script, AddressType& address_type, uint160& address_bytes);
#endif // BITCOIN_ADDRESSINDEX_H

View File

@ -14,6 +14,7 @@
#include <univalue.h>
#include <util/strencodings.h>
#include <addressindex.h>
#include <spentindex.h>
#include <evo/assetlocktx.h>
@ -213,12 +214,12 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
auto it = ptxSpentInfo->mSpentInfo.find(spentKey);
if (it != ptxSpentInfo->mSpentInfo.end()) {
auto spentInfo = it->second;
in.pushKV("value", ValueFromAmount(spentInfo.satoshis));
in.pushKV("valueSat", spentInfo.satoshis);
if (spentInfo.addressType == 1) {
in.pushKV("address", EncodeDestination(PKHash(spentInfo.addressHash)));
} else if (spentInfo.addressType == 2) {
in.pushKV("address", EncodeDestination(ScriptHash(spentInfo.addressHash)));
in.pushKV("value", ValueFromAmount(spentInfo.m_amount));
in.pushKV("valueSat", spentInfo.m_amount);
if (spentInfo.m_address_type == AddressType::P2PK_OR_P2PKH) {
in.pushKV("address", EncodeDestination(PKHash(spentInfo.m_address_bytes)));
} else if (spentInfo.m_address_type == AddressType::P2SH) {
in.pushKV("address", EncodeDestination(ScriptHash(spentInfo.m_address_bytes)));
}
}
}
@ -248,9 +249,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
auto it = ptxSpentInfo->mSpentInfo.find(spentKey);
if (it != ptxSpentInfo->mSpentInfo.end()) {
auto spentInfo = it->second;
out.pushKV("spentTxId", spentInfo.txid.GetHex());
out.pushKV("spentIndex", (int)spentInfo.inputIndex);
out.pushKV("spentHeight", spentInfo.blockHeight);
out.pushKV("spentTxId", spentInfo.m_tx_hash.GetHex());
out.pushKV("spentIndex", (int)spentInfo.m_tx_index);
out.pushKV("spentHeight", spentInfo.m_block_height);
}
}
vout.push_back(out);

View File

@ -838,8 +838,8 @@ static UniValue getblockhashes(const JSONRPCRequest& request)
}
UniValue result(UniValue::VARR);
for (std::vector<uint256>::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) {
result.push_back(it->GetHex());
for (const auto& hash : blockHashes) {
result.push_back(hash.GetHex());
}
return result;
@ -1828,9 +1828,9 @@ static UniValue getchaintips(const JSONRPCRequest& request)
}
}
for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {
if (setPrevs.erase(*it) == 0) {
setTips.insert(*it);
for (const auto& orphan : setOrphans) {
if (setPrevs.erase(orphan) == 0) {
setTips.insert(orphan);
}
}

View File

@ -4,6 +4,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <addressindex.h>
#include <chainparams.h>
#include <consensus/consensus.h>
#include <evo/mnauth.h>
@ -593,11 +594,11 @@ static UniValue mnauth(const JSONRPCRequest& request)
return fSuccess;
}
static bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address)
static bool getAddressFromIndex(const AddressType& type, const uint160 &hash, std::string &address)
{
if (type == 2) {
if (type == AddressType::P2SH) {
address = EncodeDestination(ScriptHash(hash));
} else if (type == 1) {
} else if (type == AddressType::P2PK_OR_P2PKH) {
address = EncodeDestination(PKHash(hash));
} else {
return false;
@ -605,25 +606,25 @@ static bool getAddressFromIndex(const int &type, const uint160 &hash, std::strin
return true;
}
static bool getIndexKey(const std::string& str, uint160& hashBytes, int& type)
static bool getIndexKey(const std::string& str, uint160& hashBytes, AddressType& type)
{
CTxDestination dest = DecodeDestination(str);
if (!IsValidDestination(dest)) {
type = 0;
type = AddressType::UNKNOWN;
return false;
}
const PKHash *pkhash = std::get_if<PKHash>(&dest);
const ScriptHash *scriptID = std::get_if<ScriptHash>(&dest);
type = pkhash ? 1 : 2;
type = pkhash ? AddressType::P2PK_OR_P2PKH : AddressType::P2SH;
hashBytes = pkhash ? uint160(*pkhash) : uint160(*scriptID);
return true;
}
static bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint160, int> > &addresses)
static bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint160, AddressType> > &addresses)
{
if (params[0].isStr()) {
uint160 hashBytes;
int type = 0;
AddressType type{AddressType::UNKNOWN};
if (!getIndexKey(params[0].get_str(), hashBytes, type)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
@ -635,13 +636,10 @@ static bool getAddressesFromParams(const UniValue& params, std::vector<std::pair
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) {
for (const auto& address : addressValues.getValues()) {
uint160 hashBytes;
int type = 0;
if (!getIndexKey(it->get_str(), hashBytes, type)) {
AddressType type{AddressType::UNKNOWN};
if (!getIndexKey(address.get_str(), hashBytes, type)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
addresses.push_back(std::make_pair(hashBytes, type));
@ -655,12 +653,12 @@ static bool getAddressesFromParams(const UniValue& params, std::vector<std::pair
static bool heightSort(std::pair<CAddressUnspentKey, CAddressUnspentValue> a,
std::pair<CAddressUnspentKey, CAddressUnspentValue> b) {
return a.second.blockHeight < b.second.blockHeight;
return a.second.m_block_height < b.second.m_block_height;
}
static bool timestampSort(std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> a,
std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> b) {
return a.second.time < b.second.time;
return a.second.m_time < b.second.m_time;
}
static UniValue getaddressmempool(const JSONRPCRequest& request)
@ -694,7 +692,7 @@ static UniValue getaddressmempool(const JSONRPCRequest& request)
},
}.Check(request);
std::vector<std::pair<uint160, int> > addresses;
std::vector<std::pair<uint160, AddressType> > addresses;
if (!getAddressesFromParams(request.params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
@ -711,23 +709,21 @@ static UniValue getaddressmempool(const JSONRPCRequest& request)
UniValue result(UniValue::VARR);
for (std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> >::iterator it = indexes.begin();
it != indexes.end(); it++) {
for (const auto& [mempoolAddressKey, mempoolAddressDelta] : indexes) {
std::string address;
if (!getAddressFromIndex(it->first.type, it->first.addressBytes, address)) {
if (!getAddressFromIndex(mempoolAddressKey.m_address_type, mempoolAddressKey.m_address_bytes, address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
}
UniValue delta(UniValue::VOBJ);
delta.pushKV("address", address);
delta.pushKV("txid", it->first.txhash.GetHex());
delta.pushKV("index", (int)it->first.index);
delta.pushKV("satoshis", it->second.amount);
delta.pushKV("timestamp", count_seconds(it->second.time));
if (it->second.amount < 0) {
delta.pushKV("prevtxid", it->second.prevhash.GetHex());
delta.pushKV("prevout", (int)it->second.prevout);
delta.pushKV("txid", mempoolAddressKey.m_tx_hash.GetHex());
delta.pushKV("index", (int)mempoolAddressKey.m_tx_index);
delta.pushKV("satoshis", mempoolAddressDelta.m_amount);
delta.pushKV("timestamp", count_seconds(mempoolAddressDelta.m_time));
if (mempoolAddressDelta.m_amount < 0) {
delta.pushKV("prevtxid", mempoolAddressDelta.m_prev_hash.GetHex());
delta.pushKV("prevout", (int)mempoolAddressDelta.m_prev_out);
}
result.push_back(delta);
}
@ -765,7 +761,7 @@ static UniValue getaddressutxos(const JSONRPCRequest& request)
},
}.Check(request);
std::vector<std::pair<uint160, int> > addresses;
std::vector<std::pair<uint160, AddressType> > addresses;
if (!getAddressesFromParams(request.params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
@ -773,8 +769,8 @@ static UniValue getaddressutxos(const JSONRPCRequest& request)
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)) {
for (const auto& address : addresses) {
if (!GetAddressUnspent(address.first, address.second, unspentOutputs)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
}
@ -783,19 +779,19 @@ static UniValue getaddressutxos(const JSONRPCRequest& request)
UniValue result(UniValue::VARR);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) {
for (const auto& [unspentKey, unspentValue] : unspentOutputs) {
UniValue output(UniValue::VOBJ);
std::string address;
if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) {
if (!getAddressFromIndex(unspentKey.m_address_type, unspentKey.m_address_bytes, address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
}
output.pushKV("address", address);
output.pushKV("txid", it->first.txhash.GetHex());
output.pushKV("outputIndex", (int)it->first.index);
output.pushKV("script", HexStr(it->second.script));
output.pushKV("satoshis", it->second.satoshis);
output.pushKV("height", it->second.blockHeight);
output.pushKV("txid", unspentKey.m_tx_hash.GetHex());
output.pushKV("outputIndex", (int)unspentKey.m_tx_index);
output.pushKV("script", HexStr(unspentValue.m_tx_script));
output.pushKV("satoshis", unspentValue.m_amount);
output.pushKV("height", unspentValue.m_block_height);
result.push_back(output);
}
@ -847,7 +843,7 @@ static UniValue getaddressdeltas(const JSONRPCRequest& request)
}
}
std::vector<std::pair<uint160, int> > addresses;
std::vector<std::pair<uint160, AddressType> > addresses;
if (!getAddressesFromParams(request.params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
@ -855,13 +851,13 @@ static UniValue getaddressdeltas(const JSONRPCRequest& request)
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
for (const auto& address : addresses) {
if (start > 0 && end > 0) {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) {
if (!GetAddressIndex(address.first, address.second, addressIndex, start, end)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
} else {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) {
if (!GetAddressIndex(address.first, address.second, addressIndex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
}
@ -869,18 +865,18 @@ static UniValue getaddressdeltas(const JSONRPCRequest& request)
UniValue result(UniValue::VARR);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) {
for (const auto& [indexKey, indexDelta] : addressIndex) {
std::string address;
if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) {
if (!getAddressFromIndex(indexKey.m_address_type, indexKey.m_address_bytes, address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type");
}
UniValue delta(UniValue::VOBJ);
delta.pushKV("satoshis", it->second);
delta.pushKV("txid", it->first.txhash.GetHex());
delta.pushKV("index", (int)it->first.index);
delta.pushKV("blockindex", (int)it->first.txindex);
delta.pushKV("height", it->first.blockHeight);
delta.pushKV("satoshis", indexDelta);
delta.pushKV("txid", indexKey.m_tx_hash.GetHex());
delta.pushKV("index", (int)indexKey.m_tx_index);
delta.pushKV("blockindex", (int)indexKey.m_block_tx_pos);
delta.pushKV("height", indexKey.m_block_height);
delta.pushKV("address", address);
result.push_back(delta);
}
@ -913,7 +909,7 @@ static UniValue getaddressbalance(const JSONRPCRequest& request)
},
}.Check(request);
std::vector<std::pair<uint160, int> > addresses;
std::vector<std::pair<uint160, AddressType> > addresses;
if (!getAddressesFromParams(request.params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
@ -921,8 +917,8 @@ static UniValue getaddressbalance(const JSONRPCRequest& request)
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)) {
for (const auto& address : addresses) {
if (!GetAddressIndex(address.first, address.second, addressIndex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
}
@ -935,16 +931,16 @@ static UniValue getaddressbalance(const JSONRPCRequest& request)
CAmount balance_immature = 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;
for (const auto& [indexKey, indexDelta] : addressIndex) {
if (indexDelta > 0) {
received += indexDelta;
}
if (it->first.txindex == 0 && nHeight - it->first.blockHeight < COINBASE_MATURITY) {
balance_immature += it->second;
if (indexKey.m_block_tx_pos == 0 && nHeight - indexKey.m_block_height < COINBASE_MATURITY) {
balance_immature += indexDelta;
} else {
balance_spendable += it->second;
balance_spendable += indexDelta;
}
balance += it->second;
balance += indexDelta;
}
UniValue result(UniValue::VOBJ);
@ -978,7 +974,7 @@ static UniValue getaddresstxids(const JSONRPCRequest& request)
},
}.Check(request);
std::vector<std::pair<uint160, int> > addresses;
std::vector<std::pair<uint160, AddressType> > addresses;
if (!getAddressesFromParams(request.params, addresses)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
@ -997,13 +993,13 @@ static UniValue getaddresstxids(const JSONRPCRequest& request)
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
for (const auto& address : addresses) {
if (start > 0 && end > 0) {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) {
if (!GetAddressIndex(address.first, address.second, addressIndex, start, end)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
} else {
if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) {
if (!GetAddressIndex(address.first, address.second, addressIndex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
}
}
@ -1012,9 +1008,9 @@ static UniValue getaddresstxids(const JSONRPCRequest& request)
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();
for (const auto& [indexKey, _]: addressIndex) {
int height = indexKey.m_block_height;
std::string txid = indexKey.m_tx_hash.GetHex();
if (addresses.size() > 1) {
txids.insert(std::make_pair(height, txid));
@ -1026,8 +1022,8 @@ static UniValue getaddresstxids(const JSONRPCRequest& request)
}
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);
for (const auto& tx : txids) {
result.push_back(tx.second);
}
}
@ -1078,9 +1074,9 @@ static UniValue getspentinfo(const JSONRPCRequest& request)
}
UniValue obj(UniValue::VOBJ);
obj.pushKV("txid", value.txid.GetHex());
obj.pushKV("index", (int)value.inputIndex);
obj.pushKV("height", value.blockHeight);
obj.pushKV("txid", value.m_tx_hash.GetHex());
obj.pushKV("index", (int)value.m_tx_index);
obj.pushKV("height", value.m_block_height);
return obj;
}

View File

@ -1,89 +1,96 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2016 BitPay, Inc.
// Copyright (c) 2023 The Dash 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 <addressindex.h>
#include <amount.h>
#include <script/script.h>
#include <serialize.h>
#include <uint256.h>
#include <tuple>
struct CSpentIndexKey {
uint256 txid;
unsigned int outputIndex;
SERIALIZE_METHODS(CSpentIndexKey, obj)
{
READWRITE(obj.txid, obj.outputIndex);
}
CSpentIndexKey(uint256 t, unsigned int i) {
txid = t;
outputIndex = i;
}
public:
uint256 m_tx_hash;
uint32_t m_tx_index{0};
public:
CSpentIndexKey() {
SetNull();
}
CSpentIndexKey(uint256 txout_hash, uint32_t txout_index) :
m_tx_hash{txout_hash}, m_tx_index{txout_index} {};
void SetNull() {
txid.SetNull();
outputIndex = 0;
m_tx_hash.SetNull();
m_tx_index = 0;
}
public:
SERIALIZE_METHODS(CSpentIndexKey, obj)
{
READWRITE(obj.m_tx_hash, obj.m_tx_index);
}
};
struct CSpentIndexValue {
uint256 txid;
unsigned int inputIndex;
int blockHeight;
CAmount satoshis;
int addressType;
uint160 addressHash;
SERIALIZE_METHODS(CSpentIndexValue, obj)
{
READWRITE(obj.txid, obj.inputIndex, obj.blockHeight, obj.satoshis, obj.addressType, obj.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;
}
public:
uint256 m_tx_hash;
uint32_t m_tx_index{0};
int32_t m_block_height{0};
CAmount m_amount{0};
AddressType m_address_type{AddressType::UNKNOWN};
uint160 m_address_bytes;
public:
CSpentIndexValue() {
SetNull();
}
CSpentIndexValue(uint256 txin_hash, uint32_t txin_index, int32_t block_height, CAmount amount, AddressType address_type,
uint160 address_bytes) :
m_tx_hash{txin_hash},
m_tx_index{txin_index},
m_block_height{block_height},
m_amount{amount},
m_address_type{address_type},
m_address_bytes{address_bytes} {};
void SetNull() {
txid.SetNull();
inputIndex = 0;
blockHeight = 0;
satoshis = 0;
addressType = 0;
addressHash.SetNull();
m_tx_hash.SetNull();
m_tx_index = 0;
m_block_height = 0;
m_amount = 0;
m_address_type = AddressType::UNKNOWN;
m_address_bytes.SetNull();
}
bool IsNull() const {
return txid.IsNull();
return m_tx_hash.IsNull();
}
public:
SERIALIZE_METHODS(CSpentIndexValue, obj)
{
READWRITE(obj.m_tx_hash, obj.m_tx_index, obj.m_block_height, obj.m_amount, obj.m_address_type, obj.m_address_bytes);
}
};
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;
}
auto to_tuple = [](const CSpentIndexKey& obj) {
return std::tie(obj.m_tx_hash, obj.m_tx_index);
};
return to_tuple(a) < to_tuple(b);
}
};
@ -92,274 +99,79 @@ struct CSpentIndexTxInfo
std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare> mSpentInfo;
};
struct CTimestampIndexIteratorKey {
unsigned int timestamp;
size_t GetSerializeSize(int nType, int nVersion) const {
return 4;
}
template<typename Stream>
void Serialize(Stream& s) const {
ser_writedata32be(s, timestamp);
}
template<typename Stream>
void Unserialize(Stream& s) {
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) const {
ser_writedata32be(s, timestamp);
blockHash.Serialize(s);
}
template<typename Stream>
void Unserialize(Stream& s) {
timestamp = ser_readdata32be(s);
blockHash.Unserialize(s);
}
CTimestampIndexKey(unsigned int time, uint256 hash) {
timestamp = time;
blockHash = hash;
}
CTimestampIndexKey() {
SetNull();
}
void SetNull() {
timestamp = 0;
blockHash.SetNull();
}
};
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) const {
ser_writedata8(s, type);
hashBytes.Serialize(s);
txhash.Serialize(s);
ser_writedata32(s, index);
}
template<typename Stream>
void Unserialize(Stream& s) {
type = ser_readdata8(s);
hashBytes.Unserialize(s);
txhash.Unserialize(s);
index = ser_readdata32(s);
}
CAddressUnspentKey(unsigned int addressType, uint160 addressHash, uint256 txid, size_t indexValue) {
type = addressType;
hashBytes = addressHash;
txhash = txid;
index = indexValue;
}
public:
AddressType m_address_type{AddressType::UNKNOWN};
uint160 m_address_bytes;
uint256 m_tx_hash;
uint32_t m_tx_index{0};
public:
CAddressUnspentKey() {
SetNull();
}
CAddressUnspentKey(AddressType address_type, uint160 address_bytes, uint256 tx_hash, uint32_t tx_index) :
m_address_type{address_type}, m_address_bytes{address_bytes}, m_tx_hash{tx_hash}, m_tx_index{tx_index} {};
void SetNull() {
type = 0;
hashBytes.SetNull();
txhash.SetNull();
index = 0;
m_address_type = AddressType::UNKNOWN;
m_address_bytes.SetNull();
m_tx_hash.SetNull();
m_tx_index = 0;
}
public:
size_t GetSerializeSize(int nType, int nVersion) const {
return 57;
}
template<typename Stream>
void Serialize(Stream& s) const {
ser_writedata8(s, ToUnderlying(m_address_type));
m_address_bytes.Serialize(s);
m_tx_hash.Serialize(s);
ser_writedata32(s, m_tx_index);
}
template<typename Stream>
void Unserialize(Stream& s) {
m_address_type = static_cast<AddressType>(ser_readdata8(s));
m_address_bytes.Unserialize(s);
m_tx_hash.Unserialize(s);
m_tx_index = ser_readdata32(s);
}
};
struct CAddressUnspentValue {
CAmount satoshis;
CScript script;
int blockHeight;
SERIALIZE_METHODS(CAddressUnspentValue, obj)
{
READWRITE(obj.satoshis, obj.script, obj.blockHeight);
}
CAddressUnspentValue(CAmount sats, CScript scriptPubKey, int height) {
satoshis = sats;
script = scriptPubKey;
blockHeight = height;
}
public:
CAmount m_amount{-1};
CScript m_tx_script;
int32_t m_block_height;
public:
CAddressUnspentValue() {
SetNull();
}
CAddressUnspentValue(CAmount amount, CScript tx_script, int32_t block_height) :
m_amount{amount}, m_tx_script{tx_script}, m_block_height{block_height} {};
void SetNull() {
satoshis = -1;
script.clear();
blockHeight = 0;
m_amount = -1;
m_tx_script.clear();
m_block_height = 0;
}
bool IsNull() const {
return (satoshis == -1);
return (m_amount == -1);
}
public:
SERIALIZE_METHODS(CAddressUnspentValue, obj)
{
READWRITE(obj.m_amount, obj.m_tx_script, obj.m_block_height);
}
};
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) const {
ser_writedata8(s, type);
hashBytes.Serialize(s);
// Heights are stored big-endian for key sorting in LevelDB
ser_writedata32be(s, blockHeight);
ser_writedata32be(s, txindex);
txhash.Serialize(s);
ser_writedata32(s, index);
char f = spending;
ser_writedata8(s, f);
}
template<typename Stream>
void Unserialize(Stream& s) {
type = ser_readdata8(s);
hashBytes.Unserialize(s);
blockHeight = ser_readdata32be(s);
txindex = ser_readdata32be(s);
txhash.Unserialize(s);
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) const {
ser_writedata8(s, type);
hashBytes.Serialize(s);
}
template<typename Stream>
void Unserialize(Stream& s) {
type = ser_readdata8(s);
hashBytes.Unserialize(s);
}
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) const {
ser_writedata8(s, type);
hashBytes.Serialize(s);
ser_writedata32be(s, blockHeight);
}
template<typename Stream>
void Unserialize(Stream& s) {
type = ser_readdata8(s);
hashBytes.Unserialize(s);
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;
}
};
#endif // BITCOIN_SPENTINDEX_H

81
src/timestampindex.h Normal file
View File

@ -0,0 +1,81 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2016 BitPay, Inc.
// Copyright (c) 2023 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_TIMESTAMPINDEX_H
#define BITCOIN_TIMESTAMPINDEX_H
#include <serialize.h>
#include <uint256.h>
struct CTimestampIndexIteratorKey {
public:
uint32_t m_time;
public:
CTimestampIndexIteratorKey() {
SetNull();
}
CTimestampIndexIteratorKey(uint32_t time) : m_time{time} {};
void SetNull() {
m_time = 0;
}
public:
size_t GetSerializeSize(int nType, int nVersion) const {
return 4;
}
template<typename Stream>
void Serialize(Stream& s) const {
ser_writedata32be(s, m_time);
}
template<typename Stream>
void Unserialize(Stream& s) {
m_time = ser_readdata32be(s);
}
};
struct CTimestampIndexKey {
public:
uint32_t m_block_time;
uint256 m_block_hash;
public:
CTimestampIndexKey() {
SetNull();
}
CTimestampIndexKey(uint32_t block_time, uint256 block_hash) :
m_block_time{block_time}, m_block_hash{block_hash} {};
void SetNull() {
m_block_time = 0;
m_block_hash.SetNull();
}
public:
size_t GetSerializeSize(int nType, int nVersion) const {
return 36;
}
template<typename Stream>
void Serialize(Stream& s) const {
ser_writedata32be(s, m_block_time);
m_block_hash.Serialize(s);
}
template<typename Stream>
void Unserialize(Stream& s) {
m_block_time = ser_readdata32be(s);
m_block_hash.Unserialize(s);
}
};
#endif // BITCOIN_TIMESTAMPINDEX_H

View File

@ -266,7 +266,7 @@ bool CBlockTreeDB::UpdateAddressUnspentIndex(const std::vector<std::pair<CAddres
return WriteBatch(batch);
}
bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, int type,
bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, AddressType type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs) {
std::unique_ptr<CDBIterator> pcursor(NewIterator());
@ -275,7 +275,7 @@ bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, int type,
while (pcursor->Valid()) {
std::pair<char,CAddressUnspentKey> key;
if (pcursor->GetKey(key) && key.first == DB_ADDRESSUNSPENTINDEX && key.second.hashBytes == addressHash) {
if (pcursor->GetKey(key) && key.first == DB_ADDRESSUNSPENTINDEX && key.second.m_address_bytes == addressHash) {
CAddressUnspentValue nValue;
if (pcursor->GetValue(nValue)) {
unspentOutputs.push_back(std::make_pair(key.second, nValue));
@ -305,7 +305,7 @@ bool CBlockTreeDB::EraseAddressIndex(const std::vector<std::pair<CAddressIndexKe
return WriteBatch(batch);
}
bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, AddressType type,
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
int start, int end) {
@ -319,8 +319,8 @@ bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
while (pcursor->Valid()) {
std::pair<char,CAddressIndexKey> key;
if (pcursor->GetKey(key) && key.first == DB_ADDRESSINDEX && key.second.hashBytes == addressHash) {
if (end > 0 && key.second.blockHeight > end) {
if (pcursor->GetKey(key) && key.first == DB_ADDRESSINDEX && key.second.m_address_bytes == addressHash) {
if (end > 0 && key.second.m_block_height > end) {
break;
}
CAmount nValue;
@ -359,8 +359,8 @@ bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned i
while (pcursor->Valid()) {
std::pair<char, CTimestampIndexKey> key;
if (pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp <= high) {
hashes.push_back(key.second.blockHash);
if (pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.m_block_time <= high) {
hashes.push_back(key.second.m_block_hash);
pcursor->Next();
} else {
break;

View File

@ -11,6 +11,7 @@
#include <chain.h>
#include <primitives/block.h>
#include <spentindex.h>
#include <timestampindex.h>
#include <memory>
#include <string>
@ -108,11 +109,11 @@ public:
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,
bool ReadAddressUnspentIndex(uint160 addressHash, AddressType 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,
bool ReadAddressIndex(uint160 addressHash, AddressType type,
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
int start = 0, int end = 0);
bool WriteTimestampIndex(const CTimestampIndexKey &timestampIndex);

View File

@ -474,59 +474,45 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC
const CTxIn input = tx.vin[j];
const Coin& coin = view.AccessCoin(input.prevout);
const CTxOut &prevout = coin.out;
if (prevout.scriptPubKey.IsPayToScriptHash()) {
std::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(std::make_pair(key, delta));
inserted.push_back(key);
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
std::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(std::make_pair(key, delta));
inserted.push_back(key);
} else if (prevout.scriptPubKey.IsPayToPublicKey()) {
uint160 hashBytes{Hash160(Span{prevout.scriptPubKey.data()+1, prevout.scriptPubKey.size() - 2})};
CMempoolAddressDeltaKey key(1, hashBytes, txhash, j, 1);
CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n);
mapAddress.insert(std::make_pair(key, delta));
inserted.push_back(key);
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
if (!AddressBytesFromScript(prevout.scriptPubKey, address_type, address_bytes)) {
continue;
}
CMempoolAddressDeltaKey key(address_type, address_bytes, txhash, j, /* tx_spent */ true);
CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n);
mapAddress.insert(std::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()) {
std::vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, k, 0);
mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
inserted.push_back(key);
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
std::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(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
inserted.push_back(key);
} else if (out.scriptPubKey.IsPayToPublicKey()) {
uint160 hashBytes{Hash160(Span{out.scriptPubKey.data()+1, out.scriptPubKey.size() - 2})};
std::pair<addressDeltaMap::iterator,bool> ret;
CMempoolAddressDeltaKey key(1, hashBytes, txhash, k, 0);
mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
inserted.push_back(key);
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
if (!AddressBytesFromScript(out.scriptPubKey, address_type, address_bytes)) {
continue;
}
CMempoolAddressDeltaKey key(address_type, address_bytes, txhash, k, /* tx_spent */ false);
mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
inserted.push_back(key);
}
mapAddressInserted.insert(std::make_pair(txhash, inserted));
}
bool CTxMemPool::getAddressIndex(std::vector<std::pair<uint160, int> > &addresses,
bool CTxMemPool::getAddressIndex(std::vector<std::pair<uint160, AddressType> > &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) {
for (const auto& address : addresses) {
addressDeltaMap::iterator ait = mapAddress.lower_bound(CMempoolAddressDeltaKey(address.second, address.first));
while (ait != mapAddress.end() && (*ait).first.m_address_bytes == address.first && (*ait).first.m_address_type == address.second) {
results.push_back(*ait);
ait++;
}
@ -562,29 +548,19 @@ void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCac
const CTxIn input = tx.vin[j];
const Coin& coin = view.AccessCoin(input.prevout);
const CTxOut &prevout = coin.out;
uint160 addressHash;
int addressType;
if (prevout.scriptPubKey.IsPayToScriptHash()) {
addressHash = uint160(std::vector<unsigned char> (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
addressType = 2;
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
addressHash = uint160(std::vector<unsigned char> (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
addressType = 1;
} else if (prevout.scriptPubKey.IsPayToPublicKey()) {
addressHash = Hash160(Span{prevout.scriptPubKey.data()+1, prevout.scriptPubKey.size() - 2});
addressType = 1;
} else {
addressHash.SetNull();
addressType = 0;
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
if (!AddressBytesFromScript(prevout.scriptPubKey, address_type, address_bytes)) {
continue;
}
CSpentIndexKey key = CSpentIndexKey(input.prevout.hash, input.prevout.n);
CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, addressType, addressHash);
CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, address_type, address_bytes);
mapSpent.insert(std::make_pair(key, value));
inserted.push_back(key);
}
mapSpentInserted.insert(make_pair(txhash, inserted));

View File

@ -603,7 +603,7 @@ public:
void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
void addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
bool getAddressIndex(std::vector<std::pair<uint160, int> > &addresses,
bool getAddressIndex(std::vector<std::pair<uint160, AddressType> > &addresses,
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results);
bool removeAddressIndex(const uint256 txhash);

View File

@ -1037,7 +1037,7 @@ bool GetSpentIndex(CTxMemPool& mempool, CSpentIndexKey &key, CSpentIndexValue &v
return true;
}
bool GetAddressIndex(uint160 addressHash, int type,
bool GetAddressIndex(uint160 addressHash, AddressType type,
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex, int start, int end)
{
if (!fAddressIndex)
@ -1049,7 +1049,7 @@ bool GetAddressIndex(uint160 addressHash, int type,
return true;
}
bool GetAddressUnspent(uint160 addressHash, int type,
bool GetAddressUnspent(uint160 addressHash, AddressType type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs)
{
if (!fAddressIndex)
@ -1703,38 +1703,22 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
bool is_coinbase = tx.IsCoinBase();
if (fAddressIndex) {
for (unsigned int k = tx.vout.size(); k-- > 0;) {
const CTxOut &out = tx.vout[k];
if (out.scriptPubKey.IsPayToScriptHash()) {
std::vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
// undo receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue));
// undo unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), hash, k), CAddressUnspentValue()));
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
std::vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
// undo receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue));
// undo unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, uint160(hashBytes), hash, k), CAddressUnspentValue()));
} else if (out.scriptPubKey.IsPayToPublicKey()) {
uint160 hashBytes{Hash160(Span{out.scriptPubKey.data()+1, out.scriptPubKey.size() - 2})};
addressIndex.push_back(std::make_pair(CAddressIndexKey(1, hashBytes, pindex->nHeight, i, hash, k, false), out.nValue));
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, hashBytes, hash, k), CAddressUnspentValue()));
} else {
if (!AddressBytesFromScript(out.scriptPubKey, address_type, address_bytes)) {
continue;
}
}
// undo receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, i, hash, k, false), out.nValue));
// undo unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(address_type, address_bytes, hash, k), CAddressUnspentValue()));
}
}
// Check that all outputs are available and match the outputs in the block itself
@ -1774,36 +1758,20 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
if (fAddressIndex) {
const Coin &coin = view.AccessCoin(tx.vin[j].prevout);
const CTxOut &prevout = coin.out;
if (prevout.scriptPubKey.IsPayToScriptHash()) {
std::vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
// undo spending activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
// restore unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undoHeight)));
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
std::vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
// undo spending activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
// restore unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undoHeight)));
} else if (prevout.scriptPubKey.IsPayToPublicKey()) {
uint160 hashBytes{Hash160(Span{prevout.scriptPubKey.data()+1, prevout.scriptPubKey.size()-2})};
// undo spending activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(1, hashBytes, pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
// restore unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undoHeight)));
} else {
if (!AddressBytesFromScript(prevout.scriptPubKey, address_type, address_bytes)) {
continue;
}
}
// undo spending activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
// restore unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(address_type, address_bytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undoHeight)));
}
}
// At this point, all of txundo.vprevout should have been moved out.
}
@ -2255,40 +2223,28 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
const CTxIn input = tx.vin[j];
const Coin& coin = view.AccessCoin(tx.vin[j].prevout);
const CTxOut &prevout = coin.out;
uint160 hashBytes;
int addressType;
if (prevout.scriptPubKey.IsPayToScriptHash()) {
hashBytes = uint160(std::vector<unsigned char>(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
addressType = 2;
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
hashBytes = uint160(std::vector<unsigned char>(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
addressType = 1;
} else if (prevout.scriptPubKey.IsPayToPublicKey()) {
hashBytes = Hash160(Span{prevout.scriptPubKey.data()+1, prevout.scriptPubKey.size()-2});
addressType = 1;
} else {
hashBytes.SetNull();
addressType = 0;
}
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
if (fAddressIndex && addressType > 0) {
AddressBytesFromScript(prevout.scriptPubKey, address_type, address_bytes);
if (fAddressIndex && address_type != AddressType::UNKNOWN) {
// record spending activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
addressIndex.push_back(std::make_pair(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
// remove address from unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(address_type, address_bytes, 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(std::make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes)));
spentIndex.push_back(std::make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, address_type, address_bytes)));
}
}
nTime2_index += GetTimeMicros() - nTime2_index1;
}
}
// GetTransactionSigOpCount counts 2 types of sigops:
@ -2322,31 +2278,18 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
for (unsigned int k = 0; k < tx.vout.size(); k++) {
const CTxOut &out = tx.vout[k];
if (out.scriptPubKey.IsPayToScriptHash()) {
std::vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
// record receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
std::vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
// record receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
} else if (out.scriptPubKey.IsPayToPublicKey()) {
uint160 hashBytes{Hash160(Span{out.scriptPubKey.data()+1, out.scriptPubKey.size()-2})};
addressIndex.push_back(std::make_pair(CAddressIndexKey(1, hashBytes, pindex->nHeight, i, txhash, k, false), out.nValue));
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, hashBytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
} else {
if (!AddressBytesFromScript(out.scriptPubKey, address_type, address_bytes)) {
continue;
}
// record receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(address_type, address_bytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
}
nTime2_index += GetTimeMicros() - nTime2_index2;
}
@ -4861,35 +4804,24 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i
const CTxIn input = tx->vin[j];
const Coin& coin = inputs.AccessCoin(tx->vin[j].prevout);
const CTxOut& prevout = coin.out;
uint160 hashBytes;
int addressType;
if (prevout.scriptPubKey.IsPayToScriptHash()) {
hashBytes = uint160(std::vector<unsigned char>(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
addressType = 2;
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
hashBytes = uint160(std::vector<unsigned char>(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
addressType = 1;
} else if (prevout.scriptPubKey.IsPayToPublicKey()) {
hashBytes = Hash160(Span{prevout.scriptPubKey.data()+1, prevout.scriptPubKey.size()-2});
addressType = 1;
} else {
hashBytes.SetNull();
addressType = 0;
}
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
if (fAddressIndex && addressType > 0) {
AddressBytesFromScript(prevout.scriptPubKey, address_type, address_bytes);
if (fAddressIndex && address_type != AddressType::UNKNOWN) {
// record spending activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
addressIndex.push_back(std::make_pair(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
// remove address from unspent index
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(address_type, address_bytes, 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(std::make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes)));
spentIndex.push_back(std::make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, address_type, address_bytes)));
}
}
}
@ -4898,31 +4830,18 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i
for (size_t k = 0; k < tx->vout.size(); k++) {
const CTxOut& out = tx->vout[k];
if (out.scriptPubKey.IsPayToScriptHash()) {
std::vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
AddressType address_type{AddressType::UNKNOWN};
uint160 address_bytes;
// record receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
std::vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
// record receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
} else if (out.scriptPubKey.IsPayToPublicKey()) {
uint160 hashBytes{Hash160(Span{out.scriptPubKey.data()+1, out.scriptPubKey.size()-2})};
addressIndex.push_back(std::make_pair(CAddressIndexKey(1, hashBytes, pindex->nHeight, i, txhash, k, false), out.nValue));
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, hashBytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
} else {
if (!AddressBytesFromScript(out.scriptPubKey, address_type, address_bytes)) {
continue;
}
// record receiving activity
addressIndex.push_back(std::make_pair(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, i, txhash, k, false), out.nValue));
// record unspent output
addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(address_type, address_bytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
}
}

View File

@ -307,10 +307,10 @@ public:
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &hashes);
bool GetSpentIndex(CTxMemPool& mempool, CSpentIndexKey &key, CSpentIndexValue &value);
bool GetAddressIndex(uint160 addressHash, int type,
bool GetAddressIndex(uint160 addressHash, AddressType type,
std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
int start = 0, int end = 0);
bool GetAddressUnspent(uint160 addressHash, int type,
bool GetAddressUnspent(uint160 addressHash, AddressType type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs);
/** Initializes the script-execution cache */
void InitScriptExecutionCache();