From b35d641804cc55d06002c462d43e7ef8b6b5e315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ksawery=20Wr=C3=B3bel?= Date: Fri, 31 Oct 2025 21:54:50 +0100 Subject: [PATCH 1/3] switch to raft-kv-store --- Cargo.lock | 131 ++++- Cargo.toml | 4 +- src/cluster/integration_tests.rs | 897 ------------------------------- src/cluster/mod.rs | 506 ----------------- src/cluster/storage.rs | 239 -------- src/cluster/tests.rs | 137 ----- src/config.rs | 6 +- src/main.rs | 29 +- src/persist.rs | 13 +- src/types/mod.rs | 20 + 10 files changed, 179 insertions(+), 1803 deletions(-) delete mode 100644 src/cluster/integration_tests.rs delete mode 100644 src/cluster/mod.rs delete mode 100644 src/cluster/storage.rs delete mode 100644 src/cluster/tests.rs diff --git a/Cargo.lock b/Cargo.lock index c385280..e5261b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,11 +160,22 @@ checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" [[package]] name = "bincode" -version = "1.3.3" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" dependencies = [ + "bincode_derive", "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", ] [[package]] @@ -826,6 +837,18 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "2.3.0" @@ -890,6 +913,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1066,6 +1095,18 @@ name = "hashbrown" version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown", +] [[package]] name = "heck" @@ -1561,6 +1602,17 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -1596,9 +1648,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "value-bag", ] @@ -1700,11 +1752,13 @@ dependencies = [ "prost-types", "protobuf", "raft", + "raft-kv-store", "raft-proto", "rand 0.9.1", "rand_core 0.6.4", "reqwest", "rocksdb", + "rusqlite", "serde", "serde_json", "sha2 0.10.9", @@ -2142,6 +2196,31 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "raft-kv-store" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a120cdb0d43fb135a36670dbd0ab85aa1c61946a200b6987cfc12f75996bb14a" +dependencies = [ + "bincode", + "byteorder", + "env_logger", + "log", + "percent-encoding", + "protobuf", + "raft", + "raft-proto", + "rusqlite", + "serde", + "serde_json", + "slog", + "slog-async", + "slog-stdlog", + "thiserror 1.0.69", + "tiny_http", + "toml", +] + [[package]] name = "raft-proto" version = "0.7.0" @@ -2351,6 +2430,20 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rusqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +dependencies = [ + "bitflags 2.9.1", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2465,10 +2558,11 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -2481,11 +2575,20 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -3276,6 +3379,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "url" version = "2.5.4" @@ -3347,6 +3456,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 3c81b63..47eee36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ bytes = "1.10.1" slog = "2.7.0" slog-async = "2.8.0" slog-term = "2.9.1" -bincode = "1.3.0" +bincode = { version = "2", features = ["serde"] } anyhow = "1.0.98" tiny_http = "0.12.0" rand = "0.9.1" @@ -40,6 +40,8 @@ byteorder = "1.5.0" enum_dispatch = "0.3.13" clap = { version = "4.5.45", features = ["derive"] } sha2 = "0.10.9" +raft-kv-store = "0.1.0" +rusqlite = "0.37.0" [build-dependencies] prost-build = "0.13" diff --git a/src/cluster/integration_tests.rs b/src/cluster/integration_tests.rs deleted file mode 100644 index 5eb0936..0000000 --- a/src/cluster/integration_tests.rs +++ /dev/null @@ -1,897 +0,0 @@ -use crate::backend::{Ed25519Signer, SigningBackend}; -use crate::cluster::SignerRaftNode; -use crate::config::{PeerConfig, RaftConfig}; -use crate::handle_single_request; -use crate::persist::{Persist, PersistVariants}; -use crate::proto::v0_38; -use crate::signer::Signer; -use crate::signer::mock_connection::{MockCometBFTConnection, MockConnectionHandle}; -use crate::types::SignedMsgType; -use crate::versions::VersionV0_38; -use log::info; -use prost::Message; -use rand::Rng; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::mpsc; -use std::sync::{Arc, Mutex}; -use std::thread::{self}; -use std::time::{Duration, Instant}; -use tempfile::TempDir; - -struct TestHarness { - _temp_dir: TempDir, - nodes: Vec, -} - -impl TestHarness { - fn new(num_nodes: usize) -> Self { - setup(); - let temp_dir = TempDir::new().unwrap(); - let port_prefix = rand::rng().random_range(30000..60000); - - let peers: Vec = (1..=num_nodes) - .map(|i| PeerConfig { - id: i as u64, - addr: format!("127.0.0.1:{}", port_prefix + i as u64), - }) - .collect(); - - let nodes: Vec = (1..=num_nodes) - .map(|i| create_test_node(port_prefix as u64, i as u64, peers.clone(), &temp_dir)) - .collect(); - - Self { - _temp_dir: temp_dir, - nodes, - } - } -} - -fn wait_for_leader_and_pop( - mut nodes: Vec, -) -> (SignerRaftNode, Vec) { - wait_for_leader(&nodes, Duration::from_secs(10)).expect("Failed to elect a leader"); - let leader_idx = nodes.iter().position(|n| n.is_leader()).unwrap(); - let leader_node = nodes.remove(leader_idx); - - (leader_node, nodes) -} - -fn create_signer_with_mock_conn() -> ( - Signer, VersionV0_38, MockCometBFTConnection>, - MockConnectionHandle, -) { - let (mock_conn, handle) = MockCometBFTConnection::new(); - let signing_backend = Ed25519Signer::from_key_file("./keys/privkey").unwrap(); - let backend_trait_object: Box = Box::new(signing_backend); - let signer = - Signer::<_, VersionV0_38, _>::new(backend_trait_object, mock_conn, "test-chain".into()); - (signer, handle) -} - -pub fn setup() { - let _ = env_logger::Builder::new() - .filter_level(log::LevelFilter::Info) - .try_init(); -} - -fn create_test_node( - port_prefix: u64, - node_id: u64, - peers: Vec, - temp_dir: &TempDir, -) -> SignerRaftNode { - let config = RaftConfig { - node_id, - bind_addr: format!("127.0.0.1:{}", port_prefix + node_id), - data_path: temp_dir - .path() - .join(format!("node_{}", node_id)) - .to_str() - .unwrap() - .to_string(), - peers, - initial_state_path: "./non_existent_initial_state.json".to_string(), - }; - SignerRaftNode::new(config) -} - -fn wait_for_leader(nodes: &[SignerRaftNode], timeout: Duration) -> Option<&SignerRaftNode> { - let start = Instant::now(); - while start.elapsed() < timeout { - for node in nodes { - if node.is_leader() { - return Some(&node); - } - } - thread::sleep(Duration::from_millis(30)); - } - None -} - -fn create_proposal_request_bytes(height: i64, round: i64) -> Vec { - let proposal_req = v0_38::privval::SignProposalRequest { - proposal: Some(v0_38::types::Proposal { - r#type: SignedMsgType::Proposal as i32, - height, - round: round as i32, - ..Default::default() - }), - chain_id: "test-chain".to_string(), - }; - let msg = v0_38::privval::Message { - sum: Some(v0_38::privval::message::Sum::SignProposalRequest( - proposal_req, - )), - }; - let mut req_bytes = Vec::new(); - msg.encode_length_delimited(&mut req_bytes).unwrap(); - req_bytes -} - -fn create_vote_request_bytes(height: i64, round: i64, vote_type: SignedMsgType) -> Vec { - let vote_req = v0_38::privval::SignVoteRequest { - vote: Some(v0_38::types::Vote { - r#type: vote_type as i32, - height, - round: round as i32, - ..Default::default() - }), - chain_id: "test-chain".to_string(), - }; - let msg = v0_38::privval::Message { - sum: Some(v0_38::privval::message::Sum::SignVoteRequest(vote_req)), - }; - let mut req_bytes = Vec::new(); - msg.encode_length_delimited(&mut req_bytes).unwrap(); - req_bytes -} - -fn unwrap_node(node: Arc>) -> SignerRaftNode { - let l = Arc::try_unwrap(node) - .unwrap_or_else(|_| panic!("single ref")) - .into_inner() - .unwrap(); - - match l { - PersistVariants::Local(_) => panic!("is raft"), - PersistVariants::Raft(r) => r, - } -} - -#[test] -fn happy_path_signing_on_stable_cluster() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (leader_node, followers) = wait_for_leader_and_pop(nodes); - - println!( - "Leader is node {}", - leader_node.raft_state.read().unwrap().1 - ); - - let (mut signer, handle) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle.request_sender.send(req_bytes).unwrap(); - - let leader = Arc::new(Mutex::new(PersistVariants::Raft(leader_node))); - handle_single_request(&mut signer, &leader).expect("Failed to handle request"); - - let response_bytes = handle.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_none()); - assert!(!res.proposal.unwrap().signature.is_empty()); - } - _ => panic!("Wrong response type"), - } - - for node in &followers { - let state = node.signer_state.read().unwrap(); - assert_eq!(state.height, 100); - assert_eq!(state.round, 0); - assert_eq!(state.step, SignedMsgType::Proposal); - } - let leader_state = leader.lock().unwrap().state(); - assert_eq!(leader_state.height, 100); - assert_eq!(leader_state.round, 0); - assert_eq!(leader_state.step, SignedMsgType::Proposal); -} - -// In reality this will not happen, because it's the leader who initiates the connection. -// However maybe the test will be useful to check for leadership transfers and -// maybe when simplifying the is_leader checks (which are at every other point) -#[test] -fn signing_rejected_if_not_leader() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (leader_node, mut followers) = wait_for_leader_and_pop(nodes); - - let follower_node = followers.remove(0); - - println!( - "Leader: {}, Follower: {}", - leader_node.node_id(), - follower_node.node_id() - ); - - let (mut signer, handle) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle.request_sender.send(req_bytes).unwrap(); - - handle_single_request( - &mut signer, - &Arc::new(Mutex::new(PersistVariants::Raft(follower_node))), - ) - .unwrap(); - - let response_bytes = handle.response_receiver.recv().unwrap(); - - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_some()); - println!("{}", res.error.clone().unwrap().description); - assert!( - res.error - .unwrap() - .description - .contains("Cannot persist new consensus state") - ); - } - _ => panic!("Wrong response type"), - } -} - -#[test] -fn double_sign_prevention() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (leader_node, mut followers) = wait_for_leader_and_pop(nodes); - - let (mut signer, handle) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle.request_sender.send(req_bytes.clone()).unwrap(); - - let leader = Arc::new(Mutex::new(PersistVariants::Raft(leader_node))); - handle_single_request(&mut signer, &leader).expect("Failed to handle first request"); - - let response_bytes = handle.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_none()); - assert!(!res.proposal.unwrap().signature.is_empty()); - } - _ => panic!("Wrong response type"), - } - - // Send the _same_ request again - handle.request_sender.send(req_bytes).unwrap(); - - let leader_node = unwrap_node(leader); - leader_node - .transfer_leadership(followers[0].node_id) - .unwrap(); - - followers.push(leader_node); - let nodes = followers; - - let (leader_node, _) = wait_for_leader_and_pop(nodes); - - let leader = Arc::new(Mutex::new(PersistVariants::Raft(leader_node))); - handle_single_request(&mut signer, &leader).unwrap(); - let response_bytes = handle.response_receiver.recv().unwrap(); - - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_some()); - assert!(res.error.unwrap().description.contains("double-sign")); - } - _ => panic!("Wrong response type"), - } -} - -#[test] -fn leader_election_during_signing() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (initial_leader, mut followers) = wait_for_leader_and_pop(nodes); - let initial_leader_id = initial_leader.raft_state.read().unwrap().1; - info!("initial_leader_id: {}", initial_leader_id); - - let success_count = Arc::new(AtomicU64::new(0)); - let error_count = Arc::new(AtomicU64::new(0)); - - let leader = Arc::new(Mutex::new(PersistVariants::Raft(initial_leader))); - let mut handles = Vec::new(); - for _i in 0..3 { - let success_counter = Arc::clone(&success_count); - let error_counter = Arc::clone(&error_count); - let leader = leader.clone(); - - let handle = thread::spawn(move || { - let (mut signer, handle) = create_signer_with_mock_conn(); - - for height in 100..102 { - let req_bytes = create_proposal_request_bytes(height, 0); - if handle.request_sender.send(req_bytes).is_err() { - break; - } - - match crate::handle_single_request(&mut signer, &leader) { - Ok(()) => { - if let Ok(response_bytes) = handle.response_receiver.try_recv() { - let response_msg = v0_38::privval::Message::decode_length_delimited( - response_bytes.as_slice(), - ) - .unwrap(); - if let Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) = - response_msg.sum - { - if res.error.is_none() { - success_counter.fetch_add(1, Ordering::SeqCst); - } else { - error_counter.fetch_add(1, Ordering::SeqCst); - } - } - } - } - Err(_) => { - error_counter.fetch_add(1, Ordering::SeqCst); - } - } - thread::sleep(Duration::from_millis(15)) - } - }); - handles.push(handle); - } - - thread::sleep(Duration::from_millis(500)); - - println!("initial leader id: {}", initial_leader_id); - let transferee_id = followers[0].node_id; - info!( - "Transferring leadership from {} to {}", - initial_leader_id, transferee_id - ); - - let initial_leader = unwrap_node(leader); - initial_leader.transfer_leadership(transferee_id).unwrap(); - thread::sleep(Duration::from_millis(200)); // this sleep is load-bearing for this test - - followers.push(initial_leader); - let nodes = followers; - - let (new_leader_node, _) = wait_for_leader_and_pop(nodes); - let new_leader_id = new_leader_node.raft_state.read().unwrap().1; - assert_ne!( - new_leader_id, initial_leader_id, - "Leadership should have changed" - ); - - for handle in handles { - handle.join().unwrap(); - } - let total_success = success_count.load(Ordering::SeqCst); - let total_errors = error_count.load(Ordering::SeqCst); - - println!( - "Successful signings: {}, Errors: {}", - total_success, total_errors - ); - assert!( - total_success > 0, - "Some requests should have succeeded before leadership change" - ); - assert!( - total_errors > 0, - "Some requests should have failed after leadership change" - ); -} - -#[test] -fn signing_old_blocks_after_state_advancement() { - let harness = TestHarness::new(1); - let nodes = harness.nodes; - let (leader_node, _) = wait_for_leader_and_pop(nodes); - let leader = Arc::new(Mutex::new(PersistVariants::Raft(leader_node))); - - let (mut signer, handle) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle.request_sender.send(req_bytes).unwrap(); - handle_single_request(&mut signer, &leader).unwrap(); - handle.response_receiver.recv().unwrap(); // consume response - - for height in 101..=120 { - let req_bytes = create_proposal_request_bytes(height, 0); - handle.request_sender.send(req_bytes).unwrap(); - handle_single_request(&mut signer, &leader).unwrap(); - handle.response_receiver.recv().unwrap(); - } - - assert_eq!(leader.lock().unwrap().state().height, 120); - - let old_req_bytes = create_proposal_request_bytes(50, 0); - handle.request_sender.send(old_req_bytes).unwrap(); - handle_single_request(&mut signer, &leader).unwrap(); - - // state does not go back - assert_eq!(leader.lock().unwrap().state().height, 120); - - let response_bytes = handle.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_some(), "Should reject old block"); - assert!(res.error.unwrap().description.contains("double-sign")); - } - _ => panic!("Expected SignedProposalResponse with error"), - } -} - -#[test] -fn mixed_vote_types_with_state_transitions() { - let harness = TestHarness::new(1); - let nodes = harness.nodes; - let (leader_node, _) = wait_for_leader_and_pop(nodes); - let leader = Arc::new(Mutex::new(PersistVariants::Raft(leader_node))); - let (mut signer, handle) = create_signer_with_mock_conn(); - - let height = 300; - let round = 0; - - let proposal_bytes = create_proposal_request_bytes(height, round); - handle.request_sender.send(proposal_bytes).unwrap(); - assert!(handle_single_request(&mut signer, &leader).is_ok()); - handle.response_receiver.recv().unwrap(); - - let prevote_bytes = create_vote_request_bytes(height, round, SignedMsgType::Prevote); - handle.request_sender.send(prevote_bytes).unwrap(); - assert!(handle_single_request(&mut signer, &leader).is_ok()); - handle.response_receiver.recv().unwrap(); - - let precommit_bytes = create_vote_request_bytes(height, round, SignedMsgType::Precommit); - handle.request_sender.send(precommit_bytes).unwrap(); - assert!(handle_single_request(&mut signer, &leader).is_ok()); - handle.response_receiver.recv().unwrap(); - - let duplicate_prevote_bytes = create_vote_request_bytes(height, round, SignedMsgType::Prevote); - handle.request_sender.send(duplicate_prevote_bytes).unwrap(); - handle_single_request(&mut signer, &leader).unwrap(); - - let response_bytes = handle.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedVoteResponse(res)) => { - assert!(res.error.is_some(), "Should reject duplicate prevote"); - } - _ => panic!("Expected SignedVoteResponse with error"), - } -} - -#[test] -fn leadership_handoff() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (leader_node, followers) = wait_for_leader_and_pop(nodes); - - let (mut signer, handle) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(400, 0); - handle.request_sender.send(req_bytes).unwrap(); - - leader_node - .transfer_leadership(followers[0].node_id) - .unwrap(); - - thread::sleep(Duration::from_millis(200)); - - let leader = Arc::new(Mutex::new(PersistVariants::Raft(leader_node))); - let result = handle_single_request(&mut signer, &leader); - - match result { - Err(_) => println!("Request correctly failed due to leadership loss"), - Ok(()) => { - if let Ok(response_bytes) = handle.response_receiver.try_recv() { - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()) - .unwrap(); - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - if res.error.is_some() { - println!("Request correctly returned error due to leadership loss"); - } - } - _ => {} - } - } - } - } - - let new_leader = wait_for_leader(&followers, Duration::from_secs(30)); - assert!(new_leader.is_some(), "New leader should be elected"); -} - -#[test] -fn rapid_round_advancement() { - let harness = TestHarness::new(1); - let nodes = harness.nodes; - let (leader_node, _) = wait_for_leader_and_pop(nodes); - let leader = Arc::new(Mutex::new(PersistVariants::Raft(leader_node))); - let (mut signer, handle) = create_signer_with_mock_conn(); - - let height = 500; - - for round in 0..10 { - let proposal_bytes = create_proposal_request_bytes(height, round); - handle.request_sender.send(proposal_bytes).unwrap(); - - let result = handle_single_request(&mut signer, &leader); - assert!( - result.is_ok(), - "Should be able to sign proposal at round {}", - round - ); - handle.response_receiver.recv().unwrap(); - - if round > 0 { - let old_round_bytes = create_proposal_request_bytes(height, round - 1); - handle.request_sender.send(old_round_bytes).unwrap(); - handle_single_request(&mut signer, &leader).unwrap(); - - let response_bytes = handle.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()) - .unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!( - res.error.is_some(), - "Should reject old round at round {}", - round - ); - } - _ => panic!("Expected error response for old round"), - } - } - } -} - -// sign block, leader failover, get request to sign old block, what happens -#[test] -fn double_sign_prevention_after_leadership_change() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (initial_leader, mut followers) = wait_for_leader_and_pop(nodes); - - let (mut signer1, handle1) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle1.request_sender.send(req_bytes).unwrap(); - - let leader = Arc::new(Mutex::new(PersistVariants::Raft(initial_leader))); - handle_single_request(&mut signer1, &leader).unwrap(); - - let response_bytes = handle1.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_none(), "Initial signing should succeed"); - } - _ => panic!("Expected SignedProposalResponse"), - } - - let initial_leader = unwrap_node(leader); - initial_leader - .transfer_leadership(followers[0].node_id) - .unwrap(); - thread::sleep(Duration::from_millis(2000)); - - followers.push(initial_leader); - let nodes = followers; - let (new_leader_node, _) = wait_for_leader_and_pop(nodes); - - let (mut signer2, handle2) = create_signer_with_mock_conn(); - - let duplicate_req_bytes = create_proposal_request_bytes(100, 0); - handle2.request_sender.send(duplicate_req_bytes).unwrap(); - - let new_leader = Arc::new(Mutex::new(PersistVariants::Raft(new_leader_node))); - handle_single_request(&mut signer2, &new_leader).unwrap(); - - let response_bytes2 = handle2.response_receiver.recv().unwrap(); - let response_msg2 = - v0_38::privval::Message::decode_length_delimited(response_bytes2.as_slice()).unwrap(); - - match response_msg2.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_some(), "Duplicate signing should be prevented"); - let error_desc = res.error.unwrap().description; - assert!( - error_desc.contains("double-sign") || error_desc.contains("Would double-sign"), - "Error should mention double signing, got: {}", - error_desc - ); - } - _ => panic!("Expected SignedProposalResponse with error"), - } - - let new_req_bytes = create_proposal_request_bytes(101, 0); - handle2.request_sender.send(new_req_bytes).unwrap(); - - handle_single_request(&mut signer2, &new_leader).unwrap(); - - let response_bytes3 = handle2.response_receiver.recv().unwrap(); - let response_msg3 = - v0_38::privval::Message::decode_length_delimited(response_bytes3.as_slice()).unwrap(); - - match response_msg3.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_none(), "New block signing should succeed"); - } - _ => panic!("Expected successful SignedProposalResponse"), - } -} - -#[test] -fn no_replicate_acks() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (initial_leader, followers) = wait_for_leader_and_pop(nodes); - - let (mut signer1, handle1) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle1.request_sender.send(req_bytes).unwrap(); - - for follower in &followers { - follower.shutdown().unwrap(); - } - - thread::sleep(Duration::from_millis(500)); - - let leader = Arc::new(Mutex::new(PersistVariants::Raft(initial_leader))); - handle_single_request(&mut signer1, &leader).unwrap(); - - let response_bytes = handle1.response_receiver.recv().unwrap(); - - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!( - res.error.is_some(), - "Replication should fail without followers" - ); - } - - _ => panic!("Expected SignedProposalResponse"), - } -} - -#[test] -fn new_leader_signing() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (initial_leader, followers) = wait_for_leader_and_pop(nodes); - - let (mut signer1, handle1) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle1.request_sender.send(req_bytes).unwrap(); - - initial_leader.shutdown().unwrap(); - - let (new_leader_node, _) = wait_for_leader_and_pop(followers); - - let new_leader = Arc::new(Mutex::new(PersistVariants::Raft(new_leader_node))); - handle_single_request(&mut signer1, &new_leader).unwrap(); - - let response_bytes = handle1.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_none(), "2-node cluster should still work"); - } - _ => panic!("Expected SignedProposalResponse"), - } -} - -// im struggling to implement network partition and any other scenarios :/ -#[test] -fn some_turbulence() { - let harness = TestHarness::new(7); - let nodes = harness.nodes; - - let (initial_leader, remaining_nodes) = wait_for_leader_and_pop(nodes); - - let (mut signer1, handle1) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle1.request_sender.send(req_bytes).unwrap(); - - initial_leader.shutdown().unwrap(); - thread::sleep(Duration::from_millis(500)); - - let (another_leader, remaining_nodes) = wait_for_leader_and_pop(remaining_nodes); - another_leader.shutdown().unwrap(); - thread::sleep(Duration::from_millis(500)); - - let (yet_another_leader, remaining_nodes) = wait_for_leader_and_pop(remaining_nodes); - yet_another_leader.shutdown().unwrap(); - thread::sleep(Duration::from_millis(500)); - - let (new_leader_node, _) = wait_for_leader_and_pop(remaining_nodes); - - let new_leader = Arc::new(Mutex::new(PersistVariants::Raft(new_leader_node))); - handle_single_request(&mut signer1, &new_leader).unwrap(); - - let response_bytes = handle1.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()).unwrap(); - - match response_msg.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!(res.error.is_none(), "4-node cluster should still work"); - } - _ => panic!("Expected SignedProposalResponse"), - } -} - -#[test] -fn too_much_turbulence() { - let harness = TestHarness::new(7); - let nodes = harness.nodes; - - let (initial_leader, remaining_nodes) = wait_for_leader_and_pop(nodes); - - initial_leader.shutdown().unwrap(); - thread::sleep(Duration::from_millis(500)); - - let (another_leader, remaining_nodes) = wait_for_leader_and_pop(remaining_nodes); - another_leader.shutdown().unwrap(); - thread::sleep(Duration::from_millis(500)); - - let (yet_another_leader, remaining_nodes) = wait_for_leader_and_pop(remaining_nodes); - yet_another_leader.shutdown().unwrap(); - thread::sleep(Duration::from_millis(500)); - - let (too_much_leaders, remaining_nodes) = wait_for_leader_and_pop(remaining_nodes); - too_much_leaders.shutdown().unwrap(); - thread::sleep(Duration::from_millis(500)); - - let new_leader = wait_for_leader(&remaining_nodes, Duration::from_secs(3)); - - assert!(new_leader.is_none(), "leader election should fail"); -} - -// NOTE: this test was used for the try_lock mutex. -#[test] -fn signing_lock_prevents_concurrent_requests() { - let harness = TestHarness::new(3); - let nodes = harness.nodes; - let (leader_node, followers) = wait_for_leader_and_pop(nodes); - - let (mut signer1, handle1) = create_signer_with_mock_conn(); - let (mut signer2, handle2) = create_signer_with_mock_conn(); - - let req_bytes = create_proposal_request_bytes(100, 0); - handle1.request_sender.send(req_bytes.clone()).unwrap(); - handle2.request_sender.send(req_bytes).unwrap(); - - let (tx, rx) = mpsc::channel(); - - let leader = Arc::new(Mutex::new(PersistVariants::Raft(leader_node))); - let leader1 = Arc::clone(&leader); - let leader2 = Arc::clone(&leader); - - std::thread::scope(|s| { - let tx1 = tx.clone(); - s.spawn(move || { - let _ = handle_single_request(&mut signer1, &leader1); - let response_bytes = handle1.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()) - .unwrap(); - tx1.send(response_msg).unwrap(); - }); - - s.spawn(move || { - let _ = handle_single_request(&mut signer2, &leader2); - let response_bytes = handle2.response_receiver.recv().unwrap(); - let response_msg = - v0_38::privval::Message::decode_length_delimited(response_bytes.as_slice()) - .unwrap(); - tx.send(response_msg).unwrap(); - }); - }); - - let mut responses = vec![rx.recv().unwrap(), rx.recv().unwrap()]; - - let success_response_index = responses - .iter() - .position(|r| { - if let Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) = &r.sum { - res.error.is_none() - } else { - false - } - }) - .expect("Expected one successful response"); - - let success_response = responses.remove(success_response_index); - let failure_response = responses.pop().unwrap(); - - match success_response.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - assert!( - res.error.is_none(), - "The winning request should succeed without error" - ); - assert!( - !res.proposal.unwrap().signature.is_empty(), - "The winning request should have a signature" - ); - } - _ => panic!("Expected a SignedProposalResponse for the successful case"), - } - - match failure_response.sum { - Some(v0_38::privval::message::Sum::SignedProposalResponse(res)) => { - let err = res.error.expect("The losing request should have an error"); - assert!( - err.description - .contains("Would double-sign proposal at height/round/step"), - "Error message should indicate a lock failure. Got: '{}'", - err.description - ); - assert!( - res.proposal.is_none(), - "The losing request should not contain a proposal" - ); - } - _ => panic!("Expected a SignedProposalResponse for the failure case"), - } - - let leader_node = unwrap_node(leader); - let state = leader_node.signer_state.read().unwrap(); - assert_eq!( - state.height, 100, - "State should be updated by the single successful request" - ); - assert_eq!(state.round, 0); - - for node in &followers { - let state = node.signer_state.read().unwrap(); - assert_eq!( - state.height, 100, - "State should be updated by the single successful request" - ); - assert_eq!(state.round, 0); - } -} diff --git a/src/cluster/mod.rs b/src/cluster/mod.rs deleted file mode 100644 index 1632c17..0000000 --- a/src/cluster/mod.rs +++ /dev/null @@ -1,506 +0,0 @@ -mod storage; - -use crate::cluster::storage::RocksDBStorage; -use crate::config::RaftConfig; -use crate::error::SignerError; -use crate::types::ConsensusData; -use log::{info, warn}; -use protobuf::Message as ProtobufMessage; -use raft::prelude::{ConfState, EntryType, Message as RaftProtoMessage, Snapshot}; -use raft::{Config as RaftCoreConfig, RawNode, StateRole, Storage}; -use slog::{Drain, o}; -use std::collections::{HashMap, VecDeque}; -use std::io::{BufReader, BufWriter, Read, Write}; -use std::net::{TcpListener, TcpStream}; -use std::sync::mpsc::{self, RecvTimeoutError, Sender}; -use std::sync::{Arc, RwLock}; -use std::thread; -use std::time::{Duration, Instant}; - -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; - -enum RaftMessage { - Propose(ConsensusData, Sender>), - Msg(RaftProtoMessage), - TransferLeadership(u64), - #[allow(dead_code)] - Shutdown, -} - -pub struct SignerRaftNode { - node_id: u64, - pub signer_state: Arc>, - proposal_sender: Sender, - raft_state: Arc>, - #[allow(dead_code)] - shutdown_handle: Arc>>>, -} - -impl SignerRaftNode { - #[allow(dead_code)] - pub fn shutdown(&self) -> Result<(), SignerError> { - info!("Shutting down node {}", self.node_id); - - self.proposal_sender - .send(RaftMessage::Shutdown) - .map_err(|e| SignerError::Other(format!("Failed to send shutdown: {}", e)))?; - - if let Some(handle) = self.shutdown_handle.write().unwrap().take() { - handle - .join() - .map_err(|_| SignerError::Other("Failed to join raft thread".to_string()))?; - } - - Ok(()) - } - - pub fn new(config: RaftConfig) -> Self { - let logger = stdlog_to_slog(); - let storage = create_storage(&config); - let signer_state = Arc::new(RwLock::new(storage.read_signer_state().unwrap())); - - let (in_tx, in_rx) = mpsc::channel::(); - let (out_tx, out_rx) = mpsc::channel::(); - let raft_state = Arc::new(RwLock::new((StateRole::Follower, 0))); - - start_inbound_handler(config.bind_addr.clone(), in_tx.clone()); - start_outbound_handler(out_rx, config.peers.clone(), config.node_id); - - let handle = start_raft_thread( - config.node_id, - storage, - logger, - in_rx, - out_tx, - Arc::clone(&signer_state), - Arc::clone(&raft_state), - ); - - SignerRaftNode { - signer_state, - proposal_sender: in_tx, - raft_state, - node_id: config.node_id, - shutdown_handle: Arc::new(RwLock::new(Some(handle))), - } - } - - pub fn replicate_state(&self, new_state: &ConsensusData) -> Result<(), SignerError> { - info!( - "replicating state: {}, leader_id: {}", - new_state, - self.leader_id().unwrap(), - ); - if !self.is_leader() { - return Err(SignerError::NotLeader(self.node_id.to_string())); - } - - let (tx, rx) = mpsc::channel(); - self.proposal_sender - .send(RaftMessage::Propose(*new_state, tx)) - .map_err(|e| { - SignerError::Other(format!("Failed to send proposal to raft thread: {}", e)) - })?; - - match rx.recv_timeout(Duration::from_secs(5)) { - Ok(Ok(())) => { - info!("replication successful, propagated state: {}", new_state); - Ok(()) - } - Ok(Err(e)) => { - warn!("replication failed: {:?}", e); - Err(e) - } - Err(_) => { - warn!("replication timed out"); - Err(SignerError::StateReplication( - "State replication timed out".to_string(), - )) - } - } - } - - pub fn is_leader(&self) -> bool { - self.raft_state.read().unwrap().0 == StateRole::Leader - } - - pub fn leader_id(&self) -> Option { - let state = self.raft_state.read().unwrap(); - if state.1 == 0 { None } else { Some(state.1) } - } - - #[allow(dead_code)] // TODO - pub fn node_id(&self) -> u64 { - self.node_id - } - - #[allow(dead_code)] // TODO - pub fn transfer_leadership(&self, transferee_id: u64) -> Result<(), SignerError> { - info!("transferring leadership to node {}", transferee_id); - if !self.is_leader() { - return Err(SignerError::NotLeader( - "This node is not the leader, cannot transfer leadership".to_string(), - )); - } - - self.proposal_sender - .send(RaftMessage::TransferLeadership(transferee_id)) - .map_err(|e| { - SignerError::Other(format!( - "Failed to send leadership transfer request to raft thread: {}", - e - )) - }) - } -} - -fn stdlog_to_slog() -> slog::Logger { - let drain = slog_stdlog::StdLog.fuse(); - let drain = slog_async::Async::new(drain) - .chan_size(4096) - .overflow_strategy(slog_async::OverflowStrategy::Block) - .build() - .fuse(); - slog::Logger::root(drain, o!()) -} - -fn create_storage(config: &RaftConfig) -> RocksDBStorage { - info!("storage path: {}", config.data_path); - let mut storage = RocksDBStorage::new(&config.data_path); - - let peer_ids: Vec = config.peers.iter().map(|p| p.id).collect(); - let init_state = storage.initial_state().unwrap(); - - if init_state.hard_state.commit == 0 && init_state.hard_state.term == 0 { - info!("fresh store, bootstrapping with peers: {:?}", peer_ids); - bootstrap_storage(&mut storage, peer_ids, &config.initial_state_path); - } else { - info!("found existing state, loading from DB"); - } - - storage -} - -fn bootstrap_storage(storage: &mut RocksDBStorage, peer_ids: Vec, initial_state_path: &str) { - let mut snap = Snapshot::default(); - snap.mut_metadata().set_index(1); - snap.mut_metadata().set_term(1); - let mut cs = ConfState::default(); - cs.set_voters(peer_ids); - snap.mut_metadata().set_conf_state(cs); - storage.apply_snapshot(snap).unwrap(); - - let state_file_path = std::path::Path::new(initial_state_path); - let initial_state = - if let Some(bootstrap_state) = ConsensusData::load_from_file(state_file_path) { - info!( - "loaded bootstrap state from state.json: {}", - bootstrap_state - ); - bootstrap_state - } else { - info!( - "no state file found at {}, using default state.", - initial_state_path - ); - ConsensusData::default() - }; - - storage.write_signer_state(&initial_state).unwrap(); -} - -fn start_inbound_handler(bind_addr: String, in_tx: Sender) { - thread::spawn(move || { - let listener = TcpListener::bind(&bind_addr) - .unwrap_or_else(|_| panic!("bind failed on {}", bind_addr)); - info!("listening on {}", bind_addr); - for stream in listener.incoming().flatten() { - let in_tx = in_tx.clone(); - thread::spawn(move || { - let mut reader = BufReader::new(stream); - while let Ok(len) = reader.read_u32::() { - let mut buf = vec![0; len as usize]; - if reader.read_exact(&mut buf).is_err() { - break; - } - match RaftProtoMessage::parse_from_bytes(&buf) { - Ok(msg) => { - if in_tx.send(RaftMessage::Msg(msg)).is_err() { - break; - } - } - Err(e) => warn!("parse error: {:?}", e), - } - } - }); - } - }); -} - -fn start_outbound_handler( - out_rx: mpsc::Receiver, - peers: Vec, - node_id: u64, -) { - thread::spawn(move || { - let mut peer_writers: HashMap>)> = peers - .into_iter() - .filter(|p| p.id != node_id) - .map(|p| (p.id, (p.addr, None))) - .collect(); - - while let Ok(msg) = out_rx.recv() { - let to_id = msg.to; - - let (addr, writer_opt) = match peer_writers.get_mut(&to_id) { - Some(info) => info, - None => { - warn!("trying to send message to unknown peer {}", to_id,); - continue; - } - }; - - if writer_opt.is_none() { - match TcpStream::connect(&*addr) { - Ok(stream) => { - // stream - // .set_write_timeout(Some(Duration::from_secs(1))) - // .expect("failed to set write timeout on raft stream"); - info!("connected to {} ({})", addr, to_id); - *writer_opt = Some(BufWriter::new(stream)); - } - Err(_) => { - warn!( - "failed to connect to {} ({}); will retry on next message", - addr, to_id - ); - continue; - } - } - } - - if let Some(w) = writer_opt { - let bytes = msg.write_to_bytes().unwrap(); - if w.write_u32::(bytes.len() as u32).is_err() - || w.write_all(&bytes).is_err() - || w.flush().is_err() - { - warn!( - "failed to send message to {}; connection broken. will reconnect.", - to_id - ); - *writer_opt = None; - } - } - } - }); -} - -fn start_raft_thread( - node_id: u64, - storage: RocksDBStorage, - logger: slog::Logger, - in_rx: mpsc::Receiver, - out_tx: Sender, - signer_state: Arc>, - raft_state: Arc>, -) -> thread::JoinHandle<()> { - thread::spawn(move || { - let raft_cfg = RaftCoreConfig { - id: node_id, - election_tick: 10, - check_quorum: true, - pre_vote: true, - heartbeat_tick: 3, - ..Default::default() - }; - raft_cfg.validate().unwrap(); - - let mut raft_node = RawNode::new(&raft_cfg, storage, &logger).unwrap(); - let mut last_tick = Instant::now(); - let mut timeout = Duration::from_millis(100); - let mut proposal_callbacks: VecDeque>> = VecDeque::new(); - - loop { - match in_rx.recv_timeout(timeout) { - Ok(RaftMessage::Propose(data, callback)) => { - let _ = raft_node.propose(vec![], data.to_bytes()); - proposal_callbacks.push_back(callback); - } - Ok(RaftMessage::Msg(m)) => { - let _ = raft_node.step(m); - } - Ok(RaftMessage::TransferLeadership(transferee_id)) => { - raft_node.transfer_leader(transferee_id); - } - Ok(RaftMessage::Shutdown) => { - info!("Raft thread received shutdown signal"); - for callback in proposal_callbacks.drain(..) { - let _ = callback - .send(Err(SignerError::Other("Node shutting down".to_string()))); - } - break; - } - Err(RecvTimeoutError::Timeout) => {} - Err(RecvTimeoutError::Disconnected) => break, - } - - let elapsed = last_tick.elapsed(); - if elapsed >= timeout { - raft_node.tick(); - last_tick = Instant::now(); - timeout = Duration::from_millis(100); - } else { - timeout -= elapsed; - } - on_ready( - &mut raft_node, - &signer_state, - &out_tx, - &raft_state, - &mut proposal_callbacks, - ); - } - }) -} - -fn on_ready( - raft_group: &mut RawNode, - signer_state: &Arc>, - net_tx: &Sender, - raft_state: &Arc>, - proposal_callbacks: &mut VecDeque>>, -) { - if !raft_group.has_ready() { - return; - } - - let mut ready = raft_group.ready(); - - if let Some(ss) = ready.ss() { - let was_leader = raft_state.read().unwrap().0 == StateRole::Leader; - let is_leader = ss.raft_state == StateRole::Leader; - - if was_leader && !is_leader { - warn!( - "leadership lost, failing {} pending proposals", - proposal_callbacks.len() - ); - for callback in proposal_callbacks.drain(..) { - let _ = callback.send(Err(SignerError::NotLeader( - "Lost leadership during replication".into(), - ))); - } - } - - let mut state = raft_state.write().unwrap(); - state.0 = ss.raft_state; - state.1 = ss.leader_id; - } - - for msg in ready.take_messages() { - let _ = net_tx.send(msg); - } - - if !ready.snapshot().is_empty() { - let snap = ready.snapshot().clone(); - raft_group.mut_store().apply_snapshot(snap.clone()).unwrap(); - - if let Some(sm_data) = ConsensusData::from_bytes(snap.get_data()) { - info!("loaded state machine from snapshot: {:?}", sm_data); - *signer_state.write().unwrap() = sm_data; - } - } - - if !ready.entries().is_empty() { - raft_group - .mut_store() - .append_entries(ready.entries()) - .unwrap(); - } - - if let Some(hs) = ready.hs() { - raft_group.mut_store().set_hard_state(hs.clone()).unwrap(); - } - - for msg in ready.take_persisted_messages() { - let _ = net_tx.send(msg); - } - - if !ready.committed_entries().is_empty() { - handle_committed_entries( - raft_group, - ready.take_committed_entries(), - signer_state, - proposal_callbacks, - ); - } - - let mut light_rd = raft_group.advance(ready); - - for msg in light_rd.take_messages() { - let _ = net_tx.send(msg); - } - - if !light_rd.committed_entries().is_empty() { - handle_committed_entries( - raft_group, - light_rd.take_committed_entries(), - signer_state, - proposal_callbacks, - ); - } - - raft_group.advance_apply(); -} - -fn handle_committed_entries( - raft_group: &mut RawNode, - committed_entries: Vec, - signer_state: &Arc>, - proposal_callbacks: &mut VecDeque>>, -) { - for ent in committed_entries { - match ent.get_entry_type() { - EntryType::EntryNormal => { - if !ent.get_data().is_empty() { - if let Some(ns) = ConsensusData::from_bytes(ent.get_data()) { - info!( - "applying normal entry received from master: {}, current node state: {}, node_id: {}", - ns, - signer_state.read().unwrap(), - raft_group.raft.id, - ); - *signer_state.write().unwrap() = ns; - raft_group.mut_store().write_signer_state(&ns).unwrap(); - - if let Some(callback) = proposal_callbacks.pop_front() { - if let Err(e) = callback.send(Ok(())) { - warn!("failed to send commit confirmation: {:?}", e); - } - } - } - } - } - EntryType::EntryConfChange => { - info!("applying conf change entry"); - let cc: raft::prelude::ConfChange = - protobuf::Message::parse_from_bytes(ent.get_data()).unwrap(); - let cs = raft_group.apply_conf_change(&cc).unwrap(); - raft_group.mut_store().set_conf_state(cs).unwrap(); - } - EntryType::EntryConfChangeV2 => { - warn!("unhandled EntryConfChangeV2"); - } - } - } -} - -#[cfg(test)] -mod integration_tests; - -#[cfg(test)] -mod tests; - -// #[cfg(test)] -// mod partition_tests; diff --git a/src/cluster/storage.rs b/src/cluster/storage.rs deleted file mode 100644 index d4241ec..0000000 --- a/src/cluster/storage.rs +++ /dev/null @@ -1,239 +0,0 @@ -use crate::types::ConsensusData; -use log::info; -use protobuf::Message as PbMessage; -use raft::{Error as RaftError, Storage, StorageError}; -use raft::{GetEntriesContext, prelude::*}; -use rocksdb::{DB, Options}; -use std::path::Path; - -const KEY_HARD_STATE: &[u8] = b"hard_state"; -const KEY_CONF_STATE: &[u8] = b"conf_state"; -const KEY_LAST_INDEX: &[u8] = b"last_index"; -const KEY_SIGNER_STATE: &[u8] = b"state_machine"; - -fn entry_key(index: u64) -> Vec { - format!("entry:{}", index).into_bytes() -} - -pub struct RocksDBStorage { - db: DB, -} - -impl RocksDBStorage { - pub fn new>(path: P) -> Self { - let mut opts = Options::default(); - opts.create_if_missing(true); - let db = DB::open(&opts, path).expect("Failed to open RocksDB"); - RocksDBStorage { db } - } - - pub fn read_signer_state(&self) -> raft::Result { - match self - .db - .get(KEY_SIGNER_STATE) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))? - { - Some(bytes) => Ok(ConsensusData::from_bytes(&bytes).unwrap_or_default()), - None => Ok(ConsensusData::default()), - } - } - - pub fn write_signer_state(&self, sm: &ConsensusData) -> raft::Result<()> { - let value = sm.to_bytes(); - let mut opts = rocksdb::WriteOptions::default(); - opts.set_sync(true); - self.db - .put_opt(KEY_SIGNER_STATE, &value, &opts) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e)))) - } - - pub fn append_entries(&mut self, entries: &[Entry]) -> raft::Result<()> { - let mut opts = rocksdb::WriteOptions::default(); - opts.set_sync(true); - for entry in entries { - let key = entry_key(entry.get_index()); - let value = entry - .write_to_bytes() - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?; - self.db - .put_opt(key, &value, &opts) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?; - } - if let Some(last_entry) = entries.last() { - self.db - .put_opt(KEY_LAST_INDEX, last_entry.get_index().to_be_bytes(), &opts) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?; - } - Ok(()) - } - - pub fn set_hard_state(&mut self, hs: HardState) -> raft::Result<()> { - let mut opts = rocksdb::WriteOptions::default(); - opts.set_sync(true); - let value = hs - .write_to_bytes() - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?; - self.db - .put_opt(KEY_HARD_STATE, &value, &opts) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e)))) - } - - pub fn set_conf_state(&mut self, cs: ConfState) -> raft::Result<()> { - let mut opts = rocksdb::WriteOptions::default(); - opts.set_sync(true); - let value = cs - .write_to_bytes() - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?; - self.db - .put_opt(KEY_CONF_STATE, &value, &opts) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e)))) - } - - pub fn apply_snapshot(&mut self, snapshot: Snapshot) -> raft::Result<()> { - let mut opts = rocksdb::WriteOptions::default(); - opts.set_sync(true); - info!( - "[storage] Applying snapshot at index {}", - snapshot.get_metadata().get_index() - ); - let meta = snapshot.get_metadata(); - let term = meta.get_term(); - let index = meta.get_index(); - - if let Some(sm_data) = ConsensusData::from_bytes(snapshot.get_data()) { - self.write_signer_state(&sm_data)?; - } - - self.set_conf_state(meta.get_conf_state().clone())?; - - let mut hs = self.initial_state()?.hard_state; - hs.set_term(term); - hs.set_commit(index); - self.set_hard_state(hs)?; - - self.db - .put_opt(KEY_LAST_INDEX, index.to_be_bytes(), &opts) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?; - Ok(()) - } -} - -impl Storage for RocksDBStorage { - fn initial_state(&self) -> raft::Result { - let hard_state = match self - .db - .get(KEY_HARD_STATE) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))? - { - Some(bytes) => HardState::parse_from_bytes(&bytes) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?, - None => HardState::default(), - }; - let conf_state = match self - .db - .get(KEY_CONF_STATE) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))? - { - Some(bytes) => ConfState::parse_from_bytes(&bytes) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?, - None => ConfState::default(), - }; - Ok(RaftState { - hard_state, - conf_state, - }) - } - - fn entries( - &self, - low: u64, - high: u64, - _max_size: impl Into>, - _context: GetEntriesContext, - ) -> raft::Result> { - let mut entries = Vec::with_capacity((high - low) as usize); - for i in low..high { - match self - .db - .get(entry_key(i)) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))? - { - Some(bytes) => { - let entry = Entry::parse_from_bytes(&bytes) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))?; - entries.push(entry); - } - None => return Err(RaftError::Store(StorageError::Unavailable)), - } - } - Ok(entries) - } - - fn term(&self, idx: u64) -> raft::Result { - if idx == 0 { - return Ok(0); - } - let state = self.initial_state()?; - let snapshot_index = state.hard_state.get_commit(); - if idx == snapshot_index { - return Ok(state.hard_state.get_term()); - } - if idx < snapshot_index { - return Err(RaftError::Store(StorageError::Compacted)); - } - - match self - .db - .get(entry_key(idx)) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))? - { - Some(bytes) => Ok(Entry::parse_from_bytes(&bytes) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))? - .get_term()), - None => Err(RaftError::Store(StorageError::Unavailable)), - } - } - - fn first_index(&self) -> raft::Result { - Ok(self.initial_state()?.hard_state.get_commit() + 1) - } - - fn last_index(&self) -> raft::Result { - match self - .db - .get(KEY_LAST_INDEX) - .map_err(|e| RaftError::Store(StorageError::Other(Box::new(e))))? - { - Some(bytes) => Ok(u64::from_be_bytes(bytes.try_into().unwrap_or_default())), - None => Ok(self.initial_state()?.hard_state.get_commit()), - } - } - - fn snapshot(&self, request_index: u64, _to: u64) -> raft::Result { - let state = self.initial_state()?; - let last_index = self.last_index()?; - - if request_index > last_index { - return Err(RaftError::Store(StorageError::SnapshotOutOfDate)); - } - - info!( - "[storage] Creating snapshot at index {}", - state.hard_state.get_commit() - ); - - let mut snapshot = Snapshot::default(); - snapshot.mut_metadata().set_conf_state(state.conf_state); - snapshot - .mut_metadata() - .set_index(state.hard_state.get_commit()); - snapshot - .mut_metadata() - .set_term(state.hard_state.get_term()); - - let sm_data = self.read_signer_state()?; - snapshot.set_data(sm_data.to_bytes().into()); - - Ok(snapshot) - } -} diff --git a/src/cluster/tests.rs b/src/cluster/tests.rs deleted file mode 100644 index 76bac82..0000000 --- a/src/cluster/tests.rs +++ /dev/null @@ -1,137 +0,0 @@ -use super::*; -use crate::config::{PeerConfig, RaftConfig}; -use crate::types::{ConsensusData, SignedMsgType}; -use std::sync::Arc; -use std::thread; -use std::time::{Duration, Instant}; -use tempfile::TempDir; - -fn create_test_config( - port_prefix: u64, - node_id: u64, - temp_dir: &TempDir, - peers: Vec, -) -> RaftConfig { - RaftConfig { - node_id, - bind_addr: format!("127.0.0.1:{}", port_prefix + node_id), - data_path: temp_dir - .path() - .join(format!("node_{}", node_id)) - .to_str() - .unwrap() - .to_string(), - peers, - initial_state_path: "./test_consensus_state.json".to_string(), - } -} - -fn wait_for_leader(clusters: &[Arc], timeout: Duration) -> Option { - let start = Instant::now(); - while start.elapsed() < timeout { - for cluster in clusters { - if cluster.is_leader() { - return Some(cluster.leader_id().unwrap()); - } - } - thread::sleep(Duration::from_millis(100)); - } - None -} - -fn get_leader_cluster(clusters: &[Arc]) -> Option> { - for cluster in clusters { - if cluster.is_leader() { - return Some(Arc::clone(cluster)); - } - } - None -} - -#[test] -fn single_node_cluster() { - let temp_dir = TempDir::new().unwrap(); - let peers = vec![PeerConfig { - id: 1, - addr: "127.0.0.1:8001".to_string(), - }]; - let config = create_test_config(8000, 1, &temp_dir, peers); - - let cluster = Arc::new(SignerRaftNode::new(config)); - - let leader_id = wait_for_leader(&[Arc::clone(&cluster)], Duration::from_secs(5)); - assert_eq!(leader_id, Some(1)); - assert!(cluster.is_leader()); - - let new_state = ConsensusData { - height: 100, - round: 1, - step: SignedMsgType::Proposal, - }; - - let result = cluster.replicate_state(&new_state); - assert!(result.is_ok()); - - let current_state = cluster.signer_state.read().unwrap().clone(); - assert_eq!(current_state, new_state); -} - -#[test] -fn three_node_cluster_basic() { - let temp_dir = TempDir::new().unwrap(); - let peers = vec![ - PeerConfig { - id: 1, - addr: "127.0.0.1:9001".to_string(), - }, - PeerConfig { - id: 2, - addr: "127.0.0.1:9002".to_string(), - }, - PeerConfig { - id: 3, - addr: "127.0.0.1:9003".to_string(), - }, - ]; - - let cluster1 = Arc::new(SignerRaftNode::new(create_test_config( - 9000, - 1, - &temp_dir, - peers.clone(), - ))); - let cluster2 = Arc::new(SignerRaftNode::new(create_test_config( - 9000, - 2, - &temp_dir, - peers.clone(), - ))); - let cluster3 = Arc::new(SignerRaftNode::new(create_test_config( - 9000, - 3, - &temp_dir, - peers.clone(), - ))); - - let clusters = vec![cluster1, cluster2, cluster3]; - - let leader_id = wait_for_leader(&clusters, Duration::from_secs(10)); - assert!(leader_id.is_some()); - - let leader = get_leader_cluster(&clusters).unwrap(); - let new_state = ConsensusData { - height: 200, - round: 2, - step: SignedMsgType::Prevote, - }; - - let result = leader.replicate_state(&new_state); - assert!(result.is_ok()); - - thread::sleep(Duration::from_secs(2)); - - for cluster in &clusters { - let state = cluster.signer_state.read().unwrap().clone(); - assert_eq!(state, new_state); - } -} diff --git a/src/config.rs b/src/config.rs index cf7041f..e17efbe 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,7 +12,8 @@ pub struct PeerConfig { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct RaftConfig { pub node_id: u64, - pub bind_addr: String, + pub raft_addr: String, + pub http_addr: String, pub data_path: String, pub peers: Vec, pub initial_state_path: String, @@ -87,13 +88,14 @@ impl Config { persist: PersistConfig::Raft { raft: RaftConfig { node_id: 1, - bind_addr: "127.0.0.1:8080".to_string(), + raft_addr: "127.0.0.1:8080".to_string(), data_path: "./raft_data".to_string(), peers: vec![PeerConfig { id: 1, addr: "127.0.0.1:8080".into(), }], initial_state_path: "./initial_state.json".to_string(), + http_addr: "127.0.0.1:8081".to_string(), }, }, signing: match backend { diff --git a/src/main.rs b/src/main.rs index 67c7b69..800f6ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ mod backend; -mod cluster; mod config; mod connection; mod error; @@ -15,11 +14,12 @@ use crate::backend::SigningBackend; use crate::error::SignerError; use crate::protocol::Response; use clap::{Parser as _, Subcommand}; -use cluster::SignerRaftNode; use config::{Config, PersistConfig, ProtocolVersionConfig}; use log::{LevelFilter, debug, error, info, warn}; use persist::{Persist, PersistVariants}; use protocol::{CheckedProposalRequest, CheckedVoteRequest, Request, ValidRequest}; +use raft_kv_store::NodeConfig; +use raft_kv_store::config::PeerConfig; use signer::Signer; use std::io::{Read, Write}; use std::net::TcpStream; @@ -112,9 +112,28 @@ fn start_signer(config: Config) -> Result<(), SignerError> { let state_persist: Arc> = match &config.persist { PersistConfig::Raft { raft } => { info!("Node ID: {}", raft.node_id); - Arc::new(Mutex::new(PersistVariants::Raft(SignerRaftNode::new( - raft.clone(), - )))) + let mut node_peers: Vec = vec![]; + for peer in raft.peers.clone() { + node_peers.push(PeerConfig { + id: peer.id, + addr: peer.addr, + }); + } + let raft_cfg = raft.clone(); + Arc::new(Mutex::new(PersistVariants::Raft( + raft_kv_store::start_kv_node::(NodeConfig { + node_id: raft.node_id, + peers: node_peers.clone(), + bind_addr: raft_cfg.raft_addr, + storage_path: raft_cfg.data_path, + http_addr: raft_cfg.http_addr, + linearizable: true, + heartbeat_tick: 3, + election_tick: 10, + tick_interval_ms: 2, + }) + .unwrap(), + ))) } PersistConfig::Local { local } => { info!("Local persistence path: {:?}", local.path); diff --git a/src/persist.rs b/src/persist.rs index 1ecefe6..714d8bf 100644 --- a/src/persist.rs +++ b/src/persist.rs @@ -1,7 +1,7 @@ -use crate::cluster::SignerRaftNode; use crate::protocol::ValidRequest; use crate::types::ConsensusData; use enum_dispatch::enum_dispatch; +use raft_kv_store::KvApp; use std::path::PathBuf; #[derive(Debug)] @@ -12,7 +12,7 @@ pub enum PersistError { #[enum_dispatch(Persist)] pub enum PersistVariants { - Raft(SignerRaftNode), + Raft(KvApp), Local(LocalState), } @@ -62,18 +62,15 @@ impl Persist for LocalState { } } -impl Persist for SignerRaftNode { +impl Persist for KvApp { fn persist(&mut self, request: ValidRequest) -> Result { - if !self.is_leader() { - return Err(PersistError::InvalidState("Not the leader".into())); - } let state = ConsensusData::from(&request); - if let Err(e) = self.replicate_state(&state) { + if let Err(e) = self.handle().put("latest".to_string(), state) { return Err(PersistError::CouldNotPersist(e.to_string())); } Ok(PersistedRequest(request)) } fn state(&self) -> ConsensusData { - *self.signer_state.read().unwrap() + self.handle().get("latest").unwrap().unwrap() } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 5532ca8..36b096e 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -176,6 +176,26 @@ pub struct ConsensusData { pub step: SignedMsgType, } +use rusqlite::ToSql; +use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef}; + +impl ToSql for ConsensusData { + fn to_sql(&self) -> rusqlite::Result> { + let bytes = bincode::serde::encode_to_vec(self, bincode::config::standard()) + .map_err(|e| rusqlite::Error::ToSqlConversionFailure(Box::new(e)))?; + Ok(ToSqlOutput::from(bytes)) + } +} + +impl FromSql for ConsensusData { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + let bytes = value.as_blob()?; + let (data, _): (ConsensusData, usize) = + bincode::serde::decode_from_slice(bytes, bincode::config::standard()) + .map_err(|e| FromSqlError::Other(Box::new(e)))?; + Ok(data) + } +} impl From<&ValidRequest> for ConsensusData { fn from(value: &ValidRequest) -> Self { match value { From d020d03bb57d15dea8b4f47005fadab7e61ebb20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ksawery=20Wr=C3=B3bel?= Date: Fri, 31 Oct 2025 22:10:47 +0100 Subject: [PATCH 2/3] clone --- src/main.rs | 35 +++++++++++++++++++++-------------- src/persist.rs | 5 ++++- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/main.rs b/src/main.rs index 800f6ee..964dbba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -120,20 +120,27 @@ fn start_signer(config: Config) -> Result<(), SignerError> { }); } let raft_cfg = raft.clone(); - Arc::new(Mutex::new(PersistVariants::Raft( - raft_kv_store::start_kv_node::(NodeConfig { - node_id: raft.node_id, - peers: node_peers.clone(), - bind_addr: raft_cfg.raft_addr, - storage_path: raft_cfg.data_path, - http_addr: raft_cfg.http_addr, - linearizable: true, - heartbeat_tick: 3, - election_tick: 10, - tick_interval_ms: 2, - }) - .unwrap(), - ))) + let http_addr = raft_cfg.http_addr.clone(); + + let kv_app = raft_kv_store::start_kv_node::(NodeConfig { + node_id: raft.node_id, + peers: node_peers.clone(), + bind_addr: raft_cfg.raft_addr, + storage_path: raft_cfg.data_path, + http_addr: http_addr, + linearizable: true, + heartbeat_tick: 3, + election_tick: 10, + tick_interval_ms: 2, + }) + .unwrap(); + + let _http_handle = raft_kv_store::start_http_service::( + &raft_cfg.http_addr, + kv_app.handle(), + )?; + + Arc::new(Mutex::new(PersistVariants::Raft(kv_app))) } PersistConfig::Local { local } => { info!("Local persistence path: {:?}", local.path); diff --git a/src/persist.rs b/src/persist.rs index 714d8bf..3d437f8 100644 --- a/src/persist.rs +++ b/src/persist.rs @@ -71,6 +71,9 @@ impl Persist for KvApp { Ok(PersistedRequest(request)) } fn state(&self) -> ConsensusData { - self.handle().get("latest").unwrap().unwrap() + match self.handle().get("latest").unwrap() { + Some(state) => state, + None => ConsensusData::default(), + } } } From 2f8658c2cbed351a2faaaa146d30103cbbf303be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ksawery=20Wr=C3=B3bel?= Date: Sat, 1 Nov 2025 21:39:06 +0100 Subject: [PATCH 3/3] remove unused deps --- Cargo.lock | 519 ++++------------------------------------------------- Cargo.toml | 8 - 2 files changed, 38 insertions(+), 489 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5261b9..862bba0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,44 +178,6 @@ dependencies = [ "virtue", ] -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags 2.9.1", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.101", -] - -[[package]] -name = "bindgen" -version = "0.71.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" -dependencies = [ - "bitflags 2.9.1", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "proc-macro2", - "quote", - "regex", - "rustc-hash 2.1.1", - "shlex", - "syn 2.0.101", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -228,18 +190,6 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -258,38 +208,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bls-signatures" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc7fce0356b52c2483bb6188cc8bdc11add526bce75d1a44e5e5d889a6ab008" -dependencies = [ - "bls12_381", - "ff 0.13.1", - "group 0.13.0", - "hkdf 0.11.0", - "pairing", - "rand_core 0.6.4", - "rayon", - "sha2 0.9.9", - "subtle", - "thiserror 1.0.69", -] - -[[package]] -name = "bls12_381" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403" -dependencies = [ - "digest 0.9.0", - "ff 0.13.1", - "group 0.13.0", - "pairing", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "blst" version = "0.3.14" @@ -323,36 +241,15 @@ dependencies = [ "serde", ] -[[package]] -name = "bzip2-sys" -version = "0.1.13+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "cc" version = "1.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" dependencies = [ - "jobserver", - "libc", "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -421,17 +318,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.5.45" @@ -463,7 +349,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -514,25 +400,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -571,33 +438,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest 0.10.7", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "curve25519-dalek-ng" version = "4.1.1" @@ -688,7 +528,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -728,20 +568,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "serde", - "sha2 0.10.9", - "subtle", - "zeroize", -] - [[package]] name = "either" version = "1.15.0" @@ -757,9 +583,9 @@ dependencies = [ "base16ct", "crypto-bigint", "der 0.5.1", - "ff 0.11.1", + "ff", "generic-array", - "group 0.11.0", + "group", "rand_core 0.6.4", "sec1", "subtle", @@ -775,7 +601,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -865,23 +691,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "bitvec", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - [[package]] name = "fixedbitset" version = "0.4.2" @@ -928,12 +737,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "futures" version = "0.3.31" @@ -1053,7 +856,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -1074,18 +877,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" dependencies = [ - "ff 0.11.1", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff 0.13.1", + "ff", "rand_core 0.6.4", "subtle", ] @@ -1126,16 +918,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hkdf" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" -dependencies = [ - "digest 0.9.0", - "hmac 0.11.0", -] - [[package]] name = "hkdf" version = "0.12.4" @@ -1459,15 +1241,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -1504,17 +1277,7 @@ checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", -] - -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom 0.3.3", - "libc", + "syn", ] [[package]] @@ -1555,28 +1318,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" -[[package]] -name = "libloading" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" -dependencies = [ - "cfg-if", - "windows-targets", -] - [[package]] name = "libredox" version = "0.1.3" @@ -1587,21 +1334,6 @@ dependencies = [ "libc", ] -[[package]] -name = "librocksdb-sys" -version = "0.17.1+9.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7869a512ae9982f4d46ba482c2a304f1efd80c6412a3d4bf57bb79a619679f" -dependencies = [ - "bindgen 0.69.5", - "bzip2-sys", - "cc", - "libc", - "libz-sys", - "lz4-sys", - "zstd-sys", -] - [[package]] name = "libsqlite3-sys" version = "0.35.0" @@ -1613,17 +1345,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "libz-sys" -version = "1.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1661,16 +1382,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" -[[package]] -name = "lz4-sys" -version = "1.11.1+lz4-1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "memchr" version = "2.7.4" @@ -1695,12 +1406,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.8" @@ -1731,33 +1436,26 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" name = "nebula" version = "0.1.0" dependencies = [ - "anyhow", "base64", "bincode", - "bls-signatures", "blst", "byteorder", "bytes", "chrono", "clap", "ed25519-consensus", - "ed25519-dalek", "enum_dispatch", "env_logger", "hex", "k256", "log", - "prost 0.13.5", + "prost", "prost-build", "prost-types", - "protobuf", "raft", "raft-kv-store", - "raft-proto", - "rand 0.9.1", "rand_core 0.6.4", "reqwest", - "rocksdb", "rusqlite", "serde", "serde_json", @@ -1769,20 +1467,9 @@ dependencies = [ "tempfile", "tendermint-p2p", "thiserror 2.0.12", - "tiny_http", "toml", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -1835,15 +1522,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "pairing" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" -dependencies = [ - "group 0.13.0", -] - [[package]] name = "paste" version = "1.0.15" @@ -1962,7 +1640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", - "syn 2.0.101", + "syn", ] [[package]] @@ -1984,7 +1662,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -1996,16 +1674,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - [[package]] name = "prost" version = "0.13.5" @@ -2013,7 +1681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ "bytes", - "prost-derive 0.13.5", + "prost-derive", ] [[package]] @@ -2023,32 +1691,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ "heck", - "itertools 0.12.1", + "itertools", "log", "multimap", "once_cell", "petgraph", "prettyplease", - "prost 0.13.5", + "prost", "prost-types", "regex", - "syn 2.0.101", + "syn", "tempfile", ] -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "prost-derive" version = "0.13.5" @@ -2056,10 +1711,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools", "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -2068,7 +1723,7 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" dependencies = [ - "prost 0.13.5", + "prost", ] [[package]] @@ -2112,7 +1767,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", "socket2", "thiserror 2.0.12", @@ -2132,7 +1787,7 @@ dependencies = [ "lru-slab", "rand 0.9.1", "ring", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", "rustls-pki-types", "slab", @@ -2171,12 +1826,6 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "raft" version = "0.7.0" @@ -2228,7 +1877,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb6884896294f553e8d5cfbdb55080b9f5f2f43394afff59c9f077e0f4b46d6b" dependencies = [ "bytes", - "prost 0.11.9", "protobuf", "protobuf-build", ] @@ -2292,26 +1940,6 @@ dependencies = [ "getrandom 0.3.3", ] -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "redox_users" version = "0.4.6" @@ -2420,16 +2048,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rocksdb" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec73b20525cb235bad420f911473b69f9fe27cc856c5461bccd7e4af037f43" -dependencies = [ - "libc", - "librocksdb-sys", -] - [[package]] name = "rusqlite" version = "0.37.0" @@ -2450,27 +2068,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "1.0.7" @@ -2550,12 +2153,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" - [[package]] name = "serde" version = "1.0.228" @@ -2592,7 +2189,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -2624,7 +2221,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -2693,9 +2290,6 @@ name = "signature" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "rand_core 0.6.4", -] [[package]] name = "slab" @@ -2930,17 +2524,6 @@ dependencies = [ "sval_nested", ] -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.101" @@ -2969,7 +2552,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -2978,12 +2561,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tempfile" version = "3.20.0" @@ -3010,7 +2587,7 @@ dependencies = [ "futures", "num-traits", "once_cell", - "prost 0.13.5", + "prost", "serde", "serde_bytes", "serde_json", @@ -3037,9 +2614,9 @@ dependencies = [ "eyre", "flex-error", "flume", - "hkdf 0.12.4", + "hkdf", "merlin", - "prost 0.13.5", + "prost", "rand_core 0.6.4", "sha2 0.10.9", "signature 2.2.0", @@ -3058,7 +2635,7 @@ checksum = "d2c40e13d39ca19082d8a7ed22de7595979350319833698f8b1080f29620a094" dependencies = [ "bytes", "flex-error", - "prost 0.13.5", + "prost", "serde", "serde_bytes", "subtle-encoding", @@ -3108,7 +2685,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -3119,7 +2696,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -3508,7 +3085,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn", "wasm-bindgen-shared", ] @@ -3543,7 +3120,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3629,7 +3206,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -3640,7 +3217,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -3773,15 +3350,6 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "yoke" version = "0.8.0" @@ -3802,7 +3370,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", "synstructure", ] @@ -3823,7 +3391,7 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -3843,7 +3411,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", "synstructure", ] @@ -3864,7 +3432,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn", ] [[package]] @@ -3897,16 +3465,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", -] - -[[package]] -name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" -dependencies = [ - "bindgen 0.71.1", - "cc", - "pkg-config", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 47eee36..9eddd19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ prost = "0.13" prost-types = "0.13" serde = { version = "1.0", features = ["derive"] } chrono = { version = "0.4", features = ["serde"] } -ed25519-dalek = "2.1.1" tendermint-p2p = "0.40.4" ed25519-consensus = "2.1.0" rand_core = { version = "0.6.4", features = ["std"]} @@ -22,20 +21,13 @@ serde_json = "1.0.140" reqwest = { version = "0.12.19", default-features = false, features = ["blocking", "json", "rustls-tls"] } k256 = { version = "0.10", features = ["ecdsa"] } blst = "0.3" -bls-signatures = "0.15.0" raft = "0.7.0" bytes = "1.10.1" slog = "2.7.0" slog-async = "2.8.0" slog-term = "2.9.1" bincode = { version = "2", features = ["serde"] } -anyhow = "1.0.98" -tiny_http = "0.12.0" -rand = "0.9.1" -rocksdb = "0.23.0" -raft-proto = { version = "0.7.0", features = ["prost", "protobuf-codec"] } slog-stdlog = "4.1.1" -protobuf = "2.28.0" byteorder = "1.5.0" enum_dispatch = "0.3.13" clap = { version = "4.5.45", features = ["derive"] }