diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b134c2be7bb..f1ec5c5194b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,7 +105,6 @@ jobs: - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} - args: --all-features # Full cross-platform tests required by bors to merge on main branch full: diff --git a/Cargo.lock b/Cargo.lock index c31f6b1df4f..a92af46845d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,19 +278,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits 0.2.14", - "time", - "winapi", -] - [[package]] name = "clap" version = "2.34.0" @@ -610,11 +597,11 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.9.0" -source = "git+https://github.com/yvan-sraka/dialoguer.git?branch=completion-feature#e25c3868ec88f76e84c41edd433a793b3cd146b4" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d6b4fabcd9e97e1df1ae15395ac7e49fb144946a0d453959dc2696273b9da" dependencies = [ "console", - "lazy_static", "tempfile", "zeroize", ] @@ -1519,9 +1506,9 @@ dependencies = [ "erased-serde", "futures 0.3.21", "glob", - "jsonrpc-core-client", "lazy_static", "massa_models", + "massa_sdk", "massa_signature", "massa_time", "massa_wallet", @@ -1557,7 +1544,8 @@ dependencies = [ "massa_ledger", "massa_logging", "massa_models", - "massa_network", + "massa_network_exports", + "massa_network_worker", "massa_pool", "massa_protocol_exports", "massa_protocol_worker", @@ -1607,7 +1595,7 @@ dependencies = [ "massa_graph", "massa_hash", "massa_models", - "massa_network", + "massa_network_exports", "massa_pool", "massa_protocol_exports", "massa_signature", @@ -1631,7 +1619,7 @@ dependencies = [ "massa_ledger", "massa_logging", "massa_models", - "massa_network", + "massa_network_exports", "massa_proof_of_stake_exports", "massa_signature", "massa_time", @@ -1858,7 +1846,26 @@ dependencies = [ ] [[package]] -name = "massa_network" +name = "massa_network_exports" +version = "0.1.0" +dependencies = [ + "displaydoc", + "enum-map", + "massa_hash", + "massa_logging", + "massa_models", + "massa_signature", + "massa_time", + "serde 1.0.136", + "serde_json", + "tempfile", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "massa_network_worker" version = "0.1.0" dependencies = [ "displaydoc", @@ -1868,6 +1875,7 @@ dependencies = [ "massa_hash", "massa_logging", "massa_models", + "massa_network_exports", "massa_signature", "massa_time", "num_enum", @@ -1939,7 +1947,7 @@ dependencies = [ "massa_hash", "massa_logging", "massa_models", - "massa_network", + "massa_network_exports", "massa_signature", "massa_time", "num_enum", @@ -1965,7 +1973,7 @@ dependencies = [ "massa_hash", "massa_logging", "massa_models", - "massa_network", + "massa_network_exports", "massa_protocol_exports", "massa_signature", "massa_time", @@ -1981,6 +1989,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "massa_sdk" +version = "0.1.0" +dependencies = [ + "jsonrpc-core-client", + "massa_models", + "massa_signature", + "serde 1.0.136", + "tokio", +] + [[package]] name = "massa_signature" version = "0.1.0" @@ -2002,12 +2021,12 @@ dependencies = [ name = "massa_time" version = "0.1.0" dependencies = [ - "chrono", "displaydoc", "pretty_assertions", "serde 1.0.136", "serial_test", "thiserror", + "time", "tokio", ] @@ -2291,6 +2310,15 @@ dependencies = [ "syn", ] +[[package]] +name = "num_threads" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +dependencies = [ + "libc", +] + [[package]] name = "object" version = "0.27.1" @@ -3517,12 +3545,14 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" dependencies = [ + "itoa", "libc", - "winapi", + "num_threads", + "serde 1.0.136", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ffb6a3b9cf4..780f3bb2b36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,10 @@ members = [ "massa-hash", "massa-logging", "massa-models", - "massa-network", + "massa-network-worker", + "massa-network-exports", "massa-node", + "massa-sdk", "massa-pool", "massa-proof-of-stake-exports", "massa-protocol-exports", diff --git a/massa-api/Cargo.toml b/massa-api/Cargo.toml index ee3ebf327b7..1c2528d0661 100644 --- a/massa-api/Cargo.toml +++ b/massa-api/Cargo.toml @@ -20,11 +20,11 @@ massa_execution_exports = { path = "../massa-execution-exports" } massa_graph = { path = "../massa-graph" } massa_hash = { path = "../massa-hash" } massa_models = { path = "../massa-models" } -massa_network = { path = "../massa-network" } +massa_network_exports = { path = "../massa-network-exports" } massa_pool = { path = "../massa-pool" } massa_protocol_exports = { path = "../massa-protocol-exports" } massa_signature = { path = "../massa-signature" } massa_time = { path = "../massa-time" } [features] -instrument = ["tokio/tracing", "massa_consensus_exports/instrument", "massa_graph/instrument", "massa_models/instrument", "massa_network/instrument", "massa_pool/instrument", "massa_protocol_exports/instrument", "massa_time/instrument"] +instrument = ["tokio/tracing", "massa_consensus_exports/instrument", "massa_graph/instrument", "massa_models/instrument", "massa_network_exports/instrument", "massa_pool/instrument", "massa_protocol_exports/instrument", "massa_time/instrument"] diff --git a/massa-api/src/error.rs b/massa-api/src/error.rs index f999f1cab57..f36d00a16c2 100644 --- a/massa-api/src/error.rs +++ b/massa-api/src/error.rs @@ -5,7 +5,7 @@ use massa_consensus_exports::error::ConsensusError; use massa_execution_exports::ExecutionError; use massa_hash::MassaHashError; use massa_models::ModelsError; -use massa_network::NetworkError; +use massa_network_exports::NetworkError; use massa_pool::PoolError; use massa_time::TimeError; use thiserror::Error; diff --git a/massa-api/src/lib.rs b/massa-api/src/lib.rs index 63a282bf486..f16821164fa 100644 --- a/massa-api/src/lib.rs +++ b/massa-api/src/lib.rs @@ -17,11 +17,11 @@ use massa_models::clique::Clique; use massa_models::composite::PubkeySig; use massa_models::execution::ExecuteReadOnlyResponse; use massa_models::node::NodeId; -use massa_models::operation::{Operation, OperationId}; +use massa_models::operation::OperationId; use massa_models::output_event::SCOutputEvent; use massa_models::prehash::{Map, Set}; -use massa_models::{Address, BlockId, EndorsementId, Version}; -use massa_network::{NetworkCommandSender, NetworkSettings}; +use massa_models::{Address, BlockId, EndorsementId, SignedOperation, Version}; +use massa_network_exports::{NetworkCommandSender, NetworkSettings}; use massa_pool::PoolCommandSender; use massa_signature::PrivateKey; use std::net::{IpAddr, SocketAddr}; @@ -192,7 +192,10 @@ pub trait Endpoints { /// Adds operations to pool. Returns operations that were ok and sent to pool. #[rpc(name = "send_operations")] - fn send_operations(&self, _: Vec) -> BoxFuture, ApiError>>; + fn send_operations( + &self, + _: Vec, + ) -> BoxFuture, ApiError>>; /// Get events optionnally filtered by: /// * start slot diff --git a/massa-api/src/private.rs b/massa-api/src/private.rs index 910ca29b703..14092f9e715 100644 --- a/massa-api/src/private.rs +++ b/massa-api/src/private.rs @@ -15,8 +15,8 @@ use massa_models::composite::PubkeySig; use massa_models::execution::ExecuteReadOnlyResponse; use massa_models::output_event::SCOutputEvent; use massa_models::prehash::{Map, Set}; -use massa_models::{Address, BlockId, EndorsementId, Operation, OperationId}; -use massa_network::NetworkCommandSender; +use massa_models::{Address, BlockId, EndorsementId, OperationId, SignedOperation}; +use massa_network_exports::NetworkCommandSender; use massa_signature::PrivateKey; use std::net::{IpAddr, SocketAddr}; @@ -150,7 +150,10 @@ impl Endpoints for API { crate::wrong_api::>() } - fn send_operations(&self, _: Vec) -> BoxFuture, ApiError>> { + fn send_operations( + &self, + _: Vec, + ) -> BoxFuture, ApiError>> { crate::wrong_api::>() } diff --git a/massa-api/src/public.rs b/massa-api/src/public.rs index 3efb9b2d44a..9bcc98c1d48 100644 --- a/massa-api/src/public.rs +++ b/massa-api/src/public.rs @@ -11,6 +11,8 @@ use massa_execution_exports::{ use massa_graph::{DiscardReason, ExportBlockStatus}; use massa_models::api::SCELedgerInfo; use massa_models::execution::ReadOnlyResult; +use massa_models::SignedOperation; + use massa_models::{ api::{ APISettings, AddressInfo, BlockInfo, BlockInfoContent, BlockSummary, EndorsementInfo, @@ -23,9 +25,9 @@ use massa_models::{ output_event::SCOutputEvent, prehash::{BuildMap, Map, Set}, timeslots::{get_latest_block_slot_at_timestamp, time_range_to_slot_range}, - Address, BlockId, CompactConfig, EndorsementId, Operation, OperationId, Slot, Version, + Address, BlockId, CompactConfig, EndorsementId, OperationId, Slot, Version, }; -use massa_network::{NetworkCommandSender, NetworkSettings}; +use massa_network_exports::{NetworkCommandSender, NetworkSettings}; use massa_pool::PoolCommandSender; use massa_signature::{derive_public_key, generate_random_private_key, PrivateKey}; use massa_time::MassaTime; @@ -413,41 +415,16 @@ impl Endpoints for API { let cfg = self.0.consensus_config.clone(); let api_cfg = self.0.api_settings; let pool_command_sender = self.0.pool_command_sender.clone(); + let execution_controller = self.0.execution_controller.clone(); let compensation_millis = self.0.compensation_millis; - // todo make better use of SCE ledger info - - // map SCE ledger info and check for address length - let sce_ledger_info = if addresses.len() as u64 > api_cfg.max_arguments { - Err(ApiError::TooManyArguments("too many arguments".into())) - } else { - // get SCE ledger info - let mut sce_ledger_info: Map = - Map::with_capacity_and_hasher(addresses.len(), BuildMap::default()); - for addr in &addresses { - let active_entry = match self - .0 - .execution_controller - .get_final_and_active_ledger_entry(addr) - .1 - { - None => continue, - Some(v) => SCELedgerInfo { - balance: v.parallel_balance, - module: Some(v.bytecode), - datastore: v.datastore.into_iter().collect(), - }, - }; - sce_ledger_info.insert(*addr, active_entry); - } - Ok(sce_ledger_info) - }; - let closure = async move || { - let sce_ledger_info = sce_ledger_info?; - let mut res = Vec::with_capacity(addresses.len()); + // check for address length + if addresses.len() as u64 > api_cfg.max_arguments { + return Err(ApiError::TooManyArguments("too many arguments".into())); + } // next draws info let now = MassaTime::compensated_now(compensation_millis)?; let current_slot = get_latest_block_slot_at_timestamp( @@ -479,17 +456,23 @@ impl Endpoints for API { Map::with_capacity_and_hasher(addresses.len(), BuildMap::default()); let mut endorsements: Map> = Map::with_capacity_and_hasher(addresses.len(), BuildMap::default()); + let mut final_sce_ledger_info: Map = + Map::with_capacity_and_hasher(addresses.len(), BuildMap::default()); + let mut candidate_sce_ledger_info: Map = + Map::with_capacity_and_hasher(addresses.len(), BuildMap::default()); let mut concurrent_getters = FuturesUnordered::new(); for &address in addresses.iter() { let mut pool_cmd_snd = pool_command_sender.clone(); let cmd_snd = cmd_sender.clone(); + let exec_snd = execution_controller.clone(); concurrent_getters.push(async move { let blocks = cmd_snd .get_block_ids_by_creator(address) .await? .into_keys() .collect::>(); + let get_pool_ops = pool_cmd_snd.get_operations_involving_address(address); let get_consensus_ops = cmd_snd.get_operations_involving_address(address); let (get_pool_ops, get_consensus_ops) = @@ -499,24 +482,75 @@ impl Endpoints for API { .chain(get_consensus_ops?.into_keys()) .collect(); - let get_pool_eds = pool_cmd_snd.get_endorsements_by_address(address); - let get_consensus_eds = cmd_snd.get_endorsements_by_address(address); - let (get_pool_eds, get_consensus_eds) = - tokio::join!(get_pool_eds, get_consensus_eds); - let gathered_ed: Set = get_pool_eds? - .into_keys() - .chain(get_consensus_eds?.into_keys()) - .collect(); - Result::<(Address, Set, Set, Set), ApiError>::Ok(( - address, blocks, gathered, gathered_ed + let get_pool_eds = pool_cmd_snd.get_endorsements_by_address(address); + let get_consensus_eds = cmd_snd.get_endorsements_by_address(address); + let (get_pool_eds, get_consensus_eds) = + tokio::join!(get_pool_eds, get_consensus_eds); + let gathered_ed: Set = get_pool_eds? + .into_keys() + .chain(get_consensus_eds?.into_keys()) + .collect(); + + let (final_sce, candidate_sce) = + match exec_snd.get_final_and_active_ledger_entry(&address) { + (None, None) => (SCELedgerInfo::default(), SCELedgerInfo::default()), + (None, Some(candidate)) => ( + SCELedgerInfo::default(), + SCELedgerInfo { + balance: candidate.parallel_balance, + module: candidate.bytecode, + datastore: candidate.datastore.into_iter().collect(), + }, + ), + (Some(final_entry), None) => ( + SCELedgerInfo { + balance: final_entry.parallel_balance, + module: final_entry.bytecode, + datastore: final_entry.datastore.into_iter().collect(), + }, + SCELedgerInfo::default(), + ), + (Some(final_entry), Some(candidate)) => ( + SCELedgerInfo { + balance: final_entry.parallel_balance, + module: final_entry.bytecode, + datastore: final_entry.datastore.into_iter().collect(), + }, + SCELedgerInfo { + balance: candidate.parallel_balance, + module: candidate.bytecode, + datastore: candidate.datastore.into_iter().collect(), + }, + ), + }; + + Result::< + ( + Address, + Set, + Set, + Set, + SCELedgerInfo, + SCELedgerInfo, + ), + ApiError, + >::Ok(( + address, + blocks, + gathered, + gathered_ed, + final_sce, + candidate_sce, )) }); } while let Some(res) = concurrent_getters.next().await { - let (a, bl_set, op_set, ed_set) = res?; + let (a, bl_set, op_set, ed_set, final_sce, candidate_sce) = res?; operations.insert(a, op_set); blocks.insert(a, bl_set); endorsements.insert(a, ed_set); + final_sce_ledger_info.insert(a, final_sce); + candidate_sce_ledger_info.insert(a, candidate_sce); } // compile everything per address @@ -552,7 +586,12 @@ impl Endpoints for API { .remove(&address) .ok_or(ApiError::NotFound)?, production_stats: state.production_stats, - sce_ledger_info: sce_ledger_info.get(&address).cloned().unwrap_or_default(), + final_sce_ledger_info: final_sce_ledger_info + .remove(&address) + .ok_or(ApiError::NotFound)?, + candidate_sce_ledger_info: candidate_sce_ledger_info + .remove(&address) + .ok_or(ApiError::NotFound)?, }) } Ok(res) @@ -562,7 +601,7 @@ impl Endpoints for API { fn send_operations( &self, - ops: Vec, + ops: Vec, ) -> BoxFuture, ApiError>> { let mut cmd_sender = self.0.pool_command_sender.clone(); let api_cfg = self.0.api_settings; diff --git a/massa-bootstrap/Cargo.toml b/massa-bootstrap/Cargo.toml index 7b5a818911f..6c7fe65e6e4 100644 --- a/massa-bootstrap/Cargo.toml +++ b/massa-bootstrap/Cargo.toml @@ -25,7 +25,7 @@ massa_graph = { path = "../massa-graph" } massa_hash = { path = "../massa-hash" } massa_logging = { path = "../massa-logging" } massa_models = { path = "../massa-models" } -massa_network = { path = "../massa-network" } +massa_network_exports = { path = "../massa-network-exports" } massa_proof_of_stake_exports = { path = "../massa-proof-of-stake-exports" } massa_signature = { path = "../massa-signature" } massa_time = { path = "../massa-time" } @@ -38,4 +38,4 @@ massa_ledger = { path = "../massa-ledger", features=["testing"] } [features] -instrument = ["tokio/tracing", "massa_consensus_exports/instrument", "massa_graph/instrument", "massa_models/instrument", "massa_network/instrument", "massa_proof_of_stake_exports/instrument", "massa_time/instrument"] +instrument = ["tokio/tracing", "massa_consensus_exports/instrument", "massa_graph/instrument", "massa_models/instrument", "massa_network_exports/instrument", "massa_proof_of_stake_exports/instrument", "massa_time/instrument"] diff --git a/massa-bootstrap/src/error.rs b/massa-bootstrap/src/error.rs index d65d984899a..bf50e8e57ca 100644 --- a/massa-bootstrap/src/error.rs +++ b/massa-bootstrap/src/error.rs @@ -5,7 +5,7 @@ use displaydoc::Display; use massa_consensus_exports::error::ConsensusError; use massa_hash::MassaHashError; use massa_ledger::LedgerError; -use massa_network::NetworkError; +use massa_network_exports::NetworkError; use massa_time::TimeError; use thiserror::Error; diff --git a/massa-bootstrap/src/lib.rs b/massa-bootstrap/src/lib.rs index 9e60ccd7e14..b684d7f87f9 100644 --- a/massa-bootstrap/src/lib.rs +++ b/massa-bootstrap/src/lib.rs @@ -13,7 +13,7 @@ use massa_graph::BootstrapableGraph; use massa_ledger::{FinalLedger, FinalLedgerBootstrapState}; use massa_logging::massa_trace; use massa_models::Version; -use massa_network::{BootstrapPeers, NetworkCommandSender}; +use massa_network_exports::{BootstrapPeers, NetworkCommandSender}; use massa_proof_of_stake_exports::ExportProofOfStake; use massa_signature::{PrivateKey, PublicKey}; use massa_time::MassaTime; diff --git a/massa-bootstrap/src/messages.rs b/massa-bootstrap/src/messages.rs index 07a62a4b8e1..258027ea90f 100644 --- a/massa-bootstrap/src/messages.rs +++ b/massa-bootstrap/src/messages.rs @@ -5,7 +5,7 @@ use massa_ledger::FinalLedgerBootstrapState; use massa_models::{ DeserializeCompact, DeserializeVarInt, ModelsError, SerializeCompact, SerializeVarInt, Version, }; -use massa_network::BootstrapPeers; +use massa_network_exports::BootstrapPeers; use massa_proof_of_stake_exports::ExportProofOfStake; use massa_time::MassaTime; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/massa-bootstrap/src/tests/scenarios.rs b/massa-bootstrap/src/tests/scenarios.rs index c153daba294..cbe65e6c705 100644 --- a/massa-bootstrap/src/tests/scenarios.rs +++ b/massa-bootstrap/src/tests/scenarios.rs @@ -17,7 +17,7 @@ use crate::{ use massa_consensus_exports::{commands::ConsensusCommand, ConsensusCommandSender}; use massa_ledger::{test_exports::assert_eq_ledger_bootstrap_state, FinalLedger}; use massa_models::Version; -use massa_network::{NetworkCommand, NetworkCommandSender}; +use massa_network_exports::{NetworkCommand, NetworkCommandSender}; use massa_signature::PrivateKey; use massa_time::MassaTime; use parking_lot::RwLock; diff --git a/massa-bootstrap/src/tests/tools.rs b/massa-bootstrap/src/tests/tools.rs index afa62a101d4..a6284bbe9fd 100644 --- a/massa-bootstrap/src/tests/tools.rs +++ b/massa-bootstrap/src/tests/tools.rs @@ -13,10 +13,11 @@ use massa_models::{ clique::Clique, ledger_models::{LedgerChange, LedgerChanges, LedgerData}, rolls::{RollCounts, RollUpdate, RollUpdates}, - Address, Amount, Block, BlockHeader, BlockHeaderContent, BlockId, DeserializeCompact, - Endorsement, EndorsementContent, Operation, OperationContent, SerializeCompact, Slot, + signed::Signed, + Address, Amount, Block, BlockHeader, BlockId, DeserializeCompact, Endorsement, Operation, + SerializeCompact, Slot, }; -use massa_network::{BootstrapPeers, NetworkCommand}; +use massa_network_exports::{BootstrapPeers, NetworkCommand}; use massa_proof_of_stake_exports::{ExportProofOfStake, ThreadCycleState}; use massa_signature::{ derive_public_key, generate_random_private_key, sign, PrivateKey, PublicKey, Signature, @@ -373,38 +374,44 @@ pub fn get_boot_state() -> (ExportProofOfStake, BootstrapableGraph) { let block1 = ExportActiveBlock { block: Block { - header: BlockHeader { - content: BlockHeaderContent { + header: Signed::new_signed( + BlockHeader { creator: get_random_public_key(), slot: Slot::new(1, 1), parents: vec![get_dummy_block_id("p1"), get_dummy_block_id("p2")], operation_merkle_root: Hash::compute_from("op_hash".as_bytes()), endorsements: vec![ - Endorsement { - content: EndorsementContent { + Signed::new_signed( + Endorsement { sender_public_key: get_random_public_key(), slot: Slot::new(1, 0), index: 1, endorsed_block: get_dummy_block_id("p1"), }, - signature: get_dummy_signature("dummy_sig_0"), - }, - Endorsement { - content: EndorsementContent { + &generate_random_private_key(), + ) + .unwrap() + .1, + Signed::new_signed( + Endorsement { sender_public_key: get_random_public_key(), slot: Slot::new(4, 1), index: 3, endorsed_block: get_dummy_block_id("p1"), }, - signature: get_dummy_signature("dummy_sig_00"), - }, + &generate_random_private_key(), + ) + .unwrap() + .1, ], }, - signature: get_dummy_signature("dummy_sig_1"), - }, + &generate_random_private_key(), + ) + .unwrap() + .1, operations: vec![ - Operation { - content: OperationContent { + Signed::new_signed( + Operation { sender_public_key: get_random_public_key(), fee: Amount::from_str("1524878").unwrap(), expire_period: 5787899, @@ -413,19 +420,23 @@ pub fn get_boot_state() -> (ExportProofOfStake, BootstrapableGraph) { amount: Amount::from_str("1259787").unwrap(), }, }, - signature: get_dummy_signature("dummy_sig_2"), - }, - Operation { - content: OperationContent { + &generate_random_private_key(), + ) + .unwrap() + .1, + Signed::new_signed( + Operation { sender_public_key: get_random_public_key(), fee: Amount::from_str("878763222").unwrap(), expire_period: 4557887, op: massa_models::OperationType::RollBuy { roll_count: 45544 }, }, - signature: get_dummy_signature("dummy_sig_3"), - }, - Operation { - content: OperationContent { + &generate_random_private_key(), + ) + .unwrap() + .1, + Signed::new_signed( + Operation { sender_public_key: get_random_public_key(), fee: Amount::from_str("4545").unwrap(), expire_period: 452524, @@ -433,8 +444,10 @@ pub fn get_boot_state() -> (ExportProofOfStake, BootstrapableGraph) { roll_count: 4888787, }, }, - signature: get_dummy_signature("dummy_sig_4"), - }, + &generate_random_private_key(), + ) + .unwrap() + .1, ], }, parents: vec![ diff --git a/massa-client/Cargo.toml b/massa-client/Cargo.toml index 9a4c36a377c..862788b9f35 100644 --- a/massa-client/Cargo.toml +++ b/massa-client/Cargo.toml @@ -11,12 +11,11 @@ anyhow = "1.0" atty = "0.2" config = "0.11" console = "0.15" -dialoguer = { version = "0.9", git = "https://github.com/yvan-sraka/dialoguer.git", branch = "completion-feature", features = ["history", "completion"] } +dialoguer = { version = "0.10", features = ["history", "completion"] } directories = "4.0" erased-serde = "0.3" futures = "0.3" glob = "0.3.0" -jsonrpc-core-client = { version = "18.0", features = ["http", "tls"] } lazy_static = "1.4" paw = "1.0" rev_lines = "0.2" @@ -30,6 +29,7 @@ tokio = { version = "1.15", features = ["full"] } massa_models = { path = "../massa-models" } massa_signature = { path = "../massa-signature" } massa_time = { path = "../massa-time" } +massa_sdk = { path = "../massa-sdk" } massa_wallet = { path = "../massa-wallet" } [target.'cfg(not(windows))'.dependencies] diff --git a/massa-client/src/cmds.rs b/massa-client/src/cmds.rs index b082ae8236b..17d3a978d09 100644 --- a/massa-client/src/cmds.rs +++ b/massa-client/src/cmds.rs @@ -1,7 +1,6 @@ // Copyright (c) 2022 MASSA LABS use crate::repl::Output; -use crate::rpc::Client; use anyhow::{anyhow, bail, Result}; use console::style; use massa_models::api::ReadOnlyExecution; @@ -9,8 +8,9 @@ use massa_models::api::{AddressInfo, CompactAddressInfo}; use massa_models::prehash::Map; use massa_models::timeslots::get_current_latest_block_slot; use massa_models::{ - Address, Amount, BlockId, EndorsementId, OperationContent, OperationId, OperationType, Slot, + Address, Amount, BlockId, EndorsementId, Operation, OperationId, OperationType, Slot, }; +use massa_sdk::Client; use massa_signature::{generate_random_private_key, PrivateKey, PublicKey}; use massa_time::MassaTime; use massa_wallet::{Wallet, WalletError}; @@ -839,7 +839,7 @@ async fn send_operation( }; let op = wallet.create_operation( - OperationContent { + Operation { sender_public_key, fee, expire_period, diff --git a/massa-client/src/main.rs b/massa-client/src/main.rs index f398fc939a6..12443e4395f 100644 --- a/massa-client/src/main.rs +++ b/massa-client/src/main.rs @@ -2,12 +2,12 @@ #![feature(str_split_whitespace_as_str)] -use crate::rpc::Client; use crate::settings::SETTINGS; use anyhow::Result; use atty::Stream; use cmds::Command; use console::style; +use massa_sdk::Client; use massa_wallet::Wallet; use serde::Serialize; use std::net::IpAddr; @@ -16,7 +16,6 @@ use structopt::StructOpt; mod cmds; mod repl; -mod rpc; mod settings; mod utils; diff --git a/massa-client/src/repl.rs b/massa-client/src/repl.rs index 7d00464c625..d7c770955a5 100644 --- a/massa-client/src/repl.rs +++ b/massa-client/src/repl.rs @@ -1,7 +1,6 @@ // Copyright (c) 2022 MASSA LABS use crate::cmds::{Command, ExtendedWallet}; -use crate::rpc::Client; use crate::settings::SETTINGS; use crate::utils::longest_common_prefix; use console::style; @@ -13,6 +12,7 @@ use massa_models::composite::PubkeySig; use massa_models::execution::ExecuteReadOnlyResponse; use massa_models::prehash::Set; use massa_models::{Address, OperationId}; +use massa_sdk::Client; use massa_wallet::Wallet; use rev_lines::RevLines; use std::collections::VecDeque; diff --git a/massa-consensus-exports/src/commands.rs b/massa-consensus-exports/src/commands.rs index d53a36b3fef..2b1517c3475 100644 --- a/massa-consensus-exports/src/commands.rs +++ b/massa-consensus-exports/src/commands.rs @@ -2,12 +2,11 @@ //! Contains definitions of commands used by the controller use massa_graph::{BlockGraphExport, BootstrapableGraph, ExportBlockStatus, Status}; -use massa_models::{ - address::AddressState, api::EndorsementInfo, Endorsement, EndorsementId, OperationId, -}; +use massa_models::{address::AddressState, api::EndorsementInfo, EndorsementId, OperationId}; use massa_models::{clique::Clique, stats::ConsensusStats}; use massa_models::{ - Address, Block, BlockId, OperationSearchResult, Slot, StakersCycleProductionStats, + Address, Block, BlockId, OperationSearchResult, SignedEndorsement, Slot, + StakersCycleProductionStats, }; use massa_proof_of_stake_exports::ExportProofOfStake; @@ -73,7 +72,7 @@ pub enum ConsensusCommand { }, GetEndorsementsByAddress { address: Address, - response_tx: oneshot::Sender>, + response_tx: oneshot::Sender>, }, GetEndorsementsById { endorsements: Set, diff --git a/massa-consensus-exports/src/consensus_controller.rs b/massa-consensus-exports/src/consensus_controller.rs index 2e155ed6ce1..24e7cae52b7 100644 --- a/massa-consensus-exports/src/consensus_controller.rs +++ b/massa-consensus-exports/src/consensus_controller.rs @@ -1,11 +1,10 @@ // Copyright (c) 2022 MASSA LABS use massa_graph::{BlockGraphExport, BootstrapableGraph, ExportBlockStatus, Status}; -use massa_models::{ - address::AddressState, api::EndorsementInfo, Endorsement, EndorsementId, OperationId, -}; +use massa_models::{address::AddressState, api::EndorsementInfo, EndorsementId, OperationId}; use massa_models::{clique::Clique, stats::ConsensusStats}; use massa_models::{ - Address, Block, BlockId, OperationSearchResult, Slot, StakersCycleProductionStats, + Address, Block, BlockId, OperationSearchResult, SignedEndorsement, Slot, + StakersCycleProductionStats, }; use massa_proof_of_stake_exports::ExportProofOfStake; use massa_protocol_exports::ProtocolEventReceiver; @@ -407,7 +406,7 @@ impl ConsensusCommandSender { pub async fn get_endorsements_by_address( &self, address: Address, - ) -> Result, ConsensusError> { + ) -> Result, ConsensusError> { let (response_tx, response_rx) = oneshot::channel(); massa_trace!( "consensus.consensus_controller.get_endorsements_by_address", diff --git a/massa-consensus-worker/endorsements.md b/massa-consensus-worker/endorsements.md index 2c8b5672c1c..e8ed76bbdfe 100644 --- a/massa-consensus-worker/endorsements.md +++ b/massa-consensus-worker/endorsements.md @@ -7,7 +7,7 @@ Endorsements are included in a block's header. They are created by randomly sele With that mechanism it becomes harder to gain control of the network (you now have to control `endorsement_count + 1` draw to gain control over one block) and to reward stakers more frequently. ```ignore -pub struct BlockHeaderContent { +pub struct BlockHeader { pub endorsements: Vec, .. } @@ -19,11 +19,11 @@ An endorsement is defined as follows: ```ignore pub struct Endorsement { - pub content: EndorsementContent, + pub content: Endorsement, pub signature: Signature, } -pub struct EndorsementContent { +pub struct Endorsement { /// Public key of the endorser. pub sender_public_key: PublicKey, /// slot of endorsed block (= parent in the same thread) (can be different that previous slot in the same thread) diff --git a/massa-consensus-worker/src/consensus_worker.rs b/massa-consensus-worker/src/consensus_worker.rs index 1ecbf75ee46..07dfae8c076 100644 --- a/massa-consensus-worker/src/consensus_worker.rs +++ b/massa-consensus-worker/src/consensus_worker.rs @@ -8,15 +8,18 @@ use massa_consensus_exports::{ }; use massa_graph::{BlockGraph, BlockGraphExport}; use massa_hash::hash::Hash; -use massa_models::address::AddressState; -use massa_models::api::{LedgerInfo, RollsInfo}; -use massa_models::ledger_models::LedgerData; use massa_models::prehash::{BuildMap, Map, Set}; use massa_models::timeslots::{get_block_slot_timestamp, get_latest_block_slot_at_timestamp}; use massa_models::{address::AddressCycleProductionStats, stats::ConsensusStats, OperationId}; +use massa_models::{address::AddressState, signed::Signed}; use massa_models::{ - Address, Block, BlockHeader, BlockHeaderContent, BlockId, Endorsement, EndorsementContent, - EndorsementId, Operation, OperationSearchResult, OperationType, SerializeCompact, Slot, + api::{LedgerInfo, RollsInfo}, + SignedEndorsement, +}; +use massa_models::{ledger_models::LedgerData, SignedOperation}; +use massa_models::{ + Address, Block, BlockHeader, BlockId, Endorsement, EndorsementId, OperationSearchResult, + OperationType, SerializeCompact, Slot, }; use massa_proof_of_stake_exports::{error::ProofOfStakeError, ExportProofOfStake, ProofOfStake}; use massa_protocol_exports::{ProtocolEvent, ProtocolEventReceiver}; @@ -443,15 +446,15 @@ impl ConsensusWorker { }); // create empty block - let (_block_id, header) = BlockHeader::new_signed( - creator_private_key, - BlockHeaderContent { + let (_block_id, header) = Signed::new_signed( + BlockHeader { creator: *creator_public_key, slot: cur_slot, parents: parents.iter().map(|(b, _p)| *b).collect(), operation_merkle_root: Hash::compute_from(&Vec::new()[..]), endorsements: endorsements.clone(), }, + creator_private_key, )?; let block = Block { header, @@ -505,7 +508,7 @@ impl ConsensusWorker { // gather operations let mut total_hash: Vec = Vec::new(); - let mut operations: Vec = Vec::new(); + let mut operations: Vec = Vec::new(); let mut operation_set: Map = Map::default(); // (index, validity end period) let mut finished = remaining_block_space == 0 || remaining_operation_count == 0 @@ -579,15 +582,15 @@ impl ConsensusWorker { } // compile resulting block - let (block_id, header) = BlockHeader::new_signed( - creator_private_key, - BlockHeaderContent { + let (block_id, header) = Signed::new_signed( + BlockHeader { creator: *creator_public_key, slot: cur_slot, parents: parents.iter().map(|(b, _p)| *b).collect(), operation_merkle_root: Hash::compute_from(&total_hash), endorsements, }, + creator_private_key, )?; let block = Block { header, operations }; @@ -1365,13 +1368,13 @@ pub fn create_endorsement( private_key: &PrivateKey, index: u32, endorsed_block: BlockId, -) -> Result<(EndorsementId, Endorsement)> { - let content = EndorsementContent { +) -> Result<(EndorsementId, SignedEndorsement)> { + let content = Endorsement { sender_public_key, slot, index, endorsed_block, }; - let (e_id, endorsement) = Endorsement::new_signed(private_key, content)?; + let (e_id, endorsement) = Signed::new_signed(content, private_key)?; Ok((e_id, endorsement)) } diff --git a/massa-consensus-worker/src/tests/block_factory.rs b/massa-consensus-worker/src/tests/block_factory.rs index c8c17ff4461..a25481e5796 100644 --- a/massa-consensus-worker/src/tests/block_factory.rs +++ b/massa-consensus-worker/src/tests/block_factory.rs @@ -5,15 +5,18 @@ use super::{ tools::{validate_notpropagate_block, validate_propagate_block}, }; use massa_hash::hash::Hash; -use massa_models::{Block, BlockHeader, BlockHeaderContent, BlockId, Endorsement, Operation, Slot}; +use massa_models::{ + signed::{Signable, Signed}, + Block, BlockHeader, BlockId, SignedEndorsement, SignedOperation, Slot, +}; use massa_signature::{derive_public_key, generate_random_private_key, PrivateKey}; pub struct BlockFactory { pub best_parents: Vec, pub creator_priv_key: PrivateKey, pub slot: Slot, - pub endorsements: Vec, - pub operations: Vec, + pub endorsements: Vec, + pub operations: Vec, pub protocol_controller: MockProtocolController, } @@ -34,9 +37,8 @@ impl BlockFactory { pub async fn create_and_receive_block(&mut self, valid: bool) -> (BlockId, Block) { let public_key = derive_public_key(&self.creator_priv_key); - let (hash, header) = BlockHeader::new_signed( - &self.creator_priv_key, - BlockHeaderContent { + let (hash, header) = Signed::new_signed( + BlockHeader { creator: public_key, slot: self.slot, parents: self.best_parents.clone(), @@ -44,11 +46,12 @@ impl BlockFactory { &self .operations .iter() - .flat_map(|op| op.get_operation_id().unwrap().to_bytes()) + .flat_map(|op| op.content.compute_id().unwrap().to_bytes()) .collect::>()[..], ), endorsements: self.endorsements.clone(), }, + &self.creator_priv_key, ) .unwrap(); @@ -68,9 +71,9 @@ impl BlockFactory { (hash, block) } - pub fn sign_header(&self, header: BlockHeaderContent) -> Block { + pub fn sign_header(&self, header: BlockHeader) -> Block { let _public_key = derive_public_key(&self.creator_priv_key); - let (_hash, header) = BlockHeader::new_signed(&self.creator_priv_key, header).unwrap(); + let (_hash, header) = Signed::new_signed(header, &self.creator_priv_key).unwrap(); Block { header, @@ -79,7 +82,7 @@ impl BlockFactory { } pub async fn receieve_block(&mut self, valid: bool, block: Block) { - let hash = block.header.compute_block_id().unwrap(); + let hash = block.header.content.compute_id().unwrap(); self.protocol_controller.receive_block(block.clone()).await; if valid { // Assert that the block is propagated. diff --git a/massa-consensus-worker/src/tests/mock_protocol_controller.rs b/massa-consensus-worker/src/tests/mock_protocol_controller.rs index 45d9b1b51d4..7fe26b165bd 100644 --- a/massa-consensus-worker/src/tests/mock_protocol_controller.rs +++ b/massa-consensus-worker/src/tests/mock_protocol_controller.rs @@ -1,6 +1,6 @@ // Copyright (c) 2022 MASSA LABS -use massa_models::{constants::CHANNEL_SIZE, Block, BlockHeader, BlockId}; +use massa_models::{constants::CHANNEL_SIZE, signed::Signable, Block, BlockId, SignedHeader}; use massa_protocol_exports::{ ProtocolCommand, ProtocolCommandSender, ProtocolEvent, ProtocolEventReceiver, }; @@ -46,7 +46,7 @@ impl MockProtocolController { // Note: if you care about the operation set, use another method. pub async fn receive_block(&mut self, block: Block) { - let block_id = block.header.compute_block_id().unwrap(); + let block_id = block.header.content.compute_id().unwrap(); self.protocol_event_tx .send(ProtocolEvent::ReceivedBlock { block_id, @@ -58,8 +58,8 @@ impl MockProtocolController { .expect("could not send protocol event"); } - pub async fn receive_header(&mut self, header: BlockHeader) { - let block_id = header.compute_block_id().unwrap(); + pub async fn receive_header(&mut self, header: SignedHeader) { + let block_id = header.content.compute_id().unwrap(); self.protocol_event_tx .send(ProtocolEvent::ReceivedBlockHeader { block_id, header }) .await diff --git a/massa-consensus-worker/src/tests/scenario_block_creation.rs b/massa-consensus-worker/src/tests/scenario_block_creation.rs index a3b06f4cfe2..bd7cdecca32 100644 --- a/massa-consensus-worker/src/tests/scenario_block_creation.rs +++ b/massa-consensus-worker/src/tests/scenario_block_creation.rs @@ -5,9 +5,10 @@ use massa_consensus_exports::{tools::*, ConsensusConfig}; use massa_graph::ledger::LedgerSubset; use massa_hash::hash::Hash; use massa_models::rolls::{RollCounts, RollUpdate, RollUpdates}; +use massa_models::signed::{Signable, Signed}; +use massa_models::SerializeCompact; use massa_models::{ledger_models::LedgerData, EndorsementId, OperationType}; -use massa_models::{Address, Amount, Block, BlockHeader, BlockHeaderContent, Slot}; -use massa_models::{Endorsement, SerializeCompact}; +use massa_models::{Address, Amount, Block, BlockHeader, SignedEndorsement, Slot}; use massa_pool::PoolCommand; use massa_protocol_exports::ProtocolCommand; use massa_signature::{generate_random_private_key, PrivateKey}; @@ -423,9 +424,9 @@ async fn test_order_of_inclusion() { PoolCommand::GetOperationBatch { response_tx, .. } => { response_tx .send(vec![ - (op3.get_operation_id().unwrap(), op3.clone(), 50), - (op2.get_operation_id().unwrap(), op2.clone(), 50), - (op1.get_operation_id().unwrap(), op1.clone(), 50), + (op3.content.compute_id().unwrap(), op3.clone(), 50), + (op2.content.compute_id().unwrap(), op2.clone(), 50), + (op1.content.compute_id().unwrap(), op1.clone(), 50), ]) .unwrap(); Some(()) @@ -478,8 +479,8 @@ async fn test_order_of_inclusion() { assert_eq!(block.operations.len(), 2); for i in 0..2 { assert_eq!( - expected[i].get_operation_id().unwrap(), - res[i].get_operation_id().unwrap() + expected[i].content.compute_id().unwrap(), + res[i].content.compute_id().unwrap() ); } ( @@ -611,7 +612,7 @@ async fn test_block_filling() { } => { assert_eq!(Slot::new(1, 0), target_slot); assert_eq!(parent, prev_blocks[0]); - let mut eds: Vec<(EndorsementId, Endorsement)> = Vec::new(); + let mut eds: Vec<(EndorsementId, SignedEndorsement)> = Vec::new(); for (index, creator) in creators.iter().enumerate() { let ed = if *creator == address_a { create_endorsement(priv_a, target_slot, parent, index as u32) @@ -620,7 +621,7 @@ async fn test_block_filling() { } else { panic!("invalid endorser choice"); }; - eds.push((ed.compute_endorsement_id().unwrap(), ed)); + eds.push((ed.content.compute_id().unwrap(), ed)); } response_tx.send(eds.clone()).unwrap(); Some(eds) @@ -638,7 +639,9 @@ async fn test_block_filling() { response_tx .send( ops.iter() - .map(|op| (op.get_operation_id().unwrap(), op.clone(), op_size)) + .map(|op| { + (op.content.compute_id().unwrap(), op.clone(), op_size) + }) .collect(), ) .unwrap(); @@ -691,20 +694,20 @@ async fn test_block_filling() { for (e_found, (e_expected_id, e_expected)) in block.header.content.endorsements.iter().zip(eds.iter()) { - assert_eq!(e_found.compute_endorsement_id().unwrap(), *e_expected_id); - assert_eq!(e_expected.compute_endorsement_id().unwrap(), *e_expected_id); + assert_eq!(e_found.content.compute_id().unwrap(), *e_expected_id); + assert_eq!(e_expected.content.compute_id().unwrap(), *e_expected_id); } // create empty block - let (_block_id, header) = BlockHeader::new_signed( - &priv_a, - BlockHeaderContent { + let (_block_id, header) = Signed::new_signed( + BlockHeader { creator: block.header.content.creator, slot: block.header.content.slot, parents: block.header.content.parents.clone(), operation_merkle_root: Hash::compute_from(&Vec::new()[..]), endorsements: eds.iter().map(|(_e_id, endo)| endo.clone()).collect(), }, + &priv_a, ) .unwrap(); let empty = Block { diff --git a/massa-consensus-worker/src/tests/scenario_roll.rs b/massa-consensus-worker/src/tests/scenario_roll.rs index 1e83721448f..f56f99e4892 100644 --- a/massa-consensus-worker/src/tests/scenario_roll.rs +++ b/massa-consensus-worker/src/tests/scenario_roll.rs @@ -3,6 +3,7 @@ use massa_consensus_exports::tools; use massa_consensus_exports::{settings::ConsensusChannels, ConsensusConfig}; use massa_execution_exports::test_exports::MockExecutionController; +use massa_models::signed::Signable; use massa_models::{Address, Amount, BlockId, Slot}; use massa_pool::PoolCommand; use massa_protocol_exports::ProtocolCommand; @@ -567,7 +568,7 @@ async fn test_roll_block_creation() { assert_eq!(target_slot, Slot::new(1, 0)); response_tx .send(vec![( - rb_a2_r1.clone().get_operation_id().unwrap(), + rb_a2_r1.clone().content.compute_id().unwrap(), rb_a2_r1.clone(), 10, )]) @@ -598,8 +599,8 @@ async fn test_roll_block_creation() { assert_eq!(block.header.content.slot, Slot::new(1, 0)); assert_eq!(block.operations.len(), 1); assert_eq!( - block.operations[0].get_operation_id().unwrap(), - rb_a2_r1.clone().get_operation_id().unwrap() + block.operations[0].content.compute_id().unwrap(), + rb_a2_r1.clone().content.compute_id().unwrap() ); let addr_state = consensus_command_sender @@ -673,7 +674,7 @@ async fn test_roll_block_creation() { assert_eq!(target_slot, Slot::new(2, 0)); response_tx .send(vec![( - rs_a2_r1.clone().get_operation_id().unwrap(), + rs_a2_r1.clone().content.compute_id().unwrap(), rs_a2_r1.clone(), 10, )]) @@ -704,8 +705,8 @@ async fn test_roll_block_creation() { assert_eq!(block.header.content.slot, Slot::new(2, 0)); assert_eq!(block.operations.len(), 1); assert_eq!( - block.operations[0].get_operation_id().unwrap(), - rs_a2_r1.clone().get_operation_id().unwrap() + block.operations[0].content.compute_id().unwrap(), + rs_a2_r1.clone().content.compute_id().unwrap() ); let addr_state = consensus_command_sender diff --git a/massa-consensus-worker/src/tests/scenarios_endorsements.rs b/massa-consensus-worker/src/tests/scenarios_endorsements.rs index aaa4dae50a7..e5325f88257 100644 --- a/massa-consensus-worker/src/tests/scenarios_endorsements.rs +++ b/massa-consensus-worker/src/tests/scenarios_endorsements.rs @@ -1,8 +1,7 @@ // Copyright (c) 2022 MASSA LABS -use massa_hash::hash::Hash; -use massa_models::{Amount, BlockId, Endorsement, EndorsementContent, SerializeCompact, Slot}; -use massa_signature::{derive_public_key, generate_random_private_key, sign}; +use massa_models::{signed::Signed, Amount, BlockId, Endorsement, Slot}; +use massa_signature::{derive_public_key, generate_random_private_key}; use massa_time::MassaTime; use serial_test::serial; use std::{collections::HashMap, str::FromStr}; @@ -86,72 +85,51 @@ async fn test_endorsement_check() { // create an otherwise valid endorsement with another address, include it in valid block(1,0), assert it is not propagated let sender_priv = generate_random_private_key(); let sender_public_key = derive_public_key(&sender_priv); - let content = EndorsementContent { + let content = Endorsement { sender_public_key, slot: Slot::new(1, 0), index: 0, endorsed_block: parents[0], }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - let ed = Endorsement { - content: content.clone(), - signature, - }; - + let ed = Signed::new_signed(content.clone(), &sender_priv).unwrap().1; b10.header.content.endorsements = vec![ed]; propagate_block(&mut protocol_controller, b10, false, 500).await; // create an otherwise valid endorsement at slot (1,1), include it in valid block(1,0), assert it is not propagated - let content = EndorsementContent { + let content = Endorsement { sender_public_key: pub_key_c, slot: Slot::new(1, 1), index: 0, endorsed_block: parents[1], }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - let ed = Endorsement { - content: content.clone(), - signature, - }; + let ed = Signed::new_signed(content.clone(), &sender_priv).unwrap().1; let (_, mut b10, _) = create_block(&cfg, Slot::new(1, 0), parents.clone(), priv_key_a); b10.header.content.endorsements = vec![ed]; propagate_block(&mut protocol_controller, b10, false, 500).await; // create an otherwise valid endorsement with genesis 1 as endorsed block, include it in valid block(1,0), assert it is not propagated - let content = EndorsementContent { + let content = Endorsement { sender_public_key: pub_key_b, slot: Slot::new(1, 0), index: 0, endorsed_block: parents[1], }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - let ed = Endorsement { - content: content.clone(), - signature, - }; + let ed = Signed::new_signed(content.clone(), &sender_priv).unwrap().1; let (_, mut b10, _) = create_block(&cfg, Slot::new(1, 0), parents.clone(), priv_key_a); b10.header.content.endorsements = vec![ed]; propagate_block(&mut protocol_controller, b10, false, 500).await; // create a valid endorsement, include it in valid block(1,1), assert it is propagated - let content = EndorsementContent { + let content = Endorsement { sender_public_key: pub_key_b, slot: Slot::new(1, 0), index: 0, endorsed_block: parents[0], }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - let ed = Endorsement { - content: content.clone(), - signature, - }; + let ed = Signed::new_signed(content.clone(), &sender_priv).unwrap().1; let (_, mut b10, _) = create_block(&cfg, Slot::new(1, 0), parents.clone(), priv_key_a); b10.header.content.endorsements = vec![ed]; diff --git a/massa-consensus-worker/src/tests/scenarios_get_operations.rs b/massa-consensus-worker/src/tests/scenarios_get_operations.rs index a11cd7e773c..eefdf6f9314 100644 --- a/massa-consensus-worker/src/tests/scenarios_get_operations.rs +++ b/massa-consensus-worker/src/tests/scenarios_get_operations.rs @@ -4,8 +4,10 @@ use super::tools::*; use massa_consensus_exports::ConsensusConfig; use massa_graph::{ledger::LedgerSubset, BootstrapableGraph}; +use massa_models::signed::Signable; +use massa_models::SignedOperation; use massa_models::{ - clique::Clique, ledger_models::LedgerData, Amount, BlockId, Operation, OperationSearchResult, + clique::Clique, ledger_models::LedgerData, Amount, BlockId, OperationSearchResult, OperationSearchResultStatus, Slot, }; use massa_signature::{derive_public_key, generate_random_private_key, PrivateKey, PublicKey}; @@ -78,7 +80,7 @@ async fn test_get_operation() { let ops = consensus_command_sender .get_operations( ops.iter() - .map(|op| op.get_operation_id().unwrap()) + .map(|op| op.content.compute_id().unwrap()) .collect(), ) .await @@ -87,7 +89,7 @@ async fn test_get_operation() { let mut expected = HashMap::new(); expected.insert( - op2.get_operation_id().unwrap(), + op2.content.compute_id().unwrap(), OperationSearchResult { status: OperationSearchResultStatus::Pending, op: op2, @@ -96,7 +98,7 @@ async fn test_get_operation() { }, ); expected.insert( - op3.get_operation_id().unwrap(), + op3.content.compute_id().unwrap(), OperationSearchResult { status: OperationSearchResultStatus::Pending, op: op3, @@ -125,8 +127,8 @@ async fn test_get_operation() { .. } = expected.get(id).unwrap(); assert_eq!( - op.get_operation_id().unwrap(), - ex_op.get_operation_id().unwrap() + op.content.compute_id().unwrap(), + ex_op.content.compute_id().unwrap() ); assert_eq!(in_pool, ex_pool); assert_eq!(in_blocks.len(), ex_blocks.len()); @@ -148,7 +150,7 @@ async fn test_get_operation() { fn get_bootgraph( creator: PublicKey, - operations: Vec, + operations: Vec, ledger: LedgerSubset, ) -> (BootstrapableGraph, BlockId, BlockId) { let (genesis_0, g0_id) = diff --git a/massa-consensus-worker/src/tests/scenarios_pool_commands.rs b/massa-consensus-worker/src/tests/scenarios_pool_commands.rs index 6c079f27838..a065dc4fb3d 100644 --- a/massa-consensus-worker/src/tests/scenarios_pool_commands.rs +++ b/massa-consensus-worker/src/tests/scenarios_pool_commands.rs @@ -6,7 +6,8 @@ use massa_consensus_exports::ConsensusConfig; use massa_graph::{ledger::LedgerSubset, BootstrapableGraph}; use massa_models::clique::Clique; use massa_models::ledger_models::LedgerData; -use massa_models::{Amount, BlockId, Operation, Slot}; +use massa_models::signed::Signable; +use massa_models::{Amount, BlockId, SignedOperation, Slot}; use massa_pool::PoolCommand; use massa_signature::{generate_random_private_key, PrivateKey, PublicKey}; use massa_time::MassaTime; @@ -220,8 +221,11 @@ async fn test_new_final_ops() { .wait_command(300.into(), new_final_ops_filter) .await; if let Some(finals) = final_ops { - assert!(finals.contains_key(&op.get_operation_id().unwrap())); - assert_eq!(finals.get(&op.get_operation_id().unwrap()), Some(&(10, 0))) + assert!(finals.contains_key(&op.content.compute_id().unwrap())); + assert_eq!( + finals.get(&op.content.compute_id().unwrap()), + Some(&(10, 0)) + ) } else { panic!("no final ops") } @@ -301,7 +305,7 @@ async fn test_max_attempts_get_operations() { // Send a full batch back. response_tx .send(vec![( - op.clone().get_operation_id().unwrap(), + op.clone().content.compute_id().unwrap(), op.clone(), 10, )]) @@ -386,7 +390,7 @@ async fn test_max_batch_size_get_operations() { // Send a non-full batch back. response_tx .send(vec![( - op.clone().get_operation_id().unwrap(), + op.clone().content.compute_id().unwrap(), op.clone(), 10, )]) @@ -419,7 +423,7 @@ async fn test_max_batch_size_get_operations() { fn get_bootgraph( creator: PublicKey, - operation: Operation, + operation: SignedOperation, ledger: LedgerSubset, ) -> (BootstrapableGraph, BlockId, BlockId) { let (genesis_0, g0_id) = diff --git a/massa-consensus-worker/src/tests/scenarios_reward_split.rs b/massa-consensus-worker/src/tests/scenarios_reward_split.rs index 03c4f517be0..53efbbd6989 100644 --- a/massa-consensus-worker/src/tests/scenarios_reward_split.rs +++ b/massa-consensus-worker/src/tests/scenarios_reward_split.rs @@ -2,13 +2,9 @@ use super::tools::*; use massa_consensus_exports::ConsensusConfig; - -use massa_hash::hash::Hash; use massa_models::ledger_models::LedgerData; -use massa_models::{ - Address, Amount, BlockId, Endorsement, EndorsementContent, SerializeCompact, Slot, -}; -use massa_signature::sign; +use massa_models::signed::Signed; +use massa_models::{Address, Amount, BlockId, Endorsement, Slot}; use massa_time::MassaTime; use serial_test::serial; use std::collections::HashMap; @@ -134,54 +130,45 @@ async fn test_reward_split() { .iter() .position(|&addr| addr == Address::from_public_key(&slot_two_pub_key)) .unwrap() as u32; - let content = EndorsementContent { + let content = Endorsement { sender_public_key: slot_two_pub_key, slot: Slot::new(1, 0), index, endorsed_block: b1_id, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &slot_two_priv_key).unwrap(); - let ed_1 = Endorsement { - content: content.clone(), - signature, - }; + let ed_1 = Signed::new_signed(content.clone(), &slot_two_priv_key) + .unwrap() + .1; // Creator of first block endorses the first. let index = slot_one_endorsements_addrs .iter() .position(|&addr| addr == Address::from_public_key(&slot_one_pub_key)) .unwrap() as u32; - let content = EndorsementContent { + let content = Endorsement { sender_public_key: slot_one_pub_key, slot: Slot::new(1, 0), index, endorsed_block: b1_id, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &slot_one_priv_key).unwrap(); - let ed_2 = Endorsement { - content: content.clone(), - signature, - }; + let ed_2 = Signed::new_signed(content.clone(), &slot_one_priv_key) + .unwrap() + .1; // Creator of second block endorses the first, again. let index = slot_one_endorsements_addrs .iter() .position(|&addr| addr == Address::from_public_key(&slot_two_pub_key)) .unwrap() as u32; - let content = EndorsementContent { + let content = Endorsement { sender_public_key: slot_two_pub_key, slot: Slot::new(1, 0), index, endorsed_block: b1_id, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &slot_two_priv_key).unwrap(); - let ed_3 = Endorsement { - content: content.clone(), - signature, - }; + let ed_3 = Signed::new_signed(content.clone(), &slot_two_priv_key) + .unwrap() + .1; // Add endorsements to block. b2.header.content.endorsements = vec![ed_1, ed_2, ed_3]; diff --git a/massa-consensus-worker/src/tests/test_block_graph.rs b/massa-consensus-worker/src/tests/test_block_graph.rs index 35e75e58ca0..4081b22c163 100644 --- a/massa-consensus-worker/src/tests/test_block_graph.rs +++ b/massa-consensus-worker/src/tests/test_block_graph.rs @@ -10,41 +10,50 @@ use massa_models::{ clique::Clique, ledger_models::{LedgerChange, LedgerChanges, LedgerData}, prehash::{Map, Set}, - Address, Block, BlockHeader, BlockHeaderContent, BlockId, DeserializeCompact, SerializeCompact, - Slot, + signed::Signed, + Address, Block, BlockHeader, BlockId, DeserializeCompact, SerializeCompact, Slot, }; -use massa_models::{Amount, Endorsement, EndorsementContent}; -use massa_signature::{PublicKey, Signature}; +use massa_models::{Amount, Endorsement}; +use massa_signature::{generate_random_private_key, PublicKey}; use serial_test::serial; use std::str::FromStr; use tempfile::NamedTempFile; fn get_export_active_test_block() -> ExportActiveBlock { + let pk = generate_random_private_key(); let block = Block { - header: BlockHeader { - content: BlockHeaderContent{ - creator: PublicKey::from_bs58_check("4vYrPNzUM8PKg2rYPW3ZnXPzy67j9fn5WsGCbnwAnk2Lf7jNHb").unwrap(), - operation_merkle_root: Hash::compute_from(&Vec::new()), - parents: vec![ - get_dummy_block_id("parent1"), - get_dummy_block_id("parent2"), - ], - slot: Slot::new(1, 0), - endorsements: vec![ Endorsement{content: EndorsementContent{ - sender_public_key: PublicKey::from_bs58_check("4vYrPNzUM8PKg2rYPW3ZnXPzy67j9fn5WsGCbnwAnk2Lf7jNHb").unwrap(), - endorsed_block: get_dummy_block_id("parent1"), - index: 0, - slot: Slot::new(1, 0), - }, signature: Signature::from_bs58_check( - "5f4E3opXPWc3A1gvRVV7DJufvabDfaLkT1GMterpJXqRZ5B7bxPe5LoNzGDQp9LkphQuChBN1R5yEvVJqanbjx7mgLEae" - ).unwrap() }], - }, - signature: Signature::from_bs58_check( - "5f4E3opXPWc3A1gvRVV7DJufvabDfaLkT1GMterpJXqRZ5B7bxPe5LoNzGDQp9LkphQuChBN1R5yEvVJqanbjx7mgLEae" - ).unwrap() + header: Signed::new_signed( + BlockHeader { + creator: PublicKey::from_bs58_check( + "4vYrPNzUM8PKg2rYPW3ZnXPzy67j9fn5WsGCbnwAnk2Lf7jNHb", + ) + .unwrap(), + operation_merkle_root: Hash::compute_from(&Vec::new()), + parents: vec![get_dummy_block_id("parent1"), get_dummy_block_id("parent2")], + slot: Slot::new(1, 0), + endorsements: vec![ + Signed::new_signed( + Endorsement { + sender_public_key: PublicKey::from_bs58_check( + "4vYrPNzUM8PKg2rYPW3ZnXPzy67j9fn5WsGCbnwAnk2Lf7jNHb", + ) + .unwrap(), + endorsed_block: get_dummy_block_id("parent1"), + index: 0, + slot: Slot::new(1, 0), + }, + &pk, + ) + .unwrap() + .1, + ], }, - operations: vec![] - }; + &pk, + ) + .unwrap() + .1, + operations: vec![], + }; ExportActiveBlock { parents: vec![ diff --git a/massa-consensus-worker/src/tests/tools.rs b/massa-consensus-worker/src/tests/tools.rs index f64d41f9431..14a12696a90 100644 --- a/massa-consensus-worker/src/tests/tools.rs +++ b/massa-consensus-worker/src/tests/tools.rs @@ -13,15 +13,15 @@ use massa_execution_exports::test_exports::MockExecutionController; use massa_graph::{export_active_block::ExportActiveBlock, BlockGraphExport, BootstrapableGraph}; use massa_hash::hash::Hash; use massa_models::{ - prehash::Set, Address, Amount, Block, BlockHeader, BlockHeaderContent, BlockId, Endorsement, - EndorsementContent, Operation, OperationContent, OperationType, SerializeCompact, Slot, + prehash::Set, + signed::{Signable, Signed}, + Address, Amount, Block, BlockHeader, BlockId, Endorsement, Operation, OperationType, + SerializeCompact, SignedEndorsement, SignedOperation, Slot, }; use massa_pool::PoolCommand; use massa_proof_of_stake_exports::ExportProofOfStake; use massa_protocol_exports::ProtocolCommand; -use massa_signature::{ - derive_public_key, generate_random_private_key, sign, PrivateKey, PublicKey, Signature, -}; +use massa_signature::{derive_public_key, generate_random_private_key, PrivateKey, PublicKey}; use massa_time::MassaTime; use std::{collections::HashSet, future::Future}; use std::{ @@ -313,7 +313,7 @@ pub async fn propagate_block( valid: bool, timeout_ms: u64, ) -> BlockId { - let block_hash = block.header.compute_block_id().unwrap(); + let block_hash = block.header.content.compute_id().unwrap(); protocol_controller.receive_block(block).await; if valid { // see if the block is propagated. @@ -332,22 +332,20 @@ pub fn create_roll_transaction( buy: bool, expire_period: u64, fee: u64, -) -> Operation { +) -> SignedOperation { let op = if buy { OperationType::RollBuy { roll_count } } else { OperationType::RollSell { roll_count } }; - let content = OperationContent { + let content = Operation { sender_public_key, fee: Amount::from_str(&fee.to_string()).unwrap(), expire_period, op, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &priv_key).unwrap(); - Operation { content, signature } + Signed::new_signed(content, &priv_key).unwrap().1 } pub async fn wait_pool_slot( @@ -378,21 +376,19 @@ pub fn create_transaction( amount: u64, expire_period: u64, fee: u64, -) -> Operation { +) -> SignedOperation { let op = OperationType::Transaction { recipient_address, amount: Amount::from_str(&amount.to_string()).unwrap(), }; - let content = OperationContent { + let content = Operation { sender_public_key, fee: Amount::from_str(&fee.to_string()).unwrap(), expire_period, op, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &priv_key).unwrap(); - Operation { content, signature } + Signed::new_signed(content, &priv_key).unwrap().1 } #[allow(clippy::too_many_arguments)] @@ -405,7 +401,7 @@ pub fn create_executesc( max_gas: u64, coins: u64, gas_price: u64, -) -> Operation { +) -> SignedOperation { let op = OperationType::ExecuteSC { data, max_gas, @@ -413,15 +409,13 @@ pub fn create_executesc( gas_price: Amount::from_str(&gas_price.to_string()).unwrap(), }; - let content = OperationContent { + let content = Operation { sender_public_key, fee: Amount::from_str(&fee.to_string()).unwrap(), expire_period, op, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &priv_key).unwrap(); - Operation { content, signature } + Signed::new_signed(content, &priv_key).unwrap().1 } pub fn create_roll_buy( @@ -429,18 +423,16 @@ pub fn create_roll_buy( roll_count: u64, expire_period: u64, fee: u64, -) -> Operation { +) -> SignedOperation { let op = OperationType::RollBuy { roll_count }; let sender_public_key = derive_public_key(&priv_key); - let content = OperationContent { + let content = Operation { sender_public_key, fee: Amount::from_str(&fee.to_string()).unwrap(), expire_period, op, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &priv_key).unwrap(); - Operation { content, signature } + Signed::new_signed(content, &priv_key).unwrap().1 } pub fn create_roll_sell( @@ -448,18 +440,16 @@ pub fn create_roll_sell( roll_count: u64, expire_period: u64, fee: u64, -) -> Operation { +) -> SignedOperation { let op = OperationType::RollSell { roll_count }; let sender_public_key = derive_public_key(&priv_key); - let content = OperationContent { + let content = Operation { sender_public_key, fee: Amount::from_str(&fee.to_string()).unwrap(), expire_period, op, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &priv_key).unwrap(); - Operation { content, signature } + Signed::new_signed(content, &priv_key).unwrap().1 } // returns hash and resulting discarded blocks @@ -487,15 +477,15 @@ pub fn create_block_with_merkle_root( creator: PrivateKey, ) -> (BlockId, Block, PrivateKey) { let public_key = derive_public_key(&creator); - let (hash, header) = BlockHeader::new_signed( - &creator, - BlockHeaderContent { + let (hash, header) = Signed::new_signed( + BlockHeader { creator: public_key, slot, parents: best_parents, operation_merkle_root, endorsements: Vec::new(), }, + &creator, ) .unwrap(); @@ -513,51 +503,46 @@ pub fn create_endorsement( slot: Slot, endorsed_block: BlockId, index: u32, -) -> Endorsement { +) -> SignedEndorsement { let sender_public_key = derive_public_key(&sender_priv); - let content = EndorsementContent { + let content = Endorsement { sender_public_key, slot, index, endorsed_block, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - Endorsement { content, signature } + Signed::new_signed(content, &sender_priv).unwrap().1 } pub fn get_export_active_test_block( creator: PublicKey, parents: Vec<(BlockId, u64)>, - operations: Vec, + operations: Vec, slot: Slot, is_final: bool, ) -> (ExportActiveBlock, BlockId) { let block = Block { - header: BlockHeader { - content: BlockHeaderContent{ + header: Signed::new_signed( + BlockHeader { creator, - operation_merkle_root: Hash::compute_from(&operations.iter().flat_map(|op|{ - op - .get_operation_id() - .unwrap() - .to_bytes() - }) - .collect::>()[..]), - parents: parents.iter() - .map(|(id,_)| *id) - .collect(), + operation_merkle_root: Hash::compute_from( + &operations + .iter() + .flat_map(|op| op.content.compute_id().unwrap().to_bytes()) + .collect::>()[..], + ), + parents: parents.iter().map(|(id, _)| *id).collect(), slot, endorsements: Vec::new(), }, - signature: Signature::from_bs58_check( - "5f4E3opXPWc3A1gvRVV7DJufvabDfaLkT1GMterpJXqRZ5B7bxPe5LoNzGDQp9LkphQuChBN1R5yEvVJqanbjx7mgLEae" - ).unwrap() - }, + &generate_random_private_key(), + ) + .unwrap() + .1, operations: operations.clone(), }; - let id = block.header.compute_block_id().unwrap(); + let id = block.header.content.compute_id().unwrap(); ( ExportActiveBlock { parents, @@ -578,7 +563,7 @@ pub fn create_block_with_operations( slot: Slot, best_parents: &Vec, creator: PrivateKey, - operations: Vec, + operations: Vec, ) -> (BlockId, Block, PrivateKey) { let public_key = derive_public_key(&creator); @@ -588,15 +573,15 @@ pub fn create_block_with_operations( })[..], ); - let (hash, header) = BlockHeader::new_signed( - &creator, - BlockHeaderContent { + let (hash, header) = Signed::new_signed( + BlockHeader { creator: public_key, slot, parents: best_parents.clone(), operation_merkle_root, endorsements: Vec::new(), }, + &creator, ) .unwrap(); diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index c5dd1db70a2..1331c3fb776 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -16,7 +16,8 @@ use massa_execution_exports::{ }; use massa_ledger::{Applicable, FinalLedger, LedgerChanges, LedgerEntry, SetUpdateOrDelete}; use massa_models::output_event::SCOutputEvent; -use massa_models::{Address, BlockId, Operation, OperationId, OperationType}; +use massa_models::signed::Signable; +use massa_models::{Address, BlockId, OperationId, OperationType, SignedOperation}; use massa_models::{Block, Slot}; use massa_sc_runtime::Interface; use parking_lot::{Mutex, RwLock}; @@ -231,7 +232,7 @@ impl ExecutionState { /// * block_creator_addr: address of the block creator pub fn execute_operation( &self, - operation: &Operation, + operation: &SignedOperation, block_creator_addr: Address, ) -> Result<(), ExecutionError> { // process ExecuteSC operations only, ignore other types of operations @@ -253,7 +254,8 @@ impl ExecutionState { // https://github.com/massalabs/massa/issues/1121 // https://github.com/massalabs/massa/issues/2264 let operation_id = operation - .get_operation_id() + .content + .compute_id() .expect("could not compute operation ID"); // prepare the current slot context for executing the operation diff --git a/massa-graph/src/block_graph.rs b/massa-graph/src/block_graph.rs index 3c462065ae8..f4b05ab77a2 100644 --- a/massa-graph/src/block_graph.rs +++ b/massa-graph/src/block_graph.rs @@ -11,18 +11,18 @@ use crate::{ }; use massa_hash::hash::Hash; use massa_logging::massa_trace; -use massa_models::clique::Clique; -use massa_models::ledger_models::LedgerChange; use massa_models::prehash::{BuildMap, Map, Set}; use massa_models::{ active_block::ActiveBlock, api::EndorsementInfo, rolls::{RollCounts, RollUpdate, RollUpdates}, + SignedEndorsement, SignedHeader, SignedOperation, }; +use massa_models::{clique::Clique, signed::Signable}; +use massa_models::{ledger_models::LedgerChange, signed::Signed}; use massa_models::{ - ledger_models::LedgerChanges, Address, Block, BlockHeader, BlockHeaderContent, BlockId, - Endorsement, EndorsementId, Operation, OperationId, OperationSearchResult, - OperationSearchResultBlockStatus, OperationSearchResultStatus, Slot, + ledger_models::LedgerChanges, Address, Block, BlockHeader, BlockId, EndorsementId, OperationId, + OperationSearchResult, OperationSearchResultBlockStatus, OperationSearchResultStatus, Slot, }; use massa_proof_of_stake_exports::{ error::ProofOfStakeError, OperationRollInterface, ProofOfStake, @@ -39,7 +39,7 @@ use tracing::{debug, error, info, warn}; #[derive(Debug, Clone)] enum HeaderOrBlock { - Header(BlockHeader), + Header(SignedHeader), Block( Block, Map, @@ -115,7 +115,7 @@ enum BlockStatus { /// The block was discarded and is kept to avoid reprocessing it Discarded { /// Just the header of that block - header: BlockHeader, + header: SignedHeader, /// why it was discarded reason: DiscardReason, /// Used to limit and sort the number of blocks/headers wainting for dependencies @@ -157,7 +157,7 @@ impl<'a> From<&'a BlockStatus> for ExportBlockStatus { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ExportCompiledBlock { /// Header of the corresponding block. - pub header: BlockHeader, + pub header: SignedHeader, /// For (i, set) in children, /// set contains the headers' hashes /// of blocks referencing exported block as a parent, @@ -250,7 +250,7 @@ pub struct BlockGraphExport { /// Map of active blocks, were blocks are in their exported version. pub active_blocks: Map, /// Finite cache of discarded blocks, in exported version. - pub discarded_blocks: Map, + pub discarded_blocks: Map, /// Best parents hashe in each thread. pub best_parents: Vec<(BlockId, u64)>, /// Latest final period and block hash in each thread. @@ -399,15 +399,15 @@ enum BlockOperationsCheckOutcome { pub fn create_genesis_block(cfg: &GraphConfig, thread_number: u8) -> Result<(BlockId, Block)> { let private_key = cfg.genesis_key; let public_key = derive_public_key(&private_key); - let (header_hash, header) = BlockHeader::new_signed( - &private_key, - BlockHeaderContent { + let (header_hash, header) = Signed::new_signed( + BlockHeader { creator: public_key, slot: Slot::new(0, thread_number), parents: Vec::new(), operation_merkle_root: Hash::compute_from(&Vec::new()), endorsements: Vec::new(), }, + &private_key, )?; Ok(( @@ -589,16 +589,16 @@ impl BlockGraph { pub fn block_state_try_apply_op( &self, state_accu: &mut BlockStateAccumulator, - header: &BlockHeader, - operation: &Operation, + header: &SignedHeader, + operation: &SignedOperation, pos: &mut ProofOfStake, ) -> Result<()> { let block_creator_address = Address::from_public_key(&header.content.creator); // get roll updates - let op_roll_updates = operation.get_roll_updates()?; + let op_roll_updates = operation.content.get_roll_updates()?; // get ledger changes (includes fee distribution) - let op_ledger_changes = operation.get_ledger_changes( + let op_ledger_changes = operation.content.get_ledger_changes( block_creator_address, state_accu.endorsers_addresses.clone(), state_accu.same_thread_parent_creator, @@ -627,7 +627,7 @@ impl BlockGraph { pub fn block_state_sync_rolls( &self, accu: &mut BlockStateAccumulator, - header: &BlockHeader, + header: &SignedHeader, pos: &ProofOfStake, involved_addrs: &Set
, ) -> Result<()> { @@ -657,7 +657,7 @@ impl BlockGraph { pub fn block_state_try_apply( &self, accu: &mut BlockStateAccumulator, - header: &BlockHeader, + header: &SignedHeader, mut opt_ledger_changes: Option, opt_roll_updates: Option, pos: &mut ProofOfStake, @@ -839,7 +839,7 @@ impl BlockGraph { /// initializes a block state accumulator from a block header pub fn block_state_accumulator_init( &self, - header: &BlockHeader, + header: &SignedHeader, pos: &mut ProofOfStake, ) -> Result { let block_thread = header.content.slot.thread; @@ -1151,7 +1151,7 @@ impl BlockGraph { op: active_block.block.operations[*idx].clone(), in_pool: false, in_blocks: vec![( - active_block.block.header.compute_block_id()?, + active_block.block.header.content.compute_id()?, (*idx, active_block.is_final), )] .into_iter() @@ -1261,7 +1261,7 @@ impl BlockGraph { pub fn incoming_header( &mut self, block_id: BlockId, - header: BlockHeader, + header: SignedHeader, pos: &mut ProofOfStake, current_slot: Option, ) -> Result<()> { @@ -1841,7 +1841,7 @@ impl BlockGraph { fn check_header( &self, block_id: &BlockId, - header: &BlockHeader, + header: &SignedHeader, pos: &mut ProofOfStake, current_slot: Option, ) -> Result { @@ -2170,7 +2170,7 @@ impl BlockGraph { /// * endorsed slot is parent_in_own_thread slot fn check_endorsements( &self, - header: &BlockHeader, + header: &SignedHeader, pos: &mut ProofOfStake, parent_in_own_thread: &ActiveBlock, ) -> Result { @@ -2315,6 +2315,7 @@ impl BlockGraph { .get_thread(self.cfg.thread_count); let op_start_validity_period = *operation + .content .get_validity_range(self.cfg.operation_validity_periods) .start(); @@ -3613,13 +3614,13 @@ impl BlockGraph { pub fn get_endorsement_by_address( &self, address: Address, - ) -> Result> { - let mut res: Map = Default::default(); + ) -> Result> { + let mut res: Map = Default::default(); for b_id in self.active_index.iter() { if let Some(BlockStatus::Active(ab)) = self.block_statuses.get(b_id) { if let Some(eds) = ab.addresses_to_endorsements.get(&address) { for e in ab.block.header.content.endorsements.iter() { - let id = e.compute_endorsement_id()?; + let id = e.content.compute_id()?; if eds.contains(&id) { res.insert(id, e.clone()); } @@ -3646,7 +3647,7 @@ impl BlockGraph { .is_empty() { for e in ab.block.header.content.endorsements.iter() { - let id = e.compute_endorsement_id()?; + let id = e.content.compute_id()?; if endorsements.contains(&id) { res.entry(id) .and_modify(|EndorsementInfo { in_blocks, .. }| { diff --git a/massa-graph/src/export_active_block.rs b/massa-graph/src/export_active_block.rs index c9658ff9bd2..6545ca9e108 100644 --- a/massa-graph/src/export_active_block.rs +++ b/massa-graph/src/export_active_block.rs @@ -5,6 +5,7 @@ use massa_models::{ ledger_models::{LedgerChange, LedgerChanges}, prehash::{BuildMap, Map, Set}, rolls::{RollUpdate, RollUpdates}, + signed::Signable, *, }; use serde::{Deserialize, Serialize}; @@ -54,7 +55,7 @@ impl TryFrom for ActiveBlock { .operations .iter() .enumerate() - .map(|(idx, op)| match op.get_operation_id() { + .map(|(idx, op)| match op.content.compute_id() { Ok(id) => Ok((id, (idx, op.content.expire_period))), Err(e) => Err(e), }) @@ -66,7 +67,7 @@ impl TryFrom for ActiveBlock { .content .endorsements .iter() - .map(|endo| Ok((endo.compute_endorsement_id()?, endo.content.index))) + .map(|endo| Ok((endo.content.compute_id()?, endo.content.index))) .collect::>()?; let addresses_to_operations = a_block.block.involved_addresses(&operation_set)?; diff --git a/massa-graph/src/ledger.rs b/massa-graph/src/ledger.rs index b219eecb7f2..fe37f47a5a4 100644 --- a/massa-graph/src/ledger.rs +++ b/massa-graph/src/ledger.rs @@ -1,9 +1,10 @@ +use massa_models::Operation; // Copyright (c) 2022 MASSA LABS use massa_models::ledger_models::{LedgerChange, LedgerChanges, LedgerData}; use massa_models::prehash::{BuildMap, Map, Set}; use massa_models::{ array_from_slice, constants::ADDRESS_SIZE_BYTES, Address, Amount, DeserializeCompact, - DeserializeVarInt, Operation, SerializeCompact, SerializeVarInt, + DeserializeVarInt, SerializeCompact, SerializeVarInt, }; use serde::{Deserialize, Serialize}; use sled::{Transactional, Tree}; @@ -71,11 +72,11 @@ impl OperationLedgerInterface for Operation { let mut res = LedgerChanges::default(); // sender fee - let sender_address = Address::from_public_key(&self.content.sender_public_key); + let sender_address = Address::from_public_key(&self.sender_public_key); res.apply( &sender_address, &LedgerChange { - balance_delta: self.content.fee, + balance_delta: self.fee, balance_increment: false, }, )?; @@ -85,12 +86,12 @@ impl OperationLedgerInterface for Operation { creator, endorsers, parent_creator, - self.content.fee, + self.fee, endorsement_count, )?; // operation type specific - match &self.content.op { + match &self.op { massa_models::OperationType::Transaction { recipient_address, amount, diff --git a/massa-models/src/api.rs b/massa-models/src/api.rs index 29fb2ba0d85..97914898d24 100644 --- a/massa-models/src/api.rs +++ b/massa-models/src/api.rs @@ -6,9 +6,10 @@ use crate::node::NodeId; use crate::prehash::Map; use crate::prehash::Set; use crate::stats::{ConsensusStats, NetworkStats, PoolStats}; +use crate::SignedEndorsement; +use crate::SignedOperation; use crate::{ - Address, Amount, Block, BlockId, CompactConfig, Endorsement, EndorsementId, Operation, - OperationId, Slot, Version, + Address, Amount, Block, BlockId, CompactConfig, EndorsementId, OperationId, Slot, Version, }; use massa_hash::hash::Hash; use massa_time::MassaTime; @@ -73,7 +74,7 @@ pub struct OperationInfo { pub in_pool: bool, pub in_blocks: Vec, pub is_final: bool, - pub operation: Operation, + pub operation: SignedOperation, } impl OperationInfo { @@ -141,7 +142,7 @@ impl std::fmt::Display for RollsInfo { #[derive(Debug, Deserialize, Serialize, Clone, Default)] pub struct SCELedgerInfo { pub balance: Amount, - pub module: Option>, + pub module: Vec, pub datastore: Map>, } @@ -158,7 +159,8 @@ pub struct AddressInfo { pub address: Address, pub thread: u8, pub ledger_info: LedgerInfo, - pub sce_ledger_info: SCELedgerInfo, + pub final_sce_ledger_info: SCELedgerInfo, + pub candidate_sce_ledger_info: SCELedgerInfo, pub rolls: RollsInfo, pub block_draws: HashSet, pub endorsement_draws: HashSet, @@ -173,7 +175,12 @@ impl std::fmt::Display for AddressInfo { writeln!(f, "Address: {}", self.address)?; writeln!(f, "Thread: {}", self.thread)?; writeln!(f, "Sequential balance:\n{}", self.ledger_info)?; - writeln!(f, "Parallel balance:\n{}", self.sce_ledger_info)?; + writeln!(f, "Final Parallel balance:\n{}", self.final_sce_ledger_info)?; + writeln!( + f, + "Candidate Parallel balance:\n{}", + self.candidate_sce_ledger_info + )?; writeln!(f, "Rolls:\n{}", self.rolls)?; writeln!( f, @@ -239,7 +246,8 @@ impl AddressInfo { thread: self.thread, balance: self.ledger_info, rolls: self.rolls, - sce_balance: self.sce_ledger_info.clone(), + final_sce_balance: self.final_sce_ledger_info.clone(), + candidate_sce_balance: self.candidate_sce_ledger_info.clone(), } } } @@ -263,14 +271,20 @@ pub struct CompactAddressInfo { pub thread: u8, pub balance: LedgerInfo, pub rolls: RollsInfo, - pub sce_balance: SCELedgerInfo, + pub final_sce_balance: SCELedgerInfo, + pub candidate_sce_balance: SCELedgerInfo, } impl std::fmt::Display for CompactAddressInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "Address: {}", self.address)?; writeln!(f, "Thread: {}", self.thread)?; - writeln!(f, "Sequential balance:\n{}", self.sce_balance)?; + writeln!(f, "Final Sequential balance:\n{}", self.final_sce_balance)?; + writeln!( + f, + "Candidate Sequential balance:\n{}", + self.candidate_sce_balance + )?; writeln!(f, "Parallel balance:\n{}", self.balance)?; writeln!(f, "Rolls:\n{}", self.rolls)?; Ok(()) @@ -283,7 +297,7 @@ pub struct EndorsementInfo { pub in_pool: bool, pub in_blocks: Vec, pub is_final: bool, - pub endorsement: Endorsement, + pub endorsement: SignedEndorsement, } impl std::fmt::Display for EndorsementInfo { diff --git a/massa-models/src/block.rs b/massa-models/src/block.rs index cf8e1d09377..43c2421e877 100644 --- a/massa-models/src/block.rs +++ b/massa-models/src/block.rs @@ -2,17 +2,16 @@ use crate::constants::{BLOCK_ID_SIZE_BYTES, SLOT_KEY_SIZE}; use crate::prehash::{Map, PreHashed, Set}; +use crate::signed::{Id, Signable, Signed}; use crate::{ array_from_slice, u8_from_slice, with_serialization_context, Address, DeserializeCompact, DeserializeMinBEInt, DeserializeVarInt, Endorsement, EndorsementId, ModelsError, Operation, - OperationId, SerializeCompact, SerializeMinBEInt, SerializeVarInt, Slot, + OperationId, SerializeCompact, SerializeMinBEInt, SerializeVarInt, SignedEndorsement, + SignedOperation, Slot, }; use massa_hash::hash::Hash; use massa_hash::HASH_SIZE_BYTES; -use massa_signature::{ - sign, verify_signature, PrivateKey, PublicKey, Signature, PUBLIC_KEY_SIZE_BYTES, - SIGNATURE_SIZE_BYTES, -}; +use massa_signature::{PublicKey, PUBLIC_KEY_SIZE_BYTES}; use serde::{Deserialize, Serialize}; use std::convert::TryInto; use std::fmt::Formatter; @@ -24,6 +23,11 @@ const BLOCK_ID_STRING_PREFIX: &str = "BLO"; pub struct BlockId(pub Hash); impl PreHashed for BlockId {} +impl Id for BlockId { + fn new(hash: Hash) -> Self { + BlockId(hash) + } +} impl std::fmt::Display for BlockId { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -94,17 +98,19 @@ impl BlockId { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Block { - pub header: BlockHeader, - pub operations: Vec, + pub header: SignedHeader, + pub operations: Vec, } impl Block { - pub fn contains_operation(&self, op: &Operation) -> Result { - let op_id = op.get_operation_id()?; - Ok(self - .operations - .iter() - .any(|o| o.get_operation_id().map(|id| id == op_id).unwrap_or(false))) + pub fn contains_operation(&self, op: SignedOperation) -> Result { + let op_id = op.content.compute_id()?; + Ok(self.operations.iter().any(|o| { + o.content + .compute_id() + .map(|id| id == op_id) + .unwrap_or(false) + })) } pub fn bytes_count(&self) -> Result { @@ -115,7 +121,7 @@ impl Block { pub fn get_roll_involved_addresses(&self) -> Result, ModelsError> { let mut roll_involved_addrs = Set::
::default(); for op in self.operations.iter() { - roll_involved_addrs.extend(op.get_roll_involved_addresses()?); + roll_involved_addrs.extend(op.content.get_roll_involved_addresses()?); } Ok(roll_involved_addrs) } @@ -131,7 +137,7 @@ impl Block { .iter() .try_for_each::<_, Result<(), ModelsError>>(|(op_id, (op_idx, _op_expiry))| { let op = &self.operations[*op_idx]; - let addrs = op.get_ledger_involved_addresses().map_err(|err| { + let addrs = op.content.get_ledger_involved_addresses().map_err(|err| { ModelsError::DeserializeError(format!( "could not get involved addresses: {}", err @@ -163,10 +169,10 @@ impl Block { .try_for_each::<_, Result<(), ModelsError>>(|e| { let address = Address::from_public_key(&e.content.sender_public_key); if let Some(old) = res.get_mut(&address) { - old.insert(e.compute_endorsement_id()?); + old.insert(e.content.compute_id()?); } else { let mut set = Set::::default(); - set.insert(e.compute_endorsement_id()?); + set.insert(e.content.compute_id()?); res.insert(address, set); } Ok(()) @@ -192,15 +198,28 @@ impl std::fmt::Display for Block { } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BlockHeaderContent { +pub struct BlockHeader { pub creator: PublicKey, pub slot: Slot, pub parents: Vec, pub operation_merkle_root: Hash, // all operations hash - pub endorsements: Vec, + pub endorsements: Vec, +} + +impl Signable for BlockHeader { + fn get_signature_message(&self) -> Result { + let hash = self.compute_hash()?; + let mut res = [0u8; SLOT_KEY_SIZE + BLOCK_ID_SIZE_BYTES]; + res[..SLOT_KEY_SIZE].copy_from_slice(&self.slot.to_bytes_key()); + res[SLOT_KEY_SIZE..].copy_from_slice(&hash.to_bytes()); + // rehash for safety + Ok(Hash::compute_from(&res)) + } } -impl std::fmt::Display for BlockHeaderContent { +pub type SignedHeader = Signed; + +impl std::fmt::Display for BlockHeader { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let pk = self.creator.to_string(); writeln!(f, "\tCreator: {}", pk)?; @@ -224,7 +243,7 @@ impl std::fmt::Display for BlockHeaderContent { writeln!( f, "\t\tId: {}", - ed.compute_endorsement_id().map_err(|_| std::fmt::Error)? + ed.content.compute_id().map_err(|_| std::fmt::Error)? )?; writeln!(f, "\t\tIndex: {}", ed.content.index)?; writeln!(f, "\t\tEndorsed slot: {}", ed.content.slot)?; @@ -243,12 +262,6 @@ impl std::fmt::Display for BlockHeaderContent { } } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BlockHeader { - pub content: BlockHeaderContent, - pub signature: Signature, -} - /// Checks performed: /// - Validity of header. /// - Number of operations. @@ -277,14 +290,6 @@ impl SerializeCompact for Block { } } -impl std::fmt::Display for BlockHeader { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Signature: {}", self.signature)?; - writeln!(f, "{}", self.content)?; - Ok(()) - } -} - /// Checks performed: /// - Validity of header. /// - Size of block. @@ -299,7 +304,8 @@ impl DeserializeCompact for Block { }); // header - let (header, delta) = BlockHeader::from_bytes_compact(&buffer[cursor..])?; + let (header, delta) = + Signed::::from_bytes_compact(&buffer[cursor..])?; cursor += delta; if cursor > (max_block_size as usize) { return Err(ModelsError::DeserializeError("block is too large".into())); @@ -312,9 +318,10 @@ impl DeserializeCompact for Block { if cursor > (max_block_size as usize) { return Err(ModelsError::DeserializeError("block is too large".into())); } - let mut operations: Vec = Vec::with_capacity(operation_count as usize); + let mut operations: Vec = Vec::with_capacity(operation_count as usize); for _ in 0..(operation_count as usize) { - let (operation, delta) = Operation::from_bytes_compact(&buffer[cursor..])?; + let (operation, delta) = + Signed::::from_bytes_compact(&buffer[cursor..])?; cursor += delta; if cursor > (max_block_size as usize) { return Err(ModelsError::DeserializeError("block is too large".into())); @@ -327,103 +334,6 @@ impl DeserializeCompact for Block { } impl BlockHeader { - /// Verify the signature of the header - pub fn check_signature(&self) -> Result<(), ModelsError> { - let hash = self.content.compute_hash()?; - self.verify_signature(&hash)?; - Ok(()) - } - - /// Generate the block id without verifying the integrity of the it, - /// used only in tests and logging. - pub fn compute_block_id(&self) -> Result { - Ok(BlockId(Hash::compute_from(&self.to_bytes_compact()?))) - } - - // Hash([slot, hash]) - fn get_signature_message(slot: &Slot, hash: &Hash) -> Hash { - let mut res = [0u8; SLOT_KEY_SIZE + BLOCK_ID_SIZE_BYTES]; - res[..SLOT_KEY_SIZE].copy_from_slice(&slot.to_bytes_key()); - res[SLOT_KEY_SIZE..].copy_from_slice(&hash.to_bytes()); - // rehash for safety - Hash::compute_from(&res) - } - - // check if a [slot, hash] pair was signed by a public_key - pub fn verify_slot_hash_signature( - slot: &Slot, - hash: &Hash, - signature: &Signature, - public_key: &PublicKey, - ) -> Result<(), ModelsError> { - verify_signature( - &BlockHeader::get_signature_message(slot, hash), - signature, - public_key, - ) - .map_err(|err| err.into()) - } - - pub fn new_signed( - private_key: &PrivateKey, - content: BlockHeaderContent, - ) -> Result<(BlockId, Self), ModelsError> { - let hash = content.compute_hash()?; - let signature = sign( - &BlockHeader::get_signature_message(&content.slot, &hash), - private_key, - )?; - let header = BlockHeader { content, signature }; - let block_id = header.compute_block_id()?; - Ok((block_id, header)) - } - - pub fn verify_signature(&self, hash: &Hash) -> Result<(), ModelsError> { - BlockHeader::verify_slot_hash_signature( - &self.content.slot, - hash, - &self.signature, - &self.content.creator, - ) - } -} - -/// Checks performed: -/// - Content. -impl SerializeCompact for BlockHeader { - fn to_bytes_compact(&self) -> Result, ModelsError> { - let mut res: Vec = Vec::new(); - - // signed content - res.extend(self.content.to_bytes_compact()?); - - // signature - res.extend(&self.signature.to_bytes()); - - Ok(res) - } -} - -/// Checks performed: -/// - Content -/// - Signature. -impl DeserializeCompact for BlockHeader { - fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), ModelsError> { - let mut cursor = 0usize; - - // signed content - let (content, delta) = BlockHeaderContent::from_bytes_compact(&buffer[cursor..])?; - cursor += delta; - - // signature - let signature = Signature::from_bytes(&array_from_slice(&buffer[cursor..])?)?; - cursor += SIGNATURE_SIZE_BYTES; - - Ok((BlockHeader { content, signature }, cursor)) - } -} - -impl BlockHeaderContent { pub fn compute_hash(&self) -> Result { Ok(Hash::compute_from(&self.to_bytes_compact()?)) } @@ -433,7 +343,7 @@ impl BlockHeaderContent { /// - Validity of slot. /// - Valid length of included endorsements. /// - Validity of included endorsements. -impl SerializeCompact for BlockHeaderContent { +impl SerializeCompact for BlockHeader { fn to_bytes_compact(&self) -> Result, ModelsError> { let mut res: Vec = Vec::new(); @@ -474,7 +384,7 @@ impl SerializeCompact for BlockHeaderContent { /// - Presence of parent. /// - Valid length of included endorsements. /// - Validity of included endorsements. -impl DeserializeCompact for BlockHeaderContent { +impl DeserializeCompact for BlockHeader { fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), ModelsError> { let mut cursor = 0usize; @@ -502,7 +412,7 @@ impl DeserializeCompact for BlockHeaderContent { Vec::new() } else { return Err(ModelsError::SerializeError( - "BlockHeaderContent from_bytes_compact bad has parents flags.".into(), + "BlockHeader from_bytes_compact bad has parents flags.".into(), )); }; @@ -518,15 +428,16 @@ impl DeserializeCompact for BlockHeaderContent { u32::from_varint_bytes_bounded(&buffer[cursor..], max_block_endorsements)?; cursor += delta; - let mut endorsements: Vec = Vec::with_capacity(endorsement_count as usize); + let mut endorsements = Vec::with_capacity(endorsement_count as usize); for _ in 0..endorsement_count { - let (endorsement, delta) = Endorsement::from_bytes_compact(&buffer[cursor..])?; + let (endorsement, delta) = + Signed::::from_bytes_compact(&buffer[cursor..])?; cursor += delta; endorsements.push(endorsement); } Ok(( - BlockHeaderContent { + BlockHeader { creator, slot, parents, @@ -541,7 +452,7 @@ impl DeserializeCompact for BlockHeaderContent { #[cfg(test)] mod test { use super::*; - use crate::EndorsementContent; + use crate::Endorsement; use massa_signature::{derive_public_key, generate_random_private_key}; use serial_test::serial; @@ -571,9 +482,8 @@ mod test { let public_key = derive_public_key(&private_key); // create block header - let (orig_id, orig_header) = BlockHeader::new_signed( - &private_key, - BlockHeaderContent { + let (orig_id, orig_header) = Signed::new_signed( + BlockHeader { creator: public_key, slot: Slot::new(1, 2), parents: vec![ @@ -583,28 +493,31 @@ mod test { ], operation_merkle_root: Hash::compute_from("mno".as_bytes()), endorsements: vec![ - Endorsement { - content: EndorsementContent { + Signed::new_signed( + Endorsement { sender_public_key: public_key, slot: Slot::new(1, 1), index: 1, endorsed_block: BlockId(Hash::compute_from("blk1".as_bytes())), }, - signature: sign(&Hash::compute_from("dta".as_bytes()), &private_key) - .unwrap(), - }, - Endorsement { - content: EndorsementContent { + &private_key, + ) + .unwrap() + .1, + Signed::new_signed( + Endorsement { sender_public_key: public_key, slot: Slot::new(4, 0), index: 3, endorsed_block: BlockId(Hash::compute_from("blk2".as_bytes())), }, - signature: sign(&Hash::compute_from("dat".as_bytes()), &private_key) - .unwrap(), - }, + &private_key, + ) + .unwrap() + .1, ], }, + &private_key, ) .unwrap(); @@ -622,8 +535,8 @@ mod test { assert_eq!(orig_bytes.len(), res_size); // check equality - let res_id = res_block.header.compute_block_id().unwrap(); - let generated_res_id = res_block.header.compute_block_id().unwrap(); + let res_id = res_block.header.content.compute_id().unwrap(); + let generated_res_id = res_block.header.content.compute_id().unwrap(); assert_eq!(orig_id, res_id); assert_eq!(orig_id, generated_res_id); assert_eq!(res_block.header.signature, orig_block.header.signature); diff --git a/massa-models/src/composite.rs b/massa-models/src/composite.rs index 78ec5c56f30..bb4b9ec518c 100644 --- a/massa-models/src/composite.rs +++ b/massa-models/src/composite.rs @@ -1,12 +1,10 @@ // Copyright (c) 2022 MASSA LABS -use std::fmt::Display; - -use super::operation::Operation; use crate::prehash::Map; -use crate::{Address, BlockId}; +use crate::{Address, BlockId, SignedOperation}; use massa_signature::{PublicKey, Signature}; use serde::{Deserialize, Serialize}; +use std::fmt::Display; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum OperationSearchResultBlockStatus { @@ -27,7 +25,7 @@ pub enum OperationSearchResultStatus { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct OperationSearchResult { - pub op: Operation, + pub op: SignedOperation, pub in_pool: bool, pub in_blocks: Map, // index, is_final pub status: OperationSearchResultStatus, diff --git a/massa-models/src/endorsement.rs b/massa-models/src/endorsement.rs index 3c0a5364784..b9f4dce9273 100644 --- a/massa-models/src/endorsement.rs +++ b/massa-models/src/endorsement.rs @@ -2,6 +2,7 @@ use crate::constants::{BLOCK_ID_SIZE_BYTES, ENDORSEMENT_ID_SIZE_BYTES}; use crate::prehash::PreHashed; +use crate::signed::{Id, Signable, Signed}; use crate::{ serialization::{ array_from_slice, DeserializeCompact, DeserializeVarInt, SerializeCompact, SerializeVarInt, @@ -9,10 +10,7 @@ use crate::{ with_serialization_context, BlockId, ModelsError, Slot, }; use massa_hash::hash::Hash; -use massa_signature::{ - sign, verify_signature, PrivateKey, PublicKey, Signature, PUBLIC_KEY_SIZE_BYTES, - SIGNATURE_SIZE_BYTES, -}; +use massa_signature::{PublicKey, PUBLIC_KEY_SIZE_BYTES}; use serde::{Deserialize, Serialize}; use std::{fmt::Display, str::FromStr}; @@ -21,6 +19,11 @@ const ENDORSEMENT_ID_STRING_PREFIX: &str = "END"; pub struct EndorsementId(Hash); impl PreHashed for EndorsementId {} +impl Id for EndorsementId { + fn new(hash: Hash) -> Self { + EndorsementId(hash) + } +} impl std::fmt::Display for EndorsementId { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -82,103 +85,25 @@ impl EndorsementId { } } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Endorsement { - pub content: EndorsementContent, - pub signature: Signature, -} - impl Display for Endorsement { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!( f, "Endorsed block: {} at slot {}", - self.content.endorsed_block, self.content.slot + self.endorsed_block, self.slot )?; - writeln!(f, "Index: {}", self.content.index)?; + writeln!(f, "Index: {}", self.index)?; writeln!( f, "Endorsement creator public key: {}", - self.content.sender_public_key - )?; - writeln!(f, "Signature: {}", self.signature)?; - Ok(()) - } -} - -impl EndorsementContent { - pub fn compute_hash(&self) -> Result { - Ok(Hash::compute_from(&self.to_bytes_compact()?)) - } -} - -impl Endorsement { - /// Verify the signature and integrity of the endorsement and computes ID - pub fn verify_signature(&self) -> Result<(), ModelsError> { - let content_hash = Hash::compute_from(&self.content.to_bytes_compact()?); - verify_signature( - &content_hash, - &self.signature, - &self.content.sender_public_key, + self.sender_public_key )?; Ok(()) } - - pub fn new_signed( - private_key: &PrivateKey, - content: EndorsementContent, - ) -> Result<(EndorsementId, Self), ModelsError> { - let content_hash = content.compute_hash()?; - let signature = sign(&content_hash, private_key)?; - let endorsement = Endorsement { content, signature }; - let e_id = endorsement.compute_endorsement_id()?; - Ok((e_id, endorsement)) - } - - pub fn compute_endorsement_id(&self) -> Result { - Ok(EndorsementId(Hash::compute_from(&self.to_bytes_compact()?))) - } -} - -/// Checks performed: -/// - Validity of the content. -impl SerializeCompact for Endorsement { - fn to_bytes_compact(&self) -> Result, ModelsError> { - let mut res: Vec = Vec::new(); - - // content - res.extend(self.content.to_bytes_compact()?); - - // signature - res.extend(&self.signature.to_bytes()); - - Ok(res) - } -} - -/// Checks performed: -/// - Validity of the content. -/// - Validity of the signature. -impl DeserializeCompact for Endorsement { - fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), ModelsError> { - let mut cursor = 0; - - // content - let (content, delta) = EndorsementContent::from_bytes_compact(&buffer[cursor..])?; - cursor += delta; - - // signature - let signature = Signature::from_bytes(&array_from_slice(&buffer[cursor..])?)?; - cursor += SIGNATURE_SIZE_BYTES; - - let res = Endorsement { content, signature }; - - Ok((res, cursor)) - } } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EndorsementContent { +pub struct Endorsement { /// Public key of the endorser. pub sender_public_key: PublicKey, /// slot of endorsed block @@ -189,9 +114,13 @@ pub struct EndorsementContent { pub endorsed_block: BlockId, } +impl Signable for Endorsement {} + +pub type SignedEndorsement = Signed; + /// Checks performed: /// - Validity of the slot. -impl SerializeCompact for EndorsementContent { +impl SerializeCompact for Endorsement { fn to_bytes_compact(&self) -> Result, ModelsError> { let mut res: Vec = Vec::new(); @@ -216,7 +145,7 @@ impl SerializeCompact for EndorsementContent { /// - Validity of the slot. /// - Validity of the endorsement index. /// - Validity of the endorsed block id. -impl DeserializeCompact for EndorsementContent { +impl DeserializeCompact for Endorsement { fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), ModelsError> { let max_block_endorsements = with_serialization_context(|context| context.endorsement_count); @@ -247,7 +176,7 @@ impl DeserializeCompact for EndorsementContent { cursor += BLOCK_ID_SIZE_BYTES; Ok(( - EndorsementContent { + Endorsement { sender_public_key, slot, index, @@ -260,6 +189,8 @@ impl DeserializeCompact for EndorsementContent { #[cfg(test)] mod tests { + use crate::signed::Signed; + use super::*; use massa_signature::{derive_public_key, generate_random_private_key}; use serial_test::serial; @@ -290,24 +221,20 @@ mod tests { let sender_priv = generate_random_private_key(); let sender_public_key = derive_public_key(&sender_priv); - let content = EndorsementContent { + let content = Endorsement { sender_public_key, slot: Slot::new(10, 1), index: 0, endorsed_block: BlockId(Hash::compute_from("blk".as_bytes())), }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - let endorsement = Endorsement { - content: content.clone(), - signature, - }; + let endorsement = Signed::new_signed(content.clone(), &sender_priv).unwrap().1; let ser_content = content.to_bytes_compact().unwrap(); - let (res_content, _) = EndorsementContent::from_bytes_compact(&ser_content).unwrap(); + let (res_content, _) = Endorsement::from_bytes_compact(&ser_content).unwrap(); assert_eq!(format!("{:?}", res_content), format!("{:?}", content)); let ser_endorsement = endorsement.to_bytes_compact().unwrap(); - let (res_endorsement, _) = Endorsement::from_bytes_compact(&ser_endorsement).unwrap(); + let (res_endorsement, _) = + Signed::::from_bytes_compact(&ser_endorsement).unwrap(); assert_eq!( format!("{:?}", res_endorsement), format!("{:?}", endorsement) diff --git a/massa-models/src/lib.rs b/massa-models/src/lib.rs index cb75aa2e0a1..76042106bc6 100644 --- a/massa-models/src/lib.rs +++ b/massa-models/src/lib.rs @@ -5,14 +5,14 @@ extern crate lazy_static; pub use address::Address; pub use amount::Amount; -pub use block::{Block, BlockHeader, BlockHeaderContent, BlockId}; +pub use block::{Block, BlockHeader, BlockId, SignedHeader}; pub use composite::{ OperationSearchResult, OperationSearchResultBlockStatus, OperationSearchResultStatus, StakersCycleProductionStats, }; -pub use endorsement::{Endorsement, EndorsementContent, EndorsementId}; +pub use endorsement::{Endorsement, EndorsementId, SignedEndorsement}; pub use error::ModelsError; -pub use operation::{Operation, OperationContent, OperationId, OperationType}; +pub use operation::{Operation, OperationId, OperationType, SignedOperation}; pub use serialization::{ array_from_slice, u8_from_slice, DeserializeCompact, DeserializeMinBEInt, DeserializeVarInt, SerializeCompact, SerializeMinBEInt, SerializeVarInt, @@ -42,6 +42,7 @@ pub mod prehash; pub mod rolls; mod serialization; mod serialization_context; +pub mod signed; pub mod slot; pub mod stats; pub mod timeslots; diff --git a/massa-models/src/operation.rs b/massa-models/src/operation.rs index 08dd96524c3..b69de015522 100644 --- a/massa-models/src/operation.rs +++ b/massa-models/src/operation.rs @@ -2,6 +2,7 @@ use crate::constants::{ADDRESS_SIZE_BYTES, OPERATION_ID_SIZE_BYTES}; use crate::prehash::{PreHashed, Set}; +use crate::signed::{Id, Signable, Signed}; use crate::{ serialization::{ array_from_slice, DeserializeCompact, DeserializeVarInt, SerializeCompact, SerializeVarInt, @@ -9,9 +10,7 @@ use crate::{ Address, Amount, ModelsError, }; use massa_hash::hash::Hash; -use massa_signature::{ - verify_signature, PublicKey, Signature, PUBLIC_KEY_SIZE_BYTES, SIGNATURE_SIZE_BYTES, -}; +use massa_signature::{PublicKey, PUBLIC_KEY_SIZE_BYTES}; use num_enum::{IntoPrimitive, TryFromPrimitive}; use serde::{Deserialize, Serialize}; use std::convert::TryInto; @@ -75,6 +74,11 @@ impl FromStr for OperationId { } impl PreHashed for OperationId {} +impl Id for OperationId { + fn new(hash: Hash) -> Self { + OperationId(hash) + } +} impl OperationId { pub fn to_bytes(&self) -> [u8; OPERATION_ID_SIZE_BYTES] { @@ -107,44 +111,44 @@ enum OperationTypeId { ExecuteSC = 3, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Operation { - pub content: OperationContent, - pub signature: Signature, -} - -impl std::fmt::Display for Operation { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!( - f, - "Id: {}", - match self.get_operation_id() { - Ok(id) => format!("{}", id), - Err(e) => format!("error computing id: {}", e), - } - )?; - writeln!(f, "Signature: {}", self.signature)?; - let addr = Address::from_public_key(&self.content.sender_public_key); - let amount = self.content.fee.to_string(); - writeln!( - f, - "sender: {} fee: {} expire_period: {}", - addr, amount, self.content.expire_period, - )?; - writeln!(f, "{}", self.content.op)?; - Ok(()) - } -} +// #[derive(Debug, Clone, Serialize, Deserialize)] +// pub struct Operation { +// pub content: Operation, +// pub signature: Signature, +// } + +// impl std::fmt::Display for Operation { +// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { +// writeln!( +// f, +// "Id: {}", +// match self.content.compute_id() { +// Ok(id) => format!("{}", id), +// Err(e) => format!("error computing id: {}", e), +// } +// )?; +// writeln!(f, "Signature: {}", self.signature)?; +// let addr = Address::from_public_key(&self.content.sender_public_key); +// let amount = self.content.fee.to_string(); +// writeln!( +// f, +// "sender: {} fee: {} expire_period: {}", +// addr, amount, self.content.expire_period, +// )?; +// writeln!(f, "{}", self.content.op)?; +// Ok(()) +// } +// } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct OperationContent { +pub struct Operation { pub sender_public_key: PublicKey, pub fee: Amount, pub expire_period: u64, pub op: OperationType, } -impl std::fmt::Display for OperationContent { +impl std::fmt::Display for Operation { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { writeln!(f, "Sender public key: {}", self.sender_public_key)?; writeln!(f, "Fee: {}", self.fee)?; @@ -154,6 +158,10 @@ impl std::fmt::Display for OperationContent { } } +impl Signable for Operation {} + +pub type SignedOperation = Signed; + #[derive(Debug, Clone, Serialize, Deserialize)] pub enum OperationType { Transaction { @@ -366,7 +374,7 @@ impl DeserializeCompact for OperationType { /// Checks performed: /// - Validity of the fee. /// - Validity of the operation type. -impl SerializeCompact for OperationContent { +impl SerializeCompact for Operation { fn to_bytes_compact(&self) -> Result, ModelsError> { let mut res: Vec = Vec::new(); @@ -391,7 +399,7 @@ impl SerializeCompact for OperationContent { /// - Validity of the expire period. /// - Validity of the sender public key. /// - Validity of the operation type. -impl DeserializeCompact for OperationContent { +impl DeserializeCompact for Operation { fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), ModelsError> { let mut cursor = 0usize; @@ -412,7 +420,7 @@ impl DeserializeCompact for OperationContent { cursor += delta; Ok(( - OperationContent { + Operation { fee, expire_period, sender_public_key, @@ -423,40 +431,25 @@ impl DeserializeCompact for OperationContent { } } -impl Operation { +impl SignedOperation { /// Verifies the signature and integrity of the operation and computes operation ID pub fn verify_integrity(&self) -> Result { - self.verify_signature()?; - self.get_operation_id() - } - - pub fn verify_signature(&self) -> Result<(), ModelsError> { - let content_hash = Hash::compute_from(&self.content.to_bytes_compact()?); - verify_signature( - &content_hash, - &self.signature, - &self.content.sender_public_key, - )?; - Ok(()) - } - - pub fn get_operation_id(&self) -> Result { - Ok(OperationId(Hash::compute_from(&self.to_bytes_compact()?))) + self.verify_signature(&self.content.sender_public_key)?; + self.content.compute_id() } +} +impl Operation { pub fn get_validity_range(&self, operation_validity_period: u64) -> RangeInclusive { - let start = self - .content - .expire_period - .saturating_sub(operation_validity_period); - start..=self.content.expire_period + let start = self.expire_period.saturating_sub(operation_validity_period); + start..=self.expire_period } pub fn get_ledger_involved_addresses(&self) -> Result, ModelsError> { let mut res = Set::
::default(); - let emitter_address = Address::from_public_key(&self.content.sender_public_key); + let emitter_address = Address::from_public_key(&self.sender_public_key); res.insert(emitter_address); - match self.content.op { + match self.op { OperationType::Transaction { recipient_address, .. } => { @@ -471,13 +464,13 @@ impl Operation { pub fn get_roll_involved_addresses(&self) -> Result, ModelsError> { let mut res = Set::
::default(); - match self.content.op { + match self.op { OperationType::Transaction { .. } => {} OperationType::RollBuy { .. } => { - res.insert(Address::from_public_key(&self.content.sender_public_key)); + res.insert(Address::from_public_key(&self.sender_public_key)); } OperationType::RollSell { .. } => { - res.insert(Address::from_public_key(&self.content.sender_public_key)); + res.insert(Address::from_public_key(&self.sender_public_key)); } OperationType::ExecuteSC { .. } => {} } @@ -485,47 +478,10 @@ impl Operation { } } -/// Checks performed: -/// - Content. -impl SerializeCompact for Operation { - fn to_bytes_compact(&self) -> Result, ModelsError> { - let mut res: Vec = Vec::new(); - - // content - res.extend(self.content.to_bytes_compact()?); - - // signature - res.extend(&self.signature.to_bytes()); - - Ok(res) - } -} - -/// Checks performed: -/// - Content. -/// - Signature. -impl DeserializeCompact for Operation { - fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), ModelsError> { - let mut cursor = 0; - - // content - let (content, delta) = OperationContent::from_bytes_compact(&buffer[cursor..])?; - cursor += delta; - - // signature - let signature = Signature::from_bytes(&array_from_slice(&buffer[cursor..])?)?; - cursor += SIGNATURE_SIZE_BYTES; - - let res = Operation { content, signature }; - - Ok((res, cursor)) - } -} - #[cfg(test)] mod tests { use super::*; - use massa_signature::{derive_public_key, generate_random_private_key, sign}; + use massa_signature::{derive_public_key, generate_random_private_key}; use serial_test::serial; #[test] @@ -545,7 +501,7 @@ mod tests { let (res_type, _) = OperationType::from_bytes_compact(&ser_type).unwrap(); assert_eq!(format!("{}", res_type), format!("{}", op)); - let content = OperationContent { + let content = Operation { fee: Amount::from_str("20").unwrap(), sender_public_key: sender_pub, op, @@ -553,19 +509,16 @@ mod tests { }; let ser_content = content.to_bytes_compact().unwrap(); - let (res_content, _) = OperationContent::from_bytes_compact(&ser_content).unwrap(); + let (res_content, _) = Operation::from_bytes_compact(&ser_content).unwrap(); assert_eq!(format!("{}", res_content), format!("{}", content)); - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - - let op = Operation { content, signature }; + let op = Signed::new_signed(content, &sender_priv).unwrap().1; let ser_op = op.to_bytes_compact().unwrap(); - let (res_op, _) = Operation::from_bytes_compact(&ser_op).unwrap(); + let (res_op, _) = Signed::::from_bytes_compact(&ser_op).unwrap(); assert_eq!(format!("{}", res_op), format!("{}", op)); - assert_eq!(op.get_validity_range(10), 40..=50); + assert_eq!(op.content.get_validity_range(10), 40..=50); } #[test] @@ -584,7 +537,7 @@ mod tests { let (res_type, _) = OperationType::from_bytes_compact(&ser_type).unwrap(); assert_eq!(format!("{}", res_type), format!("{}", op)); - let content = OperationContent { + let content = Operation { fee: Amount::from_str("20").unwrap(), sender_public_key: sender_pub, op, @@ -592,18 +545,15 @@ mod tests { }; let ser_content = content.to_bytes_compact().unwrap(); - let (res_content, _) = OperationContent::from_bytes_compact(&ser_content).unwrap(); + let (res_content, _) = Operation::from_bytes_compact(&ser_content).unwrap(); assert_eq!(format!("{}", res_content), format!("{}", content)); - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - - let op = Operation { content, signature }; + let op = Signed::new_signed(content, &sender_priv).unwrap().1; let ser_op = op.to_bytes_compact().unwrap(); - let (res_op, _) = Operation::from_bytes_compact(&ser_op).unwrap(); + let (res_op, _) = Signed::::from_bytes_compact(&ser_op).unwrap(); assert_eq!(format!("{}", res_op), format!("{}", op)); - assert_eq!(op.get_validity_range(10), 40..=50); + assert_eq!(op.content.get_validity_range(10), 40..=50); } } diff --git a/massa-models/src/signed.rs b/massa-models/src/signed.rs new file mode 100644 index 00000000000..78fc43671ce --- /dev/null +++ b/massa-models/src/signed.rs @@ -0,0 +1,116 @@ +use std::{fmt::Display, marker::PhantomData}; + +use crate::{array_from_slice, DeserializeCompact, ModelsError, SerializeCompact}; +use massa_hash::hash::Hash; +use massa_signature::{ + sign, verify_signature, PrivateKey, PublicKey, Signature, SIGNATURE_SIZE_BYTES, +}; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Signed +where + T: SerializeCompact + DeserializeCompact + Signable + Display, + U: Id, +{ + pub content: T, + pub signature: Signature, + phantom: PhantomData, +} +pub trait Id { + fn new(hash: Hash) -> Self; +} + +impl Display for Signed +where + T: SerializeCompact + DeserializeCompact + Signable + Display, + U: Id, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "Signature: {}", self.signature)?; + writeln!(f, "{}", self.content)?; + Ok(()) + } +} +pub trait Signable +where + U: Id, + Self: SerializeCompact, +{ + fn get_signature_message(&self) -> Result { + Ok(Hash::compute_from(&self.to_bytes_compact()?)) + } + + fn compute_id(&self) -> Result { + Ok(U::new(Hash::compute_from(&self.to_bytes_compact()?))) + } +} + +impl Signed +where + T: SerializeCompact + DeserializeCompact + Signable + Display, + U: Id, +{ + pub fn new_signed(content: T, private_key: &PrivateKey) -> Result<(U, Self), ModelsError> { + Ok(( + content.compute_id()?, + Self { + signature: sign(&content.get_signature_message()?, private_key)?, + content, + phantom: PhantomData, + }, + )) + } + + pub fn verify_signature(&self, public_key: &PublicKey) -> Result<(), ModelsError> { + Ok(verify_signature( + &self.content.get_signature_message()?, + &self.signature, + public_key, + )?) + } +} + +impl SerializeCompact for Signed +where + T: SerializeCompact + DeserializeCompact + Signable + Display, + U: Id, +{ + fn to_bytes_compact(&self) -> Result, ModelsError> { + let mut res: Vec = Vec::new(); + + // signed content + res.extend(self.content.to_bytes_compact()?); + + // signature + res.extend(&self.signature.to_bytes()); + + Ok(res) + } +} + +impl DeserializeCompact for Signed +where + T: SerializeCompact + DeserializeCompact + Signable + Display, + U: Id, +{ + fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), ModelsError> { + let mut cursor = 0usize; + + // signed content + let (content, delta) = T::from_bytes_compact(&buffer[cursor..])?; + cursor += delta; + + // signature + let signature = Signature::from_bytes(&array_from_slice(&buffer[cursor..])?)?; + cursor += SIGNATURE_SIZE_BYTES; + + Ok(( + Self { + content, + signature, + phantom: PhantomData, + }, + cursor, + )) + } +} diff --git a/massa-network-exports/Cargo.toml b/massa-network-exports/Cargo.toml new file mode 100644 index 00000000000..d1daec295cd --- /dev/null +++ b/massa-network-exports/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "massa_network_exports" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +displaydoc = "0.2" +serde = { version = "1.0", features = ["derive"] } +thiserror = "1.0" +tokio = { version = "1.15", features = ["full"] } +tracing = "0.1" +enum-map = { version = "2.0.3", features = ["serde"] } +# custom modules +massa_hash = { path = "../massa-hash" } +massa_logging = { path = "../massa-logging" } +massa_models = { path = "../massa-models" } +massa_signature = { path = "../massa-signature" } +massa_time = { path = "../massa-time" } +serde_json = "1.0" +tempfile = "3.2" + +[dev-dependencies] +massa_models = { path = "../massa-models", features = ["testing"] } + +[features] +instrument = [ "massa_models/instrument", "massa_time/instrument"] +testing = ["massa_models/testing"] diff --git a/massa-network-exports/src/commands.rs b/massa-network-exports/src/commands.rs new file mode 100644 index 00000000000..154b2d6f11c --- /dev/null +++ b/massa-network-exports/src/commands.rs @@ -0,0 +1,91 @@ +use std::{collections::HashMap, net::IpAddr}; + +use crate::{BootstrapPeers, Peers}; +use massa_models::SignedEndorsement; +use massa_models::SignedHeader; +use massa_models::SignedOperation; +use massa_models::{composite::PubkeySig, node::NodeId, stats::NetworkStats, Block, BlockId}; +use tokio::sync::oneshot; + +/// Commands that the worker can execute +#[derive(Debug)] +pub enum NetworkCommand { + /// Ask for a block from a node. + AskForBlocks { + list: HashMap>, + }, + /// Send that block to node. + SendBlock { + node: NodeId, + block: Block, + }, + /// Send a header to a node. + SendBlockHeader { + node: NodeId, + header: SignedHeader, + }, + // (PeerInfo, Vec <(NodeId, bool)>) peer info + list of associated Id nodes in connection out (true) + GetPeers(oneshot::Sender), + GetBootstrapPeers(oneshot::Sender), + Ban(NodeId), + BanIp(Vec), + Unban(Vec), + BlockNotFound { + node: NodeId, + block_id: BlockId, + }, + SendOperations { + node: NodeId, + operations: Vec, + }, + SendEndorsements { + node: NodeId, + endorsements: Vec, + }, + NodeSignMessage { + msg: Vec, + response_tx: oneshot::Sender, + }, + GetStats { + response_tx: oneshot::Sender, + }, + Whitelist(Vec), + RemoveFromWhitelist(Vec), +} + +#[derive(Debug)] +pub enum NetworkEvent { + NewConnection(NodeId), + ConnectionClosed(NodeId), + /// A block was received + ReceivedBlock { + node: NodeId, + block: Block, + }, + /// A block header was received + ReceivedBlockHeader { + source_node_id: NodeId, + header: SignedHeader, + }, + /// Someone ask for block with given header hash. + AskedForBlocks { + node: NodeId, + list: Vec, + }, + /// That node does not have this block + BlockNotFound { + node: NodeId, + block_id: BlockId, + }, + ReceivedOperations { + node: NodeId, + operations: Vec, + }, + ReceivedEndorsements { + node: NodeId, + endorsements: Vec, + }, +} + +#[derive(Debug)] +pub enum NetworkManagementCommand {} diff --git a/massa-network/src/common.rs b/massa-network-exports/src/common.rs similarity index 100% rename from massa-network/src/common.rs rename to massa-network-exports/src/common.rs diff --git a/massa-network/src/error.rs b/massa-network-exports/src/error.rs similarity index 97% rename from massa-network/src/error.rs rename to massa-network-exports/src/error.rs index d21217e7684..6a928d320fa 100644 --- a/massa-network/src/error.rs +++ b/massa-network-exports/src/error.rs @@ -1,6 +1,6 @@ // Copyright (c) 2022 MASSA LABS -use crate::{peer_info_database::PeerType, ConnectionId}; +use crate::{peers::PeerType, ConnectionId}; use displaydoc::Display; use massa_models::ModelsError; use std::net::IpAddr; @@ -60,6 +60,7 @@ pub enum HandshakeErrorType { PeerListReceived(Vec), } +#[macro_export] macro_rules! throw_handshake_error { ($err:ident) => { return Err(NetworkError::HandshakeError(HandshakeErrorType::$err)) @@ -68,7 +69,8 @@ macro_rules! throw_handshake_error { return Err(NetworkError::HandshakeError(HandshakeErrorType::$err($e))) }; } -pub(crate) use throw_handshake_error; + +pub use throw_handshake_error; #[derive(Debug, Error, Display)] #[non_exhaustive] diff --git a/massa-network-exports/src/establisher.rs b/massa-network-exports/src/establisher.rs new file mode 100644 index 00000000000..9ba20c350c8 --- /dev/null +++ b/massa-network-exports/src/establisher.rs @@ -0,0 +1,96 @@ +// Copyright (c) 2022 MASSA LABS +#[cfg(feature = "testing")] +mod types { + use crate::test_exports::mock_establisher; + + pub type ReadHalf = mock_establisher::ReadHalf; + pub type WriteHalf = mock_establisher::WriteHalf; + pub type Listener = mock_establisher::MockListener; + pub type Establisher = mock_establisher::MockEstablisher; +} +#[cfg(not(feature = "testing"))] +mod types { + use massa_time::MassaTime; + use std::{io, net::SocketAddr}; + use tokio::{ + net::{TcpListener, TcpStream}, + time::timeout, + }; + + pub type ReadHalf = tokio::net::tcp::OwnedReadHalf; + pub type WriteHalf = tokio::net::tcp::OwnedWriteHalf; + pub type Listener = DefaultListener; + pub type Establisher = DefaultEstablisher; + + /// The listener we are using + #[derive(Debug)] + pub struct DefaultListener(TcpListener); + + impl DefaultListener { + /// Accepts a new incoming connection from this listener. + pub async fn accept(&mut self) -> io::Result<(ReadHalf, WriteHalf, SocketAddr)> { + let (sock, remote_addr) = self.0.accept().await?; + let (read_half, write_half) = sock.into_split(); + Ok((read_half, write_half, remote_addr)) + } + } + + /// Initiates a connection with given timeout in millis + #[derive(Debug)] + pub struct DefaultConnector(MassaTime); + + impl DefaultConnector { + /// Tries to connect to addr + /// + /// # Argument + /// * addr: SocketAddr we are trying to connect to. + pub async fn connect(&mut self, addr: SocketAddr) -> io::Result<(ReadHalf, WriteHalf)> { + match timeout(self.0.to_duration(), TcpStream::connect(addr)).await { + Ok(Ok(sock)) => { + let (reader, writer) = sock.into_split(); + Ok((reader, writer)) + } + Ok(Err(e)) => Err(e), + Err(e) => Err(io::Error::new(io::ErrorKind::TimedOut, e)), + } + } + } + + /// Establishes a connection + #[derive(Debug)] + pub struct DefaultEstablisher; + + impl DefaultEstablisher { + /// Creates an Establisher. + pub fn new() -> Self { + DefaultEstablisher {} + } + + /// Gets the associated listener + /// + /// # Argument + /// * addr: SocketAddr we want to bind to. + pub async fn get_listener(&mut self, addr: SocketAddr) -> io::Result { + Ok(DefaultListener(TcpListener::bind(addr).await?)) + } + + /// Get the connector with associated timeout + /// + /// # Argument + /// * timeout_duration: timeout duration in millis + pub async fn get_connector( + &mut self, + timeout_duration: MassaTime, + ) -> io::Result { + Ok(DefaultConnector(timeout_duration)) + } + } + + impl Default for DefaultEstablisher { + fn default() -> Self { + Self::new() + } + } +} + +pub use types::*; diff --git a/massa-network-exports/src/lib.rs b/massa-network-exports/src/lib.rs new file mode 100644 index 00000000000..706279f6199 --- /dev/null +++ b/massa-network-exports/src/lib.rs @@ -0,0 +1,19 @@ +//! Manages a connection with a node +pub use commands::{NetworkCommand, NetworkEvent, NetworkManagementCommand}; +pub use common::{ConnectionClosureReason, ConnectionId}; +pub use error::{HandshakeErrorType, NetworkConnectionErrorType, NetworkError}; +pub use establisher::{Establisher, Listener, ReadHalf, WriteHalf}; +pub use network_controller::{NetworkCommandSender, NetworkEventReceiver, NetworkManager}; +pub use peers::{BootstrapPeers, ConnectionCount, Peer, PeerInfo, PeerType, Peers}; +pub use settings::NetworkSettings; + +mod commands; +mod common; +mod error; +mod establisher; +mod network_controller; +mod peers; +pub mod settings; + +#[cfg(feature = "testing")] +pub mod test_exports; diff --git a/massa-network/src/network_controller.rs b/massa-network-exports/src/network_controller.rs similarity index 61% rename from massa-network/src/network_controller.rs rename to massa-network-exports/src/network_controller.rs index 353d6d5f2c7..3c498a6e50b 100644 --- a/massa-network/src/network_controller.rs +++ b/massa-network-exports/src/network_controller.rs @@ -1,22 +1,13 @@ // Copyright (c) 2022 MASSA LABS use crate::{ - error::NetworkError, - establisher::Establisher, - network_worker::NetworkWorkerChannels, - network_worker::{ - NetworkCommand, NetworkEvent, NetworkManagementCommand, NetworkWorker, Peers, - }, - peer_info_database::*, - settings::NetworkSettings, - BootstrapPeers, + commands::NetworkManagementCommand, error::NetworkError, BootstrapPeers, NetworkCommand, + NetworkEvent, Peers, }; -use massa_logging::massa_trace; use massa_models::{ - composite::PubkeySig, constants::CHANNEL_SIZE, node::NodeId, stats::NetworkStats, Block, - BlockHeader, BlockId, Endorsement, Operation, Version, + composite::PubkeySig, node::NodeId, stats::NetworkStats, Block, BlockId, SignedEndorsement, + SignedHeader, SignedOperation, }; -use massa_signature::{derive_public_key, generate_random_private_key, PrivateKey}; use std::{ collections::{HashMap, VecDeque}, net::IpAddr, @@ -25,131 +16,6 @@ use tokio::{ sync::{mpsc, oneshot}, task::JoinHandle, }; -use tracing::{debug, error, info, warn}; - -/// Starts a new NetworkWorker in a spawned task -/// -/// # Arguments -/// * cfg : network configuration -pub async fn start_network_controller( - network_settings: NetworkSettings, - mut establisher: Establisher, - clock_compensation: i64, - initial_peers: Option, - version: Version, -) -> Result< - ( - NetworkCommandSender, - NetworkEventReceiver, - NetworkManager, - PrivateKey, - NodeId, - ), - NetworkError, -> { - debug!("starting network controller"); - - // check that local IP is routable - if let Some(self_ip) = network_settings.routable_ip { - if !self_ip.is_global() { - return Err(NetworkError::InvalidIpError(self_ip)); - } - } - - // try to read node private key from file, otherwise generate it & write to file. Then derive nodeId - let private_key = if std::path::Path::is_file(&network_settings.private_key_file) { - // file exists: try to load it - let private_key_bs58_check = tokio::fs::read_to_string(&network_settings.private_key_file) - .await - .map_err(|err| { - std::io::Error::new( - err.kind(), - format!("could not load node private key file: {}", err), - ) - })?; - PrivateKey::from_bs58_check(private_key_bs58_check.trim()).map_err(|err| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("node private key file corrupted: {}", err), - ) - })? - } else { - // node file does not exist: generate the key and save it - let priv_key = generate_random_private_key(); - if let Err(e) = tokio::fs::write( - &network_settings.private_key_file, - &priv_key.to_bs58_check(), - ) - .await - { - warn!("could not generate node private key file: {}", e); - } - priv_key - }; - let public_key = derive_public_key(&private_key); - let self_node_id = NodeId(public_key); - - info!("The node_id of this node is: {}", self_node_id); - massa_trace!("self_node_id", { "node_id": self_node_id }); - - // create listener - let listener = establisher.get_listener(network_settings.bind).await?; - - debug!("Loading peer database"); - // load peer info database - let mut peer_info_db = PeerInfoDatabase::new(&network_settings, clock_compensation).await?; - - // add bootstrap peers - if let Some(peers) = initial_peers { - peer_info_db.merge_candidate_peers(&peers.0)?; - } - - // launch controller - let (command_tx, controller_command_rx) = mpsc::channel::(CHANNEL_SIZE); - let (controller_event_tx, event_rx) = mpsc::channel::(CHANNEL_SIZE); - let (manager_tx, controller_manager_rx) = mpsc::channel::(1); - let cfg_copy = network_settings.clone(); - let join_handle = tokio::spawn(async move { - let res = NetworkWorker::new( - cfg_copy, - private_key, - listener, - establisher, - peer_info_db, - NetworkWorkerChannels { - controller_command_rx, - controller_event_tx, - controller_manager_rx, - }, - version, - ) - .run_loop() - .await; - match res { - Err(err) => { - error!("network worker crashed: {}", err); - Err(err) - } - Ok(v) => { - info!("network worker finished cleanly"); - Ok(v) - } - } - }); - - debug!("network controller started"); - - Ok(( - NetworkCommandSender(command_tx), - NetworkEventReceiver(event_rx), - NetworkManager { - join_handle, - manager_tx, - }, - private_key, - self_node_id, - )) -} #[derive(Clone)] pub struct NetworkCommandSender(pub mpsc::Sender); @@ -222,7 +88,7 @@ impl NetworkCommandSender { pub async fn send_block_header( &self, node: NodeId, - header: BlockHeader, + header: SignedHeader, ) -> Result<(), NetworkError> { self.0 .send(NetworkCommand::SendBlockHeader { node, header }) @@ -291,7 +157,7 @@ impl NetworkCommandSender { pub async fn send_operations( &self, node: NodeId, - operations: Vec, + operations: Vec, ) -> Result<(), NetworkError> { self.0 .send(NetworkCommand::SendOperations { node, operations }) @@ -305,7 +171,7 @@ impl NetworkCommandSender { pub async fn send_endorsements( &self, node: NodeId, - endorsements: Vec, + endorsements: Vec, ) -> Result<(), NetworkError> { self.0 .send(NetworkCommand::SendEndorsements { node, endorsements }) @@ -355,8 +221,8 @@ impl NetworkEventReceiver { } pub struct NetworkManager { - join_handle: JoinHandle>, - manager_tx: mpsc::Sender, + pub join_handle: JoinHandle>, + pub manager_tx: mpsc::Sender, } impl NetworkManager { diff --git a/massa-network-exports/src/peers.rs b/massa-network-exports/src/peers.rs new file mode 100644 index 00000000000..48a05ff41ef --- /dev/null +++ b/massa-network-exports/src/peers.rs @@ -0,0 +1,213 @@ +use crate::settings::PeerTypeConnectionConfig; +use displaydoc::Display; +use enum_map::Enum; +use massa_models::{ + node::NodeId, with_serialization_context, DeserializeCompact, DeserializeVarInt, ModelsError, + SerializeCompact, SerializeVarInt, +}; +use massa_time::MassaTime; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, net::IpAddr}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Peer { + pub peer_info: PeerInfo, + pub active_nodes: Vec<(NodeId, bool)>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Peers { + pub our_node_id: NodeId, + pub peers: HashMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BootstrapPeers(pub Vec); + +impl SerializeCompact for BootstrapPeers { + fn to_bytes_compact(&self) -> Result, massa_models::ModelsError> { + let mut res: Vec = Vec::new(); + + // peers + let peers_count: u32 = self.0.len().try_into().map_err(|err| { + ModelsError::SerializeError(format!("too many peers blocks in BootstrapPeers: {}", err)) + })?; + let max_peer_list_length = + with_serialization_context(|context| context.max_advertise_length); + if peers_count > max_peer_list_length { + return Err(ModelsError::SerializeError(format!( + "too many peers for serialization context in BootstrapPeers: {}", + peers_count + ))); + } + res.extend(peers_count.to_varint_bytes()); + for peer in self.0.iter() { + res.extend(peer.to_bytes_compact()?); + } + + Ok(res) + } +} + +impl DeserializeCompact for BootstrapPeers { + fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), massa_models::ModelsError> { + let mut cursor = 0usize; + + // peers + let (peers_count, delta) = u32::from_varint_bytes(&buffer[cursor..])?; + let max_peer_list_length = + with_serialization_context(|context| context.max_advertise_length); + if peers_count > max_peer_list_length { + return Err(ModelsError::DeserializeError(format!( + "too many peers for deserialization context in BootstrapPeers: {}", + peers_count + ))); + } + cursor += delta; + let mut peers: Vec = Vec::with_capacity(peers_count as usize); + for _ in 0..(peers_count as usize) { + let (ip, delta) = IpAddr::from_bytes_compact(&buffer[cursor..])?; + cursor += delta; + peers.push(ip); + } + + Ok((BootstrapPeers(peers), cursor)) + } +} + +/// Peer categories. +/// There is a defined number af slots for each category. +/// Order matters: less prioritized peer type first +#[derive( + Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Enum, +)] +pub enum PeerType { + /// Just a peer + Standard, + /// Connection from these nodes are always accepted + WhiteListed, + /** if the peer is in bootstrap servers list + for now it is decoupled from the real bootstrap sever list, it's just parsed + TODO: https://github.com/massalabs/massa/issues/2320 + */ + Bootstrap, +} + +mod test { + + #[test] + fn test_order() { + use crate::peers::PeerType; + assert!(PeerType::Bootstrap > PeerType::WhiteListed); + assert!(PeerType::WhiteListed > PeerType::Standard); + } +} + +impl Default for PeerType { + fn default() -> Self { + PeerType::Standard + } +} + +/// All information concerning a peer is here +#[derive(Clone, Copy, Serialize, Deserialize, Debug)] +pub struct PeerInfo { + /// Peer ip address. + pub ip: IpAddr, + /// The category the peer is in affects how it's treated. + pub peer_type: PeerType, + /// Time in millis when peer was last alive + pub last_alive: Option, + /// Time in millis of peer's last failure + pub last_failure: Option, + /// Whether peer was promoted through another peer + pub advertised: bool, + /// peer was banned + pub banned: bool, + /// Current number of active out connection attempts with that peer. + /// Isn't dump into peer file. + #[serde(default = "usize::default")] + pub active_out_connection_attempts: usize, + /// Current number of active out connections with that peer. + /// Isn't dump into peer file. + #[serde(default = "usize::default")] + pub active_out_connections: usize, + /// Current number of active in connections with that peer. + /// Isn't dump into peer file. + #[serde(default = "usize::default")] + pub active_in_connections: usize, +} + +impl PeerInfo { + /// Returns true if there is at least one connection attempt / + /// one active connection in either direction + /// with this peer + #[inline] + pub fn is_active(&self) -> bool { + self.active_out_connection_attempts > 0 + || self.active_out_connections > 0 + || self.active_in_connections > 0 + } + + /// New standard PeerInfo for ipaddr + /// + /// # Arguments + /// * ip: the IP address of the peer + /// * advertised: true if this peer was advertised as routable, + /// which means that our node can attempt outgoing connections to it + pub fn new(ip: IpAddr, advertised: bool) -> PeerInfo { + PeerInfo { + ip, + last_alive: None, + last_failure: None, + advertised, + active_out_connection_attempts: 0, + active_out_connections: 0, + active_in_connections: 0, + peer_type: Default::default(), + banned: false, + } + } + + /// peer is ready to be retried, enough time has elapsed since last failure + pub fn is_peer_ready(&self, wakeup_interval: MassaTime, now: MassaTime) -> bool { + if let Some(last_failure) = self.last_failure { + if let Some(last_alive) = self.last_alive { + if last_alive > last_failure { + return true; + } + } + return now + .saturating_sub(last_failure) + .saturating_sub(wakeup_interval) + > MassaTime::from(0u64); + } + true + } +} + +/// Connection count for a category +#[derive(Default, Debug)] +pub struct ConnectionCount { + /// Number of outgoing connections our node is currently trying to establish. + /// We might be in the process of establishing a TCP connection or handshaking with the peer. + pub active_out_connection_attempts: usize, + /// Number of currently live (TCP connection active, handshake successful) outgoing connections + pub active_out_connections: usize, + /// Number of currently live (TCP connection active, handshake successful) incoming connections + pub active_in_connections: usize, +} + +impl ConnectionCount { + #[inline] + /// Gets available out connection attempts for given connection count and settings + pub fn get_available_out_connection_attempts(&self, cfg: &PeerTypeConnectionConfig) -> usize { + std::cmp::min( + cfg.target_out_connections + .saturating_sub(self.active_out_connection_attempts) + .saturating_sub(self.active_out_connections), + cfg.max_out_attempts + .saturating_sub(self.active_out_connection_attempts), + ) + } +} diff --git a/massa-network/src/settings.rs b/massa-network-exports/src/settings.rs similarity index 95% rename from massa-network/src/settings.rs rename to massa-network-exports/src/settings.rs index 8a36f86a1a8..8fdb36838c0 100644 --- a/massa-network/src/settings.rs +++ b/massa-network-exports/src/settings.rs @@ -1,11 +1,12 @@ // Copyright (c) 2022 MASSA LABS -use crate::peer_info_database::PeerType; use enum_map::EnumMap; use massa_time::MassaTime; use serde::Deserialize; use std::net::{IpAddr, SocketAddr}; +use crate::peers::PeerType; + /// Network configuration #[derive(Debug, Deserialize, Clone)] pub struct NetworkSettings { @@ -63,11 +64,12 @@ pub struct PeerTypeConnectionConfig { pub max_out_attempts: usize, } -#[cfg(test)] -mod tests { - use crate::{peer_info_database::PeerType, NetworkSettings}; +#[cfg(feature = "testing")] +pub mod tests { + use crate::NetworkSettings; + use crate::{test_exports::tools::get_temp_private_key_file, PeerType}; use enum_map::enum_map; - use massa_models::constants::*; + use massa_models::constants::default_testing::BASE_NETWORK_CONTROLLER_IP; use massa_time::MassaTime; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; @@ -160,9 +162,7 @@ mod tests { peers_file_dump_interval: MassaTime::from(30000), message_timeout: MassaTime::from(5000u64), ask_peer_list_interval: MassaTime::from(50000u64), - private_key_file: crate::tests::tools::get_temp_private_key_file() - .path() - .to_path_buf(), + private_key_file: get_temp_private_key_file().path().to_path_buf(), max_send_wait: MassaTime::from(100), ban_timeout: MassaTime::from(100_000_000), initial_peers_file: peers_file.to_path_buf(), diff --git a/massa-network/src/tests/mock_establisher.rs b/massa-network-exports/src/test_exports/mock_establisher.rs similarity index 98% rename from massa-network/src/tests/mock_establisher.rs rename to massa-network-exports/src/test_exports/mock_establisher.rs index f6de7f1586a..55e3b8d250f 100644 --- a/massa-network/src/tests/mock_establisher.rs +++ b/massa-network-exports/src/test_exports/mock_establisher.rs @@ -116,6 +116,11 @@ pub struct MockEstablisher { } impl MockEstablisher { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + unreachable!("place holder") + } + pub async fn get_listener(&mut self, _addr: SocketAddr) -> io::Result { Ok(MockListener { connection_listener_rx: self diff --git a/massa-network-exports/src/test_exports/mod.rs b/massa-network-exports/src/test_exports/mod.rs new file mode 100644 index 00000000000..4f2bbb485e1 --- /dev/null +++ b/massa-network-exports/src/test_exports/mod.rs @@ -0,0 +1,2 @@ +pub mod mock_establisher; +pub mod tools; diff --git a/massa-network-exports/src/test_exports/tools.rs b/massa-network-exports/src/test_exports/tools.rs new file mode 100644 index 00000000000..020f625731a --- /dev/null +++ b/massa-network-exports/src/test_exports/tools.rs @@ -0,0 +1,5 @@ +use tempfile::NamedTempFile; + +pub fn get_temp_private_key_file() -> NamedTempFile { + NamedTempFile::new().expect("cannot create temp file") +} diff --git a/massa-network/Cargo.toml b/massa-network-worker/Cargo.toml similarity index 80% rename from massa-network/Cargo.toml rename to massa-network-worker/Cargo.toml index 9f3ae52f499..bc7088e5976 100644 --- a/massa-network/Cargo.toml +++ b/massa-network-worker/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "massa_network" +name = "massa_network_worker" version = "0.1.0" authors = ["Massa Labs "] edition = "2021" @@ -20,6 +20,7 @@ tokio = { version = "1.15", features = ["full"] } tracing = "0.1" # custom modules massa_hash = { path = "../massa-hash" } +massa_network_exports = { path = "../massa-network-exports" } massa_logging = { path = "../massa-logging" } massa_models = { path = "../massa-models" } massa_signature = { path = "../massa-signature" } @@ -30,6 +31,7 @@ pretty_assertions = "1.0" serial_test = "0.5.1" tempfile = "3.2" massa_models = { path = "../massa-models", features = ["testing"] } +massa_network_exports = { path = "../massa-network-exports", features = ["testing"] } [features] -instrument = ["tokio/tracing", "massa_models/instrument", "massa_time/instrument"] +instrument = ["tokio/tracing", "massa_models/instrument", "massa_time/instrument", "massa_network_exports/instrument"] diff --git a/massa-network/src/binders.rs b/massa-network-worker/src/binders.rs similarity index 98% rename from massa-network/src/binders.rs rename to massa-network-worker/src/binders.rs index 82fa442445b..9aabadadb69 100644 --- a/massa-network/src/binders.rs +++ b/massa-network-worker/src/binders.rs @@ -2,12 +2,11 @@ //! Flexbuffer layer between raw data and our objects. use super::messages::Message; -use crate::error::NetworkError; -use crate::establisher::{ReadHalf, WriteHalf}; use massa_models::{ with_serialization_context, DeserializeCompact, DeserializeMinBEInt, SerializeCompact, SerializeMinBEInt, }; +use massa_network_exports::{NetworkError, ReadHalf, WriteHalf}; use std::convert::TryInto; use tokio::io::{AsyncReadExt, AsyncWriteExt}; diff --git a/massa-network/src/handshake_worker.rs b/massa-network-worker/src/handshake_worker.rs similarity index 97% rename from massa-network/src/handshake_worker.rs rename to massa-network-worker/src/handshake_worker.rs index 2013bcb7a65..e10080f549a 100644 --- a/massa-network/src/handshake_worker.rs +++ b/massa-network-worker/src/handshake_worker.rs @@ -1,19 +1,20 @@ // Copyright (c) 2022 MASSA LABS //! Here are happening handshakes. + use super::{ binders::{ReadBinder, WriteBinder}, messages::Message, }; -use crate::{ - error::{throw_handshake_error as throw, HandshakeErrorType, NetworkError}, - ConnectionId, ReadHalf, WriteHalf, -}; use futures::future::try_join; use massa_hash::hash::Hash; use massa_logging::massa_trace; use massa_models::node::NodeId; use massa_models::Version; +use massa_network_exports::{ + throw_handshake_error as throw, ConnectionId, HandshakeErrorType, NetworkError, ReadHalf, + WriteHalf, +}; use massa_signature::{sign, verify_signature, PrivateKey}; use massa_time::MassaTime; use rand::{rngs::StdRng, RngCore, SeedableRng}; diff --git a/massa-network-worker/src/lib.rs b/massa-network-worker/src/lib.rs new file mode 100644 index 00000000000..9c8c6400c07 --- /dev/null +++ b/massa-network-worker/src/lib.rs @@ -0,0 +1,158 @@ +// Copyright (c) 2022 MASSA LABS + +#![feature(async_closure)] +#![feature(drain_filter)] +#![feature(ip)] + +//! Manages a connection with a node + +use crate::{ + network_worker::{NetworkWorker, NetworkWorkerChannels}, + peer_info_database::PeerInfoDatabase, +}; +use massa_logging::massa_trace; +use massa_models::{constants::CHANNEL_SIZE, node::NodeId, Version}; +use massa_network_exports::{ + BootstrapPeers, Establisher, NetworkCommand, NetworkCommandSender, NetworkError, NetworkEvent, + NetworkEventReceiver, NetworkManagementCommand, NetworkManager, NetworkSettings, +}; +use massa_signature::{derive_public_key, generate_random_private_key, PrivateKey}; +use tokio::sync::mpsc; +use tracing::{debug, error, info, warn}; + +//pub use establisher::Establisher; +mod binders; +mod handshake_worker; +mod messages; +mod network_cmd_impl; +mod network_event; +mod network_worker; +mod node_worker; +mod peer_info_database; + +#[cfg(test)] +pub mod tests; + +/// Starts a new NetworkWorker in a spawned task +/// +/// # Arguments +/// * cfg : network configuration +pub async fn start_network_controller( + network_settings: NetworkSettings, + mut establisher: Establisher, + clock_compensation: i64, + initial_peers: Option, + version: Version, +) -> Result< + ( + NetworkCommandSender, + NetworkEventReceiver, + NetworkManager, + PrivateKey, + NodeId, + ), + NetworkError, +> { + debug!("starting network controller"); + + // check that local IP is routable + if let Some(self_ip) = network_settings.routable_ip { + if !self_ip.is_global() { + return Err(NetworkError::InvalidIpError(self_ip)); + } + } + + // try to read node private key from file, otherwise generate it & write to file. Then derive nodeId + let private_key = if std::path::Path::is_file(&network_settings.private_key_file) { + // file exists: try to load it + let private_key_bs58_check = tokio::fs::read_to_string(&network_settings.private_key_file) + .await + .map_err(|err| { + std::io::Error::new( + err.kind(), + format!("could not load node private key file: {}", err), + ) + })?; + PrivateKey::from_bs58_check(private_key_bs58_check.trim()).map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("node private key file corrupted: {}", err), + ) + })? + } else { + // node file does not exist: generate the key and save it + let priv_key = generate_random_private_key(); + if let Err(e) = tokio::fs::write( + &network_settings.private_key_file, + &priv_key.to_bs58_check(), + ) + .await + { + warn!("could not generate node private key file: {}", e); + } + priv_key + }; + let public_key = derive_public_key(&private_key); + let self_node_id = NodeId(public_key); + + info!("The node_id of this node is: {}", self_node_id); + massa_trace!("self_node_id", { "node_id": self_node_id }); + + // create listener + let listener = establisher.get_listener(network_settings.bind).await?; + + debug!("Loading peer database"); + // load peer info database + let mut peer_info_db = PeerInfoDatabase::new(&network_settings, clock_compensation).await?; + + // add bootstrap peers + if let Some(peers) = initial_peers { + peer_info_db.merge_candidate_peers(&peers.0)?; + } + + // launch controller + let (command_tx, controller_command_rx) = mpsc::channel::(CHANNEL_SIZE); + let (controller_event_tx, event_rx) = mpsc::channel::(CHANNEL_SIZE); + let (manager_tx, controller_manager_rx) = mpsc::channel::(1); + let cfg_copy = network_settings.clone(); + let join_handle = tokio::spawn(async move { + let res = NetworkWorker::new( + cfg_copy, + private_key, + listener, + establisher, + peer_info_db, + NetworkWorkerChannels { + controller_command_rx, + controller_event_tx, + controller_manager_rx, + }, + version, + ) + .run_loop() + .await; + match res { + Err(err) => { + error!("network worker crashed: {}", err); + Err(err) + } + Ok(v) => { + info!("network worker finished cleanly"); + Ok(v) + } + } + }); + + debug!("network controller started"); + + Ok(( + NetworkCommandSender(command_tx), + NetworkEventReceiver(event_rx), + NetworkManager { + join_handle, + manager_tx, + }, + private_key, + self_node_id, + )) +} diff --git a/massa-network/src/messages.rs b/massa-network-worker/src/messages.rs similarity index 93% rename from massa-network/src/messages.rs rename to massa-network-worker/src/messages.rs index 55e1455a19e..6765b9965d4 100644 --- a/massa-network/src/messages.rs +++ b/massa-network-worker/src/messages.rs @@ -3,8 +3,10 @@ use massa_models::{ array_from_slice, constants::{BLOCK_ID_SIZE_BYTES, HANDSHAKE_RANDOMNESS_SIZE_BYTES}, + signed::Signed, with_serialization_context, Block, BlockHeader, BlockId, DeserializeCompact, DeserializeVarInt, - Endorsement, ModelsError, Operation, SerializeCompact, SerializeVarInt, Version, + Endorsement, EndorsementId, ModelsError, Operation, OperationId, SerializeCompact, + SerializeVarInt, SignedEndorsement, SignedHeader, SignedOperation, Version, }; use massa_signature::{PublicKey, Signature, PUBLIC_KEY_SIZE_BYTES, SIGNATURE_SIZE_BYTES}; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -32,7 +34,7 @@ pub enum Message { /// Whole block structure. Block(Block), /// Block header - BlockHeader(BlockHeader), + BlockHeader(SignedHeader), /// Message asking the peer for a block. AskForBlocks(Vec), /// Message asking the peer for its advertisable peers list. @@ -45,9 +47,9 @@ pub enum Message { /// Block not found BlockNotFound(BlockId), /// Operations - Operations(Vec), + Operations(Vec), /// Endorsements - Endorsements(Vec), + Endorsements(Vec), } #[derive(IntoPrimitive, Debug, Eq, PartialEq, TryFromPrimitive)] @@ -197,7 +199,8 @@ impl DeserializeCompact for Message { Message::Block(block) } MessageTypeId::BlockHeader => { - let (header, delta) = BlockHeader::from_bytes_compact(&buffer[cursor..])?; + let (header, delta) = + Signed::::from_bytes_compact(&buffer[cursor..])?; cursor += delta; Message::BlockHeader(header) } @@ -240,9 +243,10 @@ impl DeserializeCompact for Message { u32::from_varint_bytes_bounded(&buffer[cursor..], max_operations_per_message)?; cursor += delta; // operations - let mut ops: Vec = Vec::with_capacity(length as usize); + let mut ops: Vec = Vec::with_capacity(length as usize); for _ in 0..length { - let (op, delta) = Operation::from_bytes_compact(&buffer[cursor..])?; + let (op, delta) = + Signed::::from_bytes_compact(&buffer[cursor..])?; cursor += delta; ops.push(op); } @@ -256,9 +260,12 @@ impl DeserializeCompact for Message { )?; cursor += delta; // operations - let mut endorsements: Vec = Vec::with_capacity(length as usize); + let mut endorsements = Vec::with_capacity(length as usize); for _ in 0..length { - let (endorsement, delta) = Endorsement::from_bytes_compact(&buffer[cursor..])?; + let (endorsement, delta) = + Signed::::from_bytes_compact( + &buffer[cursor..], + )?; cursor += delta; endorsements.push(endorsement); } diff --git a/massa-network-worker/src/network_cmd_impl.rs b/massa-network-worker/src/network_cmd_impl.rs new file mode 100644 index 00000000000..387b7678e52 --- /dev/null +++ b/massa-network-worker/src/network_cmd_impl.rs @@ -0,0 +1,367 @@ +//! On `NetworkWorker` receive a command behaviors implementation +//! +//! All following function take by default a reference to the `NetworkWorker` +//! that in order to apply required modification. +//! +//! All following functions are necessary internals (not public) or called by +//! the `manage_network_command` in the worker. +//! +//! ```ignore +//! async fn manage_network_command(&mut self, cmd: NetworkCommand) -> Result<(), NetworkError> { +//! use crate::network_cmd_impl::*; +//! match cmd { +//! NetworkCommand::BanIp(ips) => on_ban_ip_cmd(self, ips).await?, +//! NetworkCommand::Ban(node) => on_ban_cmd(self, node).await?, +//! NetworkCommand::SendBlockHeader { node, header } => on_send_block_header_cmd(self, node, header).await?, +//! NetworkCommand::AskForBlocks { list } => on_ask_bfor_block_cmd(self, list).await, +//! NetworkCommand::SendBlock { node, block } => on_send_block_cmd(self, node, block).await?, +//! NetworkCommand::GetPeers(response_tx) => on_get_peers_cmd(self, response_tx).await, +//! NetworkCommand::GetBootstrapPeers(response_tx) => on_get_bootstrap_peers_cmd(self, response_tx).await, +//! ... +//! ``` +use crate::{network_worker::NetworkWorker, node_worker::NodeCommand}; +use massa_hash::hash::Hash; +use massa_logging::massa_trace; +use massa_models::signed::Signable; +use massa_models::{ + composite::PubkeySig, node::NodeId, stats::NetworkStats, Block, BlockId, SignedEndorsement, + SignedHeader, SignedOperation, +}; +use massa_network_exports::{ + BootstrapPeers, ConnectionClosureReason, ConnectionId, NetworkError, Peer, Peers, +}; +use massa_signature::{derive_public_key, sign}; +use std::{ + collections::{HashMap, HashSet}, + net::IpAddr, +}; +use tokio::sync::oneshot; +use tracing::warn; + +/// Remove the `ids` from the `worker` +/// - clean `worker.running_handshakes` +/// - send `NodeCommand::Close` to the active nodes +async fn ban_connection_ids(worker: &mut NetworkWorker, ids: HashSet) { + for ban_conn_id in ids.iter() { + // remove the connectionId entry in running_handshakes + worker.running_handshakes.remove(ban_conn_id); + } + for (conn_id, node_command_tx) in worker.active_nodes.values() { + if ids.contains(conn_id) { + let res = node_command_tx + .send(NodeCommand::Close(ConnectionClosureReason::Banned)) + .await; + if res.is_err() { + massa_trace!( + "network.network_worker.manage_network_command", {"err": NetworkError::ChannelError( + "close node command send failed".into(), + ).to_string()} + ); + } + }; + } +} + +/// Ban the connections corresponding to `ips` from the `worker` +/// See also [ban_connection_ids] +async fn ban_ips(worker: &mut NetworkWorker, ips: Vec) -> Result<(), NetworkError> { + for ip in ips.iter() { + worker.peer_info_db.peer_banned(ip)?; + } + let ids = worker + .active_connections + .iter() + .filter_map(|(conn_id, (ip, _))| { + if ips.contains(ip) { + Some(conn_id) + } else { + None + } + }) + .copied() + .collect::>(); + ban_connection_ids(worker, ids).await; + Ok(()) +} + +/// Ban the `node` corresponding to the NodeId from the `worker` +/// See also [ban_connection_ids] +async fn ban_node(worker: &mut NetworkWorker, node: NodeId) -> Result<(), NetworkError> { + // get all connection IDs to ban + let mut ids: HashSet = HashSet::new(); + + // Note: if we can't find the node, there is no need to resend the close event, + // since protocol will have already removed the node from it's list of active ones. + if let Some((orig_conn_id, _)) = worker.active_nodes.get(&node) { + if let Some((orig_ip, _)) = worker.active_connections.get(orig_conn_id) { + worker.peer_info_db.peer_banned(orig_ip)?; + for (target_conn_id, (target_ip, _)) in worker.active_connections.iter() { + if target_ip == orig_ip { + ids.insert(*target_conn_id); + } + } + } + } + ban_connection_ids(worker, ids).await; + Ok(()) +} + +/// For each peer get all node id associated to this peer ip. +async fn get_peers(worker: &mut NetworkWorker, response_tx: oneshot::Sender) { + let peers: HashMap = worker + .peer_info_db + .get_peers() + .iter() + .map(|(peer_ip_addr, peer)| { + ( + *peer_ip_addr, + Peer { + peer_info: *peer, + active_nodes: worker + .active_connections + .iter() + .filter(|(_, (ip_addr, _))| &peer.ip == ip_addr) + .filter_map(|(out_conn_id, (_, out_going))| { + worker + .active_nodes + .iter() + .filter_map(|(node_id, (conn_id, _))| { + if out_conn_id == conn_id { + Some(node_id) + } else { + None + } + }) + .next() + .map(|node_id| (*node_id, *out_going)) + }) + .collect(), + }, + ) + }) + .collect(); + + // HashMap) + if response_tx + .send(Peers { + peers, + our_node_id: worker.self_node_id, + }) + .is_err() + { + warn!("network: could not send GetPeersChannelError upstream"); + } +} + +pub async fn on_ban_ip_cmd( + worker: &mut NetworkWorker, + ips: Vec, +) -> Result<(), NetworkError> { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::BanIp", + { "ips": ips } + ); + ban_ips(worker, ips).await +} + +pub async fn on_ban_cmd(worker: &mut NetworkWorker, node: NodeId) -> Result<(), NetworkError> { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::Ban", + { "node": node } + ); + ban_node(worker, node).await +} + +pub async fn on_send_block_header_cmd( + worker: &mut NetworkWorker, + node: NodeId, + header: SignedHeader, +) -> Result<(), NetworkError> { + massa_trace!("network_worker.manage_network_command send NodeCommand::SendBlockHeader", {"block_id": header.content.compute_id()?, "header": header, "node": node}); + worker + .event + .forward( + &node, + worker.active_nodes.get(&node), + NodeCommand::SendBlockHeader(header), + ) + .await; + Ok(()) +} + +pub async fn on_ask_bfor_block_cmd(worker: &mut NetworkWorker, map: HashMap>) { + for (node, hash_list) in map.into_iter() { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::AskForBlocks", + { "hashlist": hash_list, "node": node } + ); + worker + .event + .forward( + &node, + worker.active_nodes.get(&node), + NodeCommand::AskForBlocks(hash_list.clone()), + ) + .await; + } +} + +pub async fn on_send_block_cmd( + worker: &mut NetworkWorker, + node: NodeId, + block: Block, +) -> Result<(), NetworkError> { + massa_trace!( + "network_worker.manage_network_command send NodeCommand::SendBlock", + {"hash": block.header.content.compute_hash()?, "block": block, "node": node} + ); + worker + .event + .forward( + &node, + worker.active_nodes.get(&node), + NodeCommand::SendBlock(block), + ) + .await; + Ok(()) +} + +pub async fn on_get_peers_cmd(worker: &mut NetworkWorker, response_tx: oneshot::Sender) { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::GetPeers", + {} + ); + get_peers(worker, response_tx).await; +} + +pub async fn on_get_bootstrap_peers_cmd( + worker: &mut NetworkWorker, + response_tx: oneshot::Sender, +) { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::GetBootstrapPeers", + {} + ); + let peer_list = worker.peer_info_db.get_advertisable_peer_ips(); + if response_tx.send(BootstrapPeers(peer_list)).is_err() { + warn!("network: could not send GetBootstrapPeers response upstream"); + } +} + +pub async fn on_block_not_found_cmd(worker: &mut NetworkWorker, node: NodeId, block_id: BlockId) { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::BlockNotFound", + { "block_id": block_id, "node": node } + ); + worker + .event + .forward( + &node, + worker.active_nodes.get(&node), + NodeCommand::BlockNotFound(block_id), + ) + .await; +} + +pub async fn on_send_operation_cmd( + worker: &mut NetworkWorker, + node: NodeId, + operations: Vec, +) { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::SendOperations", + { "node": node, "operations": operations } + ); + worker + .event + .forward( + &node, + worker.active_nodes.get(&node), + NodeCommand::SendOperations(operations), + ) + .await; +} + +pub async fn on_send_endorsements_cmd( + worker: &mut NetworkWorker, + node: NodeId, + endorsements: Vec, +) { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::SendEndorsements", + { "node": node, "endorsements": endorsements } + ); + worker + .event + .forward( + &node, + worker.active_nodes.get(&node), + NodeCommand::SendEndorsements(endorsements), + ) + .await; +} + +pub async fn on_node_sign_message_cmd( + worker: &mut NetworkWorker, + msg: Vec, + response_tx: oneshot::Sender, +) -> Result<(), NetworkError> { + massa_trace!( + "network_worker.manage_network_command receive NetworkCommand::NodeSignMessage", + { "mdg": msg } + ); + let signature = sign(&Hash::compute_from(&msg), &worker.private_key)?; + let public_key = derive_public_key(&worker.private_key); + if response_tx + .send(PubkeySig { + public_key, + signature, + }) + .is_err() + { + warn!("network: could not send NodeSignMessage response upstream"); + } + Ok(()) +} + +pub async fn on_unban_cmd( + worker: &mut NetworkWorker, + ips: Vec, +) -> Result<(), NetworkError> { + worker.peer_info_db.unban(ips) +} + +pub async fn on_whitelist_cmd( + worker: &mut NetworkWorker, + ips: Vec, +) -> Result<(), NetworkError> { + worker.peer_info_db.whitelist(ips).await +} + +pub async fn on_remove_from_whitelist_cmd( + worker: &mut NetworkWorker, + ips: Vec, +) -> Result<(), NetworkError> { + worker.peer_info_db.remove_from_whitelist(ips).await +} + +pub async fn on_get_stats_cmd( + worker: &mut NetworkWorker, + response_tx: oneshot::Sender, +) { + let res = NetworkStats { + in_connection_count: worker.peer_info_db.get_in_connection_count() as u64, + out_connection_count: worker.peer_info_db.get_out_connection_count() as u64, + known_peer_count: worker.peer_info_db.peers.len() as u64, + banned_peer_count: worker + .peer_info_db + .peers + .iter() + .filter(|(_, p)| p.banned) + .fold(0, |acc, _| acc + 1), + active_node_count: worker.active_nodes.len() as u64, + }; + if response_tx.send(res).is_err() { + warn!("network: could not send NodeSignMessage response upstream"); + } +} diff --git a/massa-network-worker/src/network_event.rs b/massa-network-worker/src/network_event.rs new file mode 100644 index 00000000000..81e9779d0cb --- /dev/null +++ b/massa-network-worker/src/network_event.rs @@ -0,0 +1,249 @@ +use crate::node_worker::{NodeCommand, NodeEvent}; +use massa_models::node::NodeId; +use massa_network_exports::{ConnectionId, NetworkError, NetworkEvent}; +use std::time::Duration; +use tokio::sync::mpsc::{self, error::SendTimeoutError}; +use tracing::debug; + +pub struct EventSender { + /// Sender for network events + controller_event_tx: mpsc::Sender, + /// Channel for sending node events. + node_event_tx: mpsc::Sender, + /// Max time spend to wait + max_send_wait: Duration, +} + +impl EventSender { + pub fn new( + controller_event_tx: mpsc::Sender, + node_event_tx: mpsc::Sender, + max_send_wait: Duration, + ) -> Self { + Self { + controller_event_tx, + node_event_tx, + max_send_wait, + } + } + + pub async fn send(&self, event: NetworkEvent) -> Result<(), NetworkError> { + let result = self + .controller_event_tx + .send_timeout(event, self.max_send_wait) + .await; + match result { + Ok(()) => return Ok(()), + Err(SendTimeoutError::Closed(event)) => { + debug!( + "Failed to send NetworkEvent due to channel closure: {:?}.", + event + ); + } + Err(SendTimeoutError::Timeout(event)) => { + debug!("Failed to send NetworkEvent due to timeout: {:?}.", event); + } + } + Err(NetworkError::ChannelError("Failed to send event.".into())) + } + + /// Forward a message to a node worker. If it fails, notify upstream about connection closure. + pub async fn forward( + &mut self, + node_id: &NodeId, + node: Option<&(ConnectionId, mpsc::Sender)>, + message: NodeCommand, + ) { + if let Some((_, node_command_tx)) = node { + if node_command_tx.send(message).await.is_err() { + debug!( + "{}", + NetworkError::ChannelError("contact with node worker lost while trying to send it a message. Probably a peer disconnect.".into()) + ); + }; + } else { + // We probably weren't able to send this event previously, + // retry it now. + let _ = self.send(NetworkEvent::ConnectionClosed(*node_id)).await; + } + } + + pub fn clone_node_sender(&self) -> mpsc::Sender { + self.node_event_tx.clone() + } + + pub fn drop(self) { + drop(self.node_event_tx) + } +} + +pub mod event_impl { + use crate::{network_worker::NetworkWorker, node_worker::NodeCommand}; + use massa_logging::massa_trace; + use massa_models::signed::Signable; + use massa_models::{ + node::NodeId, Block, BlockId, SignedEndorsement, SignedHeader, SignedOperation, + }; + use massa_network_exports::{NetworkError, NetworkEvent}; + use std::net::IpAddr; + use tracing::{debug, info}; + macro_rules! evt_failed { + ($err: ident) => { + info!("Send network event failed {}", $err) + }; + } + + // Implementation of the node event management functions + pub fn on_received_peer_list( + worker: &mut NetworkWorker, + from: NodeId, + list: &[IpAddr], + ) -> Result<(), NetworkError> { + debug!("node_id={} sent us a peer list ({} ips)", from, list.len()); + massa_trace!("peer_list_received", { + "node_id": from, + "ips": list + }); + worker.peer_info_db.merge_candidate_peers(list)?; + Ok(()) + } + + pub async fn on_received_block( + worker: &mut NetworkWorker, + from: NodeId, + block: Block, + ) -> Result<(), NetworkError> { + massa_trace!( + "network_worker.on_node_event receive NetworkEvent::ReceivedBlock", + {"block_id": block.header.content.compute_id()?, "block": block, "node": from} + ); + if let Err(err) = worker + .event + .send(NetworkEvent::ReceivedBlock { node: from, block }) + .await + { + evt_failed!(err) + } + Ok(()) + } + + pub async fn on_received_ask_for_blocks( + worker: &mut NetworkWorker, + from: NodeId, + list: Vec, + ) { + if let Err(err) = worker + .event + .send(NetworkEvent::AskedForBlocks { node: from, list }) + .await + { + evt_failed!(err) + } + } + + pub async fn on_received_block_header( + worker: &mut NetworkWorker, + from: NodeId, + header: SignedHeader, + ) -> Result<(), NetworkError> { + massa_trace!( + "network_worker.on_node_event receive NetworkEvent::ReceivedBlockHeader", + {"hash": header.content.compute_hash()?, "header": header, "node": from} + ); + if let Err(err) = worker + .event + .send(NetworkEvent::ReceivedBlockHeader { + source_node_id: from, + header, + }) + .await + { + evt_failed!(err) + } + Ok(()) + } + + pub async fn on_asked_peer_list( + worker: &mut NetworkWorker, + from: NodeId, + ) -> Result<(), NetworkError> { + debug!("node_id={} asked us for peer list", from); + massa_trace!("node_asked_peer_list", { "node_id": from }); + let peer_list = worker.peer_info_db.get_advertisable_peer_ips(); + if let Some((_, node_command_tx)) = worker.active_nodes.get(&from) { + let res = node_command_tx + .send(NodeCommand::SendPeerList(peer_list)) + .await; + if res.is_err() { + debug!( + "{}", + NetworkError::ChannelError("node command send send_peer_list failed".into(),) + ); + } + } else { + massa_trace!("node asked us for peer list and disappeared", { + "node_id": from + }) + } + Ok(()) + } + + pub async fn on_block_not_found(worker: &mut NetworkWorker, from: NodeId, block_id: BlockId) { + massa_trace!( + "network_worker.on_node_event receive NetworkEvent::BlockNotFound", + { "id": block_id } + ); + if let Err(err) = worker + .event + .send(NetworkEvent::BlockNotFound { + node: from, + block_id, + }) + .await + { + evt_failed!(err) + } + } + + pub async fn on_received_operations( + worker: &mut NetworkWorker, + from: NodeId, + operations: Vec, + ) { + massa_trace!( + "network_worker.on_node_event receive NetworkEvent::ReceivedOperations", + { "operations": operations } + ); + if let Err(err) = worker + .event + .send(NetworkEvent::ReceivedOperations { + node: from, + operations, + }) + .await + { + evt_failed!(err) + } + } + + pub async fn on_received_endorsements( + worker: &mut NetworkWorker, + from: NodeId, + endorsements: Vec, + ) { + massa_trace!( + "network_worker.on_node_event receive NetworkEvent::ReceivedEndorsements", + { "endorsements": endorsements } + ); + if let Err(err) = worker + .event + .send(NetworkEvent::ReceivedEndorsements { + node: from, + endorsements, + }) + .await + { + evt_failed!(err) + } + } +} diff --git a/massa-network/src/network_worker.rs b/massa-network-worker/src/network_worker.rs similarity index 58% rename from massa-network/src/network_worker.rs rename to massa-network-worker/src/network_worker.rs index e8b813d907c..96a9da70719 100644 --- a/massa-network/src/network_worker.rs +++ b/massa-network-worker/src/network_worker.rs @@ -2,227 +2,70 @@ //! The network worker actually does the job of managing connections use super::{ - common::{ConnectionClosureReason, ConnectionId}, - establisher::{Establisher, Listener, ReadHalf, WriteHalf}, handshake_worker::HandshakeReturnType, node_worker::{NodeCommand, NodeEvent, NodeEventType, NodeWorker}, peer_info_database::*, }; use crate::{ binders::{ReadBinder, WriteBinder}, - error::{HandshakeErrorType, NetworkConnectionErrorType, NetworkError}, handshake_worker::HandshakeWorker, messages::Message, - settings::NetworkSettings, + network_event::EventSender, }; use futures::{stream::FuturesUnordered, StreamExt}; -use massa_hash::hash::Hash; use massa_logging::massa_trace; -use massa_models::{ - composite::PubkeySig, constants::CHANNEL_SIZE, node::NodeId, stats::NetworkStats, - with_serialization_context, DeserializeCompact, DeserializeVarInt, ModelsError, - SerializeCompact, SerializeVarInt, Version, +use massa_models::{constants::CHANNEL_SIZE, node::NodeId, Version}; +use massa_network_exports::{ + ConnectionClosureReason, ConnectionId, Establisher, Listener, NetworkCommand, NetworkError, + NetworkEvent, NetworkManagementCommand, NetworkSettings, ReadHalf, WriteHalf, }; -use massa_models::{Block, BlockHeader, BlockId, Endorsement, Operation}; -use massa_signature::{derive_public_key, sign, PrivateKey}; -use serde::{Deserialize, Serialize}; +use massa_network_exports::{HandshakeErrorType, NetworkConnectionErrorType}; +use massa_signature::{derive_public_key, PrivateKey}; use std::{ collections::{hash_map, HashMap, HashSet}, - convert::TryInto, net::{IpAddr, SocketAddr}, }; -use tokio::sync::mpsc::error::SendTimeoutError; -use tokio::sync::{mpsc, oneshot}; +use tokio::sync::mpsc; use tokio::task::JoinHandle; use tracing::{debug, trace, warn}; -/// Commands that the worker can execute -#[derive(Debug)] -pub enum NetworkCommand { - /// Ask for a block from a node. - AskForBlocks { - list: HashMap>, - }, - /// Send that block to node. - SendBlock { - node: NodeId, - block: Block, - }, - /// Send a header to a node. - SendBlockHeader { - node: NodeId, - header: BlockHeader, - }, - // (PeerInfo, Vec <(NodeId, bool)>) peer info + list of associated Id nodes in connexion out (true) - GetPeers(oneshot::Sender), - GetBootstrapPeers(oneshot::Sender), - Ban(NodeId), - BanIp(Vec), - Unban(Vec), - Whitelist(Vec), - RemoveFromWhitelist(Vec), - BlockNotFound { - node: NodeId, - block_id: BlockId, - }, - SendOperations { - node: NodeId, - operations: Vec, - }, - SendEndorsements { - node: NodeId, - endorsements: Vec, - }, - NodeSignMessage { - msg: Vec, - response_tx: oneshot::Sender, - }, - GetStats { - response_tx: oneshot::Sender, - }, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Peer { - pub peer_info: PeerInfo, - pub active_nodes: Vec<(NodeId, bool)>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Peers { - pub our_node_id: NodeId, - pub peers: HashMap, -} - -#[derive(Debug)] -pub enum NetworkEvent { - NewConnection(NodeId), - ConnectionClosed(NodeId), - /// A block was received - ReceivedBlock { - node: NodeId, - block: Block, - }, - /// A block header was received - ReceivedBlockHeader { - source_node_id: NodeId, - header: BlockHeader, - }, - /// Someone ask for block with given header hash. - AskedForBlocks { - node: NodeId, - list: Vec, - }, - /// That node does not have this block - BlockNotFound { - node: NodeId, - block_id: BlockId, - }, - ReceivedOperations { - node: NodeId, - operations: Vec, - }, - ReceivedEndorsements { - node: NodeId, - endorsements: Vec, - }, -} - -#[derive(Debug)] -pub enum NetworkManagementCommand {} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BootstrapPeers(pub Vec); - -impl SerializeCompact for BootstrapPeers { - fn to_bytes_compact(&self) -> Result, massa_models::ModelsError> { - let mut res: Vec = Vec::new(); - - // peers - let peers_count: u32 = self.0.len().try_into().map_err(|err| { - ModelsError::SerializeError(format!("too many peers blocks in BootstrapPeers: {}", err)) - })?; - let max_peer_list_length = - with_serialization_context(|context| context.max_advertise_length); - if peers_count > max_peer_list_length { - return Err(ModelsError::SerializeError(format!( - "too many peers for serialization context in BootstrapPeers: {}", - peers_count - ))); - } - res.extend(peers_count.to_varint_bytes()); - for peer in self.0.iter() { - res.extend(peer.to_bytes_compact()?); - } - - Ok(res) - } -} - -impl DeserializeCompact for BootstrapPeers { - fn from_bytes_compact(buffer: &[u8]) -> Result<(Self, usize), massa_models::ModelsError> { - let mut cursor = 0usize; - - // peers - let (peers_count, delta) = u32::from_varint_bytes(&buffer[cursor..])?; - let max_peer_list_length = - with_serialization_context(|context| context.max_advertise_length); - if peers_count > max_peer_list_length { - return Err(ModelsError::DeserializeError(format!( - "too many peers for deserialization context in BootstrapPeers: {}", - peers_count - ))); - } - cursor += delta; - let mut peers: Vec = Vec::with_capacity(peers_count as usize); - for _ in 0..(peers_count as usize) { - let (ip, delta) = IpAddr::from_bytes_compact(&buffer[cursor..])?; - cursor += delta; - peers.push(ip); - } - - Ok((BootstrapPeers(peers), cursor)) - } -} - /// Real job is done by network worker pub struct NetworkWorker { /// Network configuration. cfg: NetworkSettings, /// Our private key. - private_key: PrivateKey, + pub(crate) private_key: PrivateKey, /// Our node id. - self_node_id: NodeId, + pub(crate) self_node_id: NodeId, /// Listener part of the establisher. listener: Listener, /// The connection establisher. establisher: Establisher, /// Database with peer information. - peer_info_db: PeerInfoDatabase, + pub(crate) peer_info_db: PeerInfoDatabase, /// Receiver for network commands controller_command_rx: mpsc::Receiver, - /// Sender for network events - controller_event_tx: mpsc::Sender, /// Receiver for network management commands controller_manager_rx: mpsc::Receiver, /// Set of connection id of node with running handshake. - running_handshakes: HashSet, + pub(crate) running_handshakes: HashSet, /// Running handshakes futures. handshake_futures: FuturesUnordered>, /// Running handshakes that send a list of peers. handshake_peer_list_futures: FuturesUnordered>, - /// Channel for sending node events. - node_event_tx: mpsc::Sender, /// Receiving channel for node events. node_event_rx: mpsc::Receiver, /// Ids of active nodes mapped to Connection id, node command sender and handle on the associated node worker. - active_nodes: HashMap)>, + pub(crate) active_nodes: HashMap)>, /// Node worker handles node_worker_handles: FuturesUnordered)>>, /// Map of connection to ip, is_outgoing. - active_connections: HashMap, + pub(crate) active_connections: HashMap, + /// Node version version: Version, + /// Event sender + pub(crate) event: EventSender, } pub struct NetworkWorkerChannels { @@ -259,6 +102,7 @@ impl NetworkWorker { let self_node_id = NodeId(public_key); let (node_event_tx, node_event_rx) = mpsc::channel::(CHANNEL_SIZE); + let max_wait_event = cfg.max_send_wait.to_duration(); NetworkWorker { cfg, self_node_id, @@ -267,12 +111,11 @@ impl NetworkWorker { establisher, peer_info_db, controller_command_rx, - controller_event_tx, + event: EventSender::new(controller_event_tx, node_event_tx, max_wait_event), controller_manager_rx, running_handshakes: HashSet::new(), handshake_futures: FuturesUnordered::new(), handshake_peer_list_futures: FuturesUnordered::new(), - node_event_tx, node_event_rx, active_nodes: HashMap::new(), node_worker_handles: FuturesUnordered::new(), @@ -281,26 +124,6 @@ impl NetworkWorker { } } - async fn send_network_event(&self, event: NetworkEvent) -> Result<(), NetworkError> { - let result = self - .controller_event_tx - .send_timeout(event, self.cfg.max_send_wait.to_duration()) - .await; - match result { - Ok(()) => return Ok(()), - Err(SendTimeoutError::Closed(event)) => { - debug!( - "Failed to send NetworkEvent due to channel closure: {:?}.", - event - ); - } - Err(SendTimeoutError::Timeout(event)) => { - debug!("Failed to send NetworkEvent due to timeout: {:?}.", event); - } - } - Err(NetworkError::ChannelError("Failed to send event.".into())) - } - /// Runs the main loop of the network_worker /// There is a tokio::select! inside the loop pub async fn run_loop(mut self) -> Result<(), NetworkError> { @@ -408,7 +231,7 @@ impl NetworkWorker { // we will retry a send for this event for that unknown node, // ensuring protocol eventually notes the closure. let _ = self - .send_network_event(NetworkEvent::ConnectionClosed(node_id)) + .event.send(NetworkEvent::ConnectionClosed(node_id)) .await; if let Some((connection_id, _)) = self .active_nodes @@ -448,7 +271,7 @@ impl NetworkWorker { // Cleanup of connected nodes. // drop sender - drop(self.node_event_tx); + self.event.drop(); for (_, (_, node_tx)) in self.active_nodes.drain() { // close opened connection. trace!("before sending NodeCommand::Close(ConnectionClosureReason::Normal) from node_tx in network_worker run_loop"); @@ -561,7 +384,7 @@ impl NetworkWorker { // spawn node_controller_fn let (node_command_tx, node_command_rx) = mpsc::channel::(CHANNEL_SIZE); - let node_event_tx_clone = self.node_event_tx.clone(); + let node_event_tx_clone = self.event.clone_node_sender(); let cfg_copy = self.cfg.clone(); let node_fn_handle = tokio::spawn(async move { let res = NodeWorker::new( @@ -580,7 +403,8 @@ impl NetworkWorker { self.node_worker_handles.push(node_fn_handle); let res = self - .send_network_event(NetworkEvent::NewConnection(new_node_id)) + .event + .send(NetworkEvent::NewConnection(new_node_id)) .await; // If we failed to send the event to protocol, close the connection. @@ -662,27 +486,6 @@ impl NetworkWorker { Ok(()) } - async fn ban_connection_ids(&mut self, ban_connection_ids: HashSet) { - for ban_conn_id in ban_connection_ids.iter() { - // remove the connectionId entry in running_handshakes - self.running_handshakes.remove(ban_conn_id); - } - for (conn_id, node_command_tx) in self.active_nodes.values() { - if ban_connection_ids.contains(conn_id) { - let res = node_command_tx - .send(NodeCommand::Close(ConnectionClosureReason::Banned)) - .await; - if res.is_err() { - massa_trace!( - "network.network_worker.manage_network_command", {"err": NetworkError::ChannelError( - "close node command send failed".into(), - ).to_string()} - ); - } - }; - } - } - /// Manages network commands /// Only used inside worker's run_loop /// @@ -691,243 +494,48 @@ impl NetworkWorker { /// * peer_info_db: Database with peer information. /// * active_connections: hashmap linking connection id to ipAddr to whether connection is outgoing (true) /// * event_tx: channel to send network events out. + /// + /// # Command implementation + /// The network commands are root to functions in `network_cmd_impl` + /// ex: NetworkCommand::AskForBlocks => on_ask_bfor_block_cmd(...) async fn manage_network_command(&mut self, cmd: NetworkCommand) -> Result<(), NetworkError> { + use crate::network_cmd_impl::*; match cmd { - NetworkCommand::BanIp(ips) => { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::BanIp", - { "ips": ips } - ); - for ip in ips.iter() { - self.peer_info_db.peer_banned(ip)?; - } - let ban_connection_ids = self - .active_connections - .iter() - .filter_map(|(conn_id, (ip, _))| { - if ips.contains(ip) { - Some(conn_id) - } else { - None - } - }) - .copied() - .collect::>(); - - self.ban_connection_ids(ban_connection_ids).await - } - NetworkCommand::Ban(node) => { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::Ban", - { "node": node } - ); - // get all connection IDs to ban - let mut ban_connection_ids: HashSet = HashSet::new(); - - // Note: if we can't find the node, there is no need to resend the close event, - // since protocol will have already removed the node from it's list of active ones. - if let Some((orig_conn_id, _)) = self.active_nodes.get(&node) { - if let Some((orig_ip, _)) = self.active_connections.get(orig_conn_id) { - self.peer_info_db.peer_banned(orig_ip)?; - for (target_conn_id, (target_ip, _)) in self.active_connections.iter() { - if target_ip == orig_ip { - ban_connection_ids.insert(*target_conn_id); - } - } - } - } - self.ban_connection_ids(ban_connection_ids).await - } + NetworkCommand::BanIp(ips) => on_ban_ip_cmd(self, ips).await?, + NetworkCommand::Ban(node) => on_ban_cmd(self, node).await?, NetworkCommand::SendBlockHeader { node, header } => { - massa_trace!("network_worker.manage_network_command send NodeCommand::SendBlockHeader", {"block_id": header.compute_block_id()?, "header": header, "node": node}); - self.forward_message_to_node_or_resend_close_event( - &node, - NodeCommand::SendBlockHeader(header), - ) - .await; - } - NetworkCommand::AskForBlocks { list } => { - for (node, hash_list) in list.into_iter() { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::AskForBlocks", - { "hashlist": hash_list, "node": node } - ); - self.forward_message_to_node_or_resend_close_event( - &node, - NodeCommand::AskForBlocks(hash_list.clone()), - ) - .await; - } + on_send_block_header_cmd(self, node, header).await? } + NetworkCommand::AskForBlocks { list } => on_ask_bfor_block_cmd(self, list).await, NetworkCommand::SendBlock { node, block } => { - massa_trace!( - "network_worker.manage_network_command send NodeCommand::SendBlock", - {"hash": block.header.content.compute_hash()?, "block": block, "node": node} - ); - self.forward_message_to_node_or_resend_close_event( - &node, - NodeCommand::SendBlock(block), - ) - .await; - } - NetworkCommand::GetPeers(response_tx) => { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::GetPeers", - {} - ); - - // for each peer get all node id associated to this peer ip. - let peers: HashMap = self - .peer_info_db - .get_peers() - .iter() - .map(|(peer_ip_addr, peer)| { - ( - *peer_ip_addr, - Peer { - peer_info: *peer, - active_nodes: self - .active_connections - .iter() - .filter(|(_, (ip_addr, _))| &peer.ip == ip_addr) - .filter_map(|(out_conn_id, (_, out_going))| { - self.active_nodes - .iter() - .filter_map(|(node_id, (conn_id, _))| { - if out_conn_id == conn_id { - Some(node_id) - } else { - None - } - }) - .next() - .map(|node_id| (*node_id, *out_going)) - }) - .collect(), - }, - ) - }) - .collect(); - - // HashMap) - if response_tx - .send(Peers { - peers, - our_node_id: self.self_node_id, - }) - .is_err() - { - warn!("network: could not send GetPeersChannelError upstream"); - } + on_send_block_cmd(self, node, block).await? } + NetworkCommand::GetPeers(response_tx) => on_get_peers_cmd(self, response_tx).await, NetworkCommand::GetBootstrapPeers(response_tx) => { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::GetBootstrapPeers", - {} - ); - let peer_list = self.peer_info_db.get_advertisable_peer_ips(); - if response_tx.send(BootstrapPeers(peer_list)).is_err() { - warn!("network: could not send GetBootstrapPeers response upstream"); - } + on_get_bootstrap_peers_cmd(self, response_tx).await } NetworkCommand::BlockNotFound { node, block_id } => { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::BlockNotFound", - { "block_id": block_id, "node": node } - ); - self.forward_message_to_node_or_resend_close_event( - &node, - NodeCommand::BlockNotFound(block_id), - ) - .await; + on_block_not_found_cmd(self, node, block_id).await } NetworkCommand::SendOperations { node, operations } => { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::SendOperations", - { "node": node, "operations": operations } - ); - self.forward_message_to_node_or_resend_close_event( - &node, - NodeCommand::SendOperations(operations), - ) - .await; + on_send_operation_cmd(self, node, operations).await } NetworkCommand::SendEndorsements { node, endorsements } => { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::SendEndorsements", - { "node": node, "endorsements": endorsements } - ); - self.forward_message_to_node_or_resend_close_event( - &node, - NodeCommand::SendEndorsements(endorsements), - ) - .await; + on_send_endorsements_cmd(self, node, endorsements).await } NetworkCommand::NodeSignMessage { msg, response_tx } => { - massa_trace!( - "network_worker.manage_network_command receive NetworkCommand::NodeSignMessage", - { "mdg": msg } - ); - let signature = sign(&Hash::compute_from(&msg), &self.private_key)?; - let public_key = derive_public_key(&self.private_key); - if response_tx - .send(PubkeySig { - public_key, - signature, - }) - .is_err() - { - warn!("network: could not send NodeSignMessage response upstream"); - } + on_node_sign_message_cmd(self, msg, response_tx).await? } - NetworkCommand::Unban(ip) => self.peer_info_db.unban(ip)?, - NetworkCommand::GetStats { response_tx } => { - let res = NetworkStats { - in_connection_count: self.peer_info_db.get_in_connection_count(), - out_connection_count: self.peer_info_db.get_out_connection_count(), - known_peer_count: self.peer_info_db.peers.len() as u64, - banned_peer_count: self - .peer_info_db - .peers - .iter() - .filter(|(_, p)| p.banned) - .fold(0, |acc, _| acc + 1), - active_node_count: self.active_nodes.len() as u64, - }; - if response_tx.send(res).is_err() { - warn!("network: could not send NodeSignMessage response upstream"); - } - } - NetworkCommand::Whitelist(ip) => self.peer_info_db.whitelist(ip).await?, - NetworkCommand::RemoveFromWhitelist(ip) => { - self.peer_info_db.remove_from_whitelist(ip).await? + NetworkCommand::Unban(ip) => on_unban_cmd(self, ip).await?, + NetworkCommand::GetStats { response_tx } => on_get_stats_cmd(self, response_tx).await, + NetworkCommand::Whitelist(ips) => on_whitelist_cmd(self, ips).await?, + NetworkCommand::RemoveFromWhitelist(ips) => { + on_remove_from_whitelist_cmd(self, ips).await? } - } + }; Ok(()) } - /// Forward a message to a node worker. If it fails, notify upstream about connection closure. - async fn forward_message_to_node_or_resend_close_event( - &mut self, - node: &NodeId, - message: NodeCommand, - ) { - if let Some((_, node_command_tx)) = self.active_nodes.get(node) { - if node_command_tx.send(message).await.is_err() { - debug!( - "{}", - NetworkError::ChannelError("contact with node worker lost while trying to send it a message. Probably a peer disconnect.".into()) - ); - }; - } else { - // We probably weren't able to send this event previously, - // retry it now. - let _ = self - .send_network_event(NetworkEvent::ConnectionClosed(*node)) - .await; - } - } - /// Manages out connection /// Only used inside worker's run_loop /// @@ -1126,102 +734,32 @@ impl NetworkWorker { /// # Argument /// * evt: optional node event to process. async fn on_node_event(&mut self, evt: NodeEvent) -> Result<(), NetworkError> { + use crate::network_event::*; match evt { // received a list of peers NodeEvent(from_node_id, NodeEventType::ReceivedPeerList(lst)) => { - debug!( - "node_id={} sent us a peer list ({} ips)", - from_node_id, - lst.len() - ); - massa_trace!("peer_list_received", { - "node_id": from_node_id, - "ips": lst - }); - self.peer_info_db.merge_candidate_peers(&lst)?; + event_impl::on_received_peer_list(self, from_node_id, &lst)? } NodeEvent(from_node_id, NodeEventType::ReceivedBlock(data)) => { - massa_trace!( - "network_worker.on_node_event receive NetworkEvent::ReceivedBlock", - {"block_id": data.header.compute_block_id()?, "block": data, "node": from_node_id} - ); - let _ = self - .send_network_event(NetworkEvent::ReceivedBlock { - node: from_node_id, - block: data, - }) - .await; + event_impl::on_received_block(self, from_node_id, data).await? } NodeEvent(from_node_id, NodeEventType::ReceivedAskForBlocks(list)) => { - let _ = self - .send_network_event(NetworkEvent::AskedForBlocks { - node: from_node_id, - list, - }) - .await; + event_impl::on_received_ask_for_blocks(self, from_node_id, list).await } NodeEvent(source_node_id, NodeEventType::ReceivedBlockHeader(header)) => { - massa_trace!( - "network_worker.on_node_event receive NetworkEvent::ReceivedBlockHeader", - {"hash": header.content.compute_hash()?, "header": header, "node": source_node_id} - ); - let _ = self - .send_network_event(NetworkEvent::ReceivedBlockHeader { - source_node_id, - header, - }) - .await; + event_impl::on_received_block_header(self, source_node_id, header).await? } - // asked peer list NodeEvent(from_node_id, NodeEventType::AskedPeerList) => { - debug!("node_id={} asked us for peer list", from_node_id); - massa_trace!("node_asked_peer_list", { "node_id": from_node_id }); - let peer_list = self.peer_info_db.get_advertisable_peer_ips(); - if let Some((_, node_command_tx)) = self.active_nodes.get(&from_node_id) { - let res = node_command_tx - .send(NodeCommand::SendPeerList(peer_list)) - .await; - if res.is_err() { - debug!( - "{}", - NetworkError::ChannelError( - "node command send send_peer_list failed".into(), - ) - ); - } - } else { - massa_trace!("node asked us for peer list and disappeared", { - "node_id": from_node_id - }) - } + event_impl::on_asked_peer_list(self, from_node_id).await? } - NodeEvent(node, NodeEventType::BlockNotFound(block_id)) => { - massa_trace!( - "network_worker.on_node_event receive NetworkEvent::BlockNotFound", - { "id": block_id } - ); - let _ = self - .send_network_event(NetworkEvent::BlockNotFound { node, block_id }) - .await; + event_impl::on_block_not_found(self, node, block_id).await } NodeEvent(node, NodeEventType::ReceivedOperations(operations)) => { - massa_trace!( - "network_worker.on_node_event receive NetworkEvent::ReceivedOperations", - { "operations": operations } - ); - let _ = self - .send_network_event(NetworkEvent::ReceivedOperations { node, operations }) - .await; + event_impl::on_received_operations(self, node, operations).await } NodeEvent(node, NodeEventType::ReceivedEndorsements(endorsements)) => { - massa_trace!( - "network_worker.on_node_event receive NetworkEvent::ReceivedEndorsements", - { "endorsements": endorsements } - ); - let _ = self - .send_network_event(NetworkEvent::ReceivedEndorsements { node, endorsements }) - .await; + event_impl::on_received_endorsements(self, node, endorsements).await } } Ok(()) diff --git a/massa-network/src/node_worker.rs b/massa-network-worker/src/node_worker.rs similarity index 95% rename from massa-network/src/node_worker.rs rename to massa-network-worker/src/node_worker.rs index c8a4689091a..b7d773b9868 100644 --- a/massa-network/src/node_worker.rs +++ b/massa-network-worker/src/node_worker.rs @@ -4,8 +4,7 @@ use super::{ binders::{ReadBinder, WriteBinder}, messages::Message, }; -use crate::settings::NetworkSettings; -use crate::{error::NetworkError, ConnectionClosureReason}; + use massa_logging::massa_trace; use massa_models::{ constants::{ @@ -13,8 +12,10 @@ use massa_models::{ NODE_SEND_CHANNEL_SIZE, }, node::NodeId, - Block, BlockHeader, BlockId, Endorsement, Operation, + signed::Signable, + Block, BlockId, SignedEndorsement, SignedHeader, SignedOperation, }; +use massa_network_exports::{ConnectionClosureReason, NetworkError, NetworkSettings}; use std::net::IpAddr; use tokio::{ sync::mpsc, @@ -33,7 +34,7 @@ pub enum NodeCommand { /// Send that block to node. SendBlock(Block), /// Send the header of a block to a node. - SendBlockHeader(BlockHeader), + SendBlockHeader(SignedHeader), /// Ask for a block from that node. AskForBlocks(Vec), /// Close the node worker. @@ -41,9 +42,9 @@ pub enum NodeCommand { /// Block not found BlockNotFound(BlockId), /// Operation - SendOperations(Vec), + SendOperations(Vec), /// Endorsements - SendEndorsements(Vec), + SendEndorsements(Vec), } /// Event types that node worker can emit @@ -56,15 +57,15 @@ pub enum NodeEventType { /// Node we are connected to sent block ReceivedBlock(Block), /// Node we are connected to sent block header - ReceivedBlockHeader(BlockHeader), + ReceivedBlockHeader(SignedHeader), /// Node we are connected to asks for a block. ReceivedAskForBlocks(Vec), /// Didn't found given block, BlockNotFound(BlockId), /// Operation - ReceivedOperations(Vec), + ReceivedOperations(Vec), /// Operation - ReceivedEndorsements(Vec), + ReceivedEndorsements(Vec), } /// Events node worker can emit. @@ -258,14 +259,14 @@ impl NodeWorker { Message::Block(block) => { massa_trace!( "node_worker.run_loop. receive Message::Block", - {"block_id": block.header.compute_block_id()?, "block": block, "node": self.node_id} + {"block_id": block.header.content.compute_id()?, "block": block, "node": self.node_id} ); self.send_node_event(NodeEvent(self.node_id, NodeEventType::ReceivedBlock(block))).await; }, Message::BlockHeader(header) => { massa_trace!( "node_worker.run_loop. receive Message::BlockHeader", - {"block_id": header.compute_block_id()?, "header": header, "node": self.node_id} + {"block_id": header.content.compute_id()?, "header": header, "node": self.node_id} ); self.send_node_event(NodeEvent(self.node_id, NodeEventType::ReceivedBlockHeader(header))).await; }, @@ -323,13 +324,13 @@ impl NodeWorker { } }, Some(NodeCommand::SendBlockHeader(header)) => { - massa_trace!("node_worker.run_loop. send Message::BlockHeader", {"hash": header.compute_block_id()?, "header": header, "node": self.node_id}); + massa_trace!("node_worker.run_loop. send Message::BlockHeader", {"hash": header.content.compute_id()?, "header": header, "node": self.node_id}); if self.try_send_to_node(&writer_command_tx, Message::BlockHeader(header)).is_err() { break; } }, Some(NodeCommand::SendBlock(block)) => { - massa_trace!("node_worker.run_loop. send Message::Block", {"hash": block.header.compute_block_id()?, "block": block, "node": self.node_id}); + massa_trace!("node_worker.run_loop. send Message::Block", {"hash": block.header.content.compute_id()?, "block": block, "node": self.node_id}); if self.try_send_to_node(&writer_command_tx, Message::Block(block)).is_err() { break; } diff --git a/massa-network/src/peer_info_database.rs b/massa-network-worker/src/peer_info_database.rs similarity index 87% rename from massa-network/src/peer_info_database.rs rename to massa-network-worker/src/peer_info_database.rs index 6d990fd113c..a867c3d8e2c 100644 --- a/massa-network/src/peer_info_database.rs +++ b/massa-network-worker/src/peer_info_database.rs @@ -1,14 +1,17 @@ // Copyright (c) 2022 MASSA LABS -use crate::error::{NetworkConnectionErrorType, NetworkError}; -use crate::settings::{NetworkSettings, PeerTypeConnectionConfig}; -use displaydoc::Display; -use enum_map::{Enum, EnumMap}; +use enum_map::EnumMap; use itertools::Itertools; use massa_logging::massa_trace; use massa_models::constants::MAX_ADVERTISE_LENGTH; +use massa_network_exports::settings::PeerTypeConnectionConfig; +use massa_network_exports::ConnectionCount; +use massa_network_exports::NetworkConnectionErrorType; +use massa_network_exports::NetworkError; +use massa_network_exports::NetworkSettings; +use massa_network_exports::PeerInfo; +use massa_network_exports::PeerType; use massa_time::MassaTime; -use serde::{Deserialize, Serialize}; use std::cmp::Reverse; use std::collections::HashMap; use std::net::IpAddr; @@ -17,144 +20,6 @@ use tokio::sync::watch; use tokio::task::JoinHandle; use tokio::time::{sleep, Duration}; use tracing::{trace, warn}; - -/// Peer categories. -/// There is a defined number af slots for each category. -/// Order matters: less prioritized peer type first -#[derive( - Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Enum, -)] -pub enum PeerType { - /// Just a peer - Standard, - /// Connection from these nodes are always accepted - WhiteListed, - /** if the peer is in bootstrap servers list - for now it is decoupled from the real bootstrap sever list, it's just parsed - TODO: https://github.com/massalabs/massa/issues/2320 - */ - Bootstrap, -} - -mod test { - - #[test] - fn test_order() { - use crate::peer_info_database::PeerType; - assert!(PeerType::Bootstrap > PeerType::WhiteListed); - assert!(PeerType::WhiteListed > PeerType::Standard); - } -} - -impl Default for PeerType { - fn default() -> Self { - PeerType::Standard - } -} - -/// All information concerning a peer is here -#[derive(Clone, Copy, Serialize, Deserialize, Debug)] -pub struct PeerInfo { - /// Peer ip address. - pub ip: IpAddr, - /// The category the peer is in affects how it's treated. - pub peer_type: PeerType, - /// Time in millis when peer was last alive - pub last_alive: Option, - /// Time in millis of peer's last failure - pub last_failure: Option, - /// Whether peer was promoted through another peer - pub advertised: bool, - /// peer was banned - pub banned: bool, - /// Current number of active out connection attempts with that peer. - /// Isn't dump into peer file. - #[serde(default = "usize::default")] - pub active_out_connection_attempts: usize, - /// Current number of active out connections with that peer. - /// Isn't dump into peer file. - #[serde(default = "usize::default")] - pub active_out_connections: usize, - /// Current number of active in connections with that peer. - /// Isn't dump into peer file. - #[serde(default = "usize::default")] - pub active_in_connections: usize, -} - -impl PeerInfo { - /// Returns true if there is at least one connection attempt / - /// one active connection in either direction - /// with this peer - #[inline] - pub(crate) fn is_active(&self) -> bool { - self.active_out_connection_attempts > 0 - || self.active_out_connections > 0 - || self.active_in_connections > 0 - } - - /// New standard PeerInfo for ipaddr - /// - /// # Arguments - /// * ip: the IP address of the peer - /// * advertised: true if this peer was advertised as routable, - /// which means that our node can attempt outgoing connections to it - pub fn new(ip: IpAddr, advertised: bool) -> PeerInfo { - PeerInfo { - ip, - last_alive: None, - last_failure: None, - advertised, - active_out_connection_attempts: 0, - active_out_connections: 0, - active_in_connections: 0, - peer_type: Default::default(), - banned: false, - } - } - - /// peer is ready to be retried, enough time has elapsed since last failure - fn is_peer_ready(&self, wakeup_interval: MassaTime, now: MassaTime) -> bool { - if let Some(last_failure) = self.last_failure { - if let Some(last_alive) = self.last_alive { - if last_alive > last_failure { - return true; - } - } - return now - .saturating_sub(last_failure) - .saturating_sub(wakeup_interval) - > MassaTime::from(0u64); - } - true - } -} - -/// Connection count for a category -#[derive(Default, Debug)] -pub(crate) struct ConnectionCount { - /// Number of outgoing connections our node is currently trying to establish. - /// We might be in the process of establishing a TCP connection or handshaking with the peer. - pub(crate) active_out_connection_attempts: usize, - /// Number of currently live (TCP connection active, handshake successful) outgoing connections - pub(crate) active_out_connections: usize, - /// Number of currently live (TCP connection active, handshake successful) incoming connections - pub(crate) active_in_connections: usize, -} - -impl ConnectionCount { - #[inline] - /// Gets available out connection attempts for given connection count and settings - fn get_available_out_connection_attempts(&self, cfg: &PeerTypeConnectionConfig) -> usize { - std::cmp::min( - cfg.target_out_connections - .saturating_sub(self.active_out_connection_attempts) - .saturating_sub(self.active_out_connections), - cfg.max_out_attempts - .saturating_sub(self.active_out_connection_attempts), - ) - } -} - /// Contains all information about every peers we know about. pub struct PeerInfoDatabase { /// Network configuration. diff --git a/massa-network/src/tests/mod.rs b/massa-network-worker/src/tests/mod.rs similarity index 54% rename from massa-network/src/tests/mod.rs rename to massa-network-worker/src/tests/mod.rs index 7ccdbc92d7e..c76f7750ecd 100644 --- a/massa-network/src/tests/mod.rs +++ b/massa-network-worker/src/tests/mod.rs @@ -1,6 +1,8 @@ // Copyright (c) 2022 MASSA LABS -pub mod mock_establisher; +#[cfg(test)] mod scenarios; -mod test_peer_db; +#[cfg(test)] +mod test_peer_info_database; +#[cfg(test)] pub mod tools; diff --git a/massa-network/src/tests/scenarios.rs b/massa-network-worker/src/tests/scenarios.rs similarity index 96% rename from massa-network/src/tests/scenarios.rs rename to massa-network-worker/src/tests/scenarios.rs index 4ffcfaa9ee1..1465c60f997 100644 --- a/massa-network/src/tests/scenarios.rs +++ b/massa-network-worker/src/tests/scenarios.rs @@ -2,27 +2,27 @@ // To start alone RUST_BACKTRACE=1 cargo test -- --nocapture --test-threads=1 use super::tools; -use crate::error::HandshakeErrorType; use crate::messages::Message; use crate::node_worker::{NodeCommand, NodeEvent, NodeWorker}; -use crate::ConnectionClosureReason; +use crate::tests::tools::{get_dummy_block_id, get_transaction}; use crate::NetworkError; use crate::NetworkEvent; - -use crate::peer_info_database::PeerType; -use crate::settings::PeerTypeConnectionConfig; -use crate::tests::tools::{get_dummy_block_id, get_transaction}; -use crate::PeerInfo; use crate::{ binders::{ReadBinder, WriteBinder}, - ConnectionId, NetworkSettings, + NetworkSettings, }; use enum_map::enum_map; use enum_map::EnumMap; use massa_hash::{self, hash::Hash}; -use massa_models::node::NodeId; -use massa_models::{BlockId, Endorsement, EndorsementContent, SerializeCompact, Slot}; -use massa_signature::sign; +use massa_models::{ + node::NodeId, + signed::{Signable, Signed}, +}; +use massa_models::{BlockId, Endorsement, Slot}; +use massa_network_exports::settings::PeerTypeConnectionConfig; +use massa_network_exports::{ + ConnectionClosureReason, ConnectionId, HandshakeErrorType, PeerInfo, PeerType, +}; use massa_time::MassaTime; use serial_test::serial; use std::collections::HashMap; @@ -1096,19 +1096,14 @@ async fn test_endorsements_messages() { let sender_priv = massa_signature::generate_random_private_key(); let sender_public_key = massa_signature::derive_public_key(&sender_priv); - let content = EndorsementContent { + let content = Endorsement { sender_public_key, slot: Slot::new(10, 1), index: 0, endorsed_block: BlockId(Hash::compute_from(&[])), }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - let endorsement = Endorsement { - content: content.clone(), - signature, - }; - let ref_id = endorsement.compute_endorsement_id().unwrap(); + let endorsement = Signed::new_signed(content.clone(), &sender_priv).unwrap().1; + let ref_id = endorsement.content.compute_id().unwrap(); conn1_w .send(&Message::Endorsements(vec![endorsement])) .await @@ -1126,7 +1121,7 @@ async fn test_endorsements_messages() { .await { assert_eq!(endorsements.len(), 1); - let res_id = endorsements[0].compute_endorsement_id().unwrap(); + let res_id = endorsements[0].content.compute_id().unwrap(); assert_eq!(ref_id, res_id); assert_eq!(node, conn1_id); } else { @@ -1136,19 +1131,14 @@ async fn test_endorsements_messages() { let sender_priv = massa_signature::generate_random_private_key(); let sender_public_key = massa_signature::derive_public_key(&sender_priv); - let content = EndorsementContent { + let content = Endorsement { sender_public_key, slot: Slot::new(11, 1), index: 0, endorsed_block: BlockId(Hash::compute_from(&[])), }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = massa_signature::sign(&hash, &sender_priv).unwrap(); - let endorsement = Endorsement { - content: content.clone(), - signature, - }; - let ref_id = endorsement.compute_endorsement_id().unwrap(); + let endorsement = Signed::new_signed(content.clone(), &sender_priv).unwrap().1; + let ref_id = endorsement.content.compute_id().unwrap(); // reply with another endorsement network_command_sender @@ -1164,7 +1154,7 @@ async fn test_endorsements_messages() { let evt = evt.unwrap().unwrap().1; if let Message::Endorsements(endorsements) = evt { assert_eq!(endorsements.len(), 1); - let res_id = endorsements[0].compute_endorsement_id().unwrap(); + let res_id = endorsements[0].content.compute_id().unwrap(); assert_eq!(ref_id, res_id); break; } diff --git a/massa-network/src/tests/test_peer_db.rs b/massa-network-worker/src/tests/test_peer_info_database.rs similarity index 99% rename from massa-network/src/tests/test_peer_db.rs rename to massa-network-worker/src/tests/test_peer_info_database.rs index 1c6fefc8c22..855773a44b0 100644 --- a/massa-network/src/tests/test_peer_db.rs +++ b/massa-network-worker/src/tests/test_peer_info_database.rs @@ -1,10 +1,11 @@ use crate::{ - error::NetworkConnectionErrorType, - peer_info_database::{cleanup_peers, PeerInfoDatabase, PeerType}, - settings::PeerTypeConnectionConfig, - NetworkError, NetworkSettings, PeerInfo, + peer_info_database::{cleanup_peers, PeerInfoDatabase}, + NetworkError, NetworkSettings, }; use enum_map::enum_map; +use massa_network_exports::{ + settings::PeerTypeConnectionConfig, NetworkConnectionErrorType, PeerInfo, PeerType, +}; use massa_time::MassaTime; use serial_test::serial; use std::{collections::HashMap, net::IpAddr}; @@ -109,7 +110,7 @@ async fn test_try_new_in_connection_in_connection_closed() { { assert_eq!(IpAddr::V4(std::net::Ipv4Addr::new(169, 202, 0, 11)), ip_err); } else { - panic!("ToManyConnectionAttempt error not return"); + panic!("TooManyConnectionAttempt error not return"); } } diff --git a/massa-network/src/tests/tools.rs b/massa-network-worker/src/tests/tools.rs similarity index 93% rename from massa-network/src/tests/tools.rs rename to massa-network-worker/src/tests/tools.rs index 69d5f6c0820..66149effcb4 100644 --- a/massa-network/src/tests/tools.rs +++ b/massa-network-worker/src/tests/tools.rs @@ -1,21 +1,23 @@ // Copyright (c) 2022 MASSA LABS use super::super::binders::{ReadBinder, WriteBinder}; -use super::mock_establisher::MockEstablisherInterface; -use super::{mock_establisher, tools}; +use super::tools; +use crate::handshake_worker::HandshakeWorker; use crate::messages::Message; -use crate::network_controller::{start_network_controller, NetworkCommandSender, NetworkManager}; +use crate::start_network_controller; use crate::NetworkError; +use crate::NetworkEvent; use crate::NetworkSettings; -use crate::PeerInfo; -use crate::{handshake_worker::HandshakeWorker, ConnectionId}; -use crate::{network_controller::NetworkEventReceiver, NetworkEvent}; + use massa_hash::hash::Hash; use massa_models::node::NodeId; -use massa_models::{ - Address, Amount, BlockId, Operation, OperationContent, OperationType, SerializeCompact, Version, +use massa_models::signed::Signed; +use massa_models::{Address, Amount, BlockId, Operation, OperationType, SignedOperation, Version}; +use massa_network_exports::test_exports::mock_establisher::{self, MockEstablisherInterface}; +use massa_network_exports::{ + ConnectionId, NetworkCommandSender, NetworkEventReceiver, NetworkManager, PeerInfo, }; -use massa_signature::{derive_public_key, generate_random_private_key, sign}; +use massa_signature::{derive_public_key, generate_random_private_key}; use massa_time::MassaTime; use std::str::FromStr; use std::{ @@ -45,10 +47,7 @@ pub fn generate_peers_file(peer_vec: &[PeerInfo]) -> NamedTempFile { peers_file_named } -pub fn get_temp_private_key_file() -> NamedTempFile { - NamedTempFile::new().expect("cannot create temp file") -} - +#[cfg(test)] /// Establish a full alive connection to the controller /// /// * establishes connection @@ -317,7 +316,7 @@ pub async fn incoming_message_drain_stop( join_handle.await.expect("could not join message drain") } -pub fn get_transaction(expire_period: u64, fee: u64) -> (Operation, u8) { +pub fn get_transaction(expire_period: u64, fee: u64) -> (SignedOperation, u8) { let sender_priv = generate_random_private_key(); let sender_pub = derive_public_key(&sender_priv); @@ -328,17 +327,15 @@ pub fn get_transaction(expire_period: u64, fee: u64) -> (Operation, u8) { recipient_address: Address::from_public_key(&recv_pub), amount: Amount::default(), }; - let content = OperationContent { + let content = Operation { fee: Amount::from_str(&fee.to_string()).unwrap(), op, sender_public_key: sender_pub, expire_period, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); ( - Operation { content, signature }, + Signed::new_signed(content, &sender_priv).unwrap().1, Address::from_public_key(&sender_pub).get_thread(2), ) } diff --git a/massa-network/src/establisher.rs b/massa-network/src/establisher.rs deleted file mode 100644 index 2c09358535c..00000000000 --- a/massa-network/src/establisher.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2022 MASSA LABS - -#[cfg(not(test))] -use massa_time::MassaTime; -#[cfg(not(test))] -use std::{io, net::SocketAddr}; -#[cfg(not(test))] -use tokio::{ - net::{TcpListener, TcpStream}, - time::timeout, -}; - -#[cfg(test)] -pub type ReadHalf = super::tests::mock_establisher::ReadHalf; -#[cfg(test)] -pub type WriteHalf = super::tests::mock_establisher::WriteHalf; -#[cfg(test)] -pub type Listener = super::tests::mock_establisher::MockListener; -#[cfg(test)] -pub type Connector = super::tests::mock_establisher::MockConnector; -#[cfg(test)] -pub type Establisher = super::tests::mock_establisher::MockEstablisher; - -#[cfg(not(test))] -pub type ReadHalf = tokio::net::tcp::OwnedReadHalf; -#[cfg(not(test))] -pub type WriteHalf = tokio::net::tcp::OwnedWriteHalf; -#[cfg(not(test))] -pub type Listener = DefaultListener; -#[cfg(not(test))] -pub type Connector = DefaultConnector; -#[cfg(not(test))] -pub type Establisher = DefaultEstablisher; - -/// The listener we are using -#[cfg(not(test))] -#[derive(Debug)] -pub struct DefaultListener(TcpListener); - -#[cfg(not(test))] -impl DefaultListener { - /// Accepts a new incoming connection from this listener. - pub async fn accept(&mut self) -> io::Result<(ReadHalf, WriteHalf, SocketAddr)> { - let (sock, remote_addr) = self.0.accept().await?; - let (read_half, write_half) = sock.into_split(); - Ok((read_half, write_half, remote_addr)) - } -} - -/// Initiates a connection with given timeout in millis -#[cfg(not(test))] -#[derive(Debug)] -pub struct DefaultConnector(MassaTime); - -#[cfg(not(test))] -impl DefaultConnector { - /// Tries to connect to addr - /// - /// # Argument - /// * addr: SocketAddr we are trying to connect to. - pub async fn connect(&mut self, addr: SocketAddr) -> io::Result<(ReadHalf, WriteHalf)> { - match timeout(self.0.to_duration(), TcpStream::connect(addr)).await { - Ok(Ok(sock)) => { - let (reader, writer) = sock.into_split(); - Ok((reader, writer)) - } - Ok(Err(e)) => Err(e), - Err(e) => Err(io::Error::new(io::ErrorKind::TimedOut, e)), - } - } -} - -/// Establishes a connection -#[cfg(not(test))] -#[derive(Debug)] -pub struct DefaultEstablisher; - -#[cfg(not(test))] -impl DefaultEstablisher { - /// Creates an Establisher. - pub fn new() -> Self { - DefaultEstablisher {} - } - - /// Gets the associated listener - /// - /// # Argument - /// * addr: SocketAddr we want to bind to. - pub async fn get_listener(&mut self, addr: SocketAddr) -> io::Result { - Ok(DefaultListener(TcpListener::bind(addr).await?)) - } - - /// Get the connector with associated timeout - /// - /// # Argument - /// * timeout_duration: timeout duration in millis - pub async fn get_connector( - &mut self, - timeout_duration: MassaTime, - ) -> io::Result { - Ok(DefaultConnector(timeout_duration)) - } -} - -#[cfg(not(test))] -impl Default for DefaultEstablisher { - fn default() -> Self { - Self::new() - } -} diff --git a/massa-network/src/lib.rs b/massa-network/src/lib.rs deleted file mode 100644 index 82909c8c1e2..00000000000 --- a/massa-network/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2022 MASSA LABS - -#![feature(async_closure)] -#![feature(drain_filter)] -#![feature(ip)] -#![feature(is_some_with)] -#![feature(half_open_range_patterns)] - -//! Manages a connection with a node -pub use common::{ConnectionClosureReason, ConnectionId}; -pub use error::NetworkError; -pub use establisher::Establisher; -pub use establisher::*; -pub use network_controller::{ - start_network_controller, NetworkCommandSender, NetworkEventReceiver, NetworkManager, -}; -pub use network_worker::{BootstrapPeers, NetworkCommand, NetworkEvent, Peer, Peers}; -pub use peer_info_database::PeerInfo; -pub use settings::NetworkSettings; - -mod binders; -mod common; -mod error; -mod establisher; -mod handshake_worker; -mod messages; -mod network_controller; -mod network_worker; -mod node_worker; -mod peer_info_database; -pub mod settings; - -#[cfg(test)] -pub mod tests; diff --git a/massa-node/Cargo.toml b/massa-node/Cargo.toml index a2cccf14548..cbbe972ff16 100644 --- a/massa-node/Cargo.toml +++ b/massa-node/Cargo.toml @@ -31,7 +31,8 @@ massa_execution_worker = { path = "../massa-execution-worker" } massa_logging = { path = "../massa-logging" } massa_ledger = { path = "../massa-ledger" } massa_models = { path = "../massa-models" } -massa_network = { path = "../massa-network" } +massa_network_exports = { path = "../massa-network-exports" } +massa_network_worker = { path = "../massa-network-worker" } massa_pool = { path = "../massa-pool" } massa_protocol_exports = { path = "../massa-protocol-exports" } massa_protocol_worker = { path = "../massa-protocol-worker" } @@ -44,7 +45,7 @@ serial_test = "0.5" [features] # nightly = ["beta"] beta = [] -instrument = ["tokio/tracing", "massa_api/instrument", "massa_bootstrap/instrument", "massa_consensus_exports/instrument", "massa_consensus_worker/instrument", "massa_network/instrument", "massa_pool/instrument", "massa_protocol_exports/instrument", "massa_protocol_worker/instrument"] +instrument = ["tokio/tracing", "massa_api/instrument", "massa_bootstrap/instrument", "massa_consensus_exports/instrument", "massa_consensus_worker/instrument", "massa_network_exports/instrument", "massa_pool/instrument", "massa_protocol_exports/instrument", "massa_protocol_worker/instrument","massa_network_worker/instrument"] sandbox = ["massa_consensus_exports/sandbox", "massa_consensus_worker/sandbox", "massa_models/sandbox"] [build] diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 34d3c988ca7..cfd21cf1c8d 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -23,7 +23,8 @@ use massa_models::{ }, init_serialization_context, SerializationContext, }; -use massa_network::{start_network_controller, Establisher, NetworkCommandSender, NetworkManager}; +use massa_network_exports::{Establisher, NetworkCommandSender, NetworkManager}; +use massa_network_worker::start_network_controller; use massa_pool::{start_pool_controller, PoolCommandSender, PoolManager}; use massa_protocol_exports::ProtocolManager; use massa_protocol_worker::start_protocol_controller; diff --git a/massa-node/src/settings.rs b/massa-node/src/settings.rs index cb9fb390dd5..365099da337 100644 --- a/massa-node/src/settings.rs +++ b/massa-node/src/settings.rs @@ -9,7 +9,7 @@ use massa_models::{ api::APISettings, constants::{build_massa_settings, OPERATION_VALIDITY_PERIODS, THREAD_COUNT}, }; -use massa_network::NetworkSettings; +use massa_network_exports::NetworkSettings; use massa_pool::{PoolConfig, PoolSettings}; use massa_protocol_exports::ProtocolSettings; use massa_time::MassaTime; diff --git a/massa-pool/src/endorsement_pool.rs b/massa-pool/src/endorsement_pool.rs index 396e5d35716..bd199632e10 100644 --- a/massa-pool/src/endorsement_pool.rs +++ b/massa-pool/src/endorsement_pool.rs @@ -2,10 +2,11 @@ use crate::{settings::PoolConfig, PoolError}; use massa_models::prehash::{Map, Set}; -use massa_models::{Address, BlockId, Endorsement, EndorsementContent, EndorsementId, Slot}; +use massa_models::signed::Signed; +use massa_models::{Address, BlockId, Endorsement, EndorsementId, SignedEndorsement, Slot}; pub struct EndorsementPool { - endorsements: Map, + endorsements: Map, latest_final_periods: Vec, current_slot: Option, cfg: &'static PoolConfig, @@ -29,8 +30,8 @@ impl EndorsementPool { pub fn update_latest_final_periods(&mut self, periods: Vec) { self.endorsements.retain( |_, - Endorsement { - content: EndorsementContent { slot, .. }, + Signed { + content: Endorsement { slot, .. }, .. }| slot.period >= periods[slot.thread as usize], ); @@ -44,7 +45,7 @@ impl EndorsementPool { target_slot: Slot, parent: BlockId, creators: Vec
, - ) -> Result, PoolError> { + ) -> Result, PoolError> { let mut candidates = self .endorsements .iter() @@ -59,7 +60,7 @@ impl EndorsementPool { None } }) - .collect::, PoolError>>()?; + .collect::, PoolError>>()?; candidates.sort_unstable_by_key(|(_e_id, endo)| endo.content.index); candidates.dedup_by_key(|(_e_id, endo)| endo.content.index); Ok(candidates) @@ -69,7 +70,7 @@ impl EndorsementPool { /// Prunes the pool if there are too many endorsements pub fn add_endorsements( &mut self, - endorsements: Map, + endorsements: Map, ) -> Result, PoolError> { let mut newly_added = Set::::default(); for (endorsement_id, endorsement) in endorsements.into_iter() { @@ -149,7 +150,7 @@ impl EndorsementPool { pub fn get_endorsement_by_address( &self, address: Address, - ) -> Result, PoolError> { + ) -> Result, PoolError> { let mut res = Map::default(); for (id, ed) in self.endorsements.iter() { if Address::from_public_key(&ed.content.sender_public_key) == address { @@ -162,7 +163,7 @@ impl EndorsementPool { pub fn get_endorsement_by_id( &self, endorsements: Set, - ) -> Map { + ) -> Map { self.endorsements .iter() .filter_map(|(id, ed)| { diff --git a/massa-pool/src/operation_pool.rs b/massa-pool/src/operation_pool.rs index 8983d2228e0..ebc1418b04d 100644 --- a/massa-pool/src/operation_pool.rs +++ b/massa-pool/src/operation_pool.rs @@ -3,8 +3,8 @@ use crate::{settings::PoolConfig, PoolError}; use massa_models::prehash::{Map, Set}; use massa_models::{ - Address, Operation, OperationId, OperationSearchResult, OperationSearchResultStatus, - OperationType, SerializeCompact, Slot, + Address, OperationId, OperationSearchResult, OperationSearchResultStatus, OperationType, + SerializeCompact, SignedOperation, Slot, }; use num::rational::Ratio; use std::{collections::BTreeSet, usize}; @@ -37,13 +37,13 @@ impl OperationIndex { } struct WrappedOperation { - op: Operation, + op: SignedOperation, byte_count: u64, thread: u8, } impl WrappedOperation { - fn new(op: Operation, thread_count: u8) -> Result { + fn new(op: SignedOperation, thread_count: u8) -> Result { Ok(WrappedOperation { byte_count: op.to_bytes_compact()?.len() as u64, thread: Address::from_public_key(&op.content.sender_public_key) @@ -105,7 +105,7 @@ impl OperationPool { /// pub fn add_operations( &mut self, - operations: Map, + operations: Map, ) -> Result, PoolError> { let mut newly_added = Set::::default(); @@ -137,6 +137,7 @@ impl OperationPool { let validity_start_period = *wrapped_op .op + .content .get_validity_range(self.cfg.operation_validity_periods) .start(); @@ -167,7 +168,7 @@ impl OperationPool { // insert let interest = (std::cmp::Reverse(wrapped_op.get_fee_density()), op_id); - let addrs = wrapped_op.op.get_ledger_involved_addresses()?; + let addrs = wrapped_op.op.content.get_ledger_involved_addresses()?; self.ops_by_thread_and_interest[wrapped_op.thread as usize].insert(interest); self.ops.insert(op_id, wrapped_op); @@ -190,7 +191,7 @@ impl OperationPool { .unwrap(); // will not panic because of the while condition. complexity = log or better if let Some(removed_op) = self.ops.remove(&removed_id) { // complexity: const - let addrs = removed_op.op.get_ledger_involved_addresses()?; + let addrs = removed_op.op.content.get_ledger_involved_addresses()?; for addr in addrs { self.ops_by_address .remove_op_for_address(&addr, &removed_id); @@ -211,7 +212,7 @@ impl OperationPool { if let Some(wrapped) = self.ops.remove(id) { self.ops_by_thread_and_interest[wrapped.thread as usize] .remove(&(std::cmp::Reverse(wrapped.get_fee_density()), *id)); - let addrs = wrapped.op.get_ledger_involved_addresses()?; + let addrs = wrapped.op.content.get_ledger_involved_addresses()?; for addr in addrs { self.ops_by_address.remove_op_for_address(&addr, id); } @@ -268,7 +269,7 @@ impl OperationPool { self.ops_by_thread_and_interest[wrapped_op.thread as usize].remove(&interest); // complexity: log - let addrs = wrapped_op.op.get_ledger_involved_addresses()?; + let addrs = wrapped_op.op.content.get_ledger_involved_addresses()?; for addr in addrs { self.ops_by_address.remove_op_for_address(&addr, &op_id); } @@ -285,7 +286,7 @@ impl OperationPool { exclude: Set, batch_size: usize, max_size: u64, - ) -> Result, PoolError> { + ) -> Result, PoolError> { self.ops_by_thread_and_interest[block_slot.thread as usize] .iter() .filter_map(|(_rentability, id)| { @@ -293,10 +294,10 @@ impl OperationPool { return None; } if let Some(w_op) = self.ops.get(id) { - if !w_op.op.get_validity_range(self.cfg.operation_validity_periods) + if !w_op.op.content.get_validity_range(self.cfg.operation_validity_periods) .contains(&block_slot.period) || w_op.byte_count > max_size { - massa_trace!("pool get_operation_batch not added to batch w_op.op.get_validity_range incorrect not added", { - "range": w_op.op.get_validity_range(self.cfg.operation_validity_periods), + massa_trace!("pool get_operation_batch not added to batch w_op.op.content.get_validity_range incorrect not added", { + "range": w_op.op.content.get_validity_range(self.cfg.operation_validity_periods), "block_slot.period": block_slot.period }); return None; @@ -312,7 +313,10 @@ impl OperationPool { .collect() } - pub fn get_operations(&self, operation_ids: &Set) -> Map { + pub fn get_operations( + &self, + operation_ids: &Set, + ) -> Map { operation_ids .iter() .filter_map(|op_id| self.ops.get(op_id).map(|w_op| (*op_id, w_op.op.clone()))) diff --git a/massa-pool/src/pool_controller.rs b/massa-pool/src/pool_controller.rs index 4877aea63ff..48f055ff712 100644 --- a/massa-pool/src/pool_controller.rs +++ b/massa-pool/src/pool_controller.rs @@ -11,8 +11,8 @@ use massa_models::{ constants::CHANNEL_SIZE, prehash::{Map, Set}, stats::PoolStats, - Address, BlockId, Endorsement, EndorsementId, Operation, OperationId, OperationSearchResult, - Slot, + Address, BlockId, EndorsementId, OperationId, OperationSearchResult, SignedEndorsement, + SignedOperation, Slot, }; use massa_protocol_exports::{ProtocolCommandSender, ProtocolPoolEventReceiver}; use tokio::{ @@ -74,7 +74,7 @@ pub struct PoolCommandSender(pub mpsc::Sender); impl PoolCommandSender { pub async fn add_operations( &mut self, - operations: Map, + operations: Map, ) -> Result<(), PoolError> { massa_trace!("pool.command_sender.add_operations", { "ops": operations }); let res = self @@ -147,12 +147,12 @@ impl PoolCommandSender { exclude: Set, batch_size: usize, max_size: u64, - ) -> Result, PoolError> { + ) -> Result, PoolError> { massa_trace!("pool.command_sender.get_operation_batch", { "target_slot": target_slot }); - let (response_tx, response_rx) = oneshot::channel::>(); + let (response_tx, response_rx) = oneshot::channel(); self.0 .send(PoolCommand::GetOperationBatch { target_slot, @@ -179,7 +179,7 @@ impl PoolCommandSender { target_slot: Slot, parent: BlockId, creators: Vec
, - ) -> Result, PoolError> { + ) -> Result, PoolError> { massa_trace!("pool.command_sender.get_endorsements", { "target_slot": target_slot }); @@ -206,7 +206,7 @@ impl PoolCommandSender { pub async fn get_operations( &mut self, operation_ids: Set, - ) -> Result, PoolError> { + ) -> Result, PoolError> { massa_trace!("pool.command_sender.get_operations", { "operation_ids": operation_ids }); @@ -259,7 +259,7 @@ impl PoolCommandSender { pub async fn add_endorsements( &mut self, - endorsements: Map, + endorsements: Map, ) -> Result<(), PoolError> { massa_trace!("pool.command_sender.add_endorsements", { "endorsements": endorsements @@ -275,7 +275,7 @@ impl PoolCommandSender { pub async fn get_endorsements_by_address( &self, address: Address, - ) -> Result, PoolError> { + ) -> Result, PoolError> { massa_trace!("pool.command_sender.get_endorsements_by_address", { "address": address }); @@ -302,7 +302,7 @@ impl PoolCommandSender { pub async fn get_endorsements_by_id( &self, endorsements: Set, - ) -> Result, PoolError> { + ) -> Result, PoolError> { massa_trace!("pool.command_sender.get_endorsements_by_id", { "endorsements": endorsements }); diff --git a/massa-pool/src/pool_worker.rs b/massa-pool/src/pool_worker.rs index a712b78239e..542425ebfe7 100644 --- a/massa-pool/src/pool_worker.rs +++ b/massa-pool/src/pool_worker.rs @@ -6,8 +6,8 @@ use crate::{endorsement_pool::EndorsementPool, settings::PoolConfig}; use massa_models::prehash::{Map, Set}; use massa_models::stats::PoolStats; use massa_models::{ - Address, BlockId, Endorsement, EndorsementId, Operation, OperationId, OperationSearchResult, - Slot, + Address, BlockId, EndorsementId, OperationId, OperationSearchResult, SignedEndorsement, + SignedOperation, Slot, }; use massa_protocol_exports::{ProtocolCommandSender, ProtocolPoolEvent, ProtocolPoolEventReceiver}; use tokio::sync::{mpsc, oneshot}; @@ -16,7 +16,7 @@ use tracing::warn; /// Commands that can be processed by pool. #[derive(Debug)] pub enum PoolCommand { - AddOperations(Map), + AddOperations(Map), UpdateCurrentSlot(Slot), UpdateLatestFinalPeriods(Vec), GetOperationBatch { @@ -24,11 +24,11 @@ pub enum PoolCommand { exclude: Set, batch_size: usize, max_size: u64, - response_tx: oneshot::Sender>, + response_tx: oneshot::Sender>, }, GetOperations { operation_ids: Set, - response_tx: oneshot::Sender>, + response_tx: oneshot::Sender>, }, GetRecentOperations { address: Address, @@ -39,17 +39,17 @@ pub enum PoolCommand { target_slot: Slot, parent: BlockId, creators: Vec
, - response_tx: oneshot::Sender>, + response_tx: oneshot::Sender>, }, - AddEndorsements(Map), + AddEndorsements(Map), GetStats(oneshot::Sender), GetEndorsementsByAddress { address: Address, - response_tx: oneshot::Sender>, + response_tx: oneshot::Sender>, }, GetEndorsementsById { endorsements: Set, - response_tx: oneshot::Sender>, + response_tx: oneshot::Sender>, }, } diff --git a/massa-pool/src/tests/mock_protocol_controller.rs b/massa-pool/src/tests/mock_protocol_controller.rs index fe58b9a43a0..5677f10df64 100644 --- a/massa-pool/src/tests/mock_protocol_controller.rs +++ b/massa-pool/src/tests/mock_protocol_controller.rs @@ -1,7 +1,8 @@ // Copyright (c) 2022 MASSA LABS use massa_models::prehash::Map; -use massa_models::{constants::CHANNEL_SIZE, Endorsement, EndorsementId, Operation, OperationId}; +use massa_models::{constants::CHANNEL_SIZE, EndorsementId, OperationId}; +use massa_models::{SignedEndorsement, SignedOperation}; use massa_protocol_exports::{ ProtocolCommand, ProtocolCommandSender, ProtocolPoolEvent, ProtocolPoolEventReceiver, }; @@ -45,7 +46,7 @@ impl MockProtocolController { } } - pub async fn received_operations(&mut self, operations: Map) { + pub async fn received_operations(&mut self, operations: Map) { self.pool_event_tx .send(ProtocolPoolEvent::ReceivedOperations { operations, @@ -55,7 +56,10 @@ impl MockProtocolController { .expect("could not send protocol pool event"); } - pub async fn received_endorsements(&mut self, endorsements: Map) { + pub async fn received_endorsements( + &mut self, + endorsements: Map, + ) { self.pool_event_tx .send(ProtocolPoolEvent::ReceivedEndorsements { endorsements, diff --git a/massa-pool/src/tests/operation_pool_tests.rs b/massa-pool/src/tests/operation_pool_tests.rs index 31b7113bd16..6f47a437d6c 100644 --- a/massa-pool/src/tests/operation_pool_tests.rs +++ b/massa-pool/src/tests/operation_pool_tests.rs @@ -1,10 +1,10 @@ -use massa_hash::hash::Hash; use massa_models::{ prehash::{Map, Set}, - Address, Amount, Operation, OperationContent, OperationId, OperationType, SerializeCompact, + signed::Signed, + Address, Amount, Operation, OperationId, OperationType, SerializeCompact, SignedOperation, Slot, }; -use massa_signature::{derive_public_key, generate_random_private_key, sign}; +use massa_signature::{derive_public_key, generate_random_private_key}; use serial_test::serial; use std::str::FromStr; @@ -12,7 +12,7 @@ use crate::operation_pool::OperationPool; use super::settings::POOL_CONFIG; -fn get_transaction(expire_period: u64, fee: u64) -> (Operation, u8) { +fn get_transaction(expire_period: u64, fee: u64) -> (SignedOperation, u8) { let sender_priv = generate_random_private_key(); let sender_pub = derive_public_key(&sender_priv); @@ -23,17 +23,14 @@ fn get_transaction(expire_period: u64, fee: u64) -> (Operation, u8) { recipient_address: Address::from_public_key(&recv_pub), amount: Amount::default(), }; - let content = OperationContent { + let content = Operation { fee: Amount::from_str(&fee.to_string()).unwrap(), op, sender_public_key: sender_pub, expire_period, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - ( - Operation { content, signature }, + Signed::new_signed(content, &sender_priv).unwrap().1, Address::from_public_key(&sender_pub).get_thread(2), ) } diff --git a/massa-pool/src/tests/scenario.rs b/massa-pool/src/tests/scenario.rs index 9f2278c7070..1373669b8a4 100644 --- a/massa-pool/src/tests/scenario.rs +++ b/massa-pool/src/tests/scenario.rs @@ -4,11 +4,10 @@ use super::{settings::POOL_CONFIG, tools::get_transaction}; use crate::tests::tools::create_executesc; use crate::tests::tools::{self, get_transaction_with_addresses, pool_test}; use massa_models::prehash::{Map, Set}; -use massa_models::Address; -use massa_models::Operation; +use massa_models::signed::Signable; use massa_models::OperationId; -use massa_models::SerializeCompact; -use massa_models::Slot; +use massa_models::{Address, SerializeCompact}; +use massa_models::{SignedOperation, Slot}; use massa_protocol_exports::ProtocolCommand; use massa_signature::{derive_public_key, generate_random_private_key}; use serial_test::serial; @@ -393,7 +392,7 @@ async fn test_pool_propagate_newly_added_endorsements() { let target_slot = Slot::new(10, 0); let endorsement = tools::create_endorsement(target_slot); let mut endorsements = Map::default(); - let id = endorsement.compute_endorsement_id().unwrap(); + let id = endorsement.content.compute_id().unwrap(); endorsements.insert(id, endorsement.clone()); protocol_controller @@ -434,7 +433,7 @@ async fn test_pool_propagate_newly_added_endorsements() { .await .unwrap(); assert_eq!(res.len(), 1); - assert_eq!(res[0].0, endorsement.compute_endorsement_id().unwrap()); + assert_eq!(res[0].0, endorsement.content.compute_id().unwrap()); (protocol_controller, pool_command_sender, pool_manager) }, ) @@ -454,7 +453,7 @@ async fn test_pool_add_old_endorsements() { let endorsement = tools::create_endorsement(Slot::new(1, 0)); let mut endorsements = Map::default(); - let id = endorsement.compute_endorsement_id().unwrap(); + let id = endorsement.content.compute_id().unwrap(); endorsements.insert(id, endorsement.clone()); pool_command_sender @@ -520,9 +519,9 @@ async fn test_get_involved_operations() { let (op1, _) = get_transaction_with_addresses(1, 1, pubkey_a, priv_a, pubkey_b); let (op2, _) = get_transaction_with_addresses(2, 10, pubkey_b, priv_b, pubkey_b); let (op3, _) = get_transaction_with_addresses(3, 100, pubkey_a, priv_a, pubkey_a); - let op1_id = op1.get_operation_id().unwrap(); - let op2_id = op2.get_operation_id().unwrap(); - let op3_id = op3.get_operation_id().unwrap(); + let op1_id = op1.content.compute_id().unwrap(); + let op2_id = op2.content.compute_id().unwrap(); + let op3_id = op3.content.compute_id().unwrap(); let mut ops = Map::default(); for (op, id) in vec![op1, op2, op3] .into_iter() @@ -664,10 +663,10 @@ async fn test_new_final_ops() { _ => None, }; - let mut ops: Vec<(OperationId, Operation)> = Vec::new(); + let mut ops: Vec<(OperationId, SignedOperation)> = Vec::new(); for i in 0..10 { let (op, _) = get_transaction_with_addresses(8, i, pubkey_a, priv_a, pubkey_b); - ops.push((op.get_operation_id().unwrap(), op)); + ops.push((op.content.compute_id().unwrap(), op)); } // Add ops to pool diff --git a/massa-pool/src/tests/tools.rs b/massa-pool/src/tests/tools.rs index 677b44d8ebd..7a36eab2aac 100644 --- a/massa-pool/src/tests/tools.rs +++ b/massa-pool/src/tests/tools.rs @@ -5,12 +5,10 @@ use crate::{pool_controller, settings::PoolConfig, PoolCommandSender, PoolManage use futures::Future; use massa_hash::hash::Hash; use massa_models::{ - Address, Amount, BlockId, Endorsement, EndorsementContent, Operation, OperationContent, - OperationType, SerializeCompact, Slot, -}; -use massa_signature::{ - derive_public_key, generate_random_private_key, sign, PrivateKey, PublicKey, + signed::Signed, Address, Amount, BlockId, Endorsement, Operation, OperationType, + SignedEndorsement, SignedOperation, Slot, }; +use massa_signature::{derive_public_key, generate_random_private_key, PrivateKey, PublicKey}; use std::str::FromStr; pub async fn pool_test(cfg: &'static PoolConfig, test: F) @@ -35,7 +33,7 @@ where pool_manager.stop().await.unwrap(); } -pub fn get_transaction(expire_period: u64, fee: u64) -> (Operation, u8) { +pub fn get_transaction(expire_period: u64, fee: u64) -> (SignedOperation, u8) { let sender_priv = generate_random_private_key(); let sender_pub = derive_public_key(&sender_priv); @@ -46,35 +44,30 @@ pub fn get_transaction(expire_period: u64, fee: u64) -> (Operation, u8) { recipient_address: Address::from_public_key(&recv_pub), amount: Amount::default(), }; - let content = OperationContent { + let content = Operation { fee: Amount::from_str(&fee.to_string()).unwrap(), op, sender_public_key: sender_pub, expire_period, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - ( - Operation { content, signature }, + Signed::new_signed(content, &sender_priv).unwrap().1, Address::from_public_key(&sender_pub).get_thread(2), ) } /// Creates an endorsement for use in pool tests. -pub fn create_endorsement(slot: Slot) -> Endorsement { +pub fn create_endorsement(slot: Slot) -> SignedEndorsement { let sender_priv = generate_random_private_key(); let sender_public_key = derive_public_key(&sender_priv); - let content = EndorsementContent { + let content = Endorsement { sender_public_key, slot, index: 0, endorsed_block: BlockId(Hash::compute_from("blabla".as_bytes())), }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - Endorsement { content, signature } + Signed::new_signed(content, &sender_priv).unwrap().1 } pub fn get_transaction_with_addresses( @@ -83,22 +76,19 @@ pub fn get_transaction_with_addresses( sender_pub: PublicKey, sender_priv: PrivateKey, recv_pub: PublicKey, -) -> (Operation, u8) { +) -> (SignedOperation, u8) { let op = OperationType::Transaction { recipient_address: Address::from_public_key(&recv_pub), amount: Amount::default(), }; - let content = OperationContent { + let content = Operation { fee: Amount::from_str(&fee.to_string()).unwrap(), op, sender_public_key: sender_pub, expire_period, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - ( - Operation { content, signature }, + Signed::new_signed(content, &sender_priv).unwrap().1, Address::from_public_key(&sender_pub).get_thread(2), ) } @@ -108,12 +98,12 @@ pub fn create_executesc( fee: u64, max_gas: u64, gas_price: u64, -) -> (Operation, u8) { +) -> (SignedOperation, u8) { let priv_key = generate_random_private_key(); let sender_public_key = derive_public_key(&priv_key); let data = vec![42; 7]; - let coins = 0; + let coins = 0_u64; let op = OperationType::ExecuteSC { data, @@ -122,16 +112,15 @@ pub fn create_executesc( gas_price: Amount::from_str(&gas_price.to_string()).unwrap(), }; - let content = OperationContent { + let content = Operation { sender_public_key, fee: Amount::from_str(&fee.to_string()).unwrap(), expire_period, op, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &priv_key).unwrap(); + ( - Operation { content, signature }, + Signed::new_signed(content, &priv_key).unwrap().1, Address::from_public_key(&sender_public_key).get_thread(2), ) } diff --git a/massa-proof-of-stake-exports/src/lib.rs b/massa-proof-of-stake-exports/src/lib.rs index f6249e6660b..6969cfed5aa 100644 --- a/massa-proof-of-stake-exports/src/lib.rs +++ b/massa-proof-of-stake-exports/src/lib.rs @@ -29,11 +29,11 @@ pub trait OperationRollInterface { impl OperationRollInterface for Operation { fn get_roll_updates(&self) -> Result { let mut res = RollUpdates::default(); - match self.content.op { + match self.op { OperationType::Transaction { .. } => {} OperationType::RollBuy { roll_count } => { res.apply( - &Address::from_public_key(&self.content.sender_public_key), + &Address::from_public_key(&self.sender_public_key), &RollUpdate { roll_purchases: roll_count, roll_sales: 0, @@ -42,7 +42,7 @@ impl OperationRollInterface for Operation { } OperationType::RollSell { roll_count } => { res.apply( - &Address::from_public_key(&self.content.sender_public_key), + &Address::from_public_key(&self.sender_public_key), &RollUpdate { roll_purchases: 0, roll_sales: roll_count, diff --git a/massa-protocol-exports/Cargo.toml b/massa-protocol-exports/Cargo.toml index a1f161186a8..092e343c5ab 100644 --- a/massa-protocol-exports/Cargo.toml +++ b/massa-protocol-exports/Cargo.toml @@ -22,7 +22,7 @@ tracing = "0.1" massa_hash = { path = "../massa-hash" } massa_logging = { path = "../massa-logging" } massa_models = { path = "../massa-models" } -massa_network = { path = "../massa-network" } +massa_network_exports = { path = "../massa-network-exports" } massa_signature = { path = "../massa-signature" } massa_time = { path = "../massa-time" } @@ -32,4 +32,4 @@ serial_test = "0.5" tempfile = "3.2" [features] -instrument = ["tokio/tracing", "massa_models/instrument", "massa_network/instrument", "massa_time/instrument"] +instrument = ["tokio/tracing", "massa_models/instrument", "massa_network_exports/instrument", "massa_time/instrument"] diff --git a/massa-protocol-exports/src/error.rs b/massa-protocol-exports/src/error.rs index ea62012ea88..90b652dd702 100644 --- a/massa-protocol-exports/src/error.rs +++ b/massa-protocol-exports/src/error.rs @@ -3,8 +3,8 @@ use crate::ProtocolEvent; use displaydoc::Display; use massa_models::ModelsError; -use massa_network::ConnectionId; -use massa_network::NetworkError; +use massa_network_exports::ConnectionId; +use massa_network_exports::NetworkError; use std::net::IpAddr; use thiserror::Error; diff --git a/massa-protocol-exports/src/protocol_controller.rs b/massa-protocol-exports/src/protocol_controller.rs index b31e0a2dd66..09d6fa41f64 100644 --- a/massa-protocol-exports/src/protocol_controller.rs +++ b/massa-protocol-exports/src/protocol_controller.rs @@ -4,10 +4,11 @@ use crate::error::ProtocolError; use massa_logging::massa_trace; use massa_models::prehash::{Map, Set}; + use massa_models::{ - Block, BlockHeader, BlockId, Endorsement, EndorsementId, Operation, OperationId, + Block, BlockId, EndorsementId, OperationId, SignedEndorsement, SignedHeader, SignedOperation, }; -use massa_network::NetworkEventReceiver; +use massa_network_exports::NetworkEventReceiver; use serde::Serialize; use std::collections::VecDeque; use tokio::{sync::mpsc, task::JoinHandle}; @@ -26,7 +27,7 @@ pub enum ProtocolEvent { /// A block header with a valid signature has been received. ReceivedBlockHeader { block_id: BlockId, - header: BlockHeader, + header: SignedHeader, }, /// Ask for a list of blocks from consensus. GetBlocks(Vec), @@ -36,12 +37,12 @@ pub enum ProtocolEvent { pub enum ProtocolPoolEvent { /// Operations were received ReceivedOperations { - operations: Map, + operations: Map, propagate: bool, // whether or not to propagate operations }, /// Endorsements were received ReceivedEndorsements { - endorsements: Map, + endorsements: Map, propagate: bool, // whether or not to propagate endorsements }, } @@ -69,9 +70,9 @@ pub enum ProtocolCommand { /// The response to a ProtocolEvent::GetBlocks. GetBlocksResults(BlocksResults), /// Propagate operations - PropagateOperations(Map), + PropagateOperations(Map), /// Propagate endorsements - PropagateEndorsements(Map), + PropagateEndorsements(Map), } #[derive(Debug, Serialize)] @@ -157,7 +158,7 @@ impl ProtocolCommandSender { pub async fn propagate_operations( &mut self, - operations: Map, + operations: Map, ) -> Result<(), ProtocolError> { massa_trace!("protocol.command_sender.propagate_operations", { "operations": operations @@ -174,7 +175,7 @@ impl ProtocolCommandSender { pub async fn propagate_endorsements( &mut self, - endorsements: Map, + endorsements: Map, ) -> Result<(), ProtocolError> { massa_trace!("protocol.command_sender.propagate_endorsements", { "endorsements": endorsements diff --git a/massa-protocol-exports/src/tests/mock_network_controller.rs b/massa-protocol-exports/src/tests/mock_network_controller.rs index ed55a672f81..41ed1132224 100644 --- a/massa-protocol-exports/src/tests/mock_network_controller.rs +++ b/massa-protocol-exports/src/tests/mock_network_controller.rs @@ -1,8 +1,10 @@ // Copyright (c) 2022 MASSA LABS use massa_models::{constants::CHANNEL_SIZE, node::NodeId}; -use massa_models::{Block, BlockHeader, BlockId, Endorsement, Operation}; -use massa_network::{NetworkCommand, NetworkCommandSender, NetworkEvent, NetworkEventReceiver}; +use massa_models::{Block, BlockId, SignedEndorsement, SignedHeader, SignedOperation}; +use massa_network_exports::{ + NetworkCommand, NetworkCommandSender, NetworkEvent, NetworkEventReceiver, +}; use massa_time::MassaTime; use tokio::{sync::mpsc, time::sleep}; @@ -57,7 +59,7 @@ impl MockNetworkController { .expect("Couldn't connect node to protocol."); } - pub async fn send_header(&mut self, source_node_id: NodeId, header: BlockHeader) { + pub async fn send_header(&mut self, source_node_id: NodeId, header: SignedHeader) { self.network_event_tx .send(NetworkEvent::ReceivedBlockHeader { source_node_id, @@ -77,7 +79,11 @@ impl MockNetworkController { .expect("Couldn't send block to protocol."); } - pub async fn send_operations(&mut self, source_node_id: NodeId, operations: Vec) { + pub async fn send_operations( + &mut self, + source_node_id: NodeId, + operations: Vec, + ) { self.network_event_tx .send(NetworkEvent::ReceivedOperations { node: source_node_id, @@ -90,7 +96,7 @@ impl MockNetworkController { pub async fn send_endorsements( &mut self, source_node_id: NodeId, - endorsements: Vec, + endorsements: Vec, ) { self.network_event_tx .send(NetworkEvent::ReceivedEndorsements { diff --git a/massa-protocol-exports/src/tests/tools.rs b/massa-protocol-exports/src/tests/tools.rs index f7c5d4703c0..0666eaff3ee 100644 --- a/massa-protocol-exports/src/tests/tools.rs +++ b/massa-protocol-exports/src/tests/tools.rs @@ -7,14 +7,13 @@ use crate::{ }; use massa_hash::hash::Hash; use massa_models::node::NodeId; +use massa_models::signed::{Signable, Signed}; use massa_models::{ - Address, Amount, Block, BlockHeader, BlockHeaderContent, BlockId, SerializeCompact, Slot, -}; -use massa_models::{Endorsement, EndorsementContent, Operation, OperationContent, OperationType}; -use massa_network::NetworkCommand; -use massa_signature::{ - derive_public_key, generate_random_private_key, sign, PrivateKey, PublicKey, + Address, Amount, Block, BlockHeader, BlockId, SignedEndorsement, SignedOperation, Slot, }; +use massa_models::{Endorsement, Operation, OperationType}; +use massa_network_exports::NetworkCommand; +use massa_signature::{derive_public_key, generate_random_private_key, PrivateKey, PublicKey}; use massa_time::MassaTime; use std::collections::HashMap; use tokio::time::sleep; @@ -49,9 +48,8 @@ pub async fn create_and_connect_nodes( /// without paying attention to consensus related things /// like slot, parents, and merkle root. pub fn create_block(private_key: &PrivateKey, public_key: &PublicKey) -> Block { - let (_, header) = BlockHeader::new_signed( - private_key, - BlockHeaderContent { + let (_, header) = Signed::new_signed( + BlockHeader { creator: *public_key, slot: Slot::new(1, 0), parents: vec![ @@ -61,6 +59,7 @@ pub fn create_block(private_key: &PrivateKey, public_key: &PublicKey) -> Block { operation_merkle_root: Hash::compute_from(&Vec::new()), endorsements: Vec::new(), }, + private_key, ) .unwrap(); @@ -74,16 +73,15 @@ pub fn create_block_with_operations( private_key: &PrivateKey, public_key: &PublicKey, slot: Slot, - operations: Vec, + operations: Vec, ) -> Block { let operation_merkle_root = Hash::compute_from( &operations.iter().fold(Vec::new(), |acc, v| { - [acc, v.get_operation_id().unwrap().to_bytes().to_vec()].concat() + [acc, v.content.compute_id().unwrap().to_bytes().to_vec()].concat() })[..], ); - let (_, header) = BlockHeader::new_signed( - private_key, - BlockHeaderContent { + let (_, header) = Signed::new_signed( + BlockHeader { creator: *public_key, slot, parents: vec![ @@ -93,6 +91,7 @@ pub fn create_block_with_operations( operation_merkle_root, endorsements: Vec::new(), }, + private_key, ) .unwrap(); @@ -103,11 +102,10 @@ pub fn create_block_with_endorsements( private_key: &PrivateKey, public_key: &PublicKey, slot: Slot, - endorsements: Vec, + endorsements: Vec, ) -> Block { - let (_, header) = BlockHeader::new_signed( - private_key, - BlockHeaderContent { + let (_, header) = Signed::new_signed( + BlockHeader { creator: *public_key, slot, parents: vec![ @@ -117,6 +115,7 @@ pub fn create_block_with_endorsements( operation_merkle_root: Hash::compute_from(&Vec::new()), endorsements, }, + private_key, ) .unwrap(); @@ -133,7 +132,7 @@ pub async fn send_and_propagate_block( source_node_id: NodeId, protocol_event_receiver: &mut ProtocolEventReceiver, ) { - let expected_hash = block.header.compute_block_id().unwrap(); + let expected_hash = block.header.content.compute_id().unwrap(); // Send block to protocol. network_controller.send_block(source_node_id, block).await; @@ -161,26 +160,24 @@ pub async fn send_and_propagate_block( /// Creates an endorsement for use in protocol tests, /// without paying attention to consensus related things. -pub fn create_endorsement() -> Endorsement { +pub fn create_endorsement() -> SignedEndorsement { let sender_priv = generate_random_private_key(); let sender_public_key = derive_public_key(&sender_priv); - let content = EndorsementContent { + let content = Endorsement { sender_public_key, slot: Slot::new(10, 1), index: 0, endorsed_block: BlockId(Hash::compute_from(&[])), }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, &sender_priv).unwrap(); - Endorsement { content, signature } + Signed::new_signed(content, &sender_priv).unwrap().1 } // Create an operation, from a specific sender, and with a specific expire period. pub fn create_operation_with_expire_period( sender_priv: &PrivateKey, expire_period: u64, -) -> Operation { +) -> SignedOperation { let sender_pub = derive_public_key(sender_priv); let recv_priv = generate_random_private_key(); @@ -190,16 +187,13 @@ pub fn create_operation_with_expire_period( recipient_address: Address::from_public_key(&recv_pub), amount: Amount::default(), }; - let content = OperationContent { + let content = Operation { fee: Amount::default(), op, sender_public_key: sender_pub, expire_period, }; - let hash = Hash::compute_from(&content.to_bytes_compact().unwrap()); - let signature = sign(&hash, sender_priv).unwrap(); - - Operation { content, signature } + Signed::new_signed(content, sender_priv).unwrap().1 } lazy_static::lazy_static! { diff --git a/massa-protocol-worker/Cargo.toml b/massa-protocol-worker/Cargo.toml index 2e37f3811ee..5a59b14bd04 100644 --- a/massa-protocol-worker/Cargo.toml +++ b/massa-protocol-worker/Cargo.toml @@ -22,7 +22,7 @@ tracing = "0.1" massa_hash = { path = "../massa-hash" } massa_logging = { path = "../massa-logging" } massa_models = { path = "../massa-models" } -massa_network = { path = "../massa-network" } +massa_network_exports = { path = "../massa-network-exports" } massa_protocol_exports = { path = "../massa-protocol-exports" } massa_signature = { path = "../massa-signature" } massa_time = { path = "../massa-time" } @@ -33,4 +33,4 @@ serial_test = "0.5" tempfile = "3.2" [features] -instrument = ["tokio/tracing", "massa_models/instrument", "massa_network/instrument", "massa_protocol_exports/instrument", "massa_time/instrument"] +instrument = ["tokio/tracing", "massa_models/instrument", "massa_network_exports/instrument", "massa_protocol_exports/instrument", "massa_time/instrument"] diff --git a/massa-protocol-worker/src/protocol_worker.rs b/massa-protocol-worker/src/protocol_worker.rs index 308fd1683ba..22f30c3e5f1 100644 --- a/massa-protocol-worker/src/protocol_worker.rs +++ b/massa-protocol-worker/src/protocol_worker.rs @@ -7,10 +7,11 @@ use massa_models::{ constants::CHANNEL_SIZE, node::NodeId, prehash::{BuildMap, Map, Set}, - Address, Block, BlockHeader, BlockId, Endorsement, EndorsementId, Operation, OperationId, - OperationType, + signed::Signable, + Address, Block, BlockId, EndorsementId, OperationId, OperationType, SignedEndorsement, + SignedHeader, SignedOperation, }; -use massa_network::{NetworkCommandSender, NetworkEvent, NetworkEventReceiver}; +use massa_network_exports::{NetworkCommandSender, NetworkEvent, NetworkEventReceiver}; use massa_protocol_exports::{ ProtocolCommand, ProtocolCommandSender, ProtocolError, ProtocolEvent, ProtocolEventReceiver, ProtocolManagementCommand, ProtocolManager, ProtocolPoolEvent, ProtocolPoolEventReceiver, @@ -659,7 +660,7 @@ impl ProtocolWorker { { "operations": ops } ); for (node, node_info) in self.active_nodes.iter_mut() { - let new_ops: Map = ops + let new_ops: Map = ops .iter() .filter(|(id, _)| !node_info.knows_op(*id)) .map(|(k, v)| (*k, v.clone())) @@ -682,7 +683,7 @@ impl ProtocolWorker { { "endorsements": endorsements } ); for (node, node_info) in self.active_nodes.iter_mut() { - let new_endorsements: Map = endorsements + let new_endorsements: Map = endorsements .iter() .filter(|(id, _)| !node_info.knows_endorsement(*id)) .map(|(k, v)| (*k, v.clone())) @@ -937,7 +938,7 @@ impl ProtocolWorker { /// - Block matches that of the block. async fn note_header_from_node( &mut self, - header: &BlockHeader, + header: &SignedHeader, source_node_id: &NodeId, ) -> Result, bool)>, ProtocolError> { massa_trace!("protocol.protocol_worker.note_header_from_node", { "node": source_node_id, "header": header }); @@ -958,7 +959,7 @@ impl ProtocolWorker { } // compute ID - let block_id = match header.compute_block_id() { + let block_id = match header.content.compute_id() { Ok(id) => id, Err(err) => { massa_trace!("protocol.protocol_worker.check_header.err_id", { "header": header, "err": format!("{}", err)}); @@ -1020,7 +1021,7 @@ impl ProtocolWorker { } // check header signature - if let Err(err) = header.check_signature() { + if let Err(err) = header.verify_signature(&header.content.creator) { massa_trace!("protocol.protocol_worker.check_header.err_signature", { "header": header, "err": format!("{}", err)}); return Ok(None); }; @@ -1161,6 +1162,7 @@ impl ProtocolWorker { for op in block.operations.iter() { // check validity period if !(op + .content .get_validity_range(self.operation_validity_periods) .contains(&block.header.content.slot.period)) { @@ -1219,7 +1221,7 @@ impl ProtocolWorker { /// - Valid signature async fn note_operations_from_node( &mut self, - operations: Vec, + operations: Vec, source_node_id: &NodeId, propagate: bool, ) -> Result<(Vec, Map, bool, u64), ProtocolError> { @@ -1231,7 +1233,7 @@ impl ProtocolWorker { let mut new_operations = Map::with_capacity_and_hasher(length, BuildMap::default()); let mut received_ids = Map::with_capacity_and_hasher(length, BuildMap::default()); for (idx, operation) in operations.into_iter().enumerate() { - let operation_id = operation.get_operation_id()?; + let operation_id = operation.content.compute_id()?; seen_ops.push(operation_id); // Note: we always want to update the node's view of known operations, @@ -1252,7 +1254,7 @@ impl ProtocolWorker { // Check operation signature only if not already checked. if self.checked_operations.insert(operation_id) { // check signature - operation.verify_signature()?; + operation.verify_signature(&operation.content.sender_public_key)?; new_operations.insert(operation_id, operation); }; } @@ -1291,7 +1293,7 @@ impl ProtocolWorker { /// - Valid signature. async fn note_endorsements_from_node( &mut self, - endorsements: Vec, + endorsements: Vec, source_node_id: &NodeId, propagate: bool, ) -> Result<(Map, bool), ProtocolError> { @@ -1302,7 +1304,7 @@ impl ProtocolWorker { let mut new_endorsements = Map::with_capacity_and_hasher(length, BuildMap::default()); let mut endorsement_ids = Map::default(); for endorsement in endorsements.into_iter() { - let endorsement_id = endorsement.compute_endorsement_id()?; + let endorsement_id = endorsement.content.compute_id()?; if endorsement_ids .insert(endorsement_id, endorsement.content.index) .is_some() @@ -1311,7 +1313,7 @@ impl ProtocolWorker { } // check endorsement signature if not already checked if self.checked_endorsements.insert(endorsement_id) { - endorsement.verify_signature()?; + endorsement.verify_signature(&endorsement.content.sender_public_key)?; new_endorsements.insert(endorsement_id, endorsement); } } diff --git a/massa-protocol-worker/src/tests/ask_block_scenarios.rs b/massa-protocol-worker/src/tests/ask_block_scenarios.rs index 495412c8138..20e0731ed23 100644 --- a/massa-protocol-worker/src/tests/ask_block_scenarios.rs +++ b/massa-protocol-worker/src/tests/ask_block_scenarios.rs @@ -2,8 +2,9 @@ use super::tools::protocol_test; use massa_models::prehash::Set; +use massa_models::signed::Signable; use massa_models::BlockId; -use massa_network::NetworkCommand; +use massa_network_exports::NetworkCommand; use massa_protocol_exports::tests::tools; use massa_protocol_exports::tests::tools::{asked_list, assert_hash_asked_to_node}; use massa_protocol_exports::ProtocolEvent; @@ -37,7 +38,7 @@ async fn test_without_a_priori() { // 2. Create a block coming from node 0. let block = tools::create_block(&node_a.private_key, &node_a.id.0); - let hash_1 = block.header.compute_block_id().unwrap(); + let hash_1 = block.header.content.compute_id().unwrap(); // end set up // send wishlist @@ -109,7 +110,7 @@ async fn test_someone_knows_it() { // 2. Create a block coming from node 0. let block = tools::create_block(&node_a.private_key, &node_a.id.0); - let hash_1 = block.header.compute_block_id().unwrap(); + let hash_1 = block.header.content.compute_id().unwrap(); // end set up // node c must know about block @@ -189,7 +190,7 @@ async fn test_dont_want_it_anymore() { // 2. Create a block coming from node 0. let block = tools::create_block(&node_a.private_key, &node_a.id.0); - let hash_1 = block.header.compute_block_id().unwrap(); + let hash_1 = block.header.content.compute_id().unwrap(); // end set up // send wishlist @@ -267,7 +268,7 @@ async fn test_no_one_has_it() { // 2. Create a block coming from node 0. let block = tools::create_block(&node_a.private_key, &node_a.id.0); - let hash_1 = block.header.compute_block_id().unwrap(); + let hash_1 = block.header.content.compute_id().unwrap(); // end set up // send wishlist @@ -346,10 +347,10 @@ async fn test_multiple_blocks_without_a_priori() { // 2. Create two blocks coming from node 0. let block_1 = tools::create_block(&node_a.private_key, &node_a.id.0); - let hash_1 = block_1.header.compute_block_id().unwrap(); + let hash_1 = block_1.header.content.compute_id().unwrap(); let block_2 = tools::create_block(&node_a.private_key, &node_a.id.0); - let hash_2 = block_2.header.compute_block_id().unwrap(); + let hash_2 = block_2.header.content.compute_id().unwrap(); // node a is disconnected so no node knows about wanted blocks network_controller.close_connection(node_a.id).await; diff --git a/massa-protocol-worker/src/tests/ban_nodes_scenarios.rs b/massa-protocol-worker/src/tests/ban_nodes_scenarios.rs index da862532435..9b41b05a432 100644 --- a/massa-protocol-worker/src/tests/ban_nodes_scenarios.rs +++ b/massa-protocol-worker/src/tests/ban_nodes_scenarios.rs @@ -2,8 +2,9 @@ use super::tools::protocol_test; use massa_models::prehash::{Map, Set}; +use massa_models::signed::Signable; use massa_models::{BlockId, Slot}; -use massa_network::NetworkCommand; +use massa_network_exports::NetworkCommand; use massa_protocol_exports::tests::tools; use massa_protocol_exports::ProtocolEvent; use massa_protocol_exports::ProtocolPoolEvent; @@ -249,7 +250,8 @@ async fn test_protocol_does_not_asks_for_block_from_banned_node_who_propagated_h // 3. Check that protocol sent the right header to consensus. let expected_hash = block .header - .compute_block_id() + .content + .compute_id() .expect("Failed to compute hash."); assert_eq!(expected_hash, received_hash); @@ -320,7 +322,8 @@ async fn test_protocol_does_not_send_blocks_when_asked_for_by_banned_node() { let expected_hash = block .header - .compute_block_id() + .content + .compute_id() .expect("Failed to compute hash."); // 3. Simulate two nodes asking for a block. @@ -377,7 +380,8 @@ async fn test_protocol_does_not_send_blocks_when_asked_for_by_banned_node() { Some(NetworkCommand::SendBlock { node, block }) => { let hash = block .header - .compute_block_id() + .content + .compute_id() .expect("Failed to compute hash."); assert_eq!(expected_hash, hash); assert!(expecting_block.remove(&node)); @@ -433,7 +437,8 @@ async fn test_protocol_bans_all_nodes_propagating_an_attack_attempt() { let expected_hash = block .header - .compute_block_id() + .content + .compute_id() .expect("Failed to compute hash."); // Propagate the block via 4 nodes. @@ -576,7 +581,8 @@ async fn test_protocol_removes_banned_node_on_disconnection() { // Check that protocol sent the right header to consensus. let expected_hash = block .header - .compute_block_id() + .content + .compute_id() .expect("Failed to compute hash."); assert_eq!(expected_hash, received_hash); ( diff --git a/massa-protocol-worker/src/tests/endorsements_scenarios.rs b/massa-protocol-worker/src/tests/endorsements_scenarios.rs index fdc40548c11..11cf35183f6 100644 --- a/massa-protocol-worker/src/tests/endorsements_scenarios.rs +++ b/massa-protocol-worker/src/tests/endorsements_scenarios.rs @@ -4,8 +4,9 @@ use super::tools::protocol_test; use massa_models::prehash::Map; +use massa_models::signed::Signable; use massa_models::{Address, Slot}; -use massa_network::NetworkCommand; +use massa_network_exports::NetworkCommand; use massa_protocol_exports::tests::tools; use massa_protocol_exports::{ProtocolEvent, ProtocolPoolEvent}; use serial_test::serial; @@ -30,7 +31,7 @@ async fn test_protocol_sends_valid_endorsements_it_receives_to_pool() { // 1. Create an endorsement let endorsement = tools::create_endorsement(); - let expected_endorsement_id = endorsement.compute_endorsement_id().unwrap(); + let expected_endorsement_id = endorsement.content.compute_id().unwrap(); // 3. Send endorsement to protocol. network_controller @@ -155,7 +156,7 @@ async fn test_protocol_propagates_endorsements_to_active_nodes() { _ => panic!("Unexpected or no protocol pool event."), }; - let expected_endorsement_id = endorsement.compute_endorsement_id().unwrap(); + let expected_endorsement_id = endorsement.content.compute_id().unwrap(); let mut ends = Map::default(); ends.insert(expected_endorsement_id, endorsement); @@ -173,7 +174,7 @@ async fn test_protocol_propagates_endorsements_to_active_nodes() { .await { Some(NetworkCommand::SendEndorsements { node, endorsements }) => { - let id = endorsements[0].compute_endorsement_id().unwrap(); + let id = endorsements[0].content.compute_id().unwrap(); assert_eq!(id, expected_endorsement_id); assert_eq!(nodes[1].id, node); break; @@ -235,7 +236,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou // wait for things to settle tokio::time::sleep(Duration::from_millis(250)).await; - let expected_endorsement_id = endorsement.compute_endorsement_id().unwrap(); + let expected_endorsement_id = endorsement.content.compute_id().unwrap(); // send the endorsement to protocol // it should propagate it to nodes that don't know about it @@ -255,7 +256,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou .await { Some(NetworkCommand::SendEndorsements { node, endorsements }) => { - let id = endorsements[0].compute_endorsement_id().unwrap(); + let id = endorsements[0].content.compute_id().unwrap(); assert_eq!(id, expected_endorsement_id); assert_eq!(new_nodes[0].id, node); break; @@ -296,7 +297,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou let thread = address.get_thread(serialization_context.thread_count); let endorsement = tools::create_endorsement(); - let endorsement_id = endorsement.compute_endorsement_id().unwrap(); + let endorsement_id = endorsement.content.compute_id().unwrap(); let block = tools::create_block_with_endorsements( &nodes[0].private_key, @@ -304,7 +305,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou Slot::new(1, thread), vec![endorsement.clone()], ); - let block_id = block.header.compute_block_id().unwrap(); + let block_id = block.header.content.compute_id().unwrap(); network_controller .send_ask_for_block(nodes[0].id, vec![block_id]) @@ -336,7 +337,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou { Some(NetworkCommand::SendBlock { node, block }) => { assert_eq!(node, nodes[0].id); - assert_eq!(block.header.compute_block_id().unwrap(), block_id); + assert_eq!(block.header.content.compute_id().unwrap(), block_id); } Some(_) => panic!("Unexpected network command.."), None => panic!("Block not sent."), @@ -360,7 +361,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou .await { Some(NetworkCommand::SendEndorsements { node, endorsements }) => { - let id = endorsements[0].compute_endorsement_id().unwrap(); + let id = endorsements[0].content.compute_id().unwrap(); assert_eq!(id, endorsement_id); assert_eq!(nodes[0].id, node); panic!("Unexpected propagated of endorsement."); @@ -401,7 +402,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou let thread = address.get_thread(serialization_context.thread_count); let endorsement = tools::create_endorsement(); - let endorsement_id = endorsement.compute_endorsement_id().unwrap(); + let endorsement_id = endorsement.content.compute_id().unwrap(); let block = tools::create_block_with_endorsements( &nodes[0].private_key, @@ -409,7 +410,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou Slot::new(1, thread), vec![endorsement.clone()], ); - let block_id = block.header.compute_block_id().unwrap(); + let block_id = block.header.content.compute_id().unwrap(); network_controller .send_ask_for_block(nodes[0].id, vec![block_id]) @@ -446,7 +447,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou { Some(NetworkCommand::SendBlock { node, block }) => { assert_eq!(node, nodes[0].id); - assert_eq!(block.header.compute_block_id().unwrap(), block_id); + assert_eq!(block.header.content.compute_id().unwrap(), block_id); } Some(_) => panic!("Unexpected network command.."), None => panic!("Block not sent."), @@ -470,7 +471,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou .await { Some(NetworkCommand::SendEndorsements { node, endorsements }) => { - let id = endorsements[0].compute_endorsement_id().unwrap(); + let id = endorsements[0].content.compute_id().unwrap(); assert_eq!(id, endorsement_id); assert_eq!(nodes[0].id, node); panic!("Unexpected propagated of endorsement."); @@ -511,7 +512,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou let thread = address.get_thread(serialization_context.thread_count); let endorsement = tools::create_endorsement(); - let endorsement_id = endorsement.compute_endorsement_id().unwrap(); + let endorsement_id = endorsement.content.compute_id().unwrap(); let block = tools::create_block_with_endorsements( &nodes[0].private_key, @@ -559,7 +560,7 @@ async fn test_protocol_propagates_endorsements_only_to_nodes_that_dont_know_abou .await { Some(NetworkCommand::SendEndorsements { node, endorsements }) => { - let id = endorsements[0].compute_endorsement_id().unwrap(); + let id = endorsements[0].content.compute_id().unwrap(); assert_eq!(id, endorsement_id); assert_eq!(nodes[0].id, node); panic!("Unexpected propagated of endorsement."); @@ -610,7 +611,7 @@ async fn test_protocol_does_not_propagates_endorsements_when_receiving_those_ins .send_header(creator_node.id, block.header.clone()) .await; - let expected_endorsement_id = endorsement.compute_endorsement_id().unwrap(); + let expected_endorsement_id = endorsement.content.compute_id().unwrap(); // 5. Check that the endorsements included in the header are not propagated. loop { @@ -625,7 +626,7 @@ async fn test_protocol_does_not_propagates_endorsements_when_receiving_those_ins node: _node, endorsements, }) => { - let id = endorsements[0].compute_endorsement_id().unwrap(); + let id = endorsements[0].content.compute_id().unwrap(); assert_eq!(id, expected_endorsement_id); panic!("Unexpected propagation of endorsement received inside header.") } diff --git a/massa-protocol-worker/src/tests/in_block_operations_scenarios.rs b/massa-protocol-worker/src/tests/in_block_operations_scenarios.rs index d801b98c4c5..ca8360de87e 100644 --- a/massa-protocol-worker/src/tests/in_block_operations_scenarios.rs +++ b/massa-protocol-worker/src/tests/in_block_operations_scenarios.rs @@ -2,9 +2,8 @@ use super::tools::protocol_test; use massa_hash::hash::Hash; -use massa_models::{ - get_serialization_context, Address, Amount, Block, BlockHeader, BlockHeaderContent, Slot, -}; +use massa_models::signed::Signed; +use massa_models::{get_serialization_context, Address, Amount, Block, BlockHeader, Slot}; use massa_protocol_exports::tests::tools; use massa_protocol_exports::tests::tools::{ create_and_connect_nodes, create_block_with_operations, create_operation_with_expire_period, @@ -120,15 +119,15 @@ async fn test_protocol_sends_blocks_with_operations_to_consensus() { let block = { let operation_merkle_root = Hash::compute_from("merkle root".as_bytes()); - let (_, header) = BlockHeader::new_signed( - &creator_node.private_key, - BlockHeaderContent { + let (_, header) = Signed::new_signed( + BlockHeader { creator: derive_public_key(&creator_node.private_key), slot: slot_a, parents: Vec::new(), operation_merkle_root, endorsements: Vec::new(), }, + &creator_node.private_key, ) .unwrap(); diff --git a/massa-protocol-worker/src/tests/operations_scenarios.rs b/massa-protocol-worker/src/tests/operations_scenarios.rs index fa9d3c54a76..e0a1d9627a4 100644 --- a/massa-protocol-worker/src/tests/operations_scenarios.rs +++ b/massa-protocol-worker/src/tests/operations_scenarios.rs @@ -4,8 +4,9 @@ use super::tools::protocol_test; use massa_models::prehash::{Map, Set}; +use massa_models::signed::Signable; use massa_models::{self, Address, Amount, OperationId, Slot}; -use massa_network::NetworkCommand; +use massa_network_exports::NetworkCommand; use massa_protocol_exports::tests::tools; use massa_protocol_exports::{ProtocolEvent, ProtocolPoolEvent}; use serial_test::serial; @@ -298,7 +299,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ let thread = address.get_thread(serialization_context.thread_count); let operation = tools::create_operation_with_expire_period(&nodes[0].private_key, 1); - let operation_id = operation.get_operation_id().unwrap(); + let operation_id = operation.content.compute_id().unwrap(); let block = tools::create_block_with_operations( &nodes[0].private_key, @@ -306,7 +307,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ Slot::new(1, thread), vec![operation.clone()], ); - let block_id = block.header.compute_block_id().unwrap(); + let block_id = block.header.content.compute_id().unwrap(); network_controller .send_ask_for_block(nodes[0].id, vec![block_id]) @@ -343,7 +344,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ { Some(NetworkCommand::SendBlock { node, block }) => { assert_eq!(node, nodes[0].id); - assert_eq!(block.header.compute_block_id().unwrap(), block_id); + assert_eq!(block.header.content.compute_id().unwrap(), block_id); } Some(_) => panic!("Unexpected network command.."), None => panic!("Block not sent."), @@ -367,7 +368,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ .await { Some(NetworkCommand::SendOperations { node, operations }) => { - let id = operations[0].get_operation_id().unwrap(); + let id = operations[0].content.compute_id().unwrap(); assert_eq!(id, operation_id); assert_eq!(nodes[0].id, node); panic!("Unexpected propagated of operation."); @@ -408,7 +409,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ let thread = address.get_thread(serialization_context.thread_count); let operation = tools::create_operation_with_expire_period(&nodes[0].private_key, 1); - let operation_id = operation.get_operation_id().unwrap(); + let operation_id = operation.content.compute_id().unwrap(); let block = tools::create_block_with_operations( &nodes[0].private_key, @@ -416,7 +417,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ Slot::new(1, thread), vec![operation.clone()], ); - let block_id = block.header.compute_block_id().unwrap(); + let block_id = block.header.content.compute_id().unwrap(); network_controller .send_ask_for_block(nodes[0].id, vec![block_id]) @@ -452,7 +453,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ { Some(NetworkCommand::SendBlock { node, block }) => { assert_eq!(node, nodes[0].id); - assert_eq!(block.header.compute_block_id().unwrap(), block_id); + assert_eq!(block.header.content.compute_id().unwrap(), block_id); } Some(_) => panic!("Unexpected network command.."), None => panic!("Block not sent."), @@ -476,7 +477,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ .await { Some(NetworkCommand::SendOperations { node, operations }) => { - let id = operations[0].get_operation_id().unwrap(); + let id = operations[0].content.compute_id().unwrap(); assert_eq!(id, operation_id); assert_eq!(nodes[0].id, node); panic!("Unexpected propagated of operation."); @@ -517,7 +518,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ let thread = address.get_thread(serialization_context.thread_count); let operation = tools::create_operation_with_expire_period(&nodes[0].private_key, 1); - let operation_id = operation.get_operation_id().unwrap(); + let operation_id = operation.content.compute_id().unwrap(); let block = tools::create_block_with_operations( &nodes[0].private_key, @@ -565,7 +566,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ .await { Some(NetworkCommand::SendOperations { node, operations }) => { - let id = operations[0].get_operation_id().unwrap(); + let id = operations[0].content.compute_id().unwrap(); assert_eq!(id, operation_id); assert_eq!(nodes[0].id, node); panic!("Unexpected propagated of operation."); @@ -608,7 +609,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ let operation = tools::create_operation_with_expire_period(&nodes[0].private_key, 1); let operation_2 = tools::create_operation_with_expire_period(&nodes[0].private_key, 1); - let operation_id_2 = operation_2.get_operation_id().unwrap(); + let operation_id_2 = operation_2.content.compute_id().unwrap(); let mut block = tools::create_block_with_operations( &nodes[0].private_key, @@ -662,7 +663,7 @@ async fn test_protocol_propagates_operations_only_to_nodes_that_dont_know_about_ .await { Some(NetworkCommand::SendOperations { node, operations }) => { - let id = operations[0].get_operation_id().unwrap(); + let id = operations[0].content.compute_id().unwrap(); assert_eq!(id, operation_id_2); assert_eq!(nodes[0].id, node); } diff --git a/massa-protocol-worker/src/tests/scenarios.rs b/massa-protocol-worker/src/tests/scenarios.rs index 0df4b16f648..5a4f83f900c 100644 --- a/massa-protocol-worker/src/tests/scenarios.rs +++ b/massa-protocol-worker/src/tests/scenarios.rs @@ -4,8 +4,9 @@ use super::tools::protocol_test; use massa_models::prehash::{Map, Set}; +use massa_models::signed::Signable; use massa_models::BlockId; -use massa_network::NetworkCommand; +use massa_network_exports::NetworkCommand; use massa_protocol_exports::tests::tools; use massa_protocol_exports::{ tests::tools::{create_and_connect_nodes, create_block, wait_protocol_event}, @@ -61,7 +62,7 @@ async fn test_protocol_asks_for_block_from_node_who_propagated_header() { }; // 4. Check that protocol sent the right header to consensus. - let expected_hash = block.header.compute_block_id().unwrap(); + let expected_hash = block.header.content.compute_id().unwrap(); assert_eq!(expected_hash, received_hash); // 5. Ask for block. @@ -133,7 +134,7 @@ async fn test_protocol_sends_blocks_when_asked_for() { // 2. Create a block coming from creator_node. let block = create_block(&creator_node.private_key, &creator_node.id.0); - let expected_hash = block.header.compute_block_id().unwrap(); + let expected_hash = block.header.content.compute_id().unwrap(); // 3. Simulate two nodes asking for a block. for node in nodes.iter().take(2) { @@ -179,7 +180,7 @@ async fn test_protocol_sends_blocks_when_asked_for() { .await { Some(NetworkCommand::SendBlock { node, block }) => { - let hash = block.header.compute_block_id().unwrap(); + let hash = block.header.content.compute_id().unwrap(); assert_eq!(expected_hash, hash); assert!(expecting_block.remove(&node)); } @@ -285,14 +286,14 @@ async fn test_protocol_propagates_block_to_node_who_asked_for_it_and_only_header let op_ids = ref_block .operations .iter() - .map(|op| op.get_operation_id().unwrap()) + .map(|op| op.content.compute_id().unwrap()) .collect(); let endo_ids = ref_block .header .content .endorsements .iter() - .map(|endo| endo.compute_endorsement_id().unwrap()) + .map(|endo| endo.content.compute_id().unwrap()) .collect(); protocol_command_sender .integrated_block(ref_hash, ref_block, op_ids, endo_ids) @@ -321,12 +322,12 @@ async fn test_protocol_propagates_block_to_node_who_asked_for_it_and_only_header { Some(NetworkCommand::SendBlockHeader { node, header }) => { assert!(expected_headers.remove(&node)); - let sent_header_hash = header.compute_block_id().unwrap(); + let sent_header_hash = header.content.compute_id().unwrap(); assert_eq!(sent_header_hash, ref_hash); } Some(NetworkCommand::SendBlock { node, block }) => { assert!(expected_full_blocks.remove(&node)); - let sent_header_hash = block.header.compute_block_id().unwrap(); + let sent_header_hash = block.header.content.compute_id().unwrap(); assert_eq!(sent_header_hash, ref_hash); } _ => panic!("Unexpected or no network command."), @@ -368,7 +369,7 @@ async fn test_protocol_sends_full_blocks_it_receives_to_consensus() { // 1. Create a block coming from one node. let block = create_block(&creator_node.private_key, &creator_node.id.0); - let expected_hash = block.header.compute_block_id().unwrap(); + let expected_hash = block.header.content.compute_id().unwrap(); // 3. Send block to protocol. network_controller.send_block(creator_node.id, block).await; @@ -421,7 +422,7 @@ async fn test_protocol_block_not_found() { // 1. Create a block coming from one node. let block = create_block(&creator_node.private_key, &creator_node.id.0); - let expected_hash = block.header.compute_block_id().unwrap(); + let expected_hash = block.header.content.compute_id().unwrap(); // 3. Ask block to protocol. network_controller diff --git a/massa-sdk/Cargo.toml b/massa-sdk/Cargo.toml new file mode 100644 index 00000000000..c195c5185ef --- /dev/null +++ b/massa-sdk/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "massa_sdk" +version = "0.1.0" +edition = "2021" + +[dependencies] +jsonrpc-core-client = { version = "18.0", features = ["http", "tls"] } +tokio = { version = "1.15", features = ["full"] } +massa_models = { path = "../massa-models" } +massa_signature = { path = "../massa-signature" } +serde = { version = "1.0", features = ["derive"] } diff --git a/massa-client/src/rpc.rs b/massa-sdk/src/lib.rs similarity index 75% rename from massa-client/src/rpc.rs rename to massa-sdk/src/lib.rs index a5d5bba731a..d08f0be2ae3 100644 --- a/massa-client/src/rpc.rs +++ b/massa-sdk/src/lib.rs @@ -1,6 +1,5 @@ // Copyright (c) 2022 MASSA LABS -use crate::SETTINGS; use jsonrpc_core_client::transports::http; use jsonrpc_core_client::{RpcChannel, RpcError, RpcResult, TypedClient}; use massa_models::api::{ @@ -11,7 +10,7 @@ use massa_models::clique::Clique; use massa_models::composite::PubkeySig; use massa_models::execution::ExecuteReadOnlyResponse; use massa_models::prehash::{Map, Set}; -use massa_models::{Address, BlockId, EndorsementId, Operation, OperationId}; +use massa_models::{Address, BlockId, EndorsementId, OperationId, SignedOperation}; use massa_signature::PrivateKey; use serde::de::DeserializeOwned; use serde::Serialize; @@ -22,7 +21,7 @@ pub struct Client { } impl Client { - pub(crate) async fn new(ip: IpAddr, public_port: u16, private_port: u16) -> Client { + pub async fn new(ip: IpAddr, public_port: u16, private_port: u16) -> Client { let public_socket_addr = SocketAddr::new(ip, public_port); let private_socket_addr = SocketAddr::new(ip, private_port); let public_url = format!("http://{}", public_socket_addr); @@ -34,18 +33,24 @@ impl Client { } } -pub struct RpcClient(TypedClient); +pub struct RpcClient { + client: TypedClient, + timeout: u64, +} /// This is required by `jsonrpc_core_client::transports::http::connect` impl From for RpcClient { fn from(channel: RpcChannel) -> Self { - RpcClient(channel.into()) + RpcClient { + client: channel.into(), + timeout: 10000, + } } } impl RpcClient { /// Default constructor - pub(crate) async fn from_url(url: &str) -> RpcClient { + pub async fn from_url(url: &str) -> RpcClient { match http::connect::(url).await { Ok(client) => client, Err(_) => panic!("unable to connect to Node."), @@ -59,70 +64,69 @@ impl RpcClient { returns: &str, args: T, ) -> RpcResult { - let time = SETTINGS.timeout.to_duration(); - tokio::time::timeout(time, self.0.call_method(method, returns, args)) - .await - .map_err(|e| RpcError::Client(format!("timeout during {}: {}", method, e)))? + tokio::time::timeout( + tokio::time::Duration::from_millis(self.timeout), + self.client.call_method(method, returns, args), + ) + .await + .map_err(|e| RpcError::Client(format!("timeout during {}: {}", method, e)))? } /// Gracefully stop the node. - pub(crate) async fn stop_node(&self) -> RpcResult<()> { + pub async fn stop_node(&self) -> RpcResult<()> { self.call_method("stop_node", "()", ()).await } /// Sign message with node's key. /// Returns the public key that signed the message and the signature. - pub(crate) async fn node_sign_message(&self, message: Vec) -> RpcResult { + pub async fn node_sign_message(&self, message: Vec) -> RpcResult { self.call_method("node_sign_message", "PubkeySig", vec![message]) .await } /// Add a vec of new private keys for the node to use to stake. /// No confirmation to expect. - pub(crate) async fn add_staking_private_keys( - &self, - private_keys: Vec, - ) -> RpcResult<()> { + pub async fn add_staking_private_keys(&self, private_keys: Vec) -> RpcResult<()> { self.call_method("add_staking_private_keys", "()", vec![private_keys]) .await } /// Remove a vec of addresses used to stake. /// No confirmation to expect. - pub(crate) async fn remove_staking_addresses(&self, addresses: Vec
) -> RpcResult<()> { + pub async fn remove_staking_addresses(&self, addresses: Vec
) -> RpcResult<()> { self.call_method("remove_staking_addresses", "()", vec![addresses]) .await } /// Return hashset of staking addresses. - pub(crate) async fn get_staking_addresses(&self) -> RpcResult> { + pub async fn get_staking_addresses(&self) -> RpcResult> { self.call_method("get_staking_addresses", "Set
", ()) .await } /// Bans given node id /// No confirmation to expect. - pub(crate) async fn ban(&self, ips: Vec) -> RpcResult<()> { + pub async fn ban(&self, ips: Vec) -> RpcResult<()> { self.call_method("ban", "()", vec![ips]).await } /// Unbans given ip addr /// No confirmation to expect. - pub(crate) async fn unban(&self, ips: Vec) -> RpcResult<()> { + pub async fn unban(&self, ips: Vec) -> RpcResult<()> { self.call_method("unban", "()", vec![ips]).await } - pub(crate) async fn node_whitelist(&self, ips: Vec) -> RpcResult<()> { + pub async fn node_whitelist(&self, ips: Vec) -> RpcResult<()> { self.call_method("node_whitelist", "()", vec![ips]).await } - pub(crate) async fn node_remove_from_whitelist(&self, ips: Vec) -> RpcResult<()> { + pub async fn node_remove_from_whitelist(&self, ips: Vec) -> RpcResult<()> { self.call_method("node_remove_from_whitelist", "()", vec![ips]) .await } /// execute read only bytecode - pub(crate) async fn execute_read_only_request( + pub async fn execute_read_only_request( &self, read_only_execution: ReadOnlyExecution, ) -> RpcResult { @@ -143,7 +147,7 @@ impl RpcClient { // Explorer (aggregated stats) /// summary of the current state: time, last final blocks (hash, thread, slot, timestamp), clique count, connected nodes count - pub(crate) async fn get_status(&self) -> RpcResult { + pub async fn get_status(&self) -> RpcResult { self.call_method("get_status", "NodeStatus", ()).await } @@ -160,7 +164,7 @@ impl RpcClient { } /// Returns operations information associated to a given list of operations' IDs. - pub(crate) async fn get_operations( + pub async fn get_operations( &self, operation_ids: Vec, ) -> RpcResult> { @@ -168,7 +172,7 @@ impl RpcClient { .await } - pub(crate) async fn get_endorsements( + pub async fn get_endorsements( &self, endorsement_ids: Vec, ) -> RpcResult> { @@ -181,7 +185,7 @@ impl RpcClient { } /// Get information on a block given its BlockId - pub(crate) async fn get_block(&self, block_id: BlockId) -> RpcResult { + pub async fn get_block(&self, block_id: BlockId) -> RpcResult { self.call_method("get_block", "BlockInfo", vec![block_id]) .await } @@ -196,10 +200,7 @@ impl RpcClient { .await } - pub(crate) async fn get_addresses( - &self, - addresses: Vec
, - ) -> RpcResult> { + pub async fn get_addresses(&self, addresses: Vec
) -> RpcResult> { self.call_method("get_addresses", "Vec", vec![addresses]) .await } @@ -207,9 +208,9 @@ impl RpcClient { // User (interaction with the node) /// Adds operations to pool. Returns operations that were ok and sent to pool. - pub(crate) async fn send_operations( + pub async fn send_operations( &self, - operations: Vec, + operations: Vec, ) -> RpcResult> { self.call_method("send_operations", "Vec", vec![operations]) .await diff --git a/massa-time/Cargo.toml b/massa-time/Cargo.toml index 52e1c95bbfa..e40fbe7f243 100644 --- a/massa-time/Cargo.toml +++ b/massa-time/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chrono = "0.4" +time = { version = "0.3", features = ["serde", "formatting"] } displaydoc = "0.2" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0" diff --git a/massa-time/src/lib.rs b/massa-time/src/lib.rs index 1a3f46023ae..158c9387b75 100644 --- a/massa-time/src/lib.rs +++ b/massa-time/src/lib.rs @@ -1,18 +1,18 @@ // Copyright (c) 2022 MASSA LABS mod error; -use chrono::{self, DateTime, NaiveDateTime, Utc}; pub use error::TimeError; +use serde::{Deserialize, Serialize}; use std::fmt; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::{ convert::{TryFrom, TryInto}, str::FromStr, }; +use time::format_description::well_known::Rfc3339; +use time::OffsetDateTime; use tokio::time::Instant; -use serde::{Deserialize, Serialize}; - /// Time structure used every where. /// Millis since 01/01/1970. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] @@ -338,16 +338,12 @@ impl MassaTime { /// ``` /// # use massa_time::*; - /// let massa_time : MassaTime = MassaTime::from(0); - /// assert_eq!(massa_time.to_utc_string(), "1970-01-01 00:00:00 UTC") + /// let massa_time : MassaTime = MassaTime::from(1_640_995_200_000); + /// assert_eq!(massa_time.to_utc_string(), "2022-01-01T00:00:00Z") /// ``` pub fn to_utc_string(self) -> String { - let naive = NaiveDateTime::from_timestamp( - (self.to_millis() / 1000) as i64, - ((self.to_millis() % 1000) * 1_000_000) as u32, - ); - let datetime: DateTime = DateTime::from_utc(naive, Utc); - format!("{}", datetime) + let naive = OffsetDateTime::from_unix_timestamp((self.to_millis() / 1000) as i64).unwrap(); + naive.format(&Rfc3339).unwrap() } /// ``` @@ -360,17 +356,17 @@ impl MassaTime { /// assert_eq!(secs, 6); /// ``` pub fn days_hours_mins_secs(&self) -> Result<(i64, i64, i64, i64), TimeError> { - let time = chrono::Duration::from_std(self.to_duration()) + let time: time::Duration = time::Duration::try_from(self.to_duration()) .map_err(|_| TimeError::TimeOverflowError)?; - let days = time.num_days(); - let hours = (time - chrono::Duration::days(days)).num_hours(); + let days = time.whole_days(); + let hours = (time - time::Duration::days(days)).whole_hours(); let mins = - (time - chrono::Duration::days(days) - chrono::Duration::hours(hours)).num_minutes(); + (time - time::Duration::days(days) - time::Duration::hours(hours)).whole_minutes(); let secs = (time - - chrono::Duration::days(days) - - chrono::Duration::hours(hours) - - chrono::Duration::minutes(mins)) - .num_seconds(); + - time::Duration::days(days) + - time::Duration::hours(hours) + - time::Duration::minutes(mins)) + .whole_seconds(); Ok((days, hours, mins, secs)) } } diff --git a/massa-wallet/src/lib.rs b/massa-wallet/src/lib.rs index 36c4b692bf2..2ade43de207 100644 --- a/massa-wallet/src/lib.rs +++ b/massa-wallet/src/lib.rs @@ -6,9 +6,8 @@ use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::composite::PubkeySig; use massa_models::prehash::{Map, Set}; -use massa_models::Operation; -use massa_models::OperationContent; -use massa_models::SerializeCompact; +use massa_models::signed::Signed; +use massa_models::{Operation, SignedOperation}; use massa_signature::{derive_public_key, sign, PrivateKey, PublicKey}; use massa_time::MassaTime; use serde::{Deserialize, Serialize}; @@ -117,15 +116,13 @@ impl Wallet { pub fn create_operation( &self, - content: OperationContent, + content: Operation, address: Address, - ) -> Result { - let hash = Hash::compute_from(&content.to_bytes_compact()?); + ) -> Result { let sender_priv = self .find_associated_private_key(address) .ok_or(WalletError::MissingKeyError(address))?; - let signature = sign(&hash, sender_priv)?; - Ok(Operation { content, signature }) + Ok(Signed::new_signed(content, sender_priv).unwrap().1) } }