diff --git a/.gitignore b/.gitignore index 91a1346..3b25710 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ manager/target/ **/*.rs.bk bitcoind.s9pk image.tar -.vscode/ \ No newline at end of file +.vscode/ +scripts/embassy.js \ No newline at end of file diff --git a/Makefile b/Makefile index d1d0e09..9637ac2 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ clean: rm bitcoind.s9pk rm image.tar -bitcoind.s9pk: manifest.yaml assets/compat/* image.tar instructions.md $(ASSET_PATHS) +bitcoind.s9pk: manifest.yaml assets/compat/* image.tar instructions.md scripts/embassy.js embassy-sdk pack verify: bitcoind.s9pk diff --git a/assets/compat/bitcoin.conf.template b/assets/compat/bitcoin.conf.template index ac0119e..1fffdde 100644 --- a/assets/compat/bitcoin.conf.template +++ b/assets/compat/bitcoin.conf.template @@ -101,7 +101,10 @@ discardfee={{wallet.discardfee}} ## ZERO MQ {{#IF zmq-enabled zmqpubrawblock=tcp://0.0.0.0:28332 +zmqpubhashblock=tcp://0.0.0.0:28332 zmqpubrawtx=tcp://0.0.0.0:28333 +zmqpubhashtx=tcp://0.0.0.0:28333 +zmqpubsequence=tcp://0.0.0.0:28333 }} ## TXINDEX diff --git a/assets/compat/config-set.sh b/assets/compat/config-set.sh deleted file mode 100755 index 6b6d69e..0000000 --- a/assets/compat/config-set.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# The general approach here is to diff the old and new configs and if there is a "relevant" change to pruning, defined -# as an extension of retained data, we should start with the reindex process -DATA_DIR=/root/.bitcoin - -# gather old info -cp $DATA_DIR/start9/config.yaml $DATA_DIR/start9/config-old.yaml -OLD_PRUNING_TL=$(cat $DATA_DIR/start9/config-old.yaml | grep -A2 "pruning" | tail -n 2 | head -n 1 | cut -d ':' -f 2 | tr -d ' ') -if [ "$OLD_PRUNING_TL" != "disabled" ] -then - OLD_PRUNING_SIZE=$(cat $DATA_DIR/start9/config-old.yaml | grep -A2 pruning | tail -n 1 | cut -d ':' -f 2 | tr -d ' ') -fi - -# set new config -COMPAT_RES=$(compat config set bitcoind /root/.bitcoin /mnt/assets/config_rules.yaml) - -# gather new info -NEW_PRUNING_TL=$(cat $DATA_DIR/start9/config.yaml | grep -A2 "pruning" | tail -n 2 | head -n 1 | cut -d ':' -f 2 | tr -d ' ') -if [ "$NEW_PRUNING_TL" != "disabled" ] -then - NEW_PRUNING_SIZE=$(cat $DATA_DIR/start9/config.yaml | grep -A2 pruning | tail -n 1 | cut -d ':' -f 2 | tr -d ' ') -fi - -# if the old prune config was disabled, no action required -# also do nothing if there was no previous config. this allows bootstrapping a pruned node from a non-embassy-os source such as prunednode.today -if [ "$OLD_PRUNING_TL" = "disabled" ] || [ -z "$OLD_PRUNING_TL" ] -then - >&2 echo No reindex required -# if they are the same, and the new prune cache size is reduced, no action required -elif [ "$OLD_PRUNING_TL" = "$NEW_PRUNING_TL" ] && [ "$OLD_PRUNING_SIZE" -ge "$NEW_PRUNING_SIZE" ] -then - >&2 echo No reindex required -else - >&2 echo Reindex required - touch $DATA_DIR/requires.reindex -fi -echo "$COMPAT_RES" diff --git a/assets/compat/config_rules.yaml b/assets/compat/config_rules.yaml deleted file mode 100644 index 52d486b..0000000 --- a/assets/compat/config_rules.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- rule: 'rpc.enable? OR !(''advanced.pruning.mode = "manual")' - description: "RPC must be enabled for manual pruning." -- rule: '!(txindex?) OR ''advanced.pruning.mode = "disabled"' - description: "Txindex not allowed on pruned nodes." -- rule: "!(advanced.blockfilters.peerblockfilters?) OR advanced.blockfilters.blockfilterindex?" - description: "'Compute Compact Block Filters' must be enabled if 'Serve Comopact Block Filters to Peers' is enabled." diff --git a/assets/compat/config_spec.yaml b/assets/compat/config_spec.yaml deleted file mode 100644 index b2fe391..0000000 --- a/assets/compat/config_spec.yaml +++ /dev/null @@ -1,314 +0,0 @@ -peer-tor-address: - name: Peer Tor Address - description: The Tor address of the peer interface - type: pointer - subtype: package - package-id: bitcoind - target: tor-address - interface: peer -rpc-tor-address: - name: RPC Tor Address - description: The Tor address of the RPC interface - type: pointer - subtype: package - package-id: bitcoind - target: tor-address - interface: rpc -rpc: - type: object - nullable: false - name: "RPC Settings" - description: "RPC configuration options." - spec: - enable: - type: boolean - name: "Enable" - description: "Allow remote RPC requests." - default: true - username: - type: string - nullable: false - name: "Username" - description: "The username for connecting to Bitcoin over RPC." - default: "bitcoin" - masked: true - pattern: "^[a-zA-Z0-9_]+$" - pattern-description: "Must be alphanumeric (can contain underscore)." - password: - type: string - nullable: false - name: "RPC Password" - description: "The password for connecting to Bitcoin over RPC." - default: - charset: "a-z,2-7" - len: 20 - pattern: '^[^\n"]*$' - pattern-description: "Must not contain newline or quote characters." - copyable: true - masked: true - advanced: - type: object - nullable: false - name: "Advanced" - description: "Advanced RPC Settings" - spec: - auth: - name: Authorization - description: >- - Username and hashed password for JSON-RPC connections. - RPC clients connect using the usual http basic authentication. - type: list - subtype: string - default: [] - spec: - pattern: "^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$" - pattern-description: 'Each item must be of the form ":$".' - range: "[0,*)" - serialversion: - name: Serialization Version - description: Return raw transaction or block hex with Segwit or non-SegWit serialization. - type: enum - values: - - non-segwit - - segwit - default: segwit - servertimeout: - name: Rpc Server Timeout - description: Number of seconds after which an uncompleted RPC call will time out. - type: number - nullable: false - range: "[5,300]" - integral: true - units: seconds - default: 30 - threads: - name: Threads - description: Set the number of threads for handling RPC calls. Only needed if you plan to abuse your node. - type: number - nullable: false - default: 4 - range: "[1,64]" - integral: true - units: ~ - workqueue: - name: Work Queue - description: Set the depth of the work queue to service RPC calls. Determines how long the backlog of RPC requests can get before it just rejects new ones. - type: number - nullable: false - default: 128 - range: "[8,256]" - integral: true - units: requests -zmq-enabled: - type: boolean - name: ZeroMQ Enabled - description: Enable the ZeroMQ interface - default: true -txindex: - type: boolean - name: Transaction Index - description: Enable the Transaction Index (txindex) - default: false -wallet: - type: object - nullable: false - name: "Wallet" - description: "Wallet Settings" - spec: - enable: - name: Enable Wallet - description: Load the wallet and enable wallet RPC calls. - type: boolean - default: true - avoidpartialspends: - name: Avoid Partial Spends - description: >- - Group outputs by address, selecting all or none, instead of selecting on a - per-output basis. This improves privacy at the expense of higher transaction - fees. - type: boolean - default: true - discardfee: - name: Discard Change Tolerance - description: >- - The fee rate (in BTC/kB) that indicates your tolerance - for discarding change by adding it to the fee. - type: number - nullable: false - default: 0.0001 - range: "[0,.01]" - integral: false - units: BTC/kB -advanced: - type: object - nullable: false - name: "Advanced" - description: "Advanced Settings" - spec: - mempool: - type: object - nullable: false - name: "Mempool" - description: "Mempool Settings" - spec: - persistmempool: - type: boolean - name: "Persist Mempool" - description: "Save the mempool on shutdown and load on restart." - default: true - maxmempool: - type: number - nullable: false - name: "Max Mempool Size" - description: "Keep the transaction memory pool below megabytes." - range: "[1,*)" - integral: true - units: MiB - default: 300 - mempoolexpiry: - type: number - nullable: false - name: "Mempool Expiration" - description: "Do not keep transactions in the mempool longer than hours." - range: "[1,*)" - integral: true - units: Hr - default: 336 - peers: - type: object - nullable: false - name: "Peers" - description: "Peer Connection Settings" - spec: - listen: - type: boolean - name: "Make Public" - description: "Allow other nodes to find your server on the network." - default: true - onlyconnect: - type: boolean - name: Disable Peer Discovery - description: Only connect to specified peers. - default: false - onlyonion: - type: boolean - name: Disable Clearnet - description: Only connect to peers over Tor. - default: false - addnode: - name: Add Nodes - description: Add addresses of nodes to connect to. - type: list - subtype: object - range: "[0,*)" - default: [] - spec: - type: object - nullable: false - name: "Peer" - description: "Peer to connect to" - spec: - hostname: - type: string - nullable: false - name: "Hostname" - description: "Domain or IP address of bitcoin peer" - pattern: "(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))" - pattern-description: Must be either a domain name, or an IPv4 or IPv6 address. Do not include protocol scheme (eg 'http://') or port. - port: - type: number - nullable: true - name: "Port" - description: "Port that peer is listening on for inbound p2p connections" - range: "[0,65535]" - integral: true - dbcache: - type: number - nullable: true - name: "Database Cache" - description: "How much RAM to allocate for caching the TXO set. Higher values improve syncing performance, but increase your chance of using up all your system's memory or corrupting your database in the event of an ungraceful shutdown. Set this high but comfortably below your system's total RAM during IBD, then turn down to 450 (or leave blank) once the sync completes." - warning: "WARNING: Increasing this value results in a higher chance of ungraceful shutdowns, which can leave your node unusable if it happens during the initial block download. Use this setting with caution. Be sure to set this back to the default (450 or leave blank) once your node is synced." - range: "(0,1024]" - integral: true - units: MiB - pruning: - type: union - name: "Pruning Settings" - description: | - Blockchain Pruning Options - Reduce the blockchain size on disk - warning: | - If you set pruning to Manual and your disk is smaller than the total size of the blockchain, you MUST have something running that prunes these blocks or you may overfill your disk! - Disabling pruning will convert your node into a full archival node. This requires a resync of the entire blockchain, a process that may take several days. Make sure you have enough free disk space or you may fill up your disk. - tag: - id: mode - name: Pruning Mode - description: | - - Disabled: Disable pruning - - Automatic: Limit blockchain size on disk to a certain number of megabytes - - Manual: Prune blockchain with the "pruneblockchain" RPC - variant-names: - disabled: Disabled - automatic: Automatic - manual: Manual - variants: - disabled: {} - automatic: - size: - type: number - nullable: false - name: "Max Chain Size" - description: "Limit of blockchain size on disk." - warning: "Increasing this value will require re-syncing your node." - default: 550 - range: "[550,1000000)" - integral: true - units: MiB - manual: - size: - type: number - nullable: false - name: "Failsafe Chain Size" - description: "Prune blockchain if size expands beyond this." - default: 65536 - range: "[550,1000000)" - integral: true - units: MiB - default: disabled - blockfilters: - type: object - nullable: false - name: "Block Filters" - description: "Settings for storing and serving compact block filters" - spec: - blockfilterindex: - type: boolean - name: "Compute Compact Block Filters (BIP158)" - description: >- - Generate Compact Block Filters during initial sync (IBD) to enable 'getblockfilter' RPC. This is useful if - dependent services need block filters to efficiently scan for addresses/transactions etc. - default: false - peerblockfilters: - type: boolean - name: "Serve Compact Block Filters to Peers (BIP157)" - description: >- - Serve Compact Block Filters as a peer service to other nodes on the network. This is useful if you wish to - connect an SPV client to your node to make it efficient to scan transactions without having to download all - block data. - default: false - bloomfilters: - type: object - nullable: false - name: "Bloom Filters (BIP37)" - description: "Setting for serving Bloom Filters" - spec: - peerbloomfilters: - type: boolean - name: "Serve Bloom Filters to Peers" - description: >- - Peers have the option of setting filters on each connection they make after the version handshake has completed. - Bloom filters are for clients implementing SPV (Simplified Pament Verification) that want to check that block headers - connect together correctly, without needing to verify the full blockchain. The client must trust that the transactions - in the chain are in fact valid. It is highly recommended AGAINST using for anything except Bisq integration. - warning: "This is ONLY for use with Bisq integration, please use Block Filters for all other applications." - default: false \ No newline at end of file diff --git a/docs/instructions.md b/docs/instructions.md index 7d221a2..9e56668 100644 --- a/docs/instructions.md +++ b/docs/instructions.md @@ -12,12 +12,12 @@ Depending on your Internet bandwidth, how many other services are running, and w ### Using a Wallet -Enter your QuickConnect QR code **OR** your raw RPC credentials (both located in `Properties`) into any wallet that supports connecting to a remote node over Tor. For a full list of compatible wallets, see https://github.com/start9labs/bitcoind-wrapper/blob/master/docs/wallets.md. +Enter your QuickConnect QR code **OR** your raw RPC credentials (both located in `Properties`) into any wallet that supports connecting to a remote node over Tor. For a full list of compatible wallets, as well as guides for setup, please see https://github.com/start9labs/bitcoind-wrapper/blob/master/docs/wallets.md. ## Pruning -Beginning in EOS v0.3.0, Bitcoin is now set to be an "archival" node by default. This means that it will download and verify the entire blockchain, and will not "prune." Be aware that this takes approximately 400GB as of early 2022. +Beginning in EOS v0.3.0, Bitcoin is now set to be an "archival" node by default. This means that it will download and verify the entire blockchain, and will not "prune." Be aware that this takes approximately 400GB as of early 2022. If you enable the `txindex,` this will require an additional ~40GB. -Pruning is a process by which your node discards old blocks and transactions after it verifies them. Pruned nodes and archival nodes are both "full nodes" in that they are fully validating - they validate every block and transaction. Archival nodes store the entire blockchain and are useful to people interested in doing general or historical analysis, or being a provider of blockchain data to others (eg. a blockexplorer). They are also required for the best experience with many popular wallets. +Pruning is a process by which your node discards old blocks and transactions after it verifies them. Pruned nodes and archival nodes are both "full nodes" in that they are fully validating - they validate every block and transaction. Archival nodes store the entire blockchain and are useful to people interested in doing general or historical analysis, or being a provider of blockchain data to others (eg. a blockexplorer). They are also required for the best experience with many popular wallets and other Bitcoin tools. **If you choose to prune**, the target on your Embassy is configurable and set by default to the minimum of 550MB (0.55 GB!), meaning the resulting blockchain will occupy a negligible amount of storage space. The maximum amount of blockchain data you can retain depends on the storage capacity your device. The config menu will not permit you to select a target that exceeds a certain percentage of your device's available capacity. For most use cases, we recommend sticking with a very low pruning setting. diff --git a/manager/.gitignore b/manager/.gitignore index 53eaa21..4cd3977 100644 --- a/manager/.gitignore +++ b/manager/.gitignore @@ -1,2 +1,3 @@ /target **/*.rs.bk +scripts/embassy.ts \ No newline at end of file diff --git a/manifest.yaml b/manifest.yaml index 1088fab..7386db2 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -1,11 +1,16 @@ id: bitcoind title: "Bitcoin Core" version: 23.0.0 +eos-version: 0.3.1 release-notes: | * Latest release from Core - see full release notes at https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-23.0.md * Embassy changes * Add support for Bloom Filters (BIP37), as required for Bisq integration - * It is highly recommended AGAINST using Bloom Filters for anything except Bisq integration. + * Increased options for RPC resources (Config -> RPC Settings -> Advanced) + * Implement additional ZMQ interfaces, for use with future Layer 2 integrations + * `zmqpubhashblock` + * `zmqpubhashtx` + * `zmqpubsequence` license: mit wrapper-repo: https://github.com/Start9Labs/bitcoind-wrapper upstream-repo: https://github.com/bitcoin/bitcoin @@ -55,40 +60,11 @@ health-checks: inject: true config: get: - type: docker - image: compat - system: true - entrypoint: compat - args: - - config - - get - - /root/.bitcoin - - "/mnt/assets/config_spec.yaml" - mounts: - compat: /mnt/assets - main: /root/.bitcoin - io-format: yaml + type: script set: - type: docker - image: compat - system: true - entrypoint: /mnt/assets/config-set.sh - args: [] - mounts: - compat: /mnt/assets - main: "/root/.bitcoin" - io-format: yaml + type: script properties: - type: docker - image: compat - system: true - entrypoint: compat - args: - - properties - - /root/.bitcoin - mounts: - main: /root/.bitcoin - io-format: yaml + type: script volumes: main: type: data @@ -191,11 +167,11 @@ migrations: mounts: main: /root/.bitcoin inject: false - "=22.0.0": + ">22.0.0 <23.0.0": type: docker image: main system: false - entrypoint: /usr/local/bin/migrations/eq_22_0_0.sh + entrypoint: /usr/local/bin/migrations/gt_22_0_0_lt_23_0_0.sh args: ["from"] io-format: json mounts: @@ -222,11 +198,11 @@ migrations: mounts: main: /root/.bitcoin inject: false - "=22.0.0": + ">22.0.0 <23.0.0": type: docker image: main system: false - entrypoint: /usr/local/bin/migrations/eq_22_0_0.sh + entrypoint: /usr/local/bin/migrations/gt_22_0_0_lt_23_0_0.sh args: ["to"] io-format: json mounts: diff --git a/migrations/eq_22_0_0.sh b/migrations/eq_22_0_0.sh deleted file mode 100644 index 7e63920..0000000 --- a/migrations/eq_22_0_0.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -ea - -if [ $1 = "from" ]; then - yq -i '.advanced.peers.addnode |= map(select(.hostname != ~))' /root/.bitcoin/start9/config.yaml - yq -i '.advanced.bloomfilters.peerbloomfilters = false' /root/.bitcoin/start9/config.yaml - echo '{"configured": true }' - exit 0 -elif [ $1 = "to" ]; then - yq -i 'del(.advanced.bloomfilters)' /root/.bitcoin/start9/config.yaml - echo '{"configured": false }' - exit 0 -else - echo "FATAL: Invalid argument: {from, to}. Migration failed." >&2 - exit 1 -fi diff --git a/scripts/dependencies.ts b/scripts/dependencies.ts new file mode 100644 index 0000000..a180103 --- /dev/null +++ b/scripts/dependencies.ts @@ -0,0 +1 @@ +export * from "https://deno.land/x/embassyd_sdk@v0.3.1.0.3/mod.ts"; diff --git a/scripts/embassy.ts b/scripts/embassy.ts new file mode 100644 index 0000000..2106562 --- /dev/null +++ b/scripts/embassy.ts @@ -0,0 +1,4 @@ +// @ts-check +export { setConfig } from "./services/setConfig.ts"; +export { properties } from "./services/properties.ts"; +export { getConfig } from "./services/getConfig.ts"; diff --git a/scripts/services/getConfig.ts b/scripts/services/getConfig.ts new file mode 100644 index 0000000..b440274 --- /dev/null +++ b/scripts/services/getConfig.ts @@ -0,0 +1,370 @@ +import { compat, types as T } from "../dependencies.ts"; + +export const getConfig: T.ExpectedExports.getConfig = compat.getConfig({ + "peer-tor-address": { + "name": "Peer Tor Address", + "description": "The Tor address of the peer interface", + "type": "pointer", + "subtype": "package", + "package-id": "bitcoind", + "target": "tor-address", + "interface": "peer", + }, + "rpc-tor-address": { + "name": "RPC Tor Address", + "description": "The Tor address of the RPC interface", + "type": "pointer", + "subtype": "package", + "package-id": "bitcoind", + "target": "tor-address", + "interface": "rpc", + }, + "rpc": { + "type": "object", + "name": "RPC Settings", + "description": "RPC configuration options.", + "spec": { + "enable": { + "type": "boolean", + "name": "Enable", + "description": "Allow remote RPC requests.", + "default": true, + }, + "username": { + "type": "string", + "nullable": false, + "name": "Username", + "description": "The username for connecting to Bitcoin over RPC.", + "default": "bitcoin", + "masked": true, + "pattern": "^[a-zA-Z0-9_]+$", + "pattern-description": + "Must be alphanumeric (can contain underscore).", + }, + "password": { + "type": "string", + "nullable": false, + "name": "RPC Password", + "description": "The password for connecting to Bitcoin over RPC.", + "default": { + "charset": "a-z,2-7", + "len": 20, + }, + "pattern": '^[^\\n"]*$', + "pattern-description": + "Must not contain newline or quote characters.", + "copyable": true, + "masked": true, + }, + "advanced": { + "type": "object", + "name": "Advanced", + "description": "Advanced RPC Settings", + "spec": { + "auth": { + "name": "Authorization", + "description": + "Username and hashed password for JSON-RPC connections. RPC clients connect using the usual http basic authentication.", + "type": "list", + "subtype": "string", + "default": [], + "spec": { + "pattern": + "^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$", + "pattern-description": + 'Each item must be of the form ":$".', + }, + "range": "[0,*)", + }, + "serialversion": { + "name": "Serialization Version", + "description": + "Return raw transaction or block hex with Segwit or non-SegWit serialization.", + "type": "enum", + "values": [ + "non-segwit", + "segwit", + ], + "value-names": {}, + "default": "segwit", + }, + "servertimeout": { + "name": "Rpc Server Timeout", + "description": + "Number of seconds after which an uncompleted RPC call will time out.", + "type": "number", + "nullable": false, + "range": "[5,300]", + "integral": true, + "units": "seconds", + "default": 30, + }, + "threads": { + "name": "Threads", + "description": + "Set the number of threads for handling RPC calls. Only needed if you plan to abuse your node.", + "type": "number", + "nullable": false, + "default": 4, + "range": "[1,64]", + "integral": true, + "units": undefined, + }, + "workqueue": { + "name": "Work Queue", + "description": + "Set the depth of the work queue to service RPC calls. Determines how long the backlog of RPC requests can get before it just rejects new ones.", + "type": "number", + "nullable": false, + "default": 128, + "range": "[8,256]", + "integral": true, + "units": "requests", + }, + }, + }, + }, + }, + "zmq-enabled": { + "type": "boolean", + "name": "ZeroMQ Enabled", + "description": "Enable the ZeroMQ interface", + "default": true, + }, + "txindex": { + "type": "boolean", + "name": "Transaction Index", + "description": "Enable the Transaction Index (txindex)", + "default": false, + }, + "wallet": { + "type": "object", + "name": "Wallet", + "description": "Wallet Settings", + "spec": { + "enable": { + "name": "Enable Wallet", + "description": "Load the wallet and enable wallet RPC calls.", + "type": "boolean", + "default": true, + }, + "avoidpartialspends": { + "name": "Avoid Partial Spends", + "description": + "Group outputs by address, selecting all or none, instead of selecting on a per-output basis. This improves privacy at the expense of higher transaction fees.", + "type": "boolean", + "default": true, + }, + "discardfee": { + "name": "Discard Change Tolerance", + "description": + "The fee rate (in BTC/kB) that indicates your tolerance for discarding change by adding it to the fee.", + "type": "number", + "nullable": false, + "default": 0.0001, + "range": "[0,.01]", + "integral": false, + "units": "BTC/kB", + }, + }, + }, + "advanced": { + "type": "object", + "name": "Advanced", + "description": "Advanced Settings", + "spec": { + "mempool": { + "type": "object", + "name": "Mempool", + "description": "Mempool Settings", + "spec": { + "persistmempool": { + "type": "boolean", + "name": "Persist Mempool", + "description": + "Save the mempool on shutdown and load on restart.", + "default": true, + }, + "maxmempool": { + "type": "number", + "nullable": false, + "name": "Max Mempool Size", + "description": + "Keep the transaction memory pool below megabytes.", + "range": "[1,*)", + "integral": true, + "units": "MiB", + "default": 300, + }, + "mempoolexpiry": { + "type": "number", + "nullable": false, + "name": "Mempool Expiration", + "description": + "Do not keep transactions in the mempool longer than hours.", + "range": "[1,*)", + "integral": true, + "units": "Hr", + "default": 336, + }, + }, + }, + "peers": { + "type": "object", + "name": "Peers", + "description": "Peer Connection Settings", + "spec": { + "listen": { + "type": "boolean", + "name": "Make Public", + "description": + "Allow other nodes to find your server on the network.", + "default": true, + }, + "onlyconnect": { + "type": "boolean", + "name": "Disable Peer Discovery", + "description": "Only connect to specified peers.", + "default": false, + }, + "onlyonion": { + "type": "boolean", + "name": "Disable Clearnet", + "description": "Only connect to peers over Tor.", + "default": false, + }, + "addnode": { + "name": "Add Nodes", + "description": "Add addresses of nodes to connect to.", + "type": "list", + "subtype": "object", + "range": "[0,*)", + "default": [], + "spec": { + "spec": { + "hostname": { + "type": "string", + "nullable": false, + "name": "Hostname", + "description": "Domain or IP address of bitcoin peer", + "pattern": + "(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))", + "pattern-description": + "Must be either a domain name, or an IPv4 or IPv6 address. Do not include protocol scheme (eg 'http://') or port.", + }, + "port": { + "type": "number", + "nullable": true, + "name": "Port", + "description": + "Port that peer is listening on for inbound p2p connections", + "range": "[0,65535]", + "integral": true, + }, + }, + }, + }, + }, + }, + "dbcache": { + "type": "number", + "nullable": true, + "name": "Database Cache", + "description": + "How much RAM to allocate for caching the TXO set. Higher values improve syncing performance, but increase your chance of using up all your system's memory or corrupting your database in the event of an ungraceful shutdown. Set this high but comfortably below your system's total RAM during IBD, then turn down to 450 (or leave blank) once the sync completes.", + "warning": + "WARNING: Increasing this value results in a higher chance of ungraceful shutdowns, which can leave your node unusable if it happens during the initial block download. Use this setting with caution. Be sure to set this back to the default (450 or leave blank) once your node is synced.", + "range": "(0,1024]", + "integral": true, + "units": "MiB", + }, + "pruning": { + "type": "union", + "name": "Pruning Settings", + "description": + "Blockchain Pruning Options\nReduce the blockchain size on disk\n", + "warning": + "If you set pruning to Manual and your disk is smaller than the total size of the blockchain, you MUST have something running that prunes these blocks or you may overfill your disk!\nDisabling pruning will convert your node into a full archival node. This requires a resync of the entire blockchain, a process that may take several days. Make sure you have enough free disk space or you may fill up your disk.\n", + "tag": { + "id": "mode", + "name": "Pruning Mode", + "description": + '- Disabled: Disable pruning\n- Automatic: Limit blockchain size on disk to a certain number of megabytes\n- Manual: Prune blockchain with the "pruneblockchain" RPC\n', + "variant-names": { + "disabled": "Disabled", + "automatic": "Automatic", + "manual": "Manual", + }, + }, + "variants": { + "disabled": {}, + "automatic": { + "size": { + "type": "number", + "nullable": false, + "name": "Max Chain Size", + "description": "Limit of blockchain size on disk.", + "warning": + "Increasing this value will require re-syncing your node.", + "default": 550, + "range": "[550,1000000)", + "integral": true, + "units": "MiB", + }, + }, + "manual": { + "size": { + "type": "number", + "nullable": false, + "name": "Failsafe Chain Size", + "description": "Prune blockchain if size expands beyond this.", + "default": 65536, + "range": "[550,1000000)", + "integral": true, + "units": "MiB", + }, + }, + }, + "default": "disabled", + }, + "blockfilters": { + "type": "object", + "name": "Block Filters", + "description": + "Settings for storing and serving compact block filters", + "spec": { + "blockfilterindex": { + "type": "boolean", + "name": "Compute Compact Block Filters (BIP158)", + "description": + "Generate Compact Block Filters during initial sync (IBD) to enable 'getblockfilter' RPC. This is useful if dependent services need block filters to efficiently scan for addresses/transactions etc.", + "default": false, + }, + "peerblockfilters": { + "type": "boolean", + "name": "Serve Compact Block Filters to Peers (BIP157)", + "description": + "Serve Compact Block Filters as a peer service to other nodes on the network. This is useful if you wish to connect an SPV client to your node to make it efficient to scan transactions without having to download all block data. 'Compute Compact Block Filters (BIP158)' is required.", + "default": false, + }, + }, + }, + "bloomfilters": { + "type": "object", + "name": "Bloom Filters (BIP37)", + "description": "Setting for serving Bloom Filters", + "spec": { + "peerbloomfilters": { + "type": "boolean", + "name": "Serve Bloom Filters to Peers", + "description": + "Peers have the option of setting filters on each connection they make after the version handshake has completed. Bloom filters are for clients implementing SPV (Simplified Payment Verification) that want to check that block headers connect together correctly, without needing to verify the full blockchain. The client must trust that the transactions in the chain are in fact valid. It is highly recommended AGAINST using for anything except Bisq integration.", + "warning": + "This is ONLY for use with Bisq integration, please use Block Filters for all other applications.", + "default": false, + }, + }, + }, + }, + }, +}) \ No newline at end of file diff --git a/scripts/services/properties.ts b/scripts/services/properties.ts new file mode 100644 index 0000000..9774199 --- /dev/null +++ b/scripts/services/properties.ts @@ -0,0 +1,2 @@ +import { compat } from "../dependencies.ts"; +export const properties = compat.properties \ No newline at end of file diff --git a/scripts/services/setConfig.ts b/scripts/services/setConfig.ts new file mode 100644 index 0000000..71efb7d --- /dev/null +++ b/scripts/services/setConfig.ts @@ -0,0 +1,96 @@ +import { + matches, + compat, + types, + YAML +} from "../dependencies.ts"; +const { number, shape, boolean } = matches; + +export const setConfig: types.ExpectedExports.setConfig = async ( + effects: types.Effects, + // deno-lint-ignore no-explicit-any + newConfig: any, +) => { + if (!(newConfig?.rpc?.enable || !(newConfig.advanced?.mode === "manual"))) { + return { + error: "RPC must be enabled for manual.", + }; + } + 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)) + ) { + return { + error: + "'Compute Compact Block Filters' must be enabled if 'Serve Compact Block Filters to Peers' is enabled.", + }; + } + + await effects.createDir({ + path: "start9", + volumeId: "main", + }); + + // config-set.sh + + const oldConfig = await effects.readFile({ + path: "start9/config.yaml", + volumeId: "main", + }).catch(() => null); + if (oldConfig) { + await effects.writeFile({ + path: "start9/config-old.yaml", + toWrite: oldConfig, + volumeId: "main", + }); + const oldConfigParsed = YAML.parse(oldConfig) as any; + const oldPruningTl = oldConfigParsed?.advanced?.pruning?.mode; + let oldPruningSize = 0; + if (oldPruningTl !== "disabled") { + oldPruningSize = number.unsafeCast( + oldConfigParsed?.advanced?.pruning?.size, + ); + } + const newPruningTl = newConfig.advanced.pruning.mode; + let newPruningSize = 0; + if (newPruningTl !== "disabled") { + newPruningSize = number.unsafeCast(newConfig?.advanced?.pruning?.size); + } + if (oldPruningTl == "disabled" || !oldPruningTl) { + effects.debug("No reindex required"); + } else if ( + oldPruningTl === newPruningTl && oldPruningSize >= newPruningSize + ) { + effects.debug("No reindex required"); + } else { + effects.debug("Reindex required"); + await effects.writeFile({ + path: "start9/requires.reindex", + toWrite: "", + volumeId: "main", + }); + } + } else { + effects.debug("No reindex required"); + } + + await effects.writeFile({ + path: "start9/config.yaml", + toWrite: YAML.stringify(newConfig), + volumeId: "main", + }); + + const result: types.SetResult = { + signal: "SIGTERM", + "depends-on": {}, + }; + return { result }; +};