207 lines
6.9 KiB
C++
207 lines
6.9 KiB
C++
#include <wallet/txrecord.h>
|
|
#include <wallet/wallet.h>
|
|
#include <wallet/txrecord.h>
|
|
#include <wallet/wallet.h>
|
|
|
|
#include <chain.h>
|
|
#include <core_io.h>
|
|
#include <interfaces/chain.h>
|
|
#include <key_io.h>
|
|
#include <util/check.h>
|
|
|
|
#include <chrono>
|
|
|
|
using namespace std::chrono;
|
|
|
|
bool WalletTxRecord::UpdateStatusIfNeeded(const uint256& block_hash)
|
|
{
|
|
assert(!block_hash.IsNull());
|
|
|
|
// Check if update is needed
|
|
if (status.m_cur_block_hash == block_hash && !status.needsUpdate) {
|
|
return false;
|
|
}
|
|
|
|
// Try locking the wallet
|
|
TRY_LOCK(m_pWallet->cs_wallet, locked_wallet);
|
|
if (!locked_wallet) {
|
|
return false;
|
|
}
|
|
|
|
const int last_block_height = m_pWallet->GetLastBlockHeight();
|
|
int64_t block_time = -1;
|
|
CHECK_NONFATAL(m_pWallet->chain().findBlock(m_pWallet->GetLastBlockHash(), interfaces::FoundBlock().time(block_time)));
|
|
|
|
// Sort order, unrecorded transactions sort to the top
|
|
// Sub-components sorted with standard outputs first, MWEB outputs second, then MWEB pegouts third.
|
|
std::string idx = strprintf("0%03d", 0);
|
|
if (index) {
|
|
if (index->type() == typeid(int)) {
|
|
idx = strprintf("0%03d", boost::get<int>(*index));
|
|
} else if (index->type() == typeid(mw::Hash)) {
|
|
idx = "1" + boost::get<mw::Hash>(*index).ToHex();
|
|
} else {
|
|
const PegoutIndex& pegout_idx = boost::get<PegoutIndex>(*index);
|
|
idx = "2" + pegout_idx.kernel_id.ToHex() + strprintf("%03d", pegout_idx.pos);
|
|
}
|
|
}
|
|
|
|
int block_height = m_wtx->m_confirm.block_height > 0 ? m_wtx->m_confirm.block_height : std::numeric_limits<int>::max();
|
|
int blocks_to_maturity = m_wtx->GetBlocksToMaturity();
|
|
|
|
status.sortKey = strprintf("%010d-%01d-%010u-%s",
|
|
block_height,
|
|
m_wtx->IsCoinBase() ? 1 : 0,
|
|
m_wtx->nTimeReceived,
|
|
idx);
|
|
status.countsForBalance = m_wtx->IsTrusted() && !(blocks_to_maturity > 0);
|
|
status.depth = m_wtx->GetDepthInMainChain();
|
|
status.m_cur_block_hash = block_hash;
|
|
|
|
if (m_wtx->IsInMainChain()) {
|
|
status.matures_in = blocks_to_maturity;
|
|
}
|
|
|
|
const int64_t time_since_epoch = (int64_t)duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
|
|
const bool up_to_date = (time_since_epoch - block_time < MAX_BLOCK_TIME_GAP);
|
|
if (up_to_date && !m_wtx->IsFinal()) {
|
|
if (m_wtx->tx->nLockTime < LOCKTIME_THRESHOLD) {
|
|
status.status = WalletTxStatus::OpenUntilBlock;
|
|
status.open_for = m_wtx->tx->nLockTime - last_block_height;
|
|
} else {
|
|
status.status = WalletTxStatus::OpenUntilDate;
|
|
status.open_for = m_wtx->tx->nLockTime;
|
|
}
|
|
}
|
|
|
|
// For generated transactions, determine maturity
|
|
else if (type == WalletTxRecord::Type::Generated || m_wtx->IsHogEx()) {
|
|
if (blocks_to_maturity > 0) {
|
|
status.status = WalletTxStatus::Immature;
|
|
|
|
if (!m_wtx->IsInMainChain()) {
|
|
status.status = WalletTxStatus::NotAccepted;
|
|
}
|
|
} else {
|
|
status.status = WalletTxStatus::Confirmed;
|
|
}
|
|
} else {
|
|
if (status.depth < 0) {
|
|
status.status = WalletTxStatus::Conflicted;
|
|
} else if (status.depth == 0) {
|
|
status.status = WalletTxStatus::Unconfirmed;
|
|
if (m_wtx->isAbandoned())
|
|
status.status = WalletTxStatus::Abandoned;
|
|
} else if (status.depth < RecommendedNumConfirmations) {
|
|
status.status = WalletTxStatus::Confirming;
|
|
} else {
|
|
status.status = WalletTxStatus::Confirmed;
|
|
}
|
|
}
|
|
|
|
status.needsUpdate = false;
|
|
return true;
|
|
}
|
|
|
|
const uint256& WalletTxRecord::GetTxHash() const
|
|
{
|
|
assert(m_wtx != nullptr);
|
|
return m_wtx->GetHash();
|
|
}
|
|
|
|
std::string WalletTxRecord::GetTxString() const
|
|
{
|
|
assert(m_wtx != nullptr);
|
|
|
|
if (m_wtx->IsPartialMWEB()) {
|
|
if (m_wtx->mweb_wtx_info->received_coin) {
|
|
const mw::Coin& received_coin = *m_wtx->mweb_wtx_info->received_coin;
|
|
return strprintf("MWEB Output(ID=%s, amount=%d)", received_coin.output_id.ToHex(), received_coin.amount);
|
|
} else if (m_wtx->mweb_wtx_info->spent_input) {
|
|
return strprintf("MWEB Input(ID=%s)\n", m_wtx->mweb_wtx_info->spent_input->ToHex());
|
|
}
|
|
}
|
|
|
|
return m_wtx->tx->ToString();
|
|
}
|
|
|
|
int64_t WalletTxRecord::GetTxTime() const
|
|
{
|
|
assert(m_wtx != nullptr);
|
|
return m_wtx->GetTxTime();
|
|
}
|
|
|
|
std::string WalletTxRecord::GetComponentIndex() const
|
|
{
|
|
std::string idx;
|
|
if (this->index) {
|
|
if (this->index->type() == typeid(int)) {
|
|
idx = std::to_string(boost::get<int>(*index));
|
|
} else if (index->type() == typeid(mw::Hash)) {
|
|
idx = "MWEB Output (" + boost::get<mw::Hash>(*index).ToHex() + ")";
|
|
} else {
|
|
const PegoutIndex& pegout_idx = boost::get<PegoutIndex>(*index);
|
|
idx = "Pegout (" + pegout_idx.kernel_id.ToHex() + ":" + std::to_string(pegout_idx.pos) + ")";
|
|
}
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
std::string WalletTxRecord::GetType() const
|
|
{
|
|
switch (this->type) {
|
|
case Other: return "Other";
|
|
case Generated: return "Generated";
|
|
case SendToAddress: return "SendToAddress";
|
|
case SendToOther: return "SendToOther";
|
|
case RecvWithAddress: return "RecvWithAddress";
|
|
case RecvFromOther: return "RecvFromOther";
|
|
case SendToSelf: return "SendToSelf";
|
|
}
|
|
|
|
assert(false);
|
|
}
|
|
|
|
UniValue WalletTxRecord::ToUniValue() const
|
|
{
|
|
UniValue entry(UniValue::VOBJ);
|
|
|
|
entry.pushKV("type", GetType());
|
|
entry.pushKV("amount", ValueFromAmount(GetAmount()));
|
|
entry.pushKV("net", ValueFromAmount(GetNet()));
|
|
|
|
CTxDestination destination = DecodeDestination(this->address);
|
|
if (m_wtx->IsFromMe(ISMINE_WATCH_ONLY) || (IsValidDestination(destination) && (m_pWallet->IsMine(destination) & ISMINE_WATCH_ONLY))) {
|
|
entry.pushKV("involvesWatchonly", true);
|
|
}
|
|
|
|
if (IsValidDestination(destination)) {
|
|
const auto* address_book_entry = m_pWallet->FindAddressBookEntry(destination);
|
|
if (address_book_entry) {
|
|
entry.pushKV("label", address_book_entry->GetLabel());
|
|
}
|
|
}
|
|
|
|
if (!this->address.empty()) {
|
|
entry.pushKV("address", this->address);
|
|
}
|
|
|
|
if (this->index) {
|
|
if (this->index->type() == typeid(int)) {
|
|
entry.pushKV("vout", boost::get<int>(*this->index));
|
|
} else if (this->index->type() == typeid(mw::Hash)) {
|
|
entry.pushKV("mweb_out", boost::get<mw::Hash>(*this->index).ToHex());
|
|
} else {
|
|
const PegoutIndex& pegout_idx = boost::get<PegoutIndex>(*index);
|
|
entry.pushKV("pegout", pegout_idx.kernel_id.ToHex() + ":" + std::to_string(pegout_idx.pos));
|
|
}
|
|
}
|
|
|
|
if (this->debit > 0) {
|
|
entry.pushKV("fee", ValueFromAmount(-this->fee));
|
|
entry.pushKV("abandoned", m_wtx->isAbandoned());
|
|
}
|
|
|
|
return entry;
|
|
} |