Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to show checkpointedness of transactions #866

Merged
merged 3 commits into from Oct 3, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/rpc/core_rpc_server.cpp
Expand Up @@ -192,6 +192,12 @@ namespace cryptonote
++res.height; // turn top block height into blockchain height
res.top_block_hash = string_tools::pod_to_hex(top_hash);
res.target_height = m_core.get_target_blockchain_height();

res.immutable_height = 0;
cryptonote::checkpoint_t checkpoint;
if (m_core.get_blockchain_storage().get_db().get_immutable_checkpoint(&checkpoint, res.height - 1))
res.immutable_height = checkpoint.height;

res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block();
res.target = m_core.get_blockchain_storage().get_difficulty_target();
res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/core_rpc_server_commands_defs.h
Expand Up @@ -775,6 +775,7 @@ namespace cryptonote
std::string status; // General RPC error code. "OK" means everything looks good.
uint64_t height; // Current length of longest chain known to daemon.
uint64_t target_height; // The height of the next block in the chain.
uint64_t immutable_height; // The latest height in the blockchain that can not be reorganized from (backed by atleast 2 Service Node, or 1 hardcoded checkpoint, 0 if N/A).
uint64_t difficulty; // Network difficulty (analogous to the strength of the network).
uint64_t target; // Current target for next proof of work.
uint64_t tx_count; // Total number of non-coinbase transaction in the chain.
Expand Down Expand Up @@ -810,6 +811,7 @@ namespace cryptonote
KV_SERIALIZE(status)
KV_SERIALIZE(height)
KV_SERIALIZE(target_height)
KV_SERIALIZE(immutable_height)
KV_SERIALIZE(difficulty)
KV_SERIALIZE(target)
KV_SERIALIZE(tx_count)
Expand Down
4 changes: 3 additions & 1 deletion src/simplewallet/simplewallet.cpp
Expand Up @@ -7946,12 +7946,13 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
}
}

auto formatter = boost::format("%8.8llu %6.6s %8.8s %16.16s %20.20s %s %s %14.14s %s %s - %s");
auto formatter = boost::format("%8.8llu %6.6s %8.8s %12.12s %16.16s %20.20s %s %s %14.14s %s %s - %s");

message_writer(color, false) << formatter
% transfer.block
% tools::pay_type_string(transfer.type)
% transfer.lock_msg
% (transfer.checkpointed ? "checkpointed" : "no")
% tools::get_human_readable_timestamp(transfer.timestamp)
% print_money(transfer.amount)
% string_tools::pod_to_hex(transfer.hash)
Expand Down Expand Up @@ -9265,6 +9266,7 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
else
success_msg_writer() << "locked for " << tools::get_human_readable_timespan(std::chrono::seconds(pd.m_unlock_time - threshold));
}
success_msg_writer() << "Checkpointed: " << (pd.m_block_height <= m_wallet->get_immutable_height() ? "Yes" : "No");
success_msg_writer() << "Address index: " << pd.m_subaddr_index.minor;
success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid);
return true;
Expand Down
13 changes: 13 additions & 0 deletions src/wallet/node_rpc_proxy.cpp
Expand Up @@ -58,6 +58,7 @@ void NodeRPCProxy::invalidate()
m_contributed_service_nodes.clear();

m_height = 0;
m_immutable_height = 0;
for (size_t n = 0; n < 256; ++n)
m_earliest_height[n] = 0;
m_dynamic_base_fee_estimate = {0, 0};
Expand Down Expand Up @@ -93,6 +94,8 @@ boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version
void NodeRPCProxy::set_height(uint64_t h)
{
m_height = h;
if (h < m_immutable_height)
m_immutable_height = 0;
}

boost::optional<std::string> NodeRPCProxy::get_info() const
Expand All @@ -115,6 +118,7 @@ boost::optional<std::string> NodeRPCProxy::get_info() const
m_height = resp_t.height;
m_target_height = resp_t.target_height;
m_block_weight_limit = resp_t.block_weight_limit ? resp_t.block_weight_limit : resp_t.block_size_limit;
m_immutable_height = resp_t.immutable_height;
m_get_info_time = now;
}
return boost::optional<std::string>();
Expand All @@ -138,6 +142,15 @@ boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) c
return boost::optional<std::string>();
}

