Bootstrap geth Rust workspace

This commit is contained in:
Eric Wendland 2026-05-15 15:08:20 +02:00
commit 26f81ff1ef
73 changed files with 4835 additions and 0 deletions

22
crates/geth/Cargo.toml Normal file
View file

@ -0,0 +1,22 @@
[package]
name = "geth"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
[[bin]]
name = "geth"
path = "src/main.rs"
[dependencies]
anyhow.workspace = true
tokio.workspace = true
tracing-subscriber.workspace = true
geth-cli = { path = "../geth-cli" }
[dev-dependencies]
geth-cas = { path = "../geth-cas" }
geth-config = { path = "../geth-config" }
geth-node = { path = "../geth-node" }
tempfile.workspace = true

8
crates/geth/src/main.rs Normal file
View file

@ -0,0 +1,8 @@
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.with_target(false)
.init();
geth_cli::run().await
}

View file

@ -0,0 +1,105 @@
use std::process::{Child, Command};
use std::time::{Duration, Instant};
fn unix_sockets_available(home: &std::path::Path) -> bool {
let probe = home.join("probe.sock");
match std::os::unix::net::UnixListener::bind(&probe) {
Ok(listener) => {
drop(listener);
let _ = std::fs::remove_file(probe);
true
}
Err(error) => {
eprintln!("skipping daemon socket test; Unix sockets unavailable: {error}");
false
}
}
}
fn geth_bin() -> &'static str {
env!("CARGO_BIN_EXE_geth")
}
fn run_geth(home: &std::path::Path, args: &[&str]) -> std::process::Output {
Command::new(geth_bin())
.env("GETH_HOME", home)
.args(args)
.output()
.expect("run geth")
}
fn spawn_daemon(home: &std::path::Path) -> Child {
Command::new(geth_bin())
.env("GETH_HOME", home)
.args(["daemon", "run"])
.spawn()
.expect("spawn daemon")
}
fn wait_for_socket(path: &std::path::Path) {
let started = Instant::now();
while started.elapsed() < Duration::from_secs(5) {
if path.exists() {
return;
}
std::thread::sleep(Duration::from_millis(50));
}
panic!("socket did not appear: {}", path.display());
}
#[test]
fn geth_init_in_temp_home() {
let home = tempfile::tempdir().expect("tempdir");
let output = run_geth(home.path(), &["init"]);
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
assert!(home.path().join("geth.sqlite").exists());
assert!(home.path().join("identity/agent.ed25519").exists());
assert!(home.path().join("config.toml").exists());
}
#[test]
fn geth_status_against_running_daemon() {
let home = tempfile::tempdir().expect("tempdir");
if !unix_sockets_available(home.path()) {
return;
}
assert!(run_geth(home.path(), &["init"]).status.success());
let mut daemon = spawn_daemon(home.path());
wait_for_socket(&home.path().join("run/geth.sock"));
let output = run_geth(home.path(), &["status"]);
let _ = daemon.kill();
let _ = daemon.wait();
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("geth daemon: running"));
assert!(stdout.contains("agent:"));
}
#[test]
fn initialized_node_can_roundtrip_cas_blob() {
let home = tempfile::tempdir().expect("tempdir");
let paths = geth_config::GethPaths::from_home(home.path());
let node = geth_node::init_node(&paths).expect("init node");
assert_eq!(node.paths.home(), home.path());
let cas = geth_cas::LocalCas::new(paths.cas_dir());
let output_path = home.path().join("output.txt");
let added = cas.add_bytes(b"hello geth integration").expect("add blob");
assert!(cas.has(&added.hash).expect("has blob"));
cas.get_to_path(&added.hash, &output_path)
.expect("get blob");
assert_eq!(
std::fs::read(output_path).expect("read output"),
b"hello geth integration"
);
}