feat(bootstrap): RPC-driven trusted snapshot publisher rotation (v6.1.8) (#26)

Design A: single-slot runtime override via RPC. The previous publisher
is dropped atomically on every set. The built-in fallback list
(TG8f76yktTxDrT7JJymY3wVAusXiD3fVvX, Sami's legacy key) is always
consulted if no runtime override is set, so a fresh daemon still
verifies old snapshots without operator intervention.

New RPCs:
- settrustedv2snapshotpublisher <address>
- gettrustedv2snapshotpublisher
- unsettrustedv2snapshotpublisher

Persistence: <datadir>/snapshot-publisher.json (plain JSON).
Loaded at startup in init.cpp before any snapshot verification.

Files:
  src/bootstrap.cpp          (+116 / -8)  Replace hardcoded list with single-slot + fallback
  src/bootstrap.h            (+21)        Declare new Bootstrap:: functions
  src/init.cpp               (+3)         LoadTrustedSnapshotPublisher() at startup
  src/rpcblockchain.cpp      (+89)        Three new RPC function bodies
  src/rpcblockchain.cpp      (+1)         #include "bootstrap.h"
  src/trianglesrpc.cpp       (+3)         Register three new commands
  src/trianglesrpc.h         (+3)         extern declarations
  README.md                  (+30)        New 'Trusted Snapshot Publisher' sections
  TRIANGLES-RPC-COMMANDS.md  (+3)         Three new rows in Blockchain table
  docs/snapshot-publisher.md (new, +240)  Full operator handoff guide

Co-authored-by: Krystie <krystie@openclaw.local>
This commit is contained in:
SamiAhmed7777
2026-07-10 17:29:15 -07:00
committed by GitHub
parent 330f92b7ff
commit 8598cfa781
9 changed files with 511 additions and 7 deletions
+30
View File
@@ -175,6 +175,29 @@ Check staking status:
trianglesd getstakinginfo
```
### Trusted Snapshot Publisher (UTXO Snapshots)
The daemon verifies that any UTXO snapshot it loads was signed by a
**trusted publisher**. Starting with v6.1.8, the trusted publisher can
be rotated at runtime via RPC — no rebuild required. The compiled-in
fallback (`TG8f76yktTxDrT7JJymY3wVAusXiD3fVvX`, Sami's legacy key)
remains in effect if no runtime override is set.
```bash
# Rotate to a new publisher
trianglesd settrustedv2snapshotpublisher TGotWuftzH7rD9tXC7whE8EXiyC3mr1CrH
# Check current publisher
trianglesd gettrustedv2snapshotpublisher
# Revert to the compiled-in fallback
trianglesd unsettrustedv2snapshotpublisher
```
The model is single-slot: calling `settrustedv2snapshotpublisher`
atomically drops the previous publisher. See `docs/snapshot-publisher.md`
for the full operator guide.
### Encrypted Messaging
Send and receive encrypted messages between wallet addresses:
@@ -234,6 +257,13 @@ Then set `externalip=<your-onion-address>` in `triangles.conf`.
- `smsglocalkeys` - List messaging-enabled addresses
- `smsgscanchain` - Scan blockchain for public keys
### Trusted Snapshot Publisher (v6.1.8+)
- `settrustedv2snapshotpublisher <address>` - Atomically replace the trusted snapshot publisher (previous one dropped immediately). Persists to `<datadir>/snapshot-publisher.json`.
- `gettrustedv2snapshotpublisher` - Returns the currently active runtime publisher and whether a runtime override is in effect.
- `unsettrustedv2snapshotpublisher` - Clear the runtime override and revert to the compiled-in fallback list.
See `docs/snapshot-publisher.md` for the full operator guide.
## Chain History
- **July 16, 2014** - Genesis block
+3
View File
@@ -31,6 +31,9 @@ Triangles is a Tor-only PoS cryptocurrency. PoW ended at block 9000; from block
| `getrawmempool` | | Returns all transaction IDs currently in the mempool. |
| `getcheckpoint` | | Returns info about the current synchronized checkpoint. |
| `getchaintips` | | Returns info about all known chain tips (forks). |
| `settrustedv2snapshotpublisher` | `<address>` | Atomically replaces the trusted snapshot publisher. The previous publisher is dropped immediately (no grace period). The new publisher is persisted to `<datadir>/snapshot-publisher.json`. Returns `{ previous, current }`. See `docs/snapshot-publisher.md`. |
| `gettrustedv2snapshotpublisher` | | Returns the currently active trusted snapshot publisher and whether a runtime override is in effect. Returns `{ active, has_runtime_override }`. |
| `unsettrustedv2snapshotpublisher` | | Clears the runtime trusted snapshot publisher override. Reverts to the built-in fallback list (compiled in). Removes `<datadir>/snapshot-publisher.json`. |
| `invalidateblock` | `<hash>` | Permanently marks a block as invalid and rewinds the chain past it. |
| `reconsiderblock` | `<hash>` | Removes the invalid mark from a previously invalidated block. |
| `recalculatesupply` | | Recalculates money supply by summing all UTXOs. Updates the stored value at the chain tip and persists to disk. Returns old/new supply and difference. |
+240
View File
@@ -0,0 +1,240 @@
# Trusted Snapshot Publisher — Operator Guide
This document explains how the trusted snapshot publisher mechanism works
in Triangles and how to rotate the publisher without rebuilding the
daemon. It is written for the person who operates the Triangles network
after Sami — whoever that turns out to be.
## Background
The Triangles daemon verifies that any UTXO snapshot it loads was
**signed by a trusted publisher**. This prevents a malicious snapshot
file from tricking a node into accepting a fake chain state.
In versions before v6.1.8, the trusted publisher list was hardcoded
in the binary. To rotate keys, the daemon had to be rebuilt and
re-released. That was bad for handover.
Starting with v6.1.8, the daemon supports a **runtime-configurable
single-slot trusted publisher** via RPC. The compiled-in fallback list
is still consulted if no runtime publisher is set, so a fresh daemon
never fails to verify an old snapshot.
## The model — Design A (single-slot, auto-replace)
- **At most ONE runtime publisher exists at any time.**
- Calling `settrustedv2snapshotpublisher <addr>` **atomically
replaces** the current publisher. The previous one is dropped
immediately. There is no grace period, no retirement list, no
rollback path. Pure single-slot.
- The active publisher is persisted to
`<datadir>/snapshot-publisher.json`, so it survives daemon
restarts.
- The built-in fallback list (read-only, compiled into the binary) is
consulted only if no runtime publisher is set. That list contains:
- `TG8f76yktTxDrT7JJymY3wVAusXiD3fVvX` — Sami's legacy snapshot
publisher key (the original, used from v6.1.5 through v6.1.7).
## The three RPCs
### `settrustedv2snapshotpublisher <address>`
Atomically replaces the active trusted publisher. The previous
publisher is dropped immediately. The new publisher is persisted to
`<datadir>/snapshot-publisher.json` so the choice survives restarts.
```
triangles-cli settrustedv2snapshotpublisher TGotWuftzH7rD9tXC7whE8EXiyC3mr1CrH
```
Result:
```json
{
"previous": "TG8f76yktTxDrT7JJymY3wVAusXiD3fVvX",
"current": "TGotWuftzH7rD9tXC7whE8EXiyC3mr1CrH"
}
```
The `previous` field is empty if no runtime publisher was set before.
### `gettrustedv2snapshotpublisher`
Returns the currently active runtime publisher.
```
triangles-cli gettrustedv2snapshotpublisher
```
Result:
```json
{
"active": "TGotWuftzH7rD9tXC7whE8EXiyC3mr1CrH",
"has_runtime_override": true
}
```
If `has_runtime_override` is `false`, only the built-in fallback list
is consulted. The fallback currently contains `TG8f76yktTxDrT7JJymY3wVAusXiD3fVvX`.
### `unsettrustedv2snapshotpublisher`
Clears the runtime override. Reverts to the built-in fallback list.
Also removes `<datadir>/snapshot-publisher.json`.
```
triangles-cli unsettrustedv2snapshotpublisher
```
Use this if you want to "go back to the legacy trusted signer"
without a rebuild.
## Common rotation scenarios
### Rotate to a new key (forward rotation)
1. Generate a new key in the wallet:
```
triangles-cli getnewaddress
# returns: TNewAddressHere...
```
2. (Optional but recommended) Label it so you remember its role:
```
triangles-cli setaccount TNewAddressHere... "snapshot publisher"
```
3. Set it as the trusted publisher:
```
triangles-cli settrustedv2snapshotpublisher TNewAddressHere...
```
4. Verify:
```
triangles-cli gettrustedv2snapshotpublisher
```
Should show `active: TNewAddressHere...`.
Old publisher is dropped immediately. New one is in effect for this
daemon and any daemon that syncs from `<datadir>/snapshot-publisher.json`.
### Roll back to the legacy publisher
If the new key is lost / compromised / you just want to revert:
```
triangles-cli unsettrustedv2snapshotpublisher
```
This reverts to the built-in fallback (`TG8f76ykt...`). No rebuild
required. The legacy address will continue to verify any snapshot
that was signed before your rotation.
### Rotate during a handover (publisher A hands off to publisher B)
1. Publisher B installs v6.1.8+ daemon.
2. Publisher B sets themselves as the trusted publisher:
```
triangles-cli settrustedv2snapshotpublisher TBsAddress...
```
3. Publisher B signs a new snapshot with their key (see
`publishcheckpoint` in `TRIANGLES-RPC-COMMANDS.md`).
4. Publisher A can leave the network; their key is no longer trusted
on any node that has called `settrustedv2snapshotpublisher`.
Note: because Design A auto-drops the previous publisher, **only one
operator can publish at a time.** If you need overlap (both A and B
publishing during a transition), that requires Design B (multi-slot
with grace period) — not supported in v6.1.8. Contact Sami for the
upgrade path.
## Files
| Path | Purpose |
|---|---|
| `<datadir>/snapshot-publisher.json` | Runtime publisher override. Plain JSON. Inspectable with `cat`. |
| `<datadir>/wallet.dat` | Must contain the privkey for the active publisher, otherwise `publishcheckpoint` will fail at signing time. (Trust is governed by the override; signing is governed by the wallet.) |
### `<datadir>/snapshot-publisher.json` format
```json
{
"address": "TGotWuftzH7rD9tXC7whE8EXiyC3mr1CrH",
"set_at": 1752168000,
"note": "Set via triangles-cli settrustedv2snapshotpublisher. Replace atomically; previous publisher is dropped."
}
```
`set_at` is the Unix timestamp when the RPC was last called. `note` is
informational only.
## Recovery if RPC fails
If for some reason the runtime override can't be persisted (e.g. JSON
write fails), the RPC returns a warning but the in-memory change is
already live for the current session. To check:
```
triangles-cli gettrustedv2snapshotpublisher
```
If `active` is set, you're good for the current session. The next
daemon restart will lose it unless `snapshot-publisher.json` exists.
Inspect it manually:
```
cat ~/.triangles/snapshot-publisher.json
```
If the file doesn't exist but you need the override to survive restart,
hand-write it:
```json
{
"address": "TGotWuftzH7rD9tXC7whE8EXiyC3mr1CrH",
"set_at": 1752168000,
"note": "Hand-set; rotate via triangles-cli settrustedv2snapshotpublisher."
}
```
The daemon reads this file at startup. Address must be 34 chars and
start with `T`. Anything else is logged and ignored.
## When you DO need a rebuild
- **Adding a new entry to the built-in fallback list** (the
read-only list compiled into the binary). Edit
`BUILTIN_TRUSTED_SNAPSHOT_SIGNERS[]` in `src/bootstrap.cpp`, rebuild,
release. This is only needed if you want a publisher to be trusted
*without* any operator running the RPC.
- **Changing the RPC names or argument shapes.** Edit source, rebuild.
For everyday "I want to add or rotate a trusted publisher," the RPC
is enough. Don't rebuild.
## Why "single-slot, no grace period"
Sami asked for it explicitly when designing the operator-experience
for this feature. The trade-off: if the active key is lost or
compromised, there's no automatic fallback. The operator must either
re-add the previous key (which requires they kept the JSON file or
remember the address) or rebuild with the new key in
`BUILTIN_TRUSTED_SNAPSHOT_SIGNERS[]`.
If this trade-off becomes painful — for example if multiple
operators need to publish during a handover — the alternative is
Design B (multi-slot with grace period). That's a one-day patch on
top of this one. Ask Sami for the upgrade.
## Versioning
This feature is introduced in **v6.1.8**. Daemons older than v6.1.8
still use the hardcoded `TG8f76ykt...` only — they cannot use the new
key until they upgrade.
## Related RPCs
For the publishing side (signing snapshots, not verifying them),
see:
- `publishcheckpoint <interval> <signing_address> <output_path>` —
builds and signs a checkpoint document.
- `gencheckpoints` — generates raw checkpoint data without signing.
- `getcheckpoint` — returns the current synchronized checkpoint.
See `TRIANGLES-RPC-COMMANDS.md` for full details on those.
+118 -6
View File
@@ -775,16 +775,128 @@ namespace {
// Trusted signer addresses for snapshot manifests. A snapshot is accepted
// iff its manifest's signing_address matches one of these AND its signature
// verifies under Triangles' compact-message protocol.
static const char* TRUSTED_SNAPSHOT_SIGNERS[] = {
"TG8f76yktTxDrT7JJymY3wVAusXiD3fVvX", // Sami's snapshot publisher key
//
// Design A: single-slot runtime override via RPC. The previous publisher
// is dropped atomically on every set. The built-in fallback below is
// always consulted if no runtime override is set, so a fresh daemon still
// verifies old snapshots without operator intervention.
// Built-in fallback (read-only, compiled in).
static const char* BUILTIN_TRUSTED_SNAPSHOT_SIGNERS[] = {
"TG8f76yktTxDrT7JJymY3wVAusXiD3fVvX", // Sami's legacy snapshot publisher key
};
static const size_t NUM_TRUSTED_SNAPSHOT_SIGNERS =
sizeof(TRUSTED_SNAPSHOT_SIGNERS) / sizeof(TRUSTED_SNAPSHOT_SIGNERS[0]);
static const size_t NUM_BUILTIN_TRUSTED_SNAPSHOT_SIGNERS =
sizeof(BUILTIN_TRUSTED_SNAPSHOT_SIGNERS) / sizeof(BUILTIN_TRUSTED_SNAPSHOT_SIGNERS[0]);
// Runtime override. Empty string = no override, use built-in fallback.
static std::string g_activeTrustedSnapshotPublisher;
static std::mutex g_trustedPublisherMutex;
static const char* SNAPSHOT_PUBLISHER_FILE = "snapshot-publisher.json";
std::string GetActiveTrustedSnapshotPublisher()
{
std::lock_guard<std::mutex> lock(g_trustedPublisherMutex);
return g_activeTrustedSnapshotPublisher;
}
static void SetActiveTrustedSnapshotPublisherUnlocked(const std::string& addr)
{
g_activeTrustedSnapshotPublisher = addr;
}
// Load runtime override from <datadir>/snapshot-publisher.json.
// Called once at startup from init.cpp.
void LoadTrustedSnapshotPublisher()
{
fs::path filePath = GetDataDir(true) / SNAPSHOT_PUBLISHER_FILE;
if (!fs::exists(filePath))
return;
std::ifstream f(filePath.string().c_str());
if (!f) return;
std::stringstream ss; ss << f.rdbuf();
std::string json = ss.str();
// Minimal JSON parse: "address":"<addr>"
size_t keyPos = json.find("\"address\"");
if (keyPos == std::string::npos) return;
size_t colonPos = json.find(':', keyPos);
if (colonPos == std::string::npos) return;
size_t q1 = json.find('"', colonPos);
if (q1 == std::string::npos) return;
size_t q2 = json.find('"', q1 + 1);
if (q2 == std::string::npos) return;
std::string addr = json.substr(q1 + 1, q2 - q1 - 1);
if (addr.size() != 34 || addr[0] != 'T') {
printf("Bootstrap: snapshot-publisher.json contains invalid address '%s', ignoring\n",
addr.c_str());
return;
}
{
std::lock_guard<std::mutex> lock(g_trustedPublisherMutex);
SetActiveTrustedSnapshotPublisherUnlocked(addr);
}
printf("Bootstrap: loaded trusted snapshot publisher override: %s\n", addr.c_str());
}
static bool PersistTrustedSnapshotPublisher(const std::string& addr)
{
fs::path filePath = GetDataDir(true) / SNAPSHOT_PUBLISHER_FILE;
std::ofstream f(filePath.string().c_str(), std::ios::trunc);
if (!f) return false;
f << "{\n"
<< " \"address\": \"" << addr << "\",\n"
<< " \"set_at\": " << GetTime() << ",\n"
<< " \"note\": \"Set via triangles-cli settrustedv2snapshotpublisher. "
<< "Replace atomically; previous publisher is dropped.\"\n"
<< "}\n";
return f.good();
}
bool SetTrustedSnapshotPublisher(const std::string& addr, std::string& strError)
{
if (addr.size() != 34 || addr[0] != 'T') {
strError = "settrustedv2snapshotpublisher: invalid address format (expected 34-char T-address)";
return false;
}
{
std::lock_guard<std::mutex> lock(g_trustedPublisherMutex);
SetActiveTrustedSnapshotPublisherUnlocked(addr);
}
if (!PersistTrustedSnapshotPublisher(addr)) {
strError = "settrustedv2snapshotpublisher: warning, could not persist to "
"snapshot-publisher.json (in-memory change is live for this session)";
return true;
}
return true;
}
bool UnsetTrustedSnapshotPublisher(std::string& strError)
{
{
std::lock_guard<std::mutex> lock(g_trustedPublisherMutex);
SetActiveTrustedSnapshotPublisherUnlocked(std::string());
}
fs::path filePath = GetDataDir(true) / SNAPSHOT_PUBLISHER_FILE;
fs::remove(filePath);
return true;
}
bool IsTrustedSnapshotSigner(const std::string& addr)
{
for (size_t i = 0; i < NUM_TRUSTED_SNAPSHOT_SIGNERS; ++i)
if (addr == TRUSTED_SNAPSHOT_SIGNERS[i])
// 1. Runtime override (set via RPC).
{
std::lock_guard<std::mutex> lock(g_trustedPublisherMutex);
if (!g_activeTrustedSnapshotPublisher.empty() &&
addr == g_activeTrustedSnapshotPublisher)
return true;
}
// 2. Built-in fallback (compiled in, read-only).
for (size_t i = 0; i < NUM_BUILTIN_TRUSTED_SNAPSHOT_SIGNERS; ++i)
if (addr == BUILTIN_TRUSTED_SNAPSHOT_SIGNERS[i])
return true;
return false;
}
+21
View File
@@ -73,6 +73,27 @@ namespace Bootstrap {
ProgressCallback progressFn,
std::string& strError);
// ===================================================================
// Trusted snapshot publisher — RPC-driven single-slot rotation
// ===================================================================
// Returns the currently active trusted publisher, or empty string if
// only the built-in fallback is in effect.
std::string GetActiveTrustedSnapshotPublisher();
// Atomically replaces the active publisher. The previous one is dropped
// immediately (Design A: single-slot, no grace period). Persists to
// <datadir>/snapshot-publisher.json so the choice survives restarts.
bool SetTrustedSnapshotPublisher(const std::string& addr,
std::string& strError);
// Clears the runtime override and reverts to the built-in fallback
// list. Also removes snapshot-publisher.json from disk.
bool UnsetTrustedSnapshotPublisher(std::string& strError);
// Called once at daemon startup (from init.cpp) to load any persisted
// runtime override.
void LoadTrustedSnapshotPublisher();
} // namespace Bootstrap
#endif // TRIANGLES_BOOTSTRAP_H
+3
View File
@@ -1191,6 +1191,9 @@ bool AppInit2()
bool noBootstrap = GetBoolArg("-nobootstrap", false);
bool snapshotMode = GetBoolArg("-snapshot", true);
fs::path dataPath = GetDataDir();
// Load any runtime trusted snapshot publisher override that was
// persisted by a previous settrustedv2snapshotpublisher call.
Bootstrap::LoadTrustedSnapshotPublisher();
bool needsBootstrap = Bootstrap::NeedsBootstrap(dataPath);
if (needsBootstrap && !noBootstrap) {
+89
View File
@@ -13,6 +13,7 @@
#include "utxosnapshot.h"
#include "checkpointpublisher.h"
#include "wallet.h"
#include "bootstrap.h"
#include <filesystem>
@@ -1322,3 +1323,91 @@ Value dumputxoset(const Array& params, bool fHelp)
return result;
}
// ============================================================================
// Trusted snapshot publisher RPCs (Design A: single-slot rotation)
// ============================================================================
//
// settrustedv2snapshotpublisher <address>
// - Atomically replaces the active trusted snapshot publisher.
// - The previous publisher is dropped immediately (no grace period).
// - The new publisher is persisted to <datadir>/snapshot-publisher.json
// so the choice survives daemon restarts.
//
// gettrustedv2snapshotpublisher
// - Returns the currently active runtime override.
// - Empty string means no runtime override; built-in fallback list is
// the source of truth (which contains "TG8f76ykt...").
//
// unsettrustedv2snapshotpublisher
// - Clears the runtime override.
// - The built-in fallback list (read-only, compiled in) becomes the
// source of truth again.
// - Removes <datadir>/snapshot-publisher.json.
Value settrustedv2snapshotpublisher(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"settrustedv2snapshotpublisher <address>\n"
"Atomically replace the trusted snapshot publisher.\n"
"The previous publisher is dropped immediately (no grace period).\n"
"The new publisher is persisted to <datadir>/snapshot-publisher.json.\n"
"\nArguments:\n"
"1. address (string, required) Triangles T-address (34 chars, starts with 'T')\n"
"\nResult:\n"
"{ previous: 'T...', current: 'T...' } (previous is empty if first set)\n"
"\nExample:\n"
" triangles-cli settrustedv2snapshotpublisher TGotWuftzH7rD9tXC7whE8EXiyC3mr1CrH");
std::string addr = params[0].get_str();
std::string previous = Bootstrap::GetActiveTrustedSnapshotPublisher();
std::string err;
if (!Bootstrap::SetTrustedSnapshotPublisher(addr, err)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, err);
}
Object result;
result.push_back(Pair("previous", previous));
result.push_back(Pair("current", addr));
if (!err.empty())
result.push_back(Pair("warning", err));
return result;
}
Value gettrustedv2snapshotpublisher(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"gettrustedv2snapshotpublisher\n"
"Returns the currently active trusted snapshot publisher.\n"
"Empty string means no runtime override is set; the built-in\n"
"fallback list (compiled in) is the source of truth.\n"
"\nResult:\n"
"{ active: 'T...', has_runtime_override: true|false }");
std::string active = Bootstrap::GetActiveTrustedSnapshotPublisher();
Object result;
result.push_back(Pair("active", active));
result.push_back(Pair("has_runtime_override", !active.empty()));
return result;
}
Value unsettrustedv2snapshotpublisher(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"unsettrustedv2snapshotpublisher\n"
"Clear the runtime trusted snapshot publisher override.\n"
"The built-in fallback list (compiled in) becomes the source of truth again.\n"
"Removes <datadir>/snapshot-publisher.json.\n"
"\nResult:\n"
"{ unset: true, fallback_in_effect: true }");
std::string err;
if (!Bootstrap::UnsetTrustedSnapshotPublisher(err)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, err);
}
Object result;
result.push_back(Pair("unset", true));
result.push_back(Pair("fallback_in_effect", true));
return result;
}
+3
View File
@@ -317,6 +317,9 @@ static const CRPCCommand vRPCCommands[] =
{ "getcheckpoint", &getcheckpoint, true, false },
{ "gencheckpoints", &gencheckpoints, true, false },
{ "publishcheckpoint", &publishcheckpoint, true, false },
{ "settrustedv2snapshotpublisher", &settrustedv2snapshotpublisher, false, false },
{ "gettrustedv2snapshotpublisher", &gettrustedv2snapshotpublisher, false, false },
{ "unsettrustedv2snapshotpublisher", &unsettrustedv2snapshotpublisher, false, false },
{ "getchaintips", &getchaintips, true, false },
{ "invalidateblock", &invalidateblock, false, false },
{ "reconsiderblock", &reconsiderblock, false, false },
+3
View File
@@ -228,6 +228,9 @@ extern json_spirit::Value getblockbynumber(const json_spirit::Array& params, boo
extern json_spirit::Value getcheckpoint(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gencheckpoints(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value publishcheckpoint(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value settrustedv2snapshotpublisher(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gettrustedv2snapshotpublisher(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value unsettrustedv2snapshotpublisher(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value invalidateblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool fHelp);