This commit is contained in:
copy2018 2025-03-07 11:38:30 +01:00 committed by GitHub
commit ef9d160683
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 151 additions and 46 deletions

View File

@ -83,6 +83,7 @@ COPY --from=bitcoin-core /opt /opt
COPY ./manager/target/${ARCH}-unknown-linux-musl/release/bitcoind-manager \
./docker_entrypoint.sh \
./actions/reindex.sh \
./actions/reindex_chainstate.sh \
./actions/prioritise-transaction.sh \
./check-rpc.sh \
./check-synced.sh \

View File

@ -0,0 +1,34 @@
#!/bin/sh
set -e
action_result_running=" {
\"version\": \"0\",
\"message\": \"Bitcoin Core restarting in reindex chainstate mode\",
\"value\": null,
\"copyable\": false,
\"qr\": false
}"
action_result_stopped=" {
\"version\": \"0\",
\"message\": \"Bitcoin Core will reindex the chainstate the next time the service is started\",
\"value\": null,
\"copyable\": false,
\"qr\": false
}"
action_result_pruned=" {
\"version\": \"0\",
\"message\": \"Bitcoin Core does not allow reindex-chainstate for pruned nodes. If the Chainstate is corrupted on a pruned node the entire blockchain will need to be re-downloaded from genesis with the 'Reindex Blockchain' action\",
\"value\": null,
\"copyable\": false,
\"qr\": false
}"
pruned=$(yq e '.advanced.pruning.mode' /root/.bitcoin/start9/config.yaml)
if [ "$pruned" != "disabled" ]; then
echo $action_result_pruned
else
touch /root/.bitcoin/requires.reindex_chainstate
bitcoin-cli -rpcconnect=bitcoind.embassy stop >/dev/null 2>/dev/null && echo $action_result_running || echo $action_result_stopped
fi

View File

@ -124,6 +124,11 @@ zmqpubsequence=tcp://0.0.0.0:28333
txindex=1
}}
## COINSTATSINDEX
{{#IF coinstatsindex
coinstatsindex=1
}}
## DATACARRIER
{{#IF blkconstr.datacarrier
datacarrier=1
@ -219,4 +224,4 @@ blockmaxsize={{advanced.templateconstruction.blockmaxsize}}
{{#IF advanced.templateconstruction.blockmaxweight
blockmaxweight={{advanced.templateconstruction.blockmaxweight}}
}}
}}

View File

