diff --git a/components/clarinet-cli/src/chainhooks/mod.rs b/components/clarinet-cli/src/chainhooks/mod.rs index bfcc30495..2e2887a43 100644 --- a/components/clarinet-cli/src/chainhooks/mod.rs +++ b/components/clarinet-cli/src/chainhooks/mod.rs @@ -4,7 +4,9 @@ use std::path::PathBuf; pub mod types; use crate::chainhooks::types::ChainhookSpecificationFile; -use chainhook_event_observer::chainhooks::types::{ChainhookConfig, ChainhookSpecification}; +use stacks_network::chainhook_event_observer::chainhooks::types::{ + ChainhookConfig, ChainhookSpecification, +}; use chainhook_types::{BitcoinNetwork, StacksNetwork}; diff --git a/components/clarinet-cli/src/chainhooks/types.rs b/components/clarinet-cli/src/chainhooks/types.rs index 2c9ded578..6b77bcf80 100644 --- a/components/clarinet-cli/src/chainhooks/types.rs +++ b/components/clarinet-cli/src/chainhooks/types.rs @@ -1,6 +1,6 @@ -use chainhook_event_observer::chainhooks::types::*; use chainhook_types::{BitcoinNetwork, StacksNetwork}; use serde::{Deserialize, Serialize}; +use stacks_network::chainhook_event_observer::chainhooks::types::*; use std::collections::BTreeMap; use std::fs::File; use std::io::{BufReader, Read}; @@ -42,6 +42,8 @@ pub struct ChainhookPredicateFile { p2wsh: Option>, script: Option>, scope: Option, + protocol: Option, + operation: Option, } #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -229,27 +231,37 @@ impl HookActionFile { } impl ChainhookPredicateFile { - pub fn to_bitcoin_predicate(&self) -> Result { + pub fn to_bitcoin_predicate(&self) -> Result { if let Some(ref specs) = self.op_return { - let rule = BitcoinPredicateType::OpReturn(self.extract_matching_rule(specs)?); - let scope = self.extract_scope()?; - return Ok(BitcoinTransactionFilterPredicate::new(scope, rule)); + let predicate = BitcoinPredicateType::Scope(Scopes::Outputs( + OutputPredicate::OpReturn(self.extract_matching_rule(specs)?), + )); + return Ok(predicate); } else if let Some(ref specs) = self.p2pkh { - let rule = BitcoinPredicateType::P2pkh(self.extract_exact_matching_rule(specs)?); - let scope = self.extract_scope()?; - return Ok(BitcoinTransactionFilterPredicate::new(scope, rule)); + let predicate = BitcoinPredicateType::Scope(Scopes::Outputs(OutputPredicate::P2pkh( + self.extract_exact_matching_rule(specs)?, + ))); + return Ok(predicate); } else if let Some(ref specs) = self.p2sh { - let rule = BitcoinPredicateType::P2sh(self.extract_exact_matching_rule(specs)?); - let scope = self.extract_scope()?; - return Ok(BitcoinTransactionFilterPredicate::new(scope, rule)); + let predicate = BitcoinPredicateType::Scope(Scopes::Outputs(OutputPredicate::P2sh( + self.extract_exact_matching_rule(specs)?, + ))); + return Ok(predicate); } else if let Some(ref specs) = self.p2wpkh { - let rule = BitcoinPredicateType::P2wpkh(self.extract_exact_matching_rule(specs)?); - let scope = self.extract_scope()?; - return Ok(BitcoinTransactionFilterPredicate::new(scope, rule)); + let predicate = BitcoinPredicateType::Scope(Scopes::Outputs(OutputPredicate::P2wpkh( + self.extract_exact_matching_rule(specs)?, + ))); + return Ok(predicate); } else if let Some(ref specs) = self.p2wsh { - let rule = BitcoinPredicateType::P2wsh(self.extract_exact_matching_rule(specs)?); - let scope = self.extract_scope()?; - return Ok(BitcoinTransactionFilterPredicate::new(scope, rule)); + let predicate = BitcoinPredicateType::Scope(Scopes::Outputs(OutputPredicate::P2wsh( + self.extract_exact_matching_rule(specs)?, + ))); + return Ok(predicate); + } else if let Some(ref specs) = self.protocol { + let predicate = BitcoinPredicateType::Protocol(Protocols::Ordinal( + OrdinalOperations::InscriptionRevealed, + )); + return Ok(predicate); } return Err(format!( "trigger not specified (op-return, p2pkh, p2sh, p2wpkh, p2wsh)" diff --git a/components/clarinet-cli/src/frontend/cli.rs b/components/clarinet-cli/src/frontend/cli.rs index 112376fca..11572a976 100644 --- a/components/clarinet-cli/src/frontend/cli.rs +++ b/components/clarinet-cli/src/frontend/cli.rs @@ -13,7 +13,6 @@ use crate::integrate; use crate::lsp::run_lsp; use crate::runner::run_scripts; use crate::runner::DeploymentCache; -use chainhook_event_observer::chainhooks::types::ChainhookSpecification; use chainhook_types::StacksNetwork; use chainhook_types::{BitcoinNetwork, Chain}; use clarinet_deployments::onchain::{ @@ -36,6 +35,7 @@ use clarity_repl::clarity::ClarityVersion; use clarity_repl::repl::diagnostic::{output_code, output_diagnostic}; use clarity_repl::repl::{ClarityCodeSource, ClarityContract, ContractDeployer, DEFAULT_EPOCH}; use clarity_repl::{analysis, repl, Terminal}; +use stacks_network::chainhook_event_observer::chainhooks::types::ChainhookSpecification; use stacks_network::{self, DevnetOrchestrator}; use std::collections::HashMap; use std::fs::{self, File}; diff --git a/components/clarinet-cli/src/integrate/mod.rs b/components/clarinet-cli/src/integrate/mod.rs index 943fa981b..93c517f9a 100644 --- a/components/clarinet-cli/src/integrate/mod.rs +++ b/components/clarinet-cli/src/integrate/mod.rs @@ -6,11 +6,11 @@ use std::{ }; use crate::chainhooks::load_chainhooks; -use chainhook_event_observer::utils::Context; use chainhook_types::{BitcoinNetwork, StacksNetwork}; use clarinet_deployments::types::DeploymentSpecification; use hiro_system_kit::Drain; use hiro_system_kit::{slog, slog_async, slog_term}; +use stacks_network::chainhook_event_observer::utils::Context; use stacks_network::{ do_run_devnet, ChainsCoordinatorCommand, DevnetEvent, DevnetOrchestrator, LogData, }; diff --git a/components/clarinet-cli/src/runner/api_v1.rs b/components/clarinet-cli/src/runner/api_v1.rs index 20943d64d..33db1dc36 100644 --- a/components/clarinet-cli/src/runner/api_v1.rs +++ b/components/clarinet-cli/src/runner/api_v1.rs @@ -10,13 +10,6 @@ use super::ChainhookEvent; use super::DeploymentCache; use super::SessionArtifacts; use crate::runner::api_v1::utils::serialize_event; -use chainhook_event_observer::chainhooks::stacks::evaluate_stacks_transaction_predicate_on_transaction; -use chainhook_event_observer::chainhooks::stacks::handle_stacks_hook_action; -use chainhook_event_observer::chainhooks::stacks::StacksChainhookOccurrence; -use chainhook_event_observer::chainhooks::stacks::StacksTriggerChainhook; -use chainhook_event_observer::chainhooks::types::StacksChainhookSpecification; -use chainhook_event_observer::indexer::stacks::get_standardized_stacks_receipt; -use chainhook_event_observer::utils::Context; use chainhook_types::BlockIdentifier; use chainhook_types::StacksBlockData; use chainhook_types::StacksBlockMetadata; @@ -50,6 +43,13 @@ use deno_core::serde_json::{json, Value}; use deno_core::{op, Extension}; use deno_core::{ModuleSpecifier, OpState}; use sha2::{Digest, Sha256}; +use stacks_network::chainhook_event_observer::chainhooks::stacks::evaluate_stacks_transaction_predicate_on_transaction; +use stacks_network::chainhook_event_observer::chainhooks::stacks::handle_stacks_hook_action; +use stacks_network::chainhook_event_observer::chainhooks::stacks::StacksChainhookOccurrence; +use stacks_network::chainhook_event_observer::chainhooks::stacks::StacksTriggerChainhook; +use stacks_network::chainhook_event_observer::chainhooks::types::StacksChainhookSpecification; +use stacks_network::chainhook_event_observer::indexer::stacks::get_standardized_stacks_receipt; +use stacks_network::chainhook_event_observer::utils::Context; use std::collections::{BTreeMap, HashMap}; use std::fs::OpenOptions; use std::io::Write; diff --git a/components/clarinet-cli/src/runner/deno.rs b/components/clarinet-cli/src/runner/deno.rs index 37eaadf9c..142d57b38 100644 --- a/components/clarinet-cli/src/runner/deno.rs +++ b/components/clarinet-cli/src/runner/deno.rs @@ -22,7 +22,6 @@ use super::vendor::deno_cli::tools::test::{ use super::vendor::deno_runtime::permissions::Permissions; use super::vendor::deno_runtime::tokio_util::run_local; use super::{api_v1, costs, ChainhookEvent, DeploymentCache, SessionArtifacts}; -use chainhook_event_observer::chainhooks::types::StacksChainhookSpecification; use clarinet_files::{FileLocation, ProjectManifest}; use clarity_repl::analysis::coverage::CoverageReporter; use deno_ast::swc::common::comments::CommentKind; @@ -43,6 +42,7 @@ use rand::rngs::SmallRng; use rand::seq::SliceRandom; use rand::SeedableRng; use regex::Regex; +use stacks_network::chainhook_event_observer::chainhooks::types::StacksChainhookSpecification; use std::collections::HashSet; use std::fmt::Write as _; use std::num::NonZeroUsize; diff --git a/components/clarinet-cli/src/runner/mod.rs b/components/clarinet-cli/src/runner/mod.rs index e5e8c04b3..232a6c56c 100644 --- a/components/clarinet-cli/src/runner/mod.rs +++ b/components/clarinet-cli/src/runner/mod.rs @@ -1,4 +1,3 @@ -use chainhook_event_observer::chainhooks::types::StacksChainhookSpecification; use clarinet_deployments::types::DeploymentGenerationArtifacts; use clarinet_deployments::{ initiate_session_from_deployment, update_session_with_contracts_executions, @@ -14,6 +13,7 @@ use clarity_repl::clarity::vm::types::QualifiedContractIdentifier; use clarity_repl::clarity::vm::EvaluationResult; use clarity_repl::repl::{session::CostsReport, Session}; use deno_core::error::AnyError; +use stacks_network::chainhook_event_observer::chainhooks::types::StacksChainhookSpecification; use std::collections::HashMap; use clarinet_deployments::types::DeploymentSpecification; diff --git a/components/clarinet-deployments/src/onchain/bitcoin_deployment.rs b/components/clarinet-deployments/src/onchain/bitcoin_deployment.rs index 2de9b9b06..a24c64612 100644 --- a/components/clarinet-deployments/src/onchain/bitcoin_deployment.rs +++ b/components/clarinet-deployments/src/onchain/bitcoin_deployment.rs @@ -127,6 +127,7 @@ pub fn sign_transaction( pub fn send_transaction_spec( bitcoin_rpc: &Client, + bitcoin_wallet_rpc: &Client, tx_spec: &BtcTransferSpecification, signer: &SecretKey, ) -> Result { @@ -135,7 +136,7 @@ pub fn send_transaction_spec( Address::from_str(&tx_spec.expected_sender).expect("Unable to parse address"); let addresses = vec![&sender_address]; - let mut utxos = bitcoin_rpc + let mut utxos = bitcoin_wallet_rpc .list_unspent(None, None, Some(&addresses), None, None) .expect("Unable to retrieve UTXOs"); diff --git a/components/clarinet-deployments/src/onchain/mod.rs b/components/clarinet-deployments/src/onchain/mod.rs index c7735c005..145a89330 100644 --- a/components/clarinet-deployments/src/onchain/mod.rs +++ b/components/clarinet-deployments/src/onchain/mod.rs @@ -459,11 +459,25 @@ pub fn apply_on_chain_deployment( url.host().expect("Host unknown"), url.port_or_known_default().expect("Protocol unknown") ); - let bitcoin_rpc = Client::new(&bitcoin_node_rpc_url, auth).unwrap(); + let bitcoin_rpc = Client::new(&bitcoin_node_rpc_url, auth.clone()).unwrap(); + + let bitcoin_node_wallet_rpc_url = format!( + "{}://{}:{}/wallet/", + url.scheme(), + url.host().expect("Host unknown"), + url.port_or_known_default().expect("Protocol unknown") + ); + let bitcoin_node_wallet_rpc = + Client::new(&bitcoin_node_wallet_rpc_url, auth).unwrap(); + let account = btc_accounts_lookup.get(&tx.expected_sender).unwrap(); let (secret_key, _public_key) = get_btc_keypair(account); - let _ = - bitcoin_deployment::send_transaction_spec(&bitcoin_rpc, tx, &secret_key); + let _ = bitcoin_deployment::send_transaction_spec( + &bitcoin_rpc, + &bitcoin_node_wallet_rpc, + tx, + &secret_key, + ); continue; } TransactionSpecification::ContractCall(tx) => { diff --git a/components/stacks-network/src/chains_coordinator.rs b/components/stacks-network/src/chains_coordinator.rs index b1f28509f..f4fd9ebb8 100644 --- a/components/stacks-network/src/chains_coordinator.rs +++ b/components/stacks-network/src/chains_coordinator.rs @@ -409,7 +409,6 @@ pub async fn start_chains_coordinator( } ObserverEvent::HookRegistered(hook) => { let message = format!("New hook \"{}\" registered", hook.name()); - ctx.try_log(|logger| slog::info!(logger, "{}", message)); let _ = devnet_event_tx.send(DevnetEvent::info(message)); } ObserverEvent::HookDeregistered(_hook) => {} diff --git a/components/stacks-network/src/lib.rs b/components/stacks-network/src/lib.rs index a4ea8b82a..bd7408561 100644 --- a/components/stacks-network/src/lib.rs +++ b/components/stacks-network/src/lib.rs @@ -7,7 +7,7 @@ pub mod chains_coordinator; mod orchestrator; mod ui; -pub use chainhook_event_observer::utils::Context; +pub use chainhook_event_observer::{self, utils::Context}; pub use orchestrator::DevnetOrchestrator; use std::{ diff --git a/components/stacks-network/src/orchestrator.rs b/components/stacks-network/src/orchestrator.rs index b6ae1ade6..bd1302c3a 100644 --- a/components/stacks-network/src/orchestrator.rs +++ b/components/stacks-network/src/orchestrator.rs @@ -17,6 +17,7 @@ use clarinet_files::{DevnetConfigFile, NetworkManifest, ProjectManifest, DEFAULT use futures::stream::TryStreamExt; use hiro_system_kit::slog; use reqwest::RequestBuilder; +use serde_json::Value; use std::collections::HashMap; use std::fs::{self, File}; use std::io::Write; @@ -744,6 +745,14 @@ rpcport={bitcoin_node_rpc_port} extra_hosts: Some(vec!["host.docker.internal:host-gateway".into()]), ..Default::default() }), + cmd: Some(vec![ + "/bin/bitcoind".into(), + "-conf=/etc/bitcoin/bitcoin.conf".into(), + "-nodebuglogfile".into(), + "-pid=/run/bitcoind.pid".into(), + // "-datadir=/root/.bitcoin".into(), + ]), + // cmd: Some(vec!["/bin/bitcoind -conf=/etc/bitcoin/bitcoin.conf -nodebuglogfile -pid=/run/bitcoind.pid".into()]), ..Default::default() }; @@ -2481,14 +2490,22 @@ events_keys = ["*"] "jsonrpc": "1.0", "id": "stacks-network", "method": "createwallet", - "params": [json!("")] + "params": json!({ "wallet_name": "", "disable_private_keys": true }) })) .send() .await .map_err(|e| format!("unable to send 'createwallet' request ({})", e)); match rpc_call { - Ok(_r) => break, + Ok(r) => { + if r.status().is_success() { + break; + } else { + let err = r.text().await; + let msg = format!("{:?}", err); + let _ = devnet_event_tx.send(DevnetEvent::error(msg)); + } + } Err(e) => { error_count += 1; if error_count > max_errors { @@ -2504,6 +2521,7 @@ events_keys = ["*"] let mut error_count = 0; loop { + let descriptor = format!("addr({})", miner_address); let rpc_call = base_builder( &bitcoin_node_url, &devnet_config.bitcoin_node_username, @@ -2512,16 +2530,69 @@ events_keys = ["*"] .json(&json!({ "jsonrpc": "1.0", "id": "stacks-network", - "method": "importaddress", - "params": [json!(miner_address)] + "method": "getdescriptorinfo", + "params": [json!(descriptor)] })) .send() .await - .map_err(|e| format!("unable to send 'importaddress' request ({})", e)); + .map_err(|e| format!("unable to send 'getdescriptorinfo' request ({})", e)); + + let checksum = match rpc_call { + Ok(r) => { + let res: Value = r.json().await.unwrap(); + // let _ = devnet_event_tx.send(DevnetEvent::info(format!( + // "getdescriptorinfo {:?}", + // res + // ))); + + let checksum = res + .as_object() + .unwrap() + .get("result") + .unwrap() + .as_object() + .unwrap() + .get("checksum") + .unwrap() + .as_str() + .unwrap() + .to_string(); + checksum + } + Err(e) => { + panic!() + } + }; + + let _ = devnet_event_tx.send(DevnetEvent::info(format!( + "Registering {descriptor}#{checksum}" + ))); + let payload = json!({ + "jsonrpc": "1.0", + "id": "stacks-network", + "method": "importdescriptors", + "params": { + "requests": [{ + "desc": format!("{}#{}", descriptor, checksum), + "timestamp": 0, + }] + } + }); + let rpc_call = base_builder( + &bitcoin_node_url, + &devnet_config.bitcoin_node_username, + &devnet_config.bitcoin_node_password, + ) + .json(&payload) + .send() + .await + .map_err(|e| format!("unable to send 'importdescriptors' request ({})", e)); match rpc_call { - Ok(_r) => break, + Ok(r) => { + break; + } Err(e) => { error_count += 1; if error_count > max_errors { @@ -2537,23 +2608,78 @@ events_keys = ["*"] let mut error_count = 0; loop { + let descriptor = format!("addr({})", faucet_address); let rpc_call = base_builder( &bitcoin_node_url, &devnet_config.bitcoin_node_username, &devnet_config.bitcoin_node_password, ) .json(&json!({ - "jsonrpc": "1.0", - "id": "stacks-network", - "method": "importaddress", - "params": [json!(faucet_address)] + "jsonrpc": "1.0", + "id": "stacks-network", + "method": "getdescriptorinfo", + "params": [json!(descriptor)] + })) .send() .await - .map_err(|e| format!("unable to send 'importaddress' request ({})", e)); + .map_err(|e| format!("unable to send 'getdescriptorinfo' request ({})", e)); + + let checksum = match rpc_call { + Ok(r) => { + let res: Value = r.json().await.unwrap(); + // let _ = devnet_event_tx.send(DevnetEvent::info(format!( + // "getdescriptorinfo {:?}", + // res + // ))); + + let checksum = res + .as_object() + .unwrap() + .get("result") + .unwrap() + .as_object() + .unwrap() + .get("checksum") + .unwrap() + .as_str() + .unwrap() + .to_string(); + checksum + } + Err(e) => { + panic!() + } + }; + + let _ = devnet_event_tx.send(DevnetEvent::info(format!( + "Registering {descriptor}#{checksum}" + ))); + let payload = json!({ + "jsonrpc": "1.0", + "id": "stacks-network", + "method": "importdescriptors", + "params": { + "requests": [{ + "desc": format!("{}#{}", descriptor, checksum), + "timestamp": 0, + }] + } + }); + let rpc_call = base_builder( + &bitcoin_node_url, + &devnet_config.bitcoin_node_username, + &devnet_config.bitcoin_node_password, + ) + .json(&payload) + .send() + .await + .map_err(|e| format!("unable to send 'importdescriptors' request ({})", e)); match rpc_call { - Ok(_r) => break, + Ok(r) => { + break; + } Err(e) => { error_count += 1; if error_count > max_errors { @@ -2573,23 +2699,78 @@ events_keys = ["*"] let mut error_count = 0; loop { + let descriptor = format!("addr({})", address); let rpc_call = base_builder( &bitcoin_node_url, &devnet_config.bitcoin_node_username, &devnet_config.bitcoin_node_password, ) .json(&json!({ - "jsonrpc": "1.0", - "id": "stacks-network", - "method": "importaddress", - "params": [json!(address)] - })) + "jsonrpc": "1.0", + "id": "stacks-network", + "method": "getdescriptorinfo", + "params": [json!(descriptor)] + + })) .send() .await - .map_err(|e| format!("unable to send 'importaddress' request ({})", e)); + .map_err(|e| format!("unable to send 'getdescriptorinfo' request ({})", e)); + + let checksum = match rpc_call { + Ok(r) => { + let res: Value = r.json().await.unwrap(); + // let _ = devnet_event_tx.send(DevnetEvent::info(format!( + // "getdescriptorinfo {:?}", + // res + // ))); + + let checksum = res + .as_object() + .unwrap() + .get("result") + .unwrap() + .as_object() + .unwrap() + .get("checksum") + .unwrap() + .as_str() + .unwrap() + .to_string(); + checksum + } + Err(e) => { + panic!() + } + }; + + let _ = devnet_event_tx.send(DevnetEvent::info(format!( + "Registering {descriptor}#{checksum}" + ))); + let payload = json!({ + "jsonrpc": "1.0", + "id": "stacks-network", + "method": "importdescriptors", + "params": { + "requests": [{ + "desc": format!("{}#{}", descriptor, checksum), + "timestamp": 0, + }] + } + }); + let rpc_call = base_builder( + &bitcoin_node_url, + &devnet_config.bitcoin_node_username, + &devnet_config.bitcoin_node_password, + ) + .json(&payload) + .send() + .await + .map_err(|e| format!("unable to send 'importdescriptors' request ({})", e)); match rpc_call { - Ok(_r) => break, + Ok(r) => { + break; + } Err(e) => { error_count += 1; if error_count > max_errors { diff --git a/dockerfiles/devnet/Bitcoin.dockerfile b/dockerfiles/devnet/Bitcoin.dockerfile index 41d5d803c..86a16285d 100644 --- a/dockerfiles/devnet/Bitcoin.dockerfile +++ b/dockerfiles/devnet/Bitcoin.dockerfile @@ -1,9 +1,69 @@ +FROM alpine as build + +ARG BTC_VERSION="24.0" +ARG BDB_PREFIX="/src/bitcoin/db4" + +ENV BTC_VERSION=${BTC_VERSION} +ENV BDB_PREFIX=${BDB_PREFIX} + +WORKDIR /src +RUN apk --no-cache add --update \ + libgcc \ + boost-dev \ + boost-thread \ + boost-filesystem \ + boost-system \ + openssl \ + autoconf \ + libtool \ + pkgconf \ + pkgconf-dev \ + libevent \ + git \ + czmq-dev \ + libzmq \ + gcc \ + g++ \ + openssl-dev \ + libevent-dev \ + make \ + automake \ + musl-dev \ + linux-headers \ + libc-dev \ + db-c++ \ + patch \ + sqlite-dev \ + sqlite \ + && /sbin/ldconfig /usr/lib /lib \ + && mkdir /out + + +RUN git clone --depth 1 --branch v${BTC_VERSION} https://github.com/bitcoin/bitcoin \ + && cd bitcoin \ + && sh contrib/install_db4.sh . \ + && ./autogen.sh \ + && ./configure \ + BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ + BDB_CFLAGS="-I${BDB_PREFIX}/include" \ + --disable-tests \ + --enable-static \ + --without-miniupnpc \ + --with-pic \ + --enable-cxx \ + --with-sqlite=yes \ + --with-gui=no \ + --enable-util-util=no \ + --enable-util-tx=no \ + --with-boost-libdir=/usr/lib \ + --bindir=/out \ + && make -j2 STATIC=1 \ + && make install \ + && strip /out/* + FROM alpine -ARG BTC_URL="https://github.com/hirosystems/bitcoin-docker/releases/download/0.21.1/musl-v0.21.1.tar.gz" -WORKDIR / -RUN apk add --update \ +RUN apk --no-cache add --update \ curl \ - gnupg \ boost-system \ boost-filesystem \ boost-thread \ @@ -11,12 +71,9 @@ RUN apk add --update \ libevent \ libzmq \ libgcc \ - tini \ - jq -RUN curl -L -o /bitcoin.tar.gz ${BTC_URL} -RUN tar -xzvf /bitcoin.tar.gz -RUN mkdir -p /root/.bitcoin -RUN mv /bitcoin-*/bin/* /usr/local/bin/ -RUN rm -rf /bitcoin-* -ENTRYPOINT ["/sbin/tini", "--"] -CMD [ "/usr/local/bin/bitcoind -conf=/etc/bitcoin/bitcoin.conf -nodebuglogfile -pid=/run/bitcoind.pid -datadir=/root/.bitcoin"] + sqlite \ + sqlite-libs \ + && mkdir /bitcoin +COPY --from=build /out/ /bin/ + +CMD ["/bin/bitcoind", "-server", "-datadir=/bitcoin", "-rpcuser=btcuser", "-rpcpassword=btcpass", "-rpcallowip=0.0.0.0/0", "-bind=0.0.0.0:8333", "-rpcbind=0.0.0.0:8332", "-dbcache=512", "-rpcthreads=256", "-disablewallet", "-txindex"] \ No newline at end of file