boost::optional<std::string> NodeRPCProxy::get_immutable_height(uint64_t &height) const
{
auto res = get_info();
if (res)
return res;
height = m_immutable_height;
return boost::optional<std::string>();
Copy link
Member

@jagerman jagerman Oct 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The empty case is more commonly return boost::none;, but I see nothing else here is doing that so I guess leave it. 😞

}

boost::optional<std::string> NodeRPCProxy::get_block_weight_limit(uint64_t &block_weight_limit) const
{
auto res = get_info();
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/node_rpc_proxy.h
Expand Up @@ -49,6 +49,7 @@ class NodeRPCProxy
boost::optional<std::string> get_height(uint64_t &height) const;
void set_height(uint64_t h);
boost::optional<std::string> get_target_height(uint64_t &height) const;
boost::optional<std::string> get_immutable_height(uint64_t &height) const;
boost::optional<std::string> get_block_weight_limit(uint64_t &block_weight_limit) const;
boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height) const;
boost::optional<std::string> get_dynamic_base_fee_estimate(uint64_t grace_blocks, cryptonote::byte_and_output_fees &fees) const;
Expand Down Expand Up @@ -80,6 +81,7 @@ class NodeRPCProxy
mutable std::vector<cryptonote::COMMAND_RPC_GET_SERVICE_NODES::response::entry> m_contributed_service_nodes;

mutable uint64_t m_height;
mutable uint64_t m_immutable_height;
mutable uint64_t m_earliest_height[256];
mutable cryptonote::byte_and_output_fees m_dynamic_base_fee_estimate;
mutable uint64_t m_dynamic_base_fee_estimate_cached_height;
Expand Down
18 changes: 14 additions & 4 deletions src/wallet/wallet2.cpp
Expand Up @@ -3293,6 +3293,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
if(last_tx_hash_id != (m_transfers.size() ? m_transfers.back().m_txid : null_hash))
received_money = true;

uint64_t immutable_height = 0;
boost::optional<std::string> fail_string = m_node_rpc_proxy.get_immutable_height(immutable_height);
if (!fail_string)
m_immutable_height = immutable_height;

