Skip to content

Commit

Permalink
TransactionInfo, EnoteDetails, some clean-up
Browse files Browse the repository at this point in the history
  • Loading branch information
SNeedlewoods committed Sep 16, 2024
1 parent a621fc5 commit 7d37965
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 95 deletions.
12 changes: 12 additions & 0 deletions src/wallet/api/transaction_history.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ void TransactionHistoryImpl::refresh()
ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "";
ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0;
// QUESTION : Don't we want the unlock time?
ti->m_unlock_time = pd.m_unlock_time;
ti->m_change = pd->m_change;
ti->m_tx_state = TransactionInfo::confirmed;

// single output transaction might contain multiple transfers
for (const auto &d: pd.m_dests) {
Expand Down Expand Up @@ -229,6 +233,10 @@ void TransactionHistoryImpl::refresh()
ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "";
ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = 0;
// QUESTION : Don't we want the unlock time?
ti->m_unlock_time = pd.m_tx.unlock_time;
ti->m_change = pd->m_change;
ti->m_tx_state = pd->m_state;
for (const auto &d : pd.m_dests)
{
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)});
Expand Down Expand Up @@ -258,6 +266,10 @@ void TransactionHistoryImpl::refresh()
ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index);
ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = 0;
// QUESTION : Don't we want the unlock time?
ti->m_unlock_time = pd.m_unlock_time;
ti->m_tx_state = TransactionInfo::pending_in_pool;
ti->m_double_spend_seen = i->second.m_double_spend_seen;
m_history.push_back(ti);

LOG_PRINT_L1(__FUNCTION__ << ": Unconfirmed payment found " << pd.m_amount);
Expand Down
15 changes: 15 additions & 0 deletions src/wallet/api/transaction_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,19 @@ uint64_t TransactionInfoImpl::unlockTime() const
return m_unlock_time;
}

std::uint64_t TransactionInfoImpl::receivedChangeAmount() const
{
return m_change;
}

int TransactionInfoImpl::txState() const
{
return m_tx_state;
}

bool TransactionInfoImpl::isDoubleSpendSeen() const
{
return m_double_spend_seen;
}

} // namespace
28 changes: 9 additions & 19 deletions src/wallet/api/transaction_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class TransactionInfoImpl : public TransactionInfo
virtual uint64_t confirmations() const override;
virtual uint64_t unlockTime() const override;

std::uint64_t receivedChangeAmount() const override;
int txState() const override;
bool isDoubleSpendSeen() const override;

private:
int m_direction;
bool m_pending;
Expand All @@ -81,25 +85,11 @@ class TransactionInfoImpl : public TransactionInfo
std::vector<Transfer> m_transfers;
uint64_t m_confirmations;
uint64_t m_unlock_time;

// TODO : If it's certain that we need these, then add getter functions (to `TransactionInfo` in wallet2_api.h and `TransactionInfoImpl` in transaction_info.*) and add values to new members where applicable (e.g. in `TransactionHistoryImpl`)

// from unconfirmed_transfer_details
uint64_t m_change;
// QUESTION : Can someone confirm that we don't need m_dests, because we have:
// - amount = m_transfers[i].amount
// - address = m_transfers[i].address
// - is_subaddress = m_subaddrIndex[i] != 0
// I'm especially unsure about this assumption, wasn't able to verify it:
// - is_integrated = WalletImpl::integratedAddress(m_paymentid) == m_transfers[i].address
// And I haven't figured this one out yet
// - original =
std::vector<cryptonote::tx_destination_entry> m_dests;
enum { pending, pending_in_pool, failed, confirmed } m_tx_state;
// QUESTION : Any comments if we need this? Haven't investigated yet.
std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> m_rings; // relative

// from unconfirmed_payments
// received change amount from outgoing transaction
std::uint64_t m_change;
// enum TxState
int m_tx_state;
// is double spend seen
bool m_double_spend_seen;

