Skip to content

[DRAFT] Expose AssumeUTXO Load Snapshot Functionality To The GUI #870

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

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions doc/developer-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1009,10 +1009,6 @@ Strings and formatting
buffer overflows, and surprises with `\0` characters. Also, some C string manipulations
tend to act differently depending on platform, or even the user locale.

- Use `ToIntegral` from [`strencodings.h`](/src/util/strencodings.h) for number parsing. In legacy code you might also find `ParseInt*` family of functions, `ParseDouble` or `LocaleIndependentAtoi`.

- *Rationale*: These functions do overflow checking and avoid pesky locale issues.

- For `strprintf`, `LogInfo`, `LogDebug`, etc formatting characters don't need size specifiers.

- *Rationale*: Bitcoin Core uses tinyformat, which is type safe. Leave them out to avoid confusion.
Expand Down
5 changes: 3 additions & 2 deletions src/bitcoin-cli.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2022 The Bitcoin Core developers
// Copyright (c) 2009-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

Expand Down Expand Up @@ -472,7 +472,8 @@ class NetinfoRequestHandler : public BaseRequestHandler
{
if (!args.empty()) {
uint8_t n{0};
if (ParseUInt8(args.at(0), &n)) {
if (const auto res{ToIntegral<uint8_t>(args.at(0))}) {
n = *res;
m_details_level = std::min(n, NETINFO_MAX_LEVEL);
} else {
throw std::runtime_error(strprintf("invalid -netinfo level argument: %s\nFor more information, run: bitcoin-cli -netinfo help", args.at(0)));
Expand Down
49 changes: 21 additions & 28 deletions src/bitcoin-tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,35 +211,33 @@ static CAmount ExtractAndValidateValue(const std::string& strValue)

static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
{
uint32_t newVersion;
if (!ParseUInt32(cmdVal, &newVersion) || newVersion < 1 || newVersion > TX_MAX_STANDARD_VERSION) {
const auto ver{ToIntegral<uint32_t>(cmdVal)};
if (!ver || *ver < 1 || *ver > TX_MAX_STANDARD_VERSION) {
throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");
}

tx.version = newVersion;
tx.version = *ver;
}

static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newLocktime;
if (!ParseInt64(cmdVal, &newLocktime) || newLocktime < 0LL || newLocktime > 0xffffffffLL)
const auto locktime{ToIntegral<uint32_t>(cmdVal)};
if (!locktime) {
throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'");

tx.nLockTime = (unsigned int) newLocktime;
}
tx.nLockTime = *locktime;
}

static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested index
int64_t inIdx = -1;
if (strInIdx != "" && (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size()))) {
const auto idx{ToIntegral<uint32_t>(strInIdx)};
if (strInIdx != "" && (!idx || *idx >= tx.vin.size())) {
throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
}

// set the nSequence to MAX_INT - 2 (= RBF opt in flag)
int cnt = 0;
uint32_t cnt{0};
for (CTxIn& txin : tx.vin) {
if (strInIdx == "" || cnt == inIdx) {
if (strInIdx == "" || cnt == *idx) {
if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {
txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
}
Expand Down Expand Up @@ -277,9 +275,10 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu

// extract and validate vout
const std::string& strVout = vStrInputParts[1];
int64_t vout;
if (!ParseInt64(strVout, &vout) || vout < 0 || vout > static_cast<int64_t>(maxVout))
const auto vout{ToIntegral<uint32_t>(strVout)};
if (!vout || *vout > maxVout) {
throw std::runtime_error("invalid TX input vout '" + strVout + "'");
}

// extract the optional sequence number
uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL;
Expand All @@ -288,7 +287,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
}

// append to transaction input list
CTxIn txin(*txid, vout, CScript(), nSequenceIn);
CTxIn txin{*txid, *vout, CScript{}, nSequenceIn};
tx.vin.push_back(txin);
}

Expand Down Expand Up @@ -508,26 +507,20 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str

static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested deletion index
int64_t inIdx;
if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
const auto idx{ToIntegral<uint32_t>(strInIdx)};
if (!idx || idx >= tx.vin.size()) {
throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
}

// delete input from transaction
tx.vin.erase(tx.vin.begin() + inIdx);
tx.vin.erase(tx.vin.begin() + *idx);
}

static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
{
// parse requested deletion index
int64_t outIdx;
if (!ParseInt64(strOutIdx, &outIdx) || outIdx < 0 || outIdx >= static_cast<int64_t>(tx.vout.size())) {
const auto idx{ToIntegral<uint32_t>(strOutIdx)};
if (!idx || idx >= tx.vout.size()) {
throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'");
}

// delete output from transaction
tx.vout.erase(tx.vout.begin() + outIdx);
tx.vout.erase(tx.vout.begin() + *idx);
}

static const unsigned int N_SIGHASH_OPTS = 7;
Expand Down
18 changes: 12 additions & 6 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& opti
}

const auto value{arg.substr(found + 1)};
int32_t height;
if (!ParseInt32(value, &height) || height < 0 || height >= std::numeric_limits<int>::max()) {
const auto height{ToIntegral<int32_t>(value)};
if (!height || *height < 0 || *height >= std::numeric_limits<int>::max()) {
throw std::runtime_error(strprintf("Invalid height value (%s) for -testactivationheight=name@height.", arg));
}

const auto deployment_name{arg.substr(0, found)};
if (const auto buried_deployment = GetBuriedDeployment(deployment_name)) {
options.activation_heights[*buried_deployment] = height;
options.activation_heights[*buried_deployment] = *height;
} else {
throw std::runtime_error(strprintf("Invalid name (%s) for -testactivationheight=name@height.", arg));
}
Expand All @@ -72,16 +72,22 @@ void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& opti
throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]");
}
CChainParams::VersionBitsParameters vbparams{};
if (!ParseInt64(vDeploymentParams[1], &vbparams.start_time)) {
const auto start_time{ToIntegral<int64_t>(vDeploymentParams[1])};
if (!start_time) {
throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1]));
}
if (!ParseInt64(vDeploymentParams[2], &vbparams.timeout)) {
vbparams.start_time = *start_time;
const auto timeout{ToIntegral<int64_t>(vDeploymentParams[2])};
if (!timeout) {
throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2]));
}
vbparams.timeout = *timeout;
if (vDeploymentParams.size() >= 4) {
if (!ParseInt32(vDeploymentParams[3], &vbparams.min_activation_height)) {
const auto min_activation_height{ToIntegral<int64_t>(vDeploymentParams[3])};
if (!min_activation_height) {
throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3]));
}
vbparams.min_activation_height = *min_activation_height;
} else {
vbparams.min_activation_height = 0;
}
Expand Down
4 changes: 2 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1151,8 +1151,8 @@ bool CheckHostPortOptions(const ArgsManager& args) {
"-rpcport",
}) {
if (const auto port{args.GetArg(port_option)}) {
uint16_t n;
if (!ParseUInt16(*port, &n) || n == 0) {
const auto n{ToIntegral<uint16_t>(*port)};
if (!n || *n == 0) {
return InitError(InvalidPortErrMsg(port_option, *port));
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/interfaces/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <logging.h>
#include <net.h>
#include <net_types.h>
#include <node/utxo_snapshot.h>
#include <netaddress.h>
#include <netbase.h>
#include <support/allocators/secure.h>
Expand Down Expand Up @@ -205,6 +206,9 @@ class Node
//! List rpc commands.
virtual std::vector<std::string> listRpcCommands() = 0;

//! Load and activate a snapshot file
virtual bool loadSnapshot(AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory) = 0;

//! Set RPC timer interface if unset.
virtual void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) = 0;

Expand Down Expand Up @@ -240,6 +244,10 @@ class Node
using ShowProgressFn = std::function<void(const std::string& title, int progress, bool resume_possible)>;
virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0;

//! Register handler for snapshot load progress.
using SnapshotLoadProgressFn = std::function<void(double progress)>;
virtual std::unique_ptr<Handler> handleSnapshotLoadProgress(SnapshotLoadProgressFn fn) = 0;

//! Register handler for wallet loader constructed messages.
using InitWalletFn = std::function<void()>;
virtual std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) = 0;
Expand Down
4 changes: 3 additions & 1 deletion src/ipc/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ class ProcessImpl : public Process
// in combination with other arguments because the parent process
// should be able to control the child process through the IPC protocol
// without passing information out of band.
if (!ParseInt32(argv[2], &fd)) {
const auto maybe_fd{ToIntegral<int32_t>(argv[2])};
if (!maybe_fd) {
throw std::runtime_error(strprintf("Invalid -ipcfd number '%s'", argv[2]));
}
fd = *maybe_fd;
return true;
}
int connect(const fs::path& data_dir,
Expand Down
1 change: 1 addition & 0 deletions src/kernel/notifications_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class Notifications
[[nodiscard]] virtual InterruptResult blockTip(SynchronizationState state, CBlockIndex& index) { return {}; }
virtual void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) {}
virtual void progress(const bilingual_str& title, int progress_percent, bool resume_possible) {}
virtual void snapshotLoadProgress(double progress) {}
virtual void warningSet(Warning id, const bilingual_str& message) {}
virtual void warningUnset(Warning id) {}

Expand Down
5 changes: 2 additions & 3 deletions src/netbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -829,10 +829,9 @@ CSubNet LookupSubNet(const std::string& subnet_str)
addr = static_cast<CNetAddr>(MaybeFlipIPv6toCJDNS(CService{addr.value(), /*port=*/0}));
if (slash_pos != subnet_str.npos) {
const std::string netmask_str{subnet_str.substr(slash_pos + 1)};
uint8_t netmask;
if (ParseUInt8(netmask_str, &netmask)) {
if (const auto netmask{ToIntegral<uint8_t>(netmask_str)}) {
// Valid number; assume CIDR variable-length subnet masking.
subnet = CSubNet{addr.value(), netmask};
subnet = CSubNet{addr.value(), *netmask};
} else {
// Invalid number; try full netmask syntax. Never allow lookup for netmask.
const std::optional<CNetAddr> full_netmask{LookupHost(netmask_str, /*fAllowLookup=*/false)};
Expand Down
3 changes: 3 additions & 0 deletions src/node/interface_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct UISignals {
boost::signals2::signal<CClientUIInterface::NotifyNetworkActiveChangedSig> NotifyNetworkActiveChanged;
boost::signals2::signal<CClientUIInterface::NotifyAlertChangedSig> NotifyAlertChanged;
boost::signals2::signal<CClientUIInterface::ShowProgressSig> ShowProgress;
boost::signals2::signal<CClientUIInterface::SnapshotLoadProgressSig> SnapshotLoadProgress;
boost::signals2::signal<CClientUIInterface::NotifyBlockTipSig> NotifyBlockTip;
boost::signals2::signal<CClientUIInterface::NotifyHeaderTipSig> NotifyHeaderTip;
boost::signals2::signal<CClientUIInterface::BannedListChangedSig> BannedListChanged;
Expand All @@ -43,6 +44,7 @@ ADD_SIGNALS_IMPL_WRAPPER(NotifyNumConnectionsChanged);
ADD_SIGNALS_IMPL_WRAPPER(NotifyNetworkActiveChanged);
ADD_SIGNALS_IMPL_WRAPPER(NotifyAlertChanged);
ADD_SIGNALS_IMPL_WRAPPER(ShowProgress);
ADD_SIGNALS_IMPL_WRAPPER(SnapshotLoadProgress);
ADD_SIGNALS_IMPL_WRAPPER(NotifyBlockTip);
ADD_SIGNALS_IMPL_WRAPPER(NotifyHeaderTip);
ADD_SIGNALS_IMPL_WRAPPER(BannedListChanged);
Expand All @@ -55,6 +57,7 @@ void CClientUIInterface::NotifyNumConnectionsChanged(int newNumConnections) { re
void CClientUIInterface::NotifyNetworkActiveChanged(bool networkActive) { return g_ui_signals.NotifyNetworkActiveChanged(networkActive); }
void CClientUIInterface::NotifyAlertChanged() { return g_ui_signals.NotifyAlertChanged(); }
void CClientUIInterface::ShowProgress(const std::string& title, int nProgress, bool resume_possible) { return g_ui_signals.ShowProgress(title, nProgress, resume_possible); }
void CClientUIInterface::SnapshotLoadProgress(double progress) { return g_ui_signals.SnapshotLoadProgress(progress); }
void CClientUIInterface::NotifyBlockTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyBlockTip(s, i); }
void CClientUIInterface::NotifyHeaderTip(SynchronizationState s, int64_t height, int64_t timestamp, bool presync) { return g_ui_signals.NotifyHeaderTip(s, height, timestamp, presync); }
void CClientUIInterface::BannedListChanged() { return g_ui_signals.BannedListChanged(); }
Expand Down
3 changes: 3 additions & 0 deletions src/node/interface_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ class CClientUIInterface
*/
ADD_SIGNALS_DECL_WRAPPER(ShowProgress, void, const std::string& title, int nProgress, bool resume_possible);

/** Snapshot load progress. */
ADD_SIGNALS_DECL_WRAPPER(SnapshotLoadProgress, void, double progress);

/** New block has been accepted */
ADD_SIGNALS_DECL_WRAPPER(NotifyBlockTip, void, SynchronizationState, const CBlockIndex*);

Expand Down
9 changes: 9 additions & 0 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@ class NodeImpl : public Node
return ::tableRPC.execute(req);
}
std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }
bool loadSnapshot(AutoFile& coins_file, const SnapshotMetadata& metadata, bool in_memory) override
{
auto activation_result{chainman().ActivateSnapshot(coins_file, metadata, in_memory)};
return activation_result.has_value();
}
void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); }
void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); }
std::optional<Coin> getUnspentOutput(const COutPoint& output) override
Expand Down Expand Up @@ -386,6 +391,10 @@ class NodeImpl : public Node
{
return MakeSignalHandler(::uiInterface.ShowProgress_connect(fn));
}
std::unique_ptr<Handler> handleSnapshotLoadProgress(SnapshotLoadProgressFn fn) override
{
return MakeSignalHandler(::uiInterface.SnapshotLoadProgress_connect(fn));
}
std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) override
{
return MakeSignalHandler(::uiInterface.InitWallet_connect(fn));
Expand Down
5 changes: 5 additions & 0 deletions src/node/kernel_notifications.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ void KernelNotifications::progress(const bilingual_str& title, int progress_perc
uiInterface.ShowProgress(title.translated, progress_percent, resume_possible);
}

void KernelNotifications::snapshotLoadProgress(double progress)
{
uiInterface.SnapshotLoadProgress(progress);
}

void KernelNotifications::warningSet(kernel::Warning id, const bilingual_str& message)
{
if (m_warnings.Set(id, message)) {
Expand Down
2 changes: 2 additions & 0 deletions src/node/kernel_notifications.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class KernelNotifications : public kernel::Notifications

void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override;

void snapshotLoadProgress(double progress) override;

void warningSet(kernel::Warning id, const bilingual_str& message) override;

void warningUnset(kernel::Warning id) override;
Expand Down
2 changes: 2 additions & 0 deletions src/qt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ add_library(bitcoinqt STATIC EXCLUDE_FROM_ALL
qvaluecombobox.h
rpcconsole.cpp
rpcconsole.h
snapshotmodel.cpp
snapshotmodel.h
splashscreen.cpp
splashscreen.h
trafficgraphwidget.cpp
Expand Down
Loading