@ -547,7 +547,7 @@ if mempool_info.status.success() {
}
fn inner_main(reindex: bool) -> Result<(), Box<dyn Error>> {
fn inner_main(reindex: bool, reindex_chainstate: bool) -> Result<(), Box<dyn Error>> {
while !Path::new("/root/.bitcoin/start9/config.yaml").exists() {
std::thread::sleep(std::time::Duration::from_secs(1));
}
@ -585,32 +585,29 @@ fn inner_main(reindex: bool) -> Result<(), Box<dyn Error>> {
}
if reindex {
btc_args.push("-reindex".to_owned());
}
std::io::copy(
&mut TemplatingReader::new(
std::fs::File::open("/mnt/assets/bitcoin.conf.template")?,
&config,
&"{{var}}".parse()?,
b'%',
),
&mut std::fs::File::create("/root/.bitcoin/bitcoin.conf")?,
)?;
let mut child = std::process::Command::new("bitcoind")
.args(btc_args)
.spawn()?;
if reindex {
match fs::remove_file("/root/.bitcoin/requires.reindex") {
Ok(()) => (),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => (),
a => a?,
}
} else if reindex_chainstate {
btc_args.push("-reindex-chainstate".to_owned());
match fs::remove_file("/root/.bitcoin/requires.reindex_chainstate") {
Ok(()) => (),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => (),
a => a?,
}
}
let mut child = std::process::Command::new("bitcoind")
.args(btc_args)
.spawn()?;
let raw_child = child.id();
*CHILD_PID.lock().unwrap() = Some(raw_child);
let pruned = {
config[&Value::from("advanced")][&Value::from("pruning")][&Value::from("mode")]
== "automatic"
config[&Value::from("advanced")][&Value::from("pruning")][&Value::from("mode")] == "automatic"
};
let _proxy = if pruned {
let state = Arc::new(btc_rpc_proxy::State {
@ -656,13 +653,17 @@ fn inner_main(reindex: bool) -> Result<(), Box<dyn Error>> {
} else {
1
};
std::process::exit(code)
}
fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
let reindex = Path::new("/root/.bitcoin/requires.reindex").exists();
let reindex_chainstate = Path::new("/root/.bitcoin/requires.reindex_chainstate").exists();
ctrlc::set_handler(move || {
if let Some(raw_child) = *CHILD_PID.lock().unwrap() {
use nix::{
@ -674,7 +675,7 @@ fn main() -> Result<(), Box<dyn Error>> {
std::process::exit(143)
}
})?;
inner_main(reindex)
inner_main(reindex, reindex_chainstate)
}
fn human_readable_timestamp(unix_time: u64) -> String {

View File

@ -146,6 +146,22 @@ actions:
mounts:
main: /root/.bitcoin
io-format: json
reindex-chainstate:
name: "Reindex Chainstate"
description: "Rebuilds the chainstate database using existing block index data; as the block index is not rebuilt, 'reindex_chainstate' should be strictly faster than 'reindex'. This action should only be used in the case of chainstate corruption; if the blocks stored on disk are corrupted, the 'reindex' action will need to be run instead."
warning: While faster than 'Reindex', 'Reindex Chainstate' can still take several days or more to complete. Pruned nodes do not allow 'reindex-chainstate'; if you are running a pruned node and suspect chainstate corruption the 'reindex' action (requiring redownloading the entire Blockchain) should be run instead.
allowed-statuses:
- running
- stopped
implementation:
type: docker
image: main
system: false
entrypoint: reindex_chainstate.sh
args: []
mounts:
main: /root/.bitcoin
io-format: json
delete-txindex:
name: "Delete Transaction Index"
description: "Deletes the Transaction Index (txindex) in case it gets corrupted."
@ -154,6 +170,14 @@ actions:
- stopped
implementation:
type: script
delete-coinstatsindex:
name: "Delete Coinstats Index"
description: "Deletes the Coinstats Index (coinstatsindex) in case it gets corrupted."
warning: The Coinstats Index will be rebuilt once Bitcoin Core is started again, unless you deactivate it in the config settings. Please don't do this unless instructed to by Start9 support staff.
allowed-statuses:
- stopped
implementation:
type: script
delete-peers:
name: "Delete Peer List"
description: "Deletes the Peer List (peers.dat) in case it gets corrupted."

View File

@ -57,4 +57,32 @@ export const action = {
},
};
},
async "delete-coinstatsindex"(
effect: T.Effects,
_input?: T.Config,
): Promise<T.ResultType<T.ActionResult>> {
const coinstatsinfoLocation = {
path: "indexes/coinstats",
volumeId: "main",
};
if (await util.exists(effect, coinstatsinfoLocation) === false) {
return {
result: {
copyable: false,
message: "coinstatsindex doesn't exist",
version: "0",
qr: false,
},
};
}
await effect.removeDir(coinstatsinfoLocation);
return {
result: {
copyable: false,
message: "Deleted coinstatsindex",
version: "0",
qr: false,
},
};
},
};

View File

@ -329,6 +329,12 @@ export const getConfig: T.ExpectedExports.getConfig = async (effects) => {
description: "Enable the Transaction Index (txindex)",
default: allowUnpruned,
},
coinstatsindex: {
type: "boolean",
name: "Coinstats Index",
description: "Enabling Coinstats Index reduces the time for the gettxoutsetinfo RPC to complete at the cost of using additional disk space",
default: false,
},
wallet: {
type: "object",
name: "Wallet",
@ -410,7 +416,7 @@ export const getConfig: T.ExpectedExports.getConfig = async (effects) => {
type: "boolean",
name: "Use V2 P2P Transport Protocol",
description: "Enable or disable the use of BIP324 V2 P2P transport protocol.",
default: false,
default: true,
},
addnode: {
name: "Add Nodes",

View File

@ -1,36 +1,39 @@
import {
matches,
compat,
types,
YAML
} from "../dependencies.ts";
const { number, shape, boolean } = matches;
import { matches, types, YAML } from "../dependencies.ts";
const { number } = matches;
export const setConfig: types.ExpectedExports.setConfig = async (
effects: types.Effects,
// deno-lint-ignore no-explicit-any
newConfig: any,
newConfig: any
) => {
if (!(newConfig?.rpc?.enable || !(newConfig.advanced?.pruning?.mode === "manual"))) {
if (newConfig.advanced.pruning.mode === "manual" && !newConfig.rpc.enable) {
return {
error: "RPC must be enabled for manual.",
error: "RPC must be enabled for manual pruning.",
};
}
if (
!(!newConfig.txindex || (newConfig.advanced?.pruning?.mode === "disabled"))
) {
if (newConfig.txindex && newConfig.advanced.pruning.mode !== "disabled") {
return {
error: "Txindex not allowed on pruned nodes.",
};
}
// true, false only fail case
if (
!(!newConfig.advanced.blockfilters.peerblockfilters ||
(newConfig.advanced.blockfilters.blockfilterindex))
newConfig.coinstatsindex &&
newConfig.advanced.pruning.mode !== "disabled"
) {
return {
error: "Coinstats index not allowed on pruned nodes.",
};
}
if (
newConfig.advanced.blockfilters.peerblockfilters &&
!newConfig.advanced.blockfilters.blockfilterindex
) {
return {
error:
"'Compute Compact Block Filters' must be enabled if 'Serve Compact Block Filters to Peers' is enabled.",
'"Compute Compact Block Filters" must be enabled if "Serve Compact Block Filters to Peers" is enabled.',
};
}
@ -41,10 +44,12 @@ export const setConfig: types.ExpectedExports.setConfig = async (
// config-set.sh
const oldConfig = await effects.readFile({
path: "start9/config.yaml",
volumeId: "main",
}).catch(() => null);
const oldConfig = await effects
.readFile({
path: "start9/config.yaml",
volumeId: "main",
})
.catch(() => null);
if (oldConfig) {
await effects.writeFile({
path: "start9/config-old.yaml",
@ -56,7 +61,7 @@ export const setConfig: types.ExpectedExports.setConfig = async (
let oldPruningSize = 0;
if (oldPruningTl !== "disabled") {
oldPruningSize = number.unsafeCast(
oldConfigParsed?.advanced?.pruning?.size,
oldConfigParsed?.advanced?.pruning?.size
);
}
const newPruningTl = newConfig.advanced.pruning.mode;
@ -67,7 +72,8 @@ export const setConfig: types.ExpectedExports.setConfig = async (
if (oldPruningTl == "disabled" || !oldPruningTl) {
effects.debug("No reindex required");
} else if (
oldPruningTl === newPruningTl && oldPruningSize >= newPruningSize
oldPruningTl === newPruningTl &&
oldPruningSize >= newPruningSize
) {
effects.debug("No reindex required");
} else {
@ -81,7 +87,7 @@ export const setConfig: types.ExpectedExports.setConfig = async (
} else {
effects.debug("No reindex required");
}
await effects.writeFile({
path: "start9/config.yaml",
toWrite: YAML.stringify(newConfig),