try
{
// If stop() is called we don't need to check pending transactions
Expand Down Expand Up @@ -5801,6 +5806,7 @@ void wallet2::fill_transfer_view(wallet2::transfer_view &entry, const crypto::ha
const bool unlocked = is_transfer_unlocked(entry.unlock_time, entry.height);
entry.lock_msg = unlocked ? "unlocked" : "locked";
set_confirmations(entry, get_blockchain_current_height(), get_last_block_reward());
entry.checkpointed = entry.height <= m_immutable_height;
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet2::fill_transfer_view(wallet2::transfer_view &entry, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) const
Expand Down Expand Up @@ -5832,6 +5838,7 @@ void wallet2::fill_transfer_view(wallet2::transfer_view &entry, const crypto::ha
entry.subaddr_indices.push_back({pd.m_subaddr_account, i});
entry.address = get_subaddress_as_str({pd.m_subaddr_account, 0});
entry.confirmed = true;
entry.checkpointed = entry.height <= m_immutable_height;
set_confirmations(entry, get_blockchain_current_height(), get_last_block_reward());
}
//------------------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -5966,12 +5973,12 @@ void wallet2::get_transfers(get_transfers_args_t args, std::vector<transfer_view
std::string wallet2::transfers_to_csv(const std::vector<wallet2::transfer_view>& transfers, bool formatting) const
{
uint64_t running_balance = 0;
auto data_formatter = boost::format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,'%s',%s");
auto title_formatter = boost::format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s");
auto data_formatter = boost::format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,'%s',%s");
auto title_formatter = boost::format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s");
if (formatting)
{
title_formatter = boost::format("%8.8s,%9.9s,%8.8s,%16.16s,%20.20s,%20.20s,%64.64s,%16.16s,%14.14s,%100.100s,%20.20s,%s,%s");
data_formatter = boost::format("%8.8s,%9.9s,%8.8s,%16.16s,%20.20s,%20.20s,%64.64s,%16.16s,%14.14s,%100.100s,%20.20s,\"%s\",%s");
title_formatter = boost::format("%8.8s,%9.9s,%8.8s,%14.14s,%16.16s,%20.20s,%20.20s,%64.64s,%16.16s,%14.14s,%100.100s,%20.20s,%s,%s");
data_formatter = boost::format("%8.8s,%9.9s,%8.8s,%14.14s,%16.16s,%20.20s,%20.20s,%64.64s,%16.16s,%14.14s,%100.100s,%20.20s,\"%s\",%s");
}

auto new_line = [&](std::stringstream& output){
Expand All @@ -5990,6 +5997,7 @@ std::string wallet2::transfers_to_csv(const std::vector<wallet2::transfer_view>&
% tr("block")
% tr("type")
% tr("lock")
% tr("checkpointed")
% tr("timestamp")
% tr("amount")
% tr("running balance")
Expand Down Expand Up @@ -6027,6 +6035,7 @@ std::string wallet2::transfers_to_csv(const std::vector<wallet2::transfer_view>&
% transfer.block
% pay_type_string(transfer.type)
% transfer.lock_msg
% (transfer.checkpointed ? "checkpointed" : "no")
% tools::get_human_readable_timestamp(transfer.timestamp)
% cryptonote::print_money(transfer.amount)
% cryptonote::print_money(running_balance)
Expand Down Expand Up @@ -6056,6 +6065,7 @@ std::string wallet2::transfers_to_csv(const std::vector<wallet2::transfer_view>&
% ""
% ""
% ""
% ""
% it->address
% cryptonote::print_money(it->amount)
% ""
Expand Down
8 changes: 7 additions & 1 deletion src/wallet/wallet2.h
Expand Up @@ -494,6 +494,7 @@ namespace tools
bool double_spend_seen; // True if the key image(s) for the transfer have been seen before.
uint64_t confirmations; // Number of block mined since the block containing this transaction (or block height at which the transaction should be added to a block if not yet confirmed).
uint64_t suggested_confirmations_threshold;
bool checkpointed = false; // If the transfer is backed by atleast (2 service node|| 1 hardcoded) checkpoints // TODO(loki): Make this count the number of checkpoints backing this transfer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This TODO would be nice, but I expect it is actually fairly tricky/expensive to calculate.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Non trivial atm, considering checkpoints can arrive out of order.

};

typedef std::vector<transfer_details> transfer_container;
Expand Down Expand Up @@ -963,6 +964,7 @@ namespace tools

uint64_t get_last_block_reward() const { return m_last_block_reward; }
uint64_t get_device_last_key_image_sync() const { return m_device_last_key_image_sync; }
uint64_t get_immutable_height() const { return m_immutable_height; }

template <class t_archive>
inline void serialize(t_archive &a, const unsigned int ver)
Expand Down Expand Up @@ -1077,6 +1079,9 @@ namespace tools
if(ver < 28)
return;
a & m_cold_key_images;
if(ver < 29)
return;
a & m_immutable_height;
}

/*!
Expand Down Expand Up @@ -1667,6 +1672,7 @@ namespace tools
std::string m_device_derivation_path;
uint64_t m_device_last_key_image_sync;
bool m_offline;
uint64_t m_immutable_height;

// Aux transaction data from device
std::unordered_map<crypto::hash, std::string> m_tx_device;
Expand Down Expand Up @@ -1721,7 +1727,7 @@ namespace tools
bool parse_priority (const std::string& arg, uint32_t& priority);

}
BOOST_CLASS_VERSION(tools::wallet2, 28)
BOOST_CLASS_VERSION(tools::wallet2, 29)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 12)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/wallet_rpc_server_commands_defs.h
Expand Up @@ -1499,6 +1499,7 @@ namespace wallet_rpc
bool double_spend_seen; // True if the key image(s) for the transfer have been seen before.
uint64_t confirmations; // Number of block mined since the block containing this transaction (or block height at which the transaction should be added to a block if not yet confirmed).
uint64_t suggested_confirmations_threshold; // Estimation of the confirmations needed for the transaction to be included in a block.
uint64_t checkpointed; // If transfer is backed by atleast 2 Service Node Checkpoints, 0 if it is not, see immutable_height in the daemon rpc call get_info

BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txid);
Expand All @@ -1517,6 +1518,7 @@ namespace wallet_rpc
KV_SERIALIZE(double_spend_seen)
KV_SERIALIZE_OPT(confirmations, (uint64_t)0)
KV_SERIALIZE_OPT(suggested_confirmations_threshold, (uint64_t)0)
KV_SERIALIZE(checkpointed)
END_KV_SERIALIZE_MAP()
};

Expand Down