friend class TransactionHistoryImpl;
Expand Down
50 changes: 45 additions & 5 deletions src/wallet/api/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3154,7 +3154,47 @@ void WalletImpl::processPoolState(const std::vector<std::tuple<cryptonote::trans
}
}
//-------------------------------------------------------------------------------------------------------------------
std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx)
void WalletImpl::getEnoteDetails(std::vector<EnoteDetails> enote_details) const
{
wallet2::transfer_container tc;
m_wallet->get_transfers(tc);
enote_details.reserve(tc.size());

for (auto &td : tc)
{
EnoteDetails ed{};

cryptonote::txout_target_v txout_v = td.m_tx.vout[tx.m_internal_output_index];
crypto::public_key pub_key_pod;
if (txout_v.type() == typeid(cryptonote::txout_to_key))
ed.m_onetime_address = epee::string_tools::pod_to_hex(boost::get<cryptonote::txout_to_key>(txout_v).key);
else if (txout_v.type() == typeid(cryptonote::txout_to_tagged_key))
{
ed.m_onetime_address = epee::string_tools::pod_to_hex(boost::get<cryptonote::txout_to_tagged_key>(txout_v).key);
ed.m_view_tag = epee::string_tools::pod_to_hex(boost::get<cryptonote::txout_to_tagged_key>(txout_v).view_tag);
}

ed.m_tx_id = td.m_txid;
ed.m_internal_output_index = td.m_internal_output_index;
ed.m_global_output_index = td.m_global_output_index;
ed.m_spent = td.m_spent;
ed.m_frozen = td.m_frozen;
ed.m_spent_height = td.m_spent_height;
ed.m_key_image = td.m_key_image;
ed.m_mask = td.m_mask;
ed.m_amount = td.m_mask;
ed.m_rct = td.m_rct;
// ed.m_protocol_version = td.m_rct ? EnoteDetails::rct : EnoteDetails::cn;
ed.m_key_image_known = td.m_key_image_known;
ed.m_key_image_request = td.m_key_image_request;
ed.m_pk_index = td.m_pk_index;
ed.m_uses = td.m_uses;

enote_details.push_back(ed);
}
}
//-------------------------------------------------------------------------------------------------------------------
std::string WalletImpl::convertMultisigTxToStr(const PendingTransaction &multisig_ptx)
{
clearStatus();

Expand All @@ -3176,7 +3216,7 @@ std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx)
return "";
}
//-------------------------------------------------------------------------------------------------------------------
bool saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &filename)
bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &filename)
{
clearStatus();

Expand All @@ -3198,7 +3238,7 @@ bool saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &
return false;
}
//-------------------------------------------------------------------------------------------------------------------
std::string convertTxToStr(const PendingTransaction &ptxs)
std::string WalletImpl::convertTxToStr(const PendingTransaction &ptxs)
{
clearStatus();

Expand All @@ -3211,12 +3251,12 @@ std::string convertTxToStr(const PendingTransaction &ptxs)
return tx_dump;
}
//-------------------------------------------------------------------------------------------------------------------
bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs)
bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs)
{
return m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, exported_txs.m_unsigned_tx_set);
}
//-------------------------------------------------------------------------------------------------------------------
bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs)
bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs)
{
clearStatus();

Expand Down
1 change: 1 addition & 0 deletions src/wallet/api/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ class WalletImpl : public Wallet
std::map<std::uint32_t, std::pair<std::uint64_t, std::pair<std::uint64_t, std::uint64_t>>> unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) const override;
void updatePoolState(std::vector<std::tuple<cryptonote::transaction, std::string, bool>> &process_txs, bool refreshed = false, bool try_incremental = false) override;
void processPoolState(const std::vector<std::tuple<cryptonote::transaction, std::string, bool>> &txs) override;
void getEnoteDetails(std::vector<EnoteDetails> enote_details) const override;
std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const override;
bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override;
std::string convertTxToStr(const PendingTransaction &ptxs) const override;
Expand Down
123 changes: 52 additions & 71 deletions src/wallet/api/wallet2_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,44 +74,50 @@ enum NetworkType : uint8_t {
*/
struct EnoteDetails
{
// from seraphis legacy enote types
// Ko
rct::key onetime_address;
/// a
rct::xmr_amount amount;
/// C
rct::key amount_commitment;
/// enc(x)
rct::key encoded_amount_blinding_factor;
/// enc(a)
rct::key encoded_amount;
/// view_tag
crypto::view_tag view_tag;

// TODO : figure out if we need other members from transfer_details too, these are the ones that are not part of `TransactionInfo`, but my first impression is we could have an overlap so we can find TransactionInfo from EnoteDetails and vice versa.
// from transfer_details:
cryptonote::transaction_prefix m_tx;
// index in m_tx.vout
uint64_t m_internal_output_index;
uint64_t m_global_output_index;
std::string m_onetime_address;
// view_tag
std::string m_view_tag;
// QUESTION : I'd argue block height for enote is redundant, you can get this information from TransactionHistory. Or any different opinions?
// std::uint64_t m_block_height;
// relative index in tx
std::uint64_t m_internal_output_index;
// absolute index from `cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry.output_indices`
std::uint64_t m_global_output_index;
// is spent
bool m_spent;
// is frozen
bool m_frozen;
uint64_t m_spent_height;
crypto::key_image m_key_image;
rct::key m_mask;
// blockchain height, set if spent
std::uint64_t m_spent_height;
// key image
std::string m_key_image;
// QUESTION : Is this comment correct?
// x, blinding factor in amount commitment C = x G + a H
std::string m_mask;
// a
std::uint64_t m_amount;
// QUESTION : Should we change m_rct to this enum to be prepared for the future? We could also add CryptoNote as cn before rct if that would make sense!?
// enum { rct, fcmp } m_protocol_version;
// or
// enum { cn, rct, fcmp } m_protocol_version;
// is ring confidential transaction
bool m_rct;
// is key image known
bool m_key_image_known;
bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested
// TODO : fwiw so far this only is used for get_tx_pub_key_from_extra, figure out if actually needed.
// view wallets: we want to request it; cold wallets: it was requested
bool m_key_image_request;
// public key index in tx_extra
uint64_t m_pk_index;
// TODO : This gets only filled by `wallet2::process_new_transaction` and only if `wallet2::m_track_uses` is true (default is false). Figure out if it's "too exotic" or do we need it.
std::vector<std::pair<uint64_t, crypto::hash>> m_uses;

// QUESTION : Any input on these multisig members?
// track uses of this enote in the blockchain in the format [ [block_height, tx_id], ... ] if `wallet2::m_track_uses` is true (default is false)
std::vector<std::pair<std::uint64_t, std::string>> m_uses;
// QUESTION : Any input on these multisig members? I'd ignore them for now.
// Multisig
/*
bool m_key_image_partial;
std::vector<rct::key> m_multisig_k;
std::vector<multisig_info> m_multisig_info; // one per other participant
*/
};

/**
Expand Down Expand Up @@ -220,6 +226,15 @@ struct TransactionInfo
Direction_Out
};

// QUESTION : We already have a bool for "pending" and "failed", but should we rather add two more bools (`m_pending_in_pool` & `m_confirmed`) or switch to an enum like this? I'd prefer the enum, but I guess removing `m_pending` and `m_failed` is not an option?
// If there is justificatin to keep this, any suggestions for a better name? E.g. TxTransmissionState?
enum TxState {
pending,
pending_in_pool,
failed,
confirmed
};

struct Transfer {
Transfer(uint64_t _amount, const std::string &address);
const uint64_t amount;
Expand All @@ -246,6 +261,10 @@ struct TransactionInfo
virtual std::string paymentId() const = 0;
//! only applicable for output transactions
virtual const std::vector<Transfer> & transfers() const = 0;

virtual std::uint64_t receivedChangeAmount() const = 0;
virtual int txState() const = 0;
virtual bool isDoubleSpendSeen() const = 0;
};
/**
* @brief The TransactionHistory - interface for displaying transaction history
Expand Down Expand Up @@ -1323,53 +1342,15 @@ struct Wallet
*/
virtual void processPoolState(const std::vector<std::tuple<cryptonote::transaction, std::string, bool>> &txs) = 0;
// TODO / QUESTION : How to translate the following types to a standard type for the API?
// - tools::wallet2::transfer_details & tools::wallet2::transfer_container (vector of tools::wallet2::transfer_details)
// - tools::wallet2::payment_details
// - tools::wallet2::confirmed_transfer_details
// - tools::wallet2::pool_payment_details
// - tools::wallet2::signed_tx
// - cryptonote::address_parse_info
// TODO : wallet2::transfer_container
/**
* brief: getTransfers - get all transfers
* outparam: transfers -
*/
// virtual void getTransfers(wallet2::transfer_container& transfers) const = 0;
// TODO : wallet2::payment_details
/**
* brief: getPayments - get incoming transfers
* param: payment_id -
* param: payments -
* param: min_height -
* param: subaddr_account -
* param: subaddr_indices -
*/
// virtual void getPayments(const std::string &payment_id, std::list<wallet2::payment_details> &payments, std::uint64_t min_height, const boost::optional<uint32_t> &subaddr_account, const std::set<std::uint32_t> &subaddr_indices) const = 0;
// TODO : wallet2::payment_details
/**
* brief: getPayments - get incoming transfers
* param: payments -
* param: max_height -
*/
// virtual void getPayments(std::list<std::pair<std::string, wallet2::payment_details>> &payments, std::uint64_t min_height, std::uint64_t max_height, const boost::optional<uint32_t> &subaddr_account, const std::set<std::uint32_t> &subaddr_indices) const = 0;
// TODO : wallet2::confirmed_transfer_details
/**
* brief: getPaymentsOut - get outgoing transfers
* param: confirmed_payments -
*/
// virtual void getPaymentsOut(std::list<std::pair<std::string, wallet2::confirmed_transfer_details>> &confirmed_payments, std::uint64_t min_height, std::uint64_t max_height, const boost::optional<std::uint32_t> &subaddr_account, const std::set<std::uint32_t> &subaddr_indices) const = 0;
// TODO : wallet2::unconfirmed_transfer_details
/**
* brief: getUnconfirmedPaymentsOut - get unconfirmed transfers
* param: unconfirmed_payments -
*/
// virtual void getUnconfirmedPaymentsOut(std::list<std::pair<std::string, wallet2::unconfirmed_transfer_details>> &unconfirmed_payments, const boost::optional<std::uint32_t> &subaddr_account, const std::set<std::uint32_t> &subaddr_indices) const = 0;
// TODO : wallet2::pool_payment_details

/**
* brief: getUnconfirmedPayments - get pending transfers, currently in pool
* param: unconfirmed_payments -
* brief: getEnoteDetails - get information about all enotes
* outparam: enote_details -
*/
// virtual void getUnconfirmedPayments(std::list<std::pair<std::string, wallet2::pool_payment_details>> &unconfirmed_payments, const boost::optional<std::uint32_t> &subaddr_account, const std::set<std::uint32_t> &subaddr_indices) const = 0;
virtual void getEnoteDetails(std::vector<EnoteDetails> enote_details) const = 0;

/**
* brief: convertMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction
* param: multisig_ptx - multisig pending transaction
Expand Down

0 comments on commit 7d37965

Please sign in to comment.