mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
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:
commit
2958aacf5d
@ -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
43
src/addressindex.cpp
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
138
src/rpc/misc.cpp
138
src/rpc/misc.cpp
@ -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;
|
||||
}
|
||||
|
400
src/spentindex.h
400
src/spentindex.h
@ -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
81
src/timestampindex.h
Normal 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
|
14
src/txdb.cpp
14
src/txdb.cpp
@ -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;
|
||||
|
@ -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 ×tampIndex);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user