aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFabian Jahr <fjahr@protonmail.com>2024-06-18 14:24:55 +0200
committerFabian Jahr <fjahr@protonmail.com>2024-06-19 22:32:33 +0200
commit80315c011863d69e7785673283e4c9033fbcd5ac (patch)
treef316c62c3aa2fe1f9ce27c4d4f1e92d7953efe28 /src
parent9c5cdf07f30f816cd134e2cd2dca9c27ef7067a5 (diff)
downloadbitcoin-80315c011863d69e7785673283e4c9033fbcd5ac.tar.xz
refactor: Move early loadtxoutset checks into ActiveSnapshot
Also changes the return type of ActiveSnapshot to allow returning the error message to the user of the loadtxoutset RPC.
Diffstat (limited to 'src')
-rw-r--r--src/rpc/blockchain.cpp31
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp2
-rw-r--r--src/test/util/chainstate.h4
-rw-r--r--src/validation.cpp30
-rw-r--r--src/validation.h2
5 files changed, 31 insertions, 38 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index e785678614..4de636b69f 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -62,9 +62,7 @@ using kernel::CoinStatsHashType;
using node::BlockManager;
using node::NodeContext;
using node::SnapshotMetadata;
-using util::Join;
using util::MakeUnorderedList;
-using util::ToString;
struct CUpdatedBlock
{
@@ -2821,34 +2819,15 @@ static RPCHelpMan loadtxoutset()
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Unable to parse metadata: %s", e.what()));
}
- uint256 base_blockhash = metadata.m_base_blockhash;
- int base_blockheight = metadata.m_base_blockheight;
- if (!chainman.GetParams().AssumeutxoForBlockhash(base_blockhash).has_value()) {
- auto available_heights = chainman.GetParams().GetAvailableSnapshotHeights();
- std::string heights_formatted = Join(available_heights, ", ", [&](const auto& i) { return ToString(i); });
- throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot, "
- "assumeutxo block hash in snapshot metadata not recognized (hash: %s, height: %s). The following snapshot heights are available: %s.",
- base_blockhash.ToString(),
- base_blockheight,
- heights_formatted));
- }
- CBlockIndex* snapshot_start_block = WITH_LOCK(::cs_main,
- return chainman.m_blockman.LookupBlockIndex(base_blockhash));
-
- if (!snapshot_start_block) {
- throw JSONRPCError(
- RPC_INTERNAL_ERROR,
- strprintf("The base block header (%s) must appear in the headers chain. Make sure all headers are syncing, and call this RPC again.",
- base_blockhash.ToString()));
- }
- if (!chainman.ActivateSnapshot(afile, metadata, false)) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to load UTXO snapshot " + fs::PathToString(path));
+ auto activation_result{chainman.ActivateSnapshot(afile, metadata, false)};
+ if (!activation_result) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf(_("Unable to load UTXO snapshot: %s\n"), util::ErrorString(activation_result)).original);
}
UniValue result(UniValue::VOBJ);
result.pushKV("coins_loaded", metadata.m_coins_count);
- result.pushKV("tip_hash", snapshot_start_block->GetBlockHash().ToString());
- result.pushKV("base_height", snapshot_start_block->nHeight);
+ result.pushKV("tip_hash", metadata.m_base_blockhash.ToString());
+ result.pushKV("base_height", metadata.m_base_blockheight);
result.pushKV("path", fs::PathToString(path));
return result;
},
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 8c9c67a91c..fa608385d9 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -54,7 +54,7 @@ FUZZ_TARGET(utxo_snapshot, .init = initialize_chain)
} catch (const std::ios_base::failure&) {
return false;
}
- return chainman.ActivateSnapshot(infile, metadata, /*in_memory=*/true);
+ return !!chainman.ActivateSnapshot(infile, metadata, /*in_memory=*/true);
}};
if (fuzzed_data_provider.ConsumeBool()) {
diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h
index 03b44fc894..a4636365ca 100644
--- a/src/test/util/chainstate.h
+++ b/src/test/util/chainstate.h
@@ -124,11 +124,11 @@ CreateAndActivateUTXOSnapshot(
new_active.m_chain.SetTip(*(tip->pprev));
}
- bool res = node.chainman->ActivateSnapshot(auto_infile, metadata, in_memory_chainstate);
+ auto res = node.chainman->ActivateSnapshot(auto_infile, metadata, in_memory_chainstate);
// Restore the old tip.
new_active.m_chain.SetTip(*tip);
- return res;
+ return !!res;
}
diff --git a/src/validation.cpp b/src/validation.cpp
index c34d60f137..53db1cb5b1 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -5647,23 +5647,38 @@ Chainstate& ChainstateManager::InitializeChainstate(CTxMemPool* mempool)
return destroyed && !fs::exists(db_path);
}
-bool ChainstateManager::ActivateSnapshot(
+util::Result<void> ChainstateManager::ActivateSnapshot(
AutoFile& coins_file,
const SnapshotMetadata& metadata,
bool in_memory)
{
uint256 base_blockhash = metadata.m_base_blockhash;
+ int base_blockheight = metadata.m_base_blockheight;
if (this->SnapshotBlockhash()) {
- LogPrintf("[snapshot] can't activate a snapshot-based chainstate more than once\n");
- return false;
+ return util::Error{_("Can't activate a snapshot-based chainstate more than once")};
}
{
LOCK(::cs_main);
+
+ if (!GetParams().AssumeutxoForBlockhash(base_blockhash).has_value()) {
+ auto available_heights = GetParams().GetAvailableSnapshotHeights();
+ std::string heights_formatted = util::Join(available_heights, ", ", [&](const auto& i) { return util::ToString(i); });
+ return util::Error{strprintf(_("assumeutxo block hash in snapshot metadata not recognized (hash: %s, height: %s). The following snapshot heights are available: %s."),
+ base_blockhash.ToString(),
+ base_blockheight,
+ heights_formatted)};
+ }
+
+ CBlockIndex* snapshot_start_block = m_blockman.LookupBlockIndex(base_blockhash);
+ if (!snapshot_start_block) {
+ return util::Error{strprintf(_("The base block header (%s) must appear in the headers chain. Make sure all headers are syncing, and call loadtxoutset again."),
+ base_blockhash.ToString())};
+ }
+
if (Assert(m_active_chainstate->GetMempool())->size() > 0) {
- LogPrintf("[snapshot] can't activate a snapshot when mempool not empty\n");
- return false;
+ return util::Error{_("Can't activate a snapshot when mempool not empty.")};
}
}
@@ -5713,7 +5728,6 @@ bool ChainstateManager::ActivateSnapshot(
}
auto cleanup_bad_snapshot = [&](const char* reason) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- LogPrintf("[snapshot] activation failed - %s\n", reason);
this->MaybeRebalanceCaches();
// PopulateAndValidateSnapshot can return (in error) before the leveldb datadir
@@ -5729,7 +5743,7 @@ bool ChainstateManager::ActivateSnapshot(
"Manually remove it before restarting.\n"), fs::PathToString(*snapshot_datadir)));
}
}
- return false;
+ return util::Error{_(reason)};
};
if (!this->PopulateAndValidateSnapshot(*snapshot_chainstate, coins_file, metadata)) {
@@ -5772,7 +5786,7 @@ bool ChainstateManager::ActivateSnapshot(
m_snapshot_chainstate->CoinsTip().DynamicMemoryUsage() / (1000 * 1000));
this->MaybeRebalanceCaches();
- return true;
+ return {};
}
static void FlushSnapshotToDisk(CCoinsViewCache& coins_cache, bool snapshot_loaded)
diff --git a/src/validation.h b/src/validation.h
index ab7891539a..2f5f2e2b95 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -1054,7 +1054,7 @@ public:
//! faking nTx* block index data along the way.
//! - Move the new chainstate to `m_snapshot_chainstate` and make it our
//! ChainstateActive().
- [[nodiscard]] bool ActivateSnapshot(
+ [[nodiscard]] util::Result<void> ActivateSnapshot(
AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory);
//! Once the background validation chainstate has reached the height which