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

Added Testnet4 Support #50

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.vscode
docker-images
electrs.s9pk
image.tar
scripts/embassy.js
.vscode
docker-images
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ install: $(PKG_ID).s9pk
start-cli package install $(PKG_ID).s9pk

clean:
docker run --rm -it -v "$(shell pwd)"/configurator:/home/rust/src messense/rust-musl-cross:x86_64-musl cargo clean -q
rm -rf docker-images
rm -rf image.tar
rm -f $(PKG_ID).s9pk
Expand All @@ -28,7 +29,7 @@ arm: docker-images/aarch64.tar scripts/embassy.js
x86: docker-images/x86_64.tar scripts/embassy.js
start-sdk pack

$(PKG_ID).s9pk: manifest.yaml instructions.md scripts/embassy.js electrs/LICENSE docker-images/aarch64.tar docker-images/x86_64.tar
$(PKG_ID).s9pk: manifest.yaml instructions.md scripts/embassy.js electrs/LICENSE docker-images/x86_64.tar docker-images/aarch64.tar
start-sdk pack

docker-images/aarch64.tar: Dockerfile docker_entrypoint.sh check-synced.sh check-electrum.sh configurator/target/aarch64-unknown-linux-musl/release/configurator $(ELECTRS_SRC)
Expand Down
36 changes: 25 additions & 11 deletions check-synced.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
#!/bin/bash
# vim: ts=2 sw=2 sts=2 ai et

DURATION=$(</dev/stdin)
if (($DURATION <= 9000 )); then
exit 60
else
set -e

b_host="bitcoind.embassy"
b_username=$(yq '.user' /data/start9/config.yaml)
b_password=$(yq '.password' /data/start9/config.yaml)


b_type=$(yq '.bitcoind.type' /data/start9/config.yaml)

if [ "$b_type" == "bitcoind-testnet" ]; then
b_host="bitcoind-testnet.embassy"
b_rpc_port=48332
e_monitoring_port=44224
e_db_path=/data/db/testnet4
else
b_host="bitcoind.embassy"
b_rpc_port=8332
e_monitoring_port=4224
e_db_path=/data/db/bitcoin
fi

b_username=$(yq '.bitcoind.username' /data/start9/config.yaml)
b_password=$(yq '.bitcoind.password' /data/start9/config.yaml)

