From 61c12bb74eb53ca0cdd1e4690182f3d7c3f0cd31 Mon Sep 17 00:00:00 2001 From: Maria Kuklina Date: Wed, 29 Mar 2023 17:42:54 +0200 Subject: [PATCH 1/6] extend peer identify with spell service version and allowed mounted binaries list --- Cargo.lock | 1 + particle-builtins/src/identify.rs | 2 ++ particle-node/Cargo.toml | 1 + particle-node/src/node.rs | 6 ++++++ spell-storage/src/storage.rs | 3 +++ 5 files changed, 13 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index bc700fdef3..63417900ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4406,6 +4406,7 @@ dependencies = [ "eyre", "fluence-keypair", "fluence-libp2p", + "fluence-spell-distro", "fs-utils", "fstrings", "futures", diff --git a/particle-builtins/src/identify.rs b/particle-builtins/src/identify.rs index 3851d69545..abccabb20f 100644 --- a/particle-builtins/src/identify.rs +++ b/particle-builtins/src/identify.rs @@ -22,4 +22,6 @@ pub struct NodeInfo { pub external_addresses: Vec, pub node_version: &'static str, pub air_version: &'static str, + pub spell_version: &'static str, + pub allowed_binaries: Vec, } diff --git a/particle-node/Cargo.toml b/particle-node/Cargo.toml index 93074a7145..a4426511b0 100644 --- a/particle-node/Cargo.toml +++ b/particle-node/Cargo.toml @@ -17,6 +17,7 @@ script-storage = { workspace = true } aquamarine = { workspace = true } sorcerer = { workspace = true } dhat = { version = "0.3.2", optional = true } +fluence-spell-distro = { workspace = true } fluence-libp2p = { workspace = true } diff --git a/particle-node/src/node.rs b/particle-node/src/node.rs index f23d3e64f6..578f89e6b0 100644 --- a/particle-node/src/node.rs +++ b/particle-node/src/node.rs @@ -327,6 +327,12 @@ impl Node { external_addresses, node_version: env!("CARGO_PKG_VERSION"), air_version: air_interpreter_wasm::VERSION, + spell_version: fluence_spell_distro::VERSION, + allowed_binaries: services_config + .allowed_binaries + .iter() + .map(|s| s.to_string_lossy().to_string()) + .collect::<_>(), }; Builtins::new( diff --git a/spell-storage/src/storage.rs b/spell-storage/src/storage.rs index 128eb22147..74b658ba66 100644 --- a/spell-storage/src/storage.rs +++ b/spell-storage/src/storage.rs @@ -30,6 +30,7 @@ impl SpellStorage { services: &ParticleAppServices, modules: &ModuleRepository, ) -> eyre::Result { + log::info!("creating spell storage"); let spell_config_path = spell_config_path(spells_base_dir); let spell_blueprint_id = if spell_config_path.exists() { let cfg = TomlMarineConfig::load(spell_config_path)?; @@ -47,6 +48,7 @@ impl SpellStorage { fn load_spell_service_from_crate(modules: &ModuleRepository) -> eyre::Result { use fluence_spell_distro::{modules as spell_modules, CONFIG}; + log::info!("load from crate"); log::info!( "Spell service impl version: {}", @@ -76,6 +78,7 @@ impl SpellStorage { spells_base_dir: &Path, modules: &ModuleRepository, ) -> eyre::Result { + log::info!("load from disk"); let mut hashes = Vec::new(); for config in cfg.module { let load_from = config From 656cd7da456703cdc23ed6899f3b03ad10db8a7d Mon Sep 17 00:00:00 2001 From: Maria Kuklina Date: Thu, 30 Mar 2023 11:22:01 +0200 Subject: [PATCH 2/6] remove printf --- spell-storage/src/storage.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/spell-storage/src/storage.rs b/spell-storage/src/storage.rs index 74b658ba66..128eb22147 100644 --- a/spell-storage/src/storage.rs +++ b/spell-storage/src/storage.rs @@ -30,7 +30,6 @@ impl SpellStorage { services: &ParticleAppServices, modules: &ModuleRepository, ) -> eyre::Result { - log::info!("creating spell storage"); let spell_config_path = spell_config_path(spells_base_dir); let spell_blueprint_id = if spell_config_path.exists() { let cfg = TomlMarineConfig::load(spell_config_path)?; @@ -48,7 +47,6 @@ impl SpellStorage { fn load_spell_service_from_crate(modules: &ModuleRepository) -> eyre::Result { use fluence_spell_distro::{modules as spell_modules, CONFIG}; - log::info!("load from crate"); log::info!( "Spell service impl version: {}", @@ -78,7 +76,6 @@ impl SpellStorage { spells_base_dir: &Path, modules: &ModuleRepository, ) -> eyre::Result { - log::info!("load from disk"); let mut hashes = Vec::new(); for config in cfg.module { let load_from = config From 0d4e0263ca698494fafb9aacedb61a56918f6638 Mon Sep 17 00:00:00 2001 From: Maria Kuklina Date: Thu, 30 Mar 2023 19:51:12 +0200 Subject: [PATCH 3/6] add module hashes as version for spell services from disk --- particle-builtins/src/builtins.rs | 6 ------ particle-builtins/src/identify.rs | 2 +- particle-node/src/node.rs | 29 +++++++++++++------------ sorcerer/src/sorcerer.rs | 24 +++++++++++++++++++-- spell-storage/src/storage.rs | 35 +++++++++++++++++++++---------- 5 files changed, 61 insertions(+), 35 deletions(-) diff --git a/particle-builtins/src/builtins.rs b/particle-builtins/src/builtins.rs index 257565d0b0..7f2441af90 100644 --- a/particle-builtins/src/builtins.rs +++ b/particle-builtins/src/builtins.rs @@ -51,7 +51,6 @@ use crate::debug::fmt_custom_services; use crate::error::HostClosureCallError; use crate::error::HostClosureCallError::{DecodeBase58, DecodeUTF8}; use crate::func::{binary, unary}; -use crate::identify::NodeInfo; use crate::outcome::{ok, wrap, wrap_unit}; use crate::{json, math}; @@ -87,8 +86,6 @@ pub struct Builtins { pub modules: ModuleRepository, pub services: ParticleAppServices, - pub node_info: NodeInfo, - #[derivative(Debug(format_with = "fmt_custom_services"))] pub custom_services: RwLock>, @@ -105,7 +102,6 @@ where pub fn new( connectivity: C, script_storage: ScriptStorageApi, - node_info: NodeInfo, config: ServicesConfig, services_metrics: ServicesMetrics, key_manager: KeyManager, @@ -135,7 +131,6 @@ where local_peer_id, modules, services, - node_info, particles_vault_dir, custom_services: <_>::default(), key_manager, @@ -191,7 +186,6 @@ where #[rustfmt::skip] match (args.service_id.as_str(), args.function_name.as_str()) { - ("peer", "identify") => ok(json!(self.node_info)), ("peer", "timestamp_ms") => ok(json!(now_ms() as u64)), ("peer", "timestamp_sec") => ok(json!(now_sec())), ("peer", "is_connected") => wrap(self.is_connected(args).await), diff --git a/particle-builtins/src/identify.rs b/particle-builtins/src/identify.rs index abccabb20f..4555713f98 100644 --- a/particle-builtins/src/identify.rs +++ b/particle-builtins/src/identify.rs @@ -22,6 +22,6 @@ pub struct NodeInfo { pub external_addresses: Vec, pub node_version: &'static str, pub air_version: &'static str, - pub spell_version: &'static str, + pub spell_version: String, pub allowed_binaries: Vec, } diff --git a/particle-node/src/node.rs b/particle-node/src/node.rs index 578f89e6b0..869e9154a2 100644 --- a/particle-node/src/node.rs +++ b/particle-node/src/node.rs @@ -191,9 +191,14 @@ impl Node { ) }; + let allowed_binaries = services_config + .allowed_binaries + .iter() + .map(|s| s.to_string_lossy().to_string()) + .collect::<_>(); + let builtins = Arc::new(Self::builtins( connectivity.clone(), - config.external_addresses(), services_config, script_storage_api, services_metrics, @@ -243,6 +248,13 @@ impl Node { let (spell_event_bus, spell_event_bus_api, spell_events_receiver) = SpellEventBus::new(sources); + let initial_node_info = NodeInfo { + external_addresses: config.external_addresses(), + node_version: env!("CARGO_PKG_VERSION"), + air_version: air_interpreter_wasm::VERSION, + spell_version: fluence_spell_distro::VERSION.to_string(), + allowed_binaries, + }; let (sorcerer, spell_service_functions) = Sorcerer::new( builtins.services.clone(), builtins.modules.clone(), @@ -250,6 +262,7 @@ impl Node { config.clone(), spell_event_bus_api, key_manager.clone(), + initial_node_info, ); spell_service_functions.into_iter().for_each( @@ -317,28 +330,14 @@ impl Node { pub fn builtins( connectivity: Connectivity, - external_addresses: Vec, services_config: ServicesConfig, script_storage_api: ScriptStorageApi, services_metrics: ServicesMetrics, key_manager: KeyManager, ) -> Builtins { - let node_info = NodeInfo { - external_addresses, - node_version: env!("CARGO_PKG_VERSION"), - air_version: air_interpreter_wasm::VERSION, - spell_version: fluence_spell_distro::VERSION, - allowed_binaries: services_config - .allowed_binaries - .iter() - .map(|s| s.to_string_lossy().to_string()) - .collect::<_>(), - }; - Builtins::new( connectivity, script_storage_api, - node_info, services_config, services_metrics, key_manager, diff --git a/sorcerer/src/sorcerer.rs b/sorcerer/src/sorcerer.rs index 14d1e23923..4646255616 100644 --- a/sorcerer/src/sorcerer.rs +++ b/sorcerer/src/sorcerer.rs @@ -19,6 +19,7 @@ use std::time::Duration; use fluence_spell_dtos::trigger_config::TriggerConfigValue; use futures::{FutureExt, StreamExt}; +use serde_json::json; use tokio::sync::mpsc; use tokio::task::JoinHandle; use tokio_stream::wrappers::UnboundedReceiverStream; @@ -32,7 +33,7 @@ use crate::worker_builins::{create_worker, get_worker_peer_id, remove_worker}; use aquamarine::AquamarineApi; use key_manager::KeyManager; use particle_args::JError; -use particle_builtins::{wrap, wrap_unit, CustomService}; +use particle_builtins::{ok, wrap, wrap_unit, CustomService, NodeInfo}; use particle_execution::ServiceFunction; use particle_modules::ModuleRepository; use particle_services::ParticleAppServices; @@ -59,10 +60,12 @@ impl Sorcerer { config: ResolvedConfig, spell_event_bus_api: SpellEventBusApi, key_manager: KeyManager, + mut node_info: NodeInfo, ) -> (Self, HashMap) { - let spell_storage = + let (spell_storage, spell_version) = SpellStorage::create(&config.dir_config.spell_base_dir, &services, &modules) .expect("Spell storage creation"); + node_info.spell_version = spell_version; let sorcerer = Self { aquamarine, @@ -75,6 +78,7 @@ impl Sorcerer { let mut builtin_functions = sorcerer.make_spell_builtins(); builtin_functions.extend_one(sorcerer.make_worker_builtin()); + builtin_functions.extend_one(sorcerer.make_peer_builtin(node_info)); (sorcerer, builtin_functions) } @@ -334,4 +338,20 @@ impl Sorcerer { .boxed() })) } + + fn make_peer_builtin(&self, node_info: NodeInfo) -> (String, CustomService) { + ( + "peer".to_string(), + CustomService::new( + vec![("identify", self.make_peer_identify_closure(node_info))], + None, + ), + ) + } + fn make_peer_identify_closure(&self, node_info: NodeInfo) -> ServiceFunction { + ServiceFunction::Immut(Box::new(move |_args, _params| { + let node_info = node_info.clone(); + async move { ok(json!(node_info)) }.boxed() + })) + } } diff --git a/spell-storage/src/storage.rs b/spell-storage/src/storage.rs index 128eb22147..9bee1f2653 100644 --- a/spell-storage/src/storage.rs +++ b/spell-storage/src/storage.rs @@ -29,9 +29,9 @@ impl SpellStorage { spells_base_dir: &Path, services: &ParticleAppServices, modules: &ModuleRepository, - ) -> eyre::Result { + ) -> eyre::Result<(Self, String)> { let spell_config_path = spell_config_path(spells_base_dir); - let spell_blueprint_id = if spell_config_path.exists() { + let (spell_blueprint_id, spell_version) = if spell_config_path.exists() { let cfg = TomlMarineConfig::load(spell_config_path)?; Self::load_spell_service(cfg, spells_base_dir, modules)? } else { @@ -39,13 +39,16 @@ impl SpellStorage { }; let registered_spells = Self::restore_spells(services, modules); - Ok(Self { - spell_blueprint_id, - registered_spells: Arc::new(RwLock::new(registered_spells)), - }) + Ok(( + Self { + spell_blueprint_id, + registered_spells: Arc::new(RwLock::new(registered_spells)), + }, + spell_version, + )) } - fn load_spell_service_from_crate(modules: &ModuleRepository) -> eyre::Result { + fn load_spell_service_from_crate(modules: &ModuleRepository) -> eyre::Result<(String, String)> { use fluence_spell_distro::{modules as spell_modules, CONFIG}; log::info!( @@ -68,15 +71,19 @@ impl SpellStorage { hashes.push(Dependency::Hash(hash)) } - Ok(modules.add_blueprint(AddBlueprint::new("spell".to_string(), hashes))?) + Ok(( + modules.add_blueprint(AddBlueprint::new("spell".to_string(), hashes))?, + fluence_spell_distro::VERSION.to_string(), + )) } fn load_spell_service( cfg: TomlMarineConfig, spells_base_dir: &Path, modules: &ModuleRepository, - ) -> eyre::Result { + ) -> eyre::Result<(String, String)> { let mut hashes = Vec::new(); + let mut versions = Vec::new(); for config in cfg.module { let load_from = config .load_from @@ -87,10 +94,16 @@ impl SpellStorage { let module_path = spells_base_dir.join(load_from); let module = load_module_by_path(module_path.as_ref())?; let hash = modules.add_module(module, config)?; + let hex = hash.to_hex(); + let hex = hex.as_ref(); + versions.push(String::from(&hex[..8])); hashes.push(Dependency::Hash(hash)); } - - Ok(modules.add_blueprint(AddBlueprint::new("spell".to_string(), hashes))?) + let spell_disk_version = format!("wasm hashes {}", versions.join(" ")); + Ok(( + modules.add_blueprint(AddBlueprint::new("spell".to_string(), hashes))?, + spell_disk_version, + )) } fn restore_spells( From eae989db0410904c2ef9d3d232472119199d5550 Mon Sep 17 00:00:00 2001 From: Maria Kuklina Date: Fri, 31 Mar 2023 12:11:40 +0200 Subject: [PATCH 4/6] move peer builtins out of sorcerer --- particle-node/Cargo.toml | 1 + particle-node/src/builtins.rs | 20 ++++++++++++++++++++ particle-node/src/lib.rs | 2 ++ particle-node/src/node.rs | 20 +++++++++++--------- sorcerer/src/sorcerer.rs | 26 +++----------------------- 5 files changed, 37 insertions(+), 32 deletions(-) create mode 100644 particle-node/src/builtins.rs diff --git a/particle-node/Cargo.toml b/particle-node/Cargo.toml index a4426511b0..5fc9d98406 100644 --- a/particle-node/Cargo.toml +++ b/particle-node/Cargo.toml @@ -20,6 +20,7 @@ dhat = { version = "0.3.2", optional = true } fluence-spell-distro = { workspace = true } +serde_json = { workspace = true } fluence-libp2p = { workspace = true } server-config = { workspace = true } config-utils = { workspace = true } diff --git a/particle-node/src/builtins.rs b/particle-node/src/builtins.rs new file mode 100644 index 0000000000..7f1e308b8d --- /dev/null +++ b/particle-node/src/builtins.rs @@ -0,0 +1,20 @@ +use futures::FutureExt; +use particle_builtins::{ok, CustomService, NodeInfo}; +use particle_execution::ServiceFunction; +use serde_json::json; + +pub fn make_peer_builtin(node_info: NodeInfo) -> (String, CustomService) { + ( + "peer".to_string(), + CustomService::new( + vec![("identify", make_peer_identify_closure(node_info))], + None, + ), + ) +} +fn make_peer_identify_closure(node_info: NodeInfo) -> ServiceFunction { + ServiceFunction::Immut(Box::new(move |_args, _params| { + let node_info = node_info.clone(); + async move { ok(json!(node_info)) }.boxed() + })) +} diff --git a/particle-node/src/lib.rs b/particle-node/src/lib.rs index ddd6dad9c9..1070bab0a3 100644 --- a/particle-node/src/lib.rs +++ b/particle-node/src/lib.rs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#![feature(extend_one)] #![feature(try_blocks)] #![feature(drain_filter)] #![feature(ip)] @@ -28,6 +29,7 @@ unreachable_patterns )] +mod builtins; mod connectivity; mod dispatcher; mod effectors; diff --git a/particle-node/src/node.rs b/particle-node/src/node.rs index 869e9154a2..6a031158d4 100644 --- a/particle-node/src/node.rs +++ b/particle-node/src/node.rs @@ -52,6 +52,7 @@ use spell_event_bus::bus::SpellEventBus; use tokio::sync::{mpsc, oneshot}; use tokio::task; +use crate::builtins::make_peer_builtin; use crate::dispatcher::Dispatcher; use crate::effectors::Effectors; use crate::metrics::start_metrics_endpoint; @@ -248,23 +249,24 @@ impl Node { let (spell_event_bus, spell_event_bus_api, spell_events_receiver) = SpellEventBus::new(sources); - let initial_node_info = NodeInfo { - external_addresses: config.external_addresses(), - node_version: env!("CARGO_PKG_VERSION"), - air_version: air_interpreter_wasm::VERSION, - spell_version: fluence_spell_distro::VERSION.to_string(), - allowed_binaries, - }; - let (sorcerer, spell_service_functions) = Sorcerer::new( + let (sorcerer, mut spell_service_functions, spell_version) = Sorcerer::new( builtins.services.clone(), builtins.modules.clone(), aquamarine_api.clone(), config.clone(), spell_event_bus_api, key_manager.clone(), - initial_node_info, ); + let node_info = NodeInfo { + external_addresses: config.external_addresses(), + node_version: env!("CARGO_PKG_VERSION"), + air_version: air_interpreter_wasm::VERSION, + spell_version, + allowed_binaries, + }; + spell_service_functions.extend_one(make_peer_builtin(node_info)); + spell_service_functions.into_iter().for_each( move |( service_id, diff --git a/sorcerer/src/sorcerer.rs b/sorcerer/src/sorcerer.rs index c8a9573211..01105264d7 100644 --- a/sorcerer/src/sorcerer.rs +++ b/sorcerer/src/sorcerer.rs @@ -19,7 +19,6 @@ use std::time::Duration; use fluence_spell_dtos::trigger_config::TriggerConfigValue; use futures::{FutureExt, StreamExt}; -use serde_json::json; use tokio::sync::mpsc; use tokio::task::JoinHandle; use tokio_stream::wrappers::UnboundedReceiverStream; @@ -33,7 +32,7 @@ use crate::worker_builins::{create_worker, get_worker_peer_id, remove_worker, wo use aquamarine::AquamarineApi; use key_manager::KeyManager; use particle_args::JError; -use particle_builtins::{ok, wrap, wrap_unit, CustomService, NodeInfo}; +use particle_builtins::{wrap, wrap_unit, CustomService}; use particle_execution::ServiceFunction; use particle_modules::ModuleRepository; use particle_services::ParticleAppServices; @@ -60,12 +59,10 @@ impl Sorcerer { config: ResolvedConfig, spell_event_bus_api: SpellEventBusApi, key_manager: KeyManager, - mut node_info: NodeInfo, - ) -> (Self, HashMap) { + ) -> (Self, HashMap, String) { let (spell_storage, spell_version) = SpellStorage::create(&config.dir_config.spell_base_dir, &services, &modules) .expect("Spell storage creation"); - node_info.spell_version = spell_version; let sorcerer = Self { aquamarine, @@ -78,9 +75,8 @@ impl Sorcerer { let mut builtin_functions = sorcerer.make_spell_builtins(); builtin_functions.extend_one(sorcerer.make_worker_builtin()); - builtin_functions.extend_one(sorcerer.make_peer_builtin(node_info)); - (sorcerer, builtin_functions) + (sorcerer, builtin_functions, spell_version) } async fn resubscribe_spells(&self) { @@ -352,20 +348,4 @@ impl Sorcerer { .boxed() })) } - - fn make_peer_builtin(&self, node_info: NodeInfo) -> (String, CustomService) { - ( - "peer".to_string(), - CustomService::new( - vec![("identify", self.make_peer_identify_closure(node_info))], - None, - ), - ) - } - fn make_peer_identify_closure(&self, node_info: NodeInfo) -> ServiceFunction { - ServiceFunction::Immut(Box::new(move |_args, _params| { - let node_info = node_info.clone(); - async move { ok(json!(node_info)) }.boxed() - })) - } } From 38da15739e0f82d42ba52115af380bf7fe8dc566 Mon Sep 17 00:00:00 2001 From: Maria Kuklina Date: Fri, 31 Mar 2023 12:14:40 +0200 Subject: [PATCH 5/6] refactor --- Cargo.lock | 1 - particle-node/Cargo.toml | 1 - particle-node/src/builtins.rs | 16 ++++++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f4897711c..b01991e8a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4406,7 +4406,6 @@ dependencies = [ "eyre", "fluence-keypair", "fluence-libp2p", - "fluence-spell-distro", "fs-utils", "fstrings", "futures", diff --git a/particle-node/Cargo.toml b/particle-node/Cargo.toml index 5fc9d98406..85572c4a9d 100644 --- a/particle-node/Cargo.toml +++ b/particle-node/Cargo.toml @@ -17,7 +17,6 @@ script-storage = { workspace = true } aquamarine = { workspace = true } sorcerer = { workspace = true } dhat = { version = "0.3.2", optional = true } -fluence-spell-distro = { workspace = true } serde_json = { workspace = true } diff --git a/particle-node/src/builtins.rs b/particle-node/src/builtins.rs index 7f1e308b8d..6908842f7a 100644 --- a/particle-node/src/builtins.rs +++ b/particle-node/src/builtins.rs @@ -1,3 +1,19 @@ +/* + * Copyright 2023 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + use futures::FutureExt; use particle_builtins::{ok, CustomService, NodeInfo}; use particle_execution::ServiceFunction; From 702302562931d04fec24826670c0720969b248d5 Mon Sep 17 00:00:00 2001 From: Maria Kuklina Date: Fri, 31 Mar 2023 14:19:45 +0200 Subject: [PATCH 6/6] rename --- particle-node/src/node.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/particle-node/src/node.rs b/particle-node/src/node.rs index 6a031158d4..5d0cee10b3 100644 --- a/particle-node/src/node.rs +++ b/particle-node/src/node.rs @@ -249,7 +249,7 @@ impl Node { let (spell_event_bus, spell_event_bus_api, spell_events_receiver) = SpellEventBus::new(sources); - let (sorcerer, mut spell_service_functions, spell_version) = Sorcerer::new( + let (sorcerer, mut custom_service_functions, spell_version) = Sorcerer::new( builtins.services.clone(), builtins.modules.clone(), aquamarine_api.clone(), @@ -265,9 +265,9 @@ impl Node { spell_version, allowed_binaries, }; - spell_service_functions.extend_one(make_peer_builtin(node_info)); + custom_service_functions.extend_one(make_peer_builtin(node_info)); - spell_service_functions.into_iter().for_each( + custom_service_functions.into_iter().for_each( move |( service_id, CustomService {