From 734ee7af439c5a997bfb50b9781a2e4dc99f0cef Mon Sep 17 00:00:00 2001 From: Tim A <41004+takinbo@users.noreply.github.com> Date: Sun, 26 Jan 2025 10:45:59 +0000 Subject: [PATCH 1/3] added testnet4 support and restored btc-rpc-proxy support --- configurator/src/electrs.toml.template | 2 +- configurator/src/main.rs | 58 ++++-- manifest.yaml | 31 +++- scripts/deps.ts | 3 +- scripts/services/dependencies.ts | 235 ++++++++++++++++++++++--- scripts/services/getConfig.ts | 102 +++++++++-- scripts/services/migrations.ts | 48 ++++- scripts/services/setConfig.ts | 23 ++- 8 files changed, 443 insertions(+), 59 deletions(-) diff --git a/configurator/src/electrs.toml.template b/configurator/src/electrs.toml.template index 58754ed..2664cdd 100644 --- a/configurator/src/electrs.toml.template +++ b/configurator/src/electrs.toml.template @@ -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} diff --git a/configurator/src/main.rs b/configurator/src/main.rs index 3661dd6..0269718 100644 --- a/configurator/src/main.rs +++ b/configurator/src/main.rs @@ -1,28 +1,65 @@ 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, index_lookup_limit: Option, } +#[derive(Deserialize)] +#[serde(tag = "type")] +enum BitcoinCoreConfig { + #[serde(rename = "bitcoind")] + Bitcoind { + username: String, + password: String, + }, + #[serde(rename = "bitcoind-proxy")] + BitcoindProxy { + 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::BitcoindProxy { username, password } => { + let hostname = format!("{}", "btc-rpc-proxy.embassy"); + let p2p_hostname = format!("{}", "bitcoind.embassy"); + let network = format!("{}", "bitcoin"); + (username, password, hostname.clone(), 8332, p2p_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!( @@ -42,12 +79,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, diff --git a/manifest.yaml b/manifest.yaml index 6122f8a..93e4326 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -1,7 +1,9 @@ id: electrs title: "electrs" -version: 0.10.8 +version: 0.10.8.1 release-notes: | + * Update electrs-wrapper tag to v0.10.8.1 + * Added support for testnet4 and restored support for btc-rpc-proxy * Update upstream electrs to [v0.10.8](https://github.com/romanz/electrs/blob/master/RELEASE-NOTES.md#0108-dec-30-2024) * Update Rust base Docker image license: mit @@ -78,13 +80,38 @@ dependencies: bitcoind: version: ">=0.21.1.2 <29.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 + btc-rpc-proxy: + version: '>=0.3.2.1 <0.5.0' + requirement: + type: 'opt-in' + how: Set "Bitcoin Core" to "Bitcoin Core" + description: Provides bitcoin rpc interface needed for info about fees, blockchain, mempool, network, and transactions. Can also use bitcoind for rpc interface, or an external node for both. + config: + check: + type: script + auto-configure: + type: script backup: create: type: script diff --git a/scripts/deps.ts b/scripts/deps.ts index ee0dcd8..409c077 100644 --- a/scripts/deps.ts +++ b/scripts/deps.ts @@ -1 +1,2 @@ -export * from "https://deno.land/x/embassyd_sdk@v0.3.3.0.8/mod.ts"; +export * from "https://deno.land/x/embassyd_sdk@v0.3.3.0.11/mod.ts"; +export * from "https://deno.land/x/embassyd_sdk@v0.3.3.0.11/util.ts"; diff --git a/scripts/services/dependencies.ts b/scripts/services/dependencies.ts index 4a13361..fdbe992 100644 --- a/scripts/services/dependencies.ts +++ b/scripts/services/dependencies.ts @@ -1,6 +1,100 @@ import { types as T, matches } from "../deps.ts"; -const { shape, number, boolean, string } = matches; +const { shape, arrayOf, number, boolean, string } = matches; + +const matchProxyConfig = shape({ + users: arrayOf( + shape( + { + name: string, + 'allowed-calls': arrayOf(string), + password: string, + 'fetch-blocks': boolean, + }, + ['fetch-blocks'], + ), + ), +}) + +function times(fn: (i: number) => T, amount: number): T[] { + const answer = new Array(amount) + for (let i = 0; i < amount; i++) { + answer[i] = fn(i) + } + return answer +} + +function randomItemString(input: string) { + return input[Math.floor(Math.random() * input.length)] +} + +const serviceName = 'electrs' +const fullChars = + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' +type Check = { + currentError(config: T.Config): string | void + fix(config: T.Config): void +} + +const proxyChecks: Array = [ + { + currentError(config) { + if (!matchProxyConfig.test(config)) { + return 'Config is not the correct shape' + } + if (config.users.some((x) => x.name === serviceName)) { + return + } + return `Must have an RPC user named "${serviceName}"` + }, + fix(config) { + if (!matchProxyConfig.test(config)) { + return + } + config.users.push({ + name: serviceName, + 'allowed-calls': [], + password: times(() => randomItemString(fullChars), 22).join(''), + }) + }, + }, + ...[ + 'estimatesmartfee', + 'getblockchaininfo', + 'getblockcount', + 'getmempoolentry', + 'getnetworkinfo', + 'getrawmempool', + 'getrawtransaction', + ].map( + (operator): Check => ({ + currentError(config) { + if (!matchProxyConfig.test(config)) { + return 'Config is not the correct shape' + } + if ( + config.users + .find((x) => x.name === serviceName) + ?.['allowed-calls']?.some((x) => x === operator) ?? + false + ) { + return + } + return `RPC user "${serviceName}" must have "${operator}" enabled` + }, + fix(config) { + if (!matchProxyConfig.test(config)) { + throw new Error('Config is not the correct shape') + } + const found = config.users.find((x) => x.name === serviceName) + if (!found) { + throw new Error(`No user ${serviceName} found`) + } + found['allowed-calls'] = [...(found['allowed-calls'] ?? []), operator] + }, + }), + ), +] const matchBitcoindConfig = shape({ rpc: shape({ @@ -19,41 +113,134 @@ 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 = [ + { + 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 = { + 'btc-rpc-proxy': { + // deno-lint-ignore require-await + async check(effects, configInput) { + effects.info('check btc-rpc-proxy') + for (const checker of proxyChecks) { + 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 btc-rpc-proxy') + for (const checker of proxyChecks) { + const error = checker.currentError(configInput) + if (error) { + checker.fix(configInput) + } + } + return { result: configInput } + }, + }, + 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') + 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 } }, }, }; diff --git a/scripts/services/getConfig.ts b/scripts/services/getConfig.ts index 0cd8825..749e33c 100644 --- a/scripts/services/getConfig.ts +++ b/scripts/services/getConfig.ts @@ -10,25 +10,89 @@ export const getConfig: T.ExpectedExports.getConfig = compat.getConfig({ target: "tor-address", interface: "electrum", }, - user: { - type: "pointer", - name: "RPC Username", - description: "The username for Bitcoin Core's RPC interface", - subtype: "package", - "package-id": "bitcoind", - target: "config", - multi: false, - selector: "$.rpc.username", - }, - password: { - type: "pointer", - name: "RPC Password", - description: "The password for Bitcoin Core's RPC interface", - subtype: "package", - "package-id": "bitcoind", - target: "config", - multi: false, - selector: "$.rpc.password", + "bitcoind": { + "type": "union", + "name": "Bitcoin Node", + "description": "The Bitcoin node type you would like to use for electrs", + "tag": { + "id": "type", + "name": "Select Bitcoin Node", + "variant-names": { + "bitcoind": "Bitcoin Core", + "bitcoind-proxy": "Bitcoin Core (proxy)", + "bitcoind-testnet": "Bitcoin Core (testnet4)", + }, + "description": "The Bitcoin node type you would like to use for electrs", + }, + "default": "bitcoind", + "variants": { + "bitcoind": { + "username": { + "type": "pointer", + "name": "RPC Username", + "description": "The username for Bitcoin Core's RPC interface", + "subtype": "package", + "package-id": "bitcoind", + "target": "config", + "multi": false, + "selector": "$.rpc.username", + }, + "password": { + "type": "pointer", + "name": "RPC Password", + "description": "The password for Bitcoin Core's RPC interface", + "subtype": "package", + "package-id": "bitcoind", + "target": "config", + "multi": false, + "selector": "$.rpc.password", + }, + }, + "bitcoind-proxy": { + "username": { + "type": "pointer", + "name": "RPC Username", + "description": "The username for the RPC user allocated to electrs", + "subtype": "package", + "package-id": "btc-rpc-proxy", + "target": "config", + "multi": false, + "selector": "$.users[?(@.name == \"electrs\")].name", + }, + "password": { + "type": "pointer", + "name": "RPC Password", + "description": "The password for the RPC user allocated to electrs", + "subtype": "package", + "package-id": "btc-rpc-proxy", + "target": "config", + "multi": false, + "selector": "$.users[?(@.name == \"electrs\")].password", + }, + }, + "bitcoind-testnet": { + "username": { + "type": "pointer", + "name": "RPC Username", + "description": "The username for Bitcoin Core Testnet RPC interface", + "subtype": "package", + "package-id": "bitcoind-testnet", + "target": "config", + "multi": false, + "selector": "$.rpc.username", + }, + "password": { + "type": "pointer", + "name": "RPC Password", + "description": "The password for Bitcoin Core Testnet RPC interface", + "subtype": "package", + "package-id": "bitcoind-testnet", + "target": "config", + "multi": false, + "selector": "$.rpc.password", + }, + }, + }, }, "log-filters": { type: "enum", diff --git a/scripts/services/migrations.ts b/scripts/services/migrations.ts index ecf222b..757149e 100644 --- a/scripts/services/migrations.ts +++ b/scripts/services/migrations.ts @@ -34,6 +34,52 @@ export const migration: T.ExpectedExports.migration = { version: "0.9.14.2", type: "down" } ), }, + "0.10.8.1": { + up: compat.migrations.updateConfig( + (config: any) => { + switch (config.type) { + case "internal-proxy": + config.type = "bitcoind-proxy"; + break; + default: + config.type = "bitcoind"; + break; + } + config.bitcoind = { + type: config.type, + username: config.user, + password: config.password, + }; + + delete config.user; + delete config.password; + + return config; + }, + true, + { version: "0.10.8.1", type: "up" } + ), + down: compat.migrations.updateConfig( + (config: any) => { + switch (config.bitcoind.type) { + case "bitcoind-proxy": + config.type = "internal-proxy"; + break; + default: + config.type = "internal"; + break; + } + config.user = config.bitcoind.username; + config.password = config.bitcoind.password; + + delete config.bitcoind; + + return config; + }, + true, + { version: "0.10.8.1", type: "down" } + ), + }, }, - "0.10.8" + "0.10.8.1" ); diff --git a/scripts/services/setConfig.ts b/scripts/services/setConfig.ts index 6a0fd1d..df9aa68 100644 --- a/scripts/services/setConfig.ts +++ b/scripts/services/setConfig.ts @@ -1,3 +1,24 @@ import { compat, types as T } from "../deps.ts"; -export const setConfig: T.ExpectedExports.setConfig = compat.setConfig; +// deno-lint-ignore require-await +export const setConfig: T.ExpectedExports.setConfig = async ( + effects: T.Effects, + newConfig: T.Config, +) => { + // deno-lint-ignore no-explicit-any + const dependsOnBitcoind: { [key: string]: string[] } = + (newConfig as any)?.bitcoind?.type === 'bitcoind' + ? { bitcoind: ['synced'] } + : {} + + // deno-lint-ignore no-explicit-any + const dependsOnBitcoindTestnet: { [key: string]: string[] } = + (newConfig as any)?.bitcoind?.type === 'bitcoind-testnet' + ? { 'bitcoind-testnet': ['synced'] } + : {} + + return compat.setConfig(effects, newConfig, { + ...dependsOnBitcoind, + ...dependsOnBitcoindTestnet, + }) +} From c840e31d931220591f8b833b891ee9ea0eaae6ac Mon Sep 17 00:00:00 2001 From: Tim A <41004+takinbo@users.noreply.github.com> Date: Sun, 26 Jan 2025 10:48:01 +0000 Subject: [PATCH 2/3] updated check-synced.sh and copyright notice in LICENSE --- LICENSE | 2 +- check-synced.sh | 35 +++++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/LICENSE b/LICENSE index 599ad42..ec3ecc6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Start9 Labs +Copyright (c) 2025 Start9 Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/check-synced.sh b/check-synced.sh index 96e1aab..99ee9ff 100644 --- a/check-synced.sh +++ b/check-synced.sh @@ -1,17 +1,36 @@ #!/bin/bash +# vim: ts=2 sw=2 sts=2 ai et DURATION=$(&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 @@ -37,7 +56,7 @@ 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 @@ -50,7 +69,7 @@ else #^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="tail -$chk_numlines $log_file" compaction_job=$($tail_log|grep EVENT_LOG|grep "ManualCompaction"|tail -1|cut -d" " -f7) if [ -n "$compaction_job" ] ; then @@ -82,4 +101,4 @@ else exit 61 fi fi -fi \ No newline at end of file +fi From 6589786bb0b69fd29cb94b42a6ac323146544d35 Mon Sep 17 00:00:00 2001 From: Tim A <41004+takinbo@users.noreply.github.com> Date: Wed, 19 Feb 2025 07:30:36 +0000 Subject: [PATCH 3/3] Removed support for btc-rpc-proxy --- .gitignore | 4 +- Makefile | 3 +- check-synced.sh | 13 ++-- configurator/src/main.rs | 11 --- manifest.yaml | 11 --- scripts/services/dependencies.ts | 116 +------------------------------ scripts/services/getConfig.ts | 23 ------ scripts/services/migrations.ts | 20 +----- 8 files changed, 12 insertions(+), 189 deletions(-) diff --git a/.gitignore b/.gitignore index 504133a..446acff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ +.vscode +docker-images electrs.s9pk image.tar scripts/embassy.js -.vscode -docker-images diff --git a/Makefile b/Makefile index 24f8ce8..d778655 100644 --- a/Makefile +++ b/Makefile @@ -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 @@ -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) diff --git a/check-synced.sh b/check-synced.sh index 9492b33..673d183 100644 --- a/check-synced.sh +++ b/check-synced.sh @@ -14,11 +14,6 @@ if [ "$b_type" == "bitcoind-testnet" ]; then b_rpc_port=48332 e_monitoring_port=44224 e_db_path=/data/db/testnet4 -elif [ "$b_type" == "bitcoind-proxy" ]; then - b_host="btc-rpc-proxy.embassy" - b_rpc_port=8332 - e_monitoring_port=4224 - e_db_path=/data/db/bitcoin else b_host="bitcoind.embassy" b_rpc_port=8332 @@ -28,7 +23,7 @@ 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:$b_rpc_port/ 2>&1) error_code=$? @@ -58,18 +53,18 @@ fi #Gather keys/values from prometheus rpc: 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 diff --git a/configurator/src/main.rs b/configurator/src/main.rs index 0269718..799997c 100644 --- a/configurator/src/main.rs +++ b/configurator/src/main.rs @@ -22,11 +22,6 @@ enum BitcoinCoreConfig { username: String, password: String, }, - #[serde(rename = "bitcoind-proxy")] - BitcoindProxy { - username: String, - password: String, - }, #[serde(rename = "bitcoind-testnet")] BitcoindTestnet { username: String, @@ -47,12 +42,6 @@ fn main() -> Result<(), anyhow::Error> { let network = format!("{}", "bitcoin"); (username, password, hostname.clone(), 8332, hostname.clone(), 8333, network.clone()) } - BitcoinCoreConfig::BitcoindProxy { username, password } => { - let hostname = format!("{}", "btc-rpc-proxy.embassy"); - let p2p_hostname = format!("{}", "bitcoind.embassy"); - let network = format!("{}", "bitcoin"); - (username, password, hostname.clone(), 8332, p2p_hostname.clone(), 8333, network.clone()) - } BitcoinCoreConfig::BitcoindTestnet { username, password } => { let hostname = format!("{}", "bitcoind-testnet.embassy"); let network = format!("{}", "testnet4"); diff --git a/manifest.yaml b/manifest.yaml index d272c3b..330ac4f 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -101,17 +101,6 @@ dependencies: auto-configure: type: script requires-runtime-config: true - btc-rpc-proxy: - version: '>=0.3.2.1 <0.5.0' - requirement: - type: 'opt-in' - how: Set "Bitcoin Core" to "Bitcoin Core" - description: Provides bitcoin rpc interface needed for info about fees, blockchain, mempool, network, and transactions. Can also use bitcoind for rpc interface, or an external node for both. - config: - check: - type: script - auto-configure: - type: script backup: create: type: script diff --git a/scripts/services/dependencies.ts b/scripts/services/dependencies.ts index fdbe992..7208e75 100644 --- a/scripts/services/dependencies.ts +++ b/scripts/services/dependencies.ts @@ -1,101 +1,12 @@ import { types as T, matches } from "../deps.ts"; -const { shape, arrayOf, number, boolean, string } = matches; +const { shape, number, boolean, string } = matches; -const matchProxyConfig = shape({ - users: arrayOf( - shape( - { - name: string, - 'allowed-calls': arrayOf(string), - password: string, - 'fetch-blocks': boolean, - }, - ['fetch-blocks'], - ), - ), -}) - -function times(fn: (i: number) => T, amount: number): T[] { - const answer = new Array(amount) - for (let i = 0; i < amount; i++) { - answer[i] = fn(i) - } - return answer -} - -function randomItemString(input: string) { - return input[Math.floor(Math.random() * input.length)] -} - -const serviceName = 'electrs' -const fullChars = - 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' type Check = { currentError(config: T.Config): string | void fix(config: T.Config): void } -const proxyChecks: Array = [ - { - currentError(config) { - if (!matchProxyConfig.test(config)) { - return 'Config is not the correct shape' - } - if (config.users.some((x) => x.name === serviceName)) { - return - } - return `Must have an RPC user named "${serviceName}"` - }, - fix(config) { - if (!matchProxyConfig.test(config)) { - return - } - config.users.push({ - name: serviceName, - 'allowed-calls': [], - password: times(() => randomItemString(fullChars), 22).join(''), - }) - }, - }, - ...[ - 'estimatesmartfee', - 'getblockchaininfo', - 'getblockcount', - 'getmempoolentry', - 'getnetworkinfo', - 'getrawmempool', - 'getrawtransaction', - ].map( - (operator): Check => ({ - currentError(config) { - if (!matchProxyConfig.test(config)) { - return 'Config is not the correct shape' - } - if ( - config.users - .find((x) => x.name === serviceName) - ?.['allowed-calls']?.some((x) => x === operator) ?? - false - ) { - return - } - return `RPC user "${serviceName}" must have "${operator}" enabled` - }, - fix(config) { - if (!matchProxyConfig.test(config)) { - throw new Error('Config is not the correct shape') - } - const found = config.users.find((x) => x.name === serviceName) - if (!found) { - throw new Error(`No user ${serviceName} found`) - } - found['allowed-calls'] = [...(found['allowed-calls'] ?? []), operator] - }, - }), - ), -] - const matchBitcoindConfig = shape({ rpc: shape({ enable: boolean, @@ -168,31 +79,6 @@ const bitcoindChecks: Array = [ ] export const dependencies: T.ExpectedExports.dependencies = { - 'btc-rpc-proxy': { - // deno-lint-ignore require-await - async check(effects, configInput) { - effects.info('check btc-rpc-proxy') - for (const checker of proxyChecks) { - 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 btc-rpc-proxy') - for (const checker of proxyChecks) { - const error = checker.currentError(configInput) - if (error) { - checker.fix(configInput) - } - } - return { result: configInput } - }, - }, bitcoind: { // deno-lint-ignore require-await async check(effects, configInput) { diff --git a/scripts/services/getConfig.ts b/scripts/services/getConfig.ts index 749e33c..7a301b1 100644 --- a/scripts/services/getConfig.ts +++ b/scripts/services/getConfig.ts @@ -19,7 +19,6 @@ export const getConfig: T.ExpectedExports.getConfig = compat.getConfig({ "name": "Select Bitcoin Node", "variant-names": { "bitcoind": "Bitcoin Core", - "bitcoind-proxy": "Bitcoin Core (proxy)", "bitcoind-testnet": "Bitcoin Core (testnet4)", }, "description": "The Bitcoin node type you would like to use for electrs", @@ -48,28 +47,6 @@ export const getConfig: T.ExpectedExports.getConfig = compat.getConfig({ "selector": "$.rpc.password", }, }, - "bitcoind-proxy": { - "username": { - "type": "pointer", - "name": "RPC Username", - "description": "The username for the RPC user allocated to electrs", - "subtype": "package", - "package-id": "btc-rpc-proxy", - "target": "config", - "multi": false, - "selector": "$.users[?(@.name == \"electrs\")].name", - }, - "password": { - "type": "pointer", - "name": "RPC Password", - "description": "The password for the RPC user allocated to electrs", - "subtype": "package", - "package-id": "btc-rpc-proxy", - "target": "config", - "multi": false, - "selector": "$.users[?(@.name == \"electrs\")].password", - }, - }, "bitcoind-testnet": { "username": { "type": "pointer", diff --git a/scripts/services/migrations.ts b/scripts/services/migrations.ts index 8bd85cc..4e5139f 100644 --- a/scripts/services/migrations.ts +++ b/scripts/services/migrations.ts @@ -37,22 +37,15 @@ export const migration: T.ExpectedExports.migration = "0.10.8.1": { up: compat.migrations.updateConfig( (config: any) => { - switch (config.type) { - case "internal-proxy": - config.type = "bitcoind-proxy"; - break; - default: - config.type = "bitcoind"; - break; - } config.bitcoind = { - type: config.type, + type: "bitcoind", username: config.user, password: config.password, }; delete config.user; delete config.password; + delete config.type; return config; }, @@ -61,14 +54,7 @@ export const migration: T.ExpectedExports.migration = ), down: compat.migrations.updateConfig( (config: any) => { - switch (config.bitcoind.type) { - case "bitcoind-proxy": - config.type = "internal-proxy"; - break; - default: - config.type = "internal"; - break; - } + config.type = config.bitcoind.type; config.user = config.bitcoind.username; config.password = config.bitcoind.password;