#Get blockchain info from the bitcoin rpc
b_gbc_result=$(curl -sS --user $b_username:$b_password --data-binary '{"jsonrpc": "1.0", "id": "sync-hck", "method": "getblockchaininfo", "params": []}' -H 'content-type: text/plain;' http://$b_host:8332/ 2>&1)
b_gbc_result=$(curl -sS --user $b_username:$b_password --data-binary '{"jsonrpc": "1.0", "id": "sync-hck", "method": "getblockchaininfo", "params": []}' -H 'content-type: text/plain;' http://$b_host:$b_rpc_port/ 2>&1)
error_code=$?
b_gbc_error=$(echo $b_gbc_result | yq '.error' -)
if [[ $error_code -ne 0 ]]; then
Expand All @@ -37,20 +51,20 @@ else
exit 61
else
#Gather keys/values from prometheus rpc:
curl_res=$(curl -sS localhost:4224)
curl_res=$(curl -sS localhost:$e_monitoring_port 2>/dev/null)
error_code=$?

if [[ $error_code -ne 0 ]]; then
echo "Error contacting the electrs Prometheus RPC" >&2
exit 61
fi

#Determine whether we are actively doing a database compaction:
#compaction_res=$(echo -e "$features_res" | grep num-running-compactions | sed "s/\s$//g" | grep " [^0]$"|awk '{print $NF}'|head -1)
#^The prometheus RPC's num-running-compactions key doesn't seem to correspond to actual
# compaction events, so we'll determine compaction by another, dumber but accurate method:
chk_numlines=100000 #Look through the last 100,000 lines of the db LOG
log_file="/data/db/bitcoin/LOG"
log_file="$e_db_path/LOG"
tail_log="ionice -c3 tail -$chk_numlines $log_file"
compaction_job=$($tail_log|nice -n19 grep EVENT_LOG|nice -n19 grep "ManualCompaction"|nice -n19 tail -1|nice -n19 cut -d" " -f7)
if [ -n "$compaction_job" ] ; then
Expand Down Expand Up @@ -82,4 +96,4 @@ else
exit 61
fi
fi
fi
fi
2 changes: 1 addition & 1 deletion configurator/src/electrs.toml.template
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
auth = "{bitcoin_rpc_user:}:{bitcoin_rpc_pass}"
daemon_rpc_addr = "{bitcoin_rpc_host}:{bitcoin_rpc_port}"
daemon_p2p_addr = "{bitcoin_p2p_host}:{bitcoin_p2p_port}"
network = "bitcoin"
network = "{network}"
electrum_rpc_addr = "0.0.0.0:50001"
log_filters = "{log_filters}"
{index_batch_size}
Expand Down
47 changes: 37 additions & 10 deletions configurator/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,54 @@
use std::fs::File;
use std::io::Write;

use http::Uri;
use serde::{
de::{Deserializer, Error as DeserializeError, Unexpected},
Deserialize,
};

#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
struct Config {
user: String,
password: String,
bitcoind: BitcoinCoreConfig,
log_filters: String,
index_batch_size: Option<u16>,
index_lookup_limit: Option<u16>,
}

#[derive(Deserialize)]
#[serde(tag = "type")]
enum BitcoinCoreConfig {
#[serde(rename = "bitcoind")]
Bitcoind {
username: String,
password: String,
},
#[serde(rename = "bitcoind-testnet")]
BitcoindTestnet {
username: String,
password: String,
},
}

fn main() -> Result<(), anyhow::Error> {
let config: Config = serde_yaml::from_reader(File::open("/data/start9/config.yaml")?)?;

{
let mut outfile = File::create("/data/electrs.toml")?;

let (bitcoin_rpc_user, bitcoin_rpc_pass, bitcoin_rpc_host, bitcoin_rpc_port, bitcoin_p2p_host, bitcoin_p2p_port, network) =
match config.bitcoind {
BitcoinCoreConfig::Bitcoind { username, password } => {
let hostname = format!("{}", "bitcoind.embassy");
let network = format!("{}", "bitcoin");
(username, password, hostname.clone(), 8332, hostname.clone(), 8333, network.clone())
}
BitcoinCoreConfig::BitcoindTestnet { username, password } => {
let hostname = format!("{}", "bitcoind-testnet.embassy");
let network = format!("{}", "testnet4");
(username, password, hostname.clone(), 48332, hostname.clone(), 8333, network.clone())
}
};

let mut index_batch_size: String = "".to_string();
if config.index_batch_size.is_some() {
index_batch_size = format!(
Expand All @@ -42,12 +68,13 @@ fn main() -> Result<(), anyhow::Error> {
write!(
outfile,
include_str!("electrs.toml.template"),
bitcoin_rpc_user = config.user,
bitcoin_rpc_pass = config.password,
bitcoin_rpc_host = "bitcoind.embassy",
bitcoin_rpc_port = 8332,
bitcoin_p2p_host = "bitcoind.embassy",
bitcoin_p2p_port = 8333,
bitcoin_rpc_user = bitcoin_rpc_user,
bitcoin_rpc_pass = bitcoin_rpc_pass,
bitcoin_rpc_host = bitcoin_rpc_host,
bitcoin_rpc_port = bitcoin_rpc_port,
bitcoin_p2p_host = bitcoin_p2p_host,
bitcoin_p2p_port = bitcoin_p2p_port,
network = network,
log_filters = config.log_filters,
index_batch_size = index_batch_size,
index_lookup_limit = index_lookup_limit,
Expand Down
19 changes: 17 additions & 2 deletions manifest.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
id: electrs
title: "electrs"
version: 0.10.9
version: 0.10.9.1
release-notes: |
* Update electrs-wrapper tag to v0.10.9.1, added support for testnet4
* Update upstream electrs to [v0.10.9](https://github.com/romanz/electrs/blob/master/RELEASE-NOTES.md#0109-feb-01-2025)
* Update Rust base Docker image
* Make some parts of the check-synced healthcheck script (io)nice
Expand Down Expand Up @@ -79,13 +80,27 @@ dependencies:
bitcoind:
version: ">=0.21.1.2 <30.0.0"
requirement:
type: "required"
type: "opt-out"
how: Set "Bitcoin Core" to "Bitcoin Core"
description: Needed for peer interface and rpc interface.
config:
check:
type: script
auto-configure:
type: script
requires-runtime-config: true
bitcoind-testnet:
version: '>=0.21.1.2 <29.0.0'
requirement:
type: 'opt-in'
how: Set "Bitcoin Core" type to "Bitcoin Core (testnet)"
description: Testnet Bitcoin Core node for testing purposes
config:
check:
type: script
auto-configure:
type: script
requires-runtime-config: true
backup:
create:
type: script
Expand Down
119 changes: 96 additions & 23 deletions scripts/services/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { types as T, matches } from "../deps.ts";

const { shape, number, boolean, string } = matches;

type Check = {
currentError(config: T.Config): string | void
fix(config: T.Config): void
}

const matchBitcoindConfig = shape({
rpc: shape({
enable: boolean,
Expand All @@ -19,41 +24,109 @@ const matchBitcoindConfig = shape({
}),
});

export const dependencies: T.ExpectedExports.dependencies = {
bitcoind: {
// deno-lint-ignore require-await
async check(effects, configInput) {
effects.info("check bitcoind");
const config = matchBitcoindConfig.unsafeCast(configInput);
const bitcoindChecks: Array<Check> = [
{
currentError(config) {
if (!matchBitcoindConfig.test(config)) {
return { error: "Bitcoind config is not the correct shape" };
return 'Config is not the correct shape'
}
if (!config.rpc.enable) {
return { error: "Must have RPC enabled" };
return 'Must have RPC enabled'
}
return
},
fix(config) {
if (!matchBitcoindConfig.test(config)) {
return
}
config.rpc.enable = true
},
},
{
currentError(config) {
if (!matchBitcoindConfig.test(config)) {
return 'Config is not the correct shape'
}
if (!config.advanced.peers.listen) {
return { error: "Must have peer interface enabled" };
return 'Must have peer interface enabled'
}
return
},
fix(config) {
if (!matchBitcoindConfig.test(config)) {
return
}
config.advanced.peers.listen = true
},
},
{
currentError(config) {
if (!matchBitcoindConfig.test(config)) {
return 'Config is not the correct shape'
}
if (config.advanced.pruning.mode !== "disabled") {
return { error: "Pruning must be disabled (must be an archival node)" };
if (config.advanced.pruning.mode !== 'disabled') {
return 'Pruning must be disabled (must be an archival node)'
}
if (config.rpc.advanced.threads < 4) {
return { error: "Must be greater than or equal to 4" };
return
},
fix(config) {
if (!matchBitcoindConfig.test(config)) {
return
}
return { result: null };
config.advanced.pruning.mode = 'disabled'
},
},
]

export const dependencies: T.ExpectedExports.dependencies = {
bitcoind: {
// deno-lint-ignore require-await
async check(effects, configInput) {
effects.info('check bitcoind')
for (const checker of bitcoindChecks) {
const error = checker.currentError(configInput)
if (error) {
effects.error(`throwing error: ${error}`)
return { error }
}
}
return { result: null }
},
// deno-lint-ignore require-await
async autoConfigure(effects, configInput) {
effects.info("autoconfigure bitcoind");
const config = matchBitcoindConfig.unsafeCast(configInput);
config.rpc.enable = true;
config.advanced.peers.listen = true;
config.advanced.pruning.mode = "disabled";
if (config.rpc.advanced.threads < 4) {
config.rpc.advanced.threads = 4;
}
return { result: config };
effects.info('autoconfigure bitcoind')
for (const checker of bitcoindChecks) {
const error = checker.currentError(configInput)
if (error) {
checker.fix(configInput)
}
}
return { result: configInput }
},
},
'bitcoind-testnet': {
// deno-lint-ignore require-await
async check(effects, configInput) {
effects.info('check bitcoind-testnet')
for (const checker of bitcoindChecks) {
const error = checker.currentError(configInput)
if (error) {
effects.error(`throwing error: ${error}`)
return { error }
}
}
return { result: null }
},
// deno-lint-ignore require-await
async autoConfigure(effects, configInput) {
effects.info('autoconfigure bitcoind-testnet')
for (const checker of bitcoindChecks) {
const error = checker.currentError(configInput)
if (error) {
checker.fix(configInput)
}
}
return { result: configInput }
},
},
};
Loading