Skip to content

Commit 40501fb

Browse files
committed
Citrea docker support
1 parent d3b6daf commit 40501fb

File tree

16 files changed

+841
-513
lines changed

16 files changed

+841
-513
lines changed

.github/workflows/code_checks.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,11 @@ jobs:
4646
with:
4747
version: "latest"
4848
args: "--workspace --all-features --all-targets"
49+
50+
test:
51+
name: Tests
52+
runs-on: ubuntu-latest
53+
steps:
54+
- uses: actions/checkout@v4
55+
- name: Run Cargo test
56+
run: cargo test

src/bitcoin.rs

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct BitcoinNode {
3535

3636
impl BitcoinNode {
3737
pub async fn new(config: &BitcoinConfig, docker: Arc<Option<DockerEnv>>) -> Result<Self> {
38-
let spawn_output = Self::spawn(config, &docker).await?;
38+
let spawn_output = <Self as NodeT>::spawn(config, &docker).await?;
3939

4040
let rpc_url = format!(
4141
"http://127.0.0.1:{}/wallet/{}",
@@ -136,12 +136,26 @@ impl BitcoinNode {
136136
.await;
137137
}
138138

139-
// Switch this over to Node signature once we add support for docker to citrea nodes
140-
async fn spawn(config: &BitcoinConfig, docker: &Arc<Option<DockerEnv>>) -> Result<SpawnOutput> {
141-
match docker.as_ref() {
142-
Some(docker) => docker.spawn(config.into()).await,
143-
None => <Self as NodeT>::spawn(config),
144-
}
139+
fn spawn(config: &BitcoinConfig) -> Result<SpawnOutput> {
140+
let args = config.args();
141+
debug!("Running bitcoind with args : {args:?}");
142+
143+
info!(
144+
"Bitcoin debug.log available at : {}",
145+
config.log_path().display()
146+
);
147+
148+
let stderr_path = config.stderr_path();
149+
let stderr_file = File::create(stderr_path).context("Failed to create stderr file")?;
150+
151+
Command::new("bitcoind")
152+
.args(&args)
153+
.kill_on_drop(true)
154+
.envs(config.env.clone())
155+
.stderr(Stdio::from(stderr_file))
156+
.spawn()
157+
.context("Failed to spawn bitcoind process")
158+
.map(SpawnOutput::Child)
145159
}
146160
}
147161

@@ -182,26 +196,11 @@ impl NodeT for BitcoinNode {
182196
type Config = BitcoinConfig;
183197
type Client = Client;
184198

185-
fn spawn(config: &Self::Config) -> Result<SpawnOutput> {
186-
let args = config.args();
187-
debug!("Running bitcoind with args : {args:?}");
188-
189-
info!(
190-
"Bitcoin debug.log available at : {}",
191-
config.log_path().display()
192-
);
193-
194-
let stderr_path = config.stderr_path();
195-
let stderr_file = File::create(stderr_path).context("Failed to create stderr file")?;
196-
197-
Command::new("bitcoind")
198-
.args(&args)
199-
.kill_on_drop(true)
200-
.envs(config.env.clone())
201-
.stderr(Stdio::from(stderr_file))
202-
.spawn()
203-
.context("Failed to spawn bitcoind process")
204-
.map(SpawnOutput::Child)
199+
async fn spawn(config: &Self::Config, docker: &Arc<Option<DockerEnv>>) -> Result<SpawnOutput> {
200+
match docker.as_ref() {
201+
Some(docker) => docker.spawn(config.into()).await,
202+
None => Self::spawn(config),
203+
}
205204
}
206205

207206
fn spawn_output(&mut self) -> &mut SpawnOutput {
@@ -270,7 +269,7 @@ impl Restart for BitcoinNode {
270269
if let Some(config) = config {
271270
self.config = config;
272271
}
273-
self.spawn_output = Self::spawn(&self.config, &self.docker_env).await?;
272+
self.spawn_output = <Self as NodeT>::spawn(&self.config, &self.docker_env).await?;
274273

275274
self.wait_for_ready(None).await?;
276275

src/citrea_config/rollup.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use std::path::PathBuf;
22

33
use serde::{Deserialize, Serialize};
4+
use tempfile::TempDir;
5+
6+
use crate::config::{BitcoinConfig, BitcoinServiceConfig};
47

58
/// Runner configuration.
69
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
@@ -121,6 +124,74 @@ pub struct FullNodeConfig<BitcoinServiceConfig> {
121124
pub public_keys: RollupPublicKeys,
122125
}
123126

127+
impl Default for FullNodeConfig<BitcoinServiceConfig> {
128+
fn default() -> Self {
129+
Self {
130+
rpc: RpcConfig {
131+
bind_host: "127.0.0.1".into(),
132+
bind_port: 0,
133+
max_connections: 100,
134+
max_request_body_size: 10 * 1024 * 1024,
135+
max_response_body_size: 10 * 1024 * 1024,
136+
batch_requests_limit: 50,
137+
enable_subscriptions: true,
138+
max_subscriptions_per_connection: 100,
139+
},
140+
storage: StorageConfig {
141+
path: TempDir::new()
142+
.expect("Failed to create temporary directory")
143+
.into_path(),
144+
db_max_open_files: None,
145+
},
146+
runner: None,
147+
da: BitcoinServiceConfig {
148+
node_url: String::new(),
149+
node_username: String::from("user"),
150+
node_password: String::from("password"),
151+
network: bitcoin::Network::Regtest,
152+
da_private_key: None,
153+
tx_backup_dir: TempDir::new()
154+
.expect("Failed to create temporary directory")
155+
.into_path()
156+
.display()
157+
.to_string(),
158+
},
159+
public_keys: RollupPublicKeys {
160+
sequencer_public_key: vec![
161+
32, 64, 64, 227, 100, 193, 15, 43, 236, 156, 31, 229, 0, 161, 205, 76, 36, 124,
162+
137, 214, 80, 160, 30, 215, 232, 44, 171, 168, 103, 135, 124, 33,
163+
],
164+
// private key [4, 95, 252, 129, 163, 193, 253, 179, 175, 19, 89, 219, 242, 209, 20, 176, 179, 239, 191, 127, 41, 204, 156, 93, 160, 18, 103, 170, 57, 210, 199, 141]
165+
// Private Key (WIF): KwNDSCvKqZqFWLWN1cUzvMiJQ7ck6ZKqR6XBqVKyftPZtvmbE6YD
166+
sequencer_da_pub_key: vec![
167+
3, 136, 195, 18, 11, 187, 25, 37, 38, 109, 184, 237, 247, 208, 131, 219, 162,
168+
70, 35, 174, 234, 47, 239, 247, 60, 51, 174, 242, 247, 112, 186, 222, 30,
169+
],
170+
// private key [117, 186, 249, 100, 208, 116, 89, 70, 0, 54, 110, 91, 17, 26, 29, 168, 248, 107, 46, 254, 45, 34, 218, 81, 200, 216, 33, 38, 160, 252, 172, 114]
171+
// Private Key (WIF): L1AZdJXzDGGENBBPZGSL7dKJnwn5xSKqzszgK6CDwiBGThYQEVTo
172+
prover_da_pub_key: vec![
173+
2, 138, 232, 157, 214, 46, 7, 210, 235, 33, 105, 239, 71, 169, 105, 233, 239,
174+
84, 172, 112, 13, 54, 9, 206, 106, 138, 251, 218, 15, 28, 137, 112, 127,
175+
],
176+
},
177+
}
178+
}
179+
}
180+
181+
impl From<BitcoinConfig> for BitcoinServiceConfig {
182+
fn from(v: BitcoinConfig) -> Self {
183+
let ip = v.docker_ip.unwrap_or(String::from("127.0.0.1"));
184+
Self {
185+
node_url: format!("{}:{}", ip, v.rpc_port),
186+
node_username: v.rpc_user,
187+
node_password: v.rpc_password,
188+
network: v.network,
189+
da_private_key: None,
190+
tx_backup_dir: String::new(),
191+
}
192+
}
193+
}
194+
124195
/// A configuration type to define the behaviour of the pruner.
125196
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
126197
pub struct PruningConfig {

src/config/bitcoin.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub struct BitcoinConfig {
1717
pub docker_image: Option<String>,
1818
pub env: Vec<(&'static str, &'static str)>,
1919
pub idx: usize,
20+
pub docker_ip: Option<String>,
2021
}
2122

2223
impl Default for BitcoinConfig {
@@ -34,6 +35,7 @@ impl Default for BitcoinConfig {
3435
docker_image: Some("bitcoin/bitcoin:28.0".to_string()),
3536
env: Vec::new(),
3637
idx: 0,
38+
docker_ip: None,
3739
}
3840
}
3941
}

src/config/docker.rs

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1+
use std::fmt::Debug;
12
use std::path::PathBuf;
23

3-
use super::{BitcoinConfig, FullSequencerConfig};
4+
use serde::Serialize;
5+
use tracing::debug;
6+
7+
use super::{BitcoinConfig, FullL2NodeConfig, NodeKindMarker};
8+
use crate::log_provider::LogPathProvider;
9+
use crate::node::{get_citrea_args, Config, NodeKind};
410
use crate::utils::get_genesis_path;
511

12+
const DEFAULT_BITCOIN_DOCKER_IMAGE: &str = "bitcoin/bitcoin:28.0";
13+
const DEFAULT_CITREA_DOCKER_IMAGE: &str =
14+
"chainwayxyz/citrea:e7db3c1c1787014ec4f7eb365bd8657d8f0917a0";
15+
616
#[derive(Debug)]
717
pub struct VolumeConfig {
818
pub name: String,
@@ -16,11 +26,13 @@ pub struct DockerConfig {
1626
pub cmd: Vec<String>,
1727
pub log_path: PathBuf,
1828
pub volume: VolumeConfig,
29+
pub host_dir: Option<Vec<String>>,
30+
pub kind: NodeKind,
1931
}
2032

2133
impl From<&BitcoinConfig> for DockerConfig {
22-
fn from(v: &BitcoinConfig) -> Self {
23-
let mut args = v.args();
34+
fn from(config: &BitcoinConfig) -> Self {
35+
let mut args = config.args();
2436

2537
// Docker specific args
2638
args.extend([
@@ -30,48 +42,55 @@ impl From<&BitcoinConfig> for DockerConfig {
3042
]);
3143

3244
Self {
33-
ports: vec![v.rpc_port, v.p2p_port],
34-
image: v
45+
ports: vec![config.rpc_port, config.p2p_port],
46+
image: config
3547
.docker_image
3648
.clone()
37-
.unwrap_or_else(|| "bitcoin/bitcoin:28.0".to_string()),
49+
.unwrap_or_else(|| DEFAULT_BITCOIN_DOCKER_IMAGE.to_string()),
3850
cmd: args,
39-
log_path: v.data_dir.join("regtest").join("debug.log"),
51+
log_path: config.data_dir.join("regtest").join("debug.log"),
4052
volume: VolumeConfig {
41-
name: format!("bitcoin-{}", v.idx),
53+
name: format!("bitcoin-{}", config.idx),
4254
target: "/home/bitcoin/.bitcoin".to_string(),
4355
},
56+
host_dir: None,
57+
kind: NodeKind::Bitcoin,
4458
}
4559
}
4660
}
4761

48-
impl From<&FullSequencerConfig> for DockerConfig {
49-
fn from(v: &FullSequencerConfig) -> Self {
50-
let args = vec![
51-
"--da-layer".to_string(),
52-
"bitcoin".to_string(),
53-
"--rollup-config-path".to_string(),
54-
"sequencer_rollup_config.toml".to_string(),
55-
"--sequencer-config-path".to_string(),
56-
"sequencer_config.toml".to_string(),
57-
"--genesis-paths".to_string(),
58-
get_genesis_path(v.dir.parent().expect("Couldn't get parent dir"))
59-
.display()
60-
.to_string(),
61-
];
62+
impl<T> From<FullL2NodeConfig<T>> for DockerConfig
63+
where
64+
T: Clone + Serialize + Debug,
65+
FullL2NodeConfig<T>: NodeKindMarker,
66+
{
67+
fn from(config: FullL2NodeConfig<T>) -> Self {
68+
let kind = FullL2NodeConfig::<T>::kind();
69+
70+
debug!("Converting config {config:?} for {kind} to docker config");
71+
72+
let args = get_citrea_args(&config);
6273

6374
Self {
64-
ports: vec![v.rollup.rpc.bind_port],
65-
image: v
66-
.docker_image
67-
.clone()
68-
.unwrap_or_else(|| "citrea:latest".to_string()), // Default to local image
75+
ports: vec![config.rollup.rpc.bind_port],
76+
image: config.docker_image.clone().unwrap_or_else(|| {
77+
let base_img = DEFAULT_CITREA_DOCKER_IMAGE;
78+
match std::env::var("SHORT_PREFIX") {
79+
Ok(_) => format!("{base_img}-short-prefix"),
80+
_ => base_img.to_string(),
81+
}
82+
}),
6983
cmd: args,
70-
log_path: v.dir.join("stdout"),
84+
log_path: config.dir.join("stdout.log"),
7185
volume: VolumeConfig {
72-
name: "sequencer".to_string(),
73-
target: "/sequencer/data".to_string(),
86+
name: format!("{kind}"),
87+
target: format!("/{kind}/data"),
7488
},
89+
host_dir: Some(vec![
90+
config.dir().to_owned().display().to_string(),
91+
get_genesis_path(&config),
92+
]),
93+
kind,
7594
}
7695
}
7796
}

0 commit comments

Comments
 (0)