diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/Cargo.toml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/Cargo.toml new file mode 100644 index 0000000..b443c8a --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "curl_adapter" +version = "0.1.0" +authors = ["Fluence Labs"] +edition = "2018" +publish = false + +[[bin]] +path = "src/main.rs" +name = "curl_adapter" + +[dependencies] +marine-rs-sdk = "0.6.14" +log = "0.4.8" diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/src/main.rs b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/src/main.rs new file mode 100644 index 0000000..861cbf8 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/src/main.rs @@ -0,0 +1,37 @@ +/* + * Copyright 2021 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. + */ + +#![allow(improper_ctypes)] + +use marine_rs_sdk::marine; +use marine_rs_sdk::module_manifest; + +use marine_rs_sdk::MountedBinaryResult; + +module_manifest!(); + +pub fn main() {} + +#[marine] +pub fn curl_request(cmd: Vec) -> MountedBinaryResult { + curl(cmd) +} + +#[marine] +#[link(wasm_import_module = "host")] +extern "C" { + fn curl(cmd: Vec) -> MountedBinaryResult; +} diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/Cargo.toml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/Cargo.toml new file mode 100644 index 0000000..8841672 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "multi_provider_query" +version = "0.1.5" +authors = ["boneyard93501 <4523011+boneyard93501@users.noreply.github.com>"] +edition = "2018" +description = "multi-provider-query, a Marine wasi module" +license = "Apache-2.0" + +[[bin]] +name = "multi_provider_query" +path = "src/main.rs" + +[dependencies] +marine-rs-sdk = { version = "0.6.15", features = ["logger"] } +log = "0.4.14" +serde_json = "1.0.81" +serde = "1.0.137" + +[dev-dependencies] +marine-rs-sdk-test = "0.6.0" + +[dev] +[profile.release] +opt-level = "s" diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/src/main.rs b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/src/main.rs new file mode 100644 index 0000000..7a2362b --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/src/main.rs @@ -0,0 +1,159 @@ +/* + * Copyright 2022 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 marine_rs_sdk::{marine, module_manifest, MountedBinaryResult}; +use serde::{Deserialize, Serialize}; +use serde_json; +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub static NONCE_COUNTER: AtomicUsize = AtomicUsize::new(1); + +module_manifest!(); + +fn main() {} + +fn get_nonce() -> u64 { + NONCE_COUNTER.fetch_add(1, Ordering::SeqCst) as u64 +} + +#[marine] +pub struct ProviderInfo { + pub url: String, + pub name: String, +} + +#[marine] +pub struct EVMResult { + pub provider: String, + pub stdout: String, + pub stderr: String, +} + +#[derive(Serialize, Deserialize)] +struct RpcData { + jsonrpc: String, + method: String, + params: Vec, + id: u64, +} + +#[derive(Serialize, Deserialize, Debug)] +struct RpcResponseError { + code: i32, + message: String, +} +#[derive(Serialize, Deserialize, Debug)] +struct RpcResponse { + jsonrpc: String, + error: Option, + result: Option, +} + +impl RpcData { + fn new(method: String, params: Vec) -> Self { + let nonce = get_nonce(); + RpcData { + jsonrpc: "2.0".to_owned(), + method: method, + params: params, + id: nonce, + } + } +} + +fn curl_cmd_builder(url: String, data: String) -> Vec { + let curl_cmd: Vec = vec![ + url, + "-X".to_string(), + "POST".to_string(), + "-H".to_string(), + "Accept: application/json".to_string(), + "-H".to_string(), + "Content-Type: application/json".to_string(), + "-d".to_string(), + data, + ]; + + curl_cmd +} + +fn get_curl_response(curl_cmd: Vec) -> RpcResponse { + let response = curl_request(curl_cmd); + let response = String::from_utf8(response.stdout).unwrap(); + let response: Result = serde_json::from_str(&response); + match response { + Ok(r) => r, + Err(e) => RpcResponse { + jsonrpc: "".to_owned(), + error: Some(RpcResponseError { + code: -1, + message: e.to_string(), + }), + result: None, + }, + } +} + +#[marine] +// see https://eth.wiki/json-rpc/API#eth_blocknumbers +fn get_block_number(provider: ProviderInfo) -> EVMResult { + let method = "eth_blockNumber"; + let params: Vec = vec![]; + let url = provider.url; + + let data = RpcData::new(method.to_owned(), params); + let data = serde_json::to_string(&data).unwrap(); + + let curl_cmd = curl_cmd_builder(url, data); + let response = get_curl_response(curl_cmd); + + if response.error.is_none() { + let raw_response = response.result.unwrap(); + let block_height = u64::from_str_radix(raw_response.trim_start_matches("0x"), 16); + + let result = match block_height { + Ok(r) => { + let j_res = serde_json::json!({ "block-height": r }); + EVMResult { + provider: provider.name, + stdout: j_res.to_string(), + stderr: "".to_owned(), + } + } + Err(e) => { + let err = format!("unable to convert {} to u64 with error {}", raw_response, e); + EVMResult { + provider: provider.name, + stdout: "".to_owned(), + stderr: err, + } + } + }; + return result; + } + + EVMResult { + provider: provider.name, + stdout: "".to_owned(), + stderr: serde_json::to_string(&response.error).unwrap(), + } +} + +#[marine] +#[link(wasm_import_module = "curl_adapter")] +extern "C" { + pub fn curl_request(cmd: Vec) -> MountedBinaryResult; +} diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/Cargo.toml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/Cargo.toml new file mode 100644 index 0000000..f03f982 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "simple-quorum" +version = "0.1.0" +authors = ["boneyard93501 <4523011+boneyard93501@users.noreply.github.com>"] +edition = "2018" +description = "simple-quorum, a Marine wasi module" +license = "Apache-2.0" + +[[bin]] +name = "simple_quorum" +path = "src/main.rs" + +[dependencies] +marine-rs-sdk = { version = "0.6.15", features = ["logger"] } +log = "0.4.14" +serde_json = "1.0.81" +serde = "1.0.137" +streaming-stats = "0.2.3" + +[dev-dependencies] +marine-rs-sdk-test = "0.6.0" + +[dev] +[profile.release] +opt-level = "s" diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/src/main.rs b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/src/main.rs new file mode 100644 index 0000000..7b2b69c --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/src/main.rs @@ -0,0 +1,117 @@ +/* + * Copyright 2022 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 marine_rs_sdk::{marine, module_manifest}; +use std::collections::HashMap; + +module_manifest!(); + +fn main() {} + +// very simple mode calculator with much room for improvement +// see https://github.com/BurntSushi/rust-stats for inspiration +fn mode<'a>(data: impl ExactSizeIterator) -> (u32, u64) { + let frequencies = data + .into_iter() + .fold(HashMap::::new(), |mut freqs, value| { + *freqs + .entry( + match serde_json::from_str::(&value.stdout) { + Ok(r) => r["block-height"].as_u64().unwrap(), + Err(_e) => 0 as u64, + }, + ) + .or_insert(0) += 1; + freqs + }); + + let mode = frequencies + .iter() + .max_by_key(|&(_, count)| count) + .map(|(value, _)| value) + .unwrap(); + + (*frequencies.get(&mode).unwrap(), *mode) +} + +fn mean<'a>(data: impl ExactSizeIterator) -> Option { + let n = data.len() as u64; + if n < 1 { + return None; + } + let res = (data.sum::() / n) as f64; + Some(res) +} + +#[marine] +pub struct EVMResult { + pub provider: String, + pub stdout: String, + pub stderr: String, +} + +#[marine] +#[derive(Default, Debug)] +pub struct Quorum { + pub n: u32, + pub mode: u64, + pub freq: u32, + pub err_str: String, +} + +#[marine] +pub fn point_estimate(data: Vec, min_points: u32) -> Quorum { + if data.len() < min_points as usize { + return Quorum { + err_str: format!( + "Expected at least {} points but only got {}.", + min_points, + data.len() + ), + ..<_>::default() + }; + } + + if data.len() < 1 { + return Quorum { + err_str: format!("Expected at least one timestamp."), + ..<_>::default() + }; + } + + let (freq, mode) = mode(data.iter()); + + Quorum { + n: data.len() as u32, + mode, + freq, + ..<_>::default() + } +} + +#[marine] +pub fn int_div(nom: u64, denom: u64) -> f64 { + nom as f64 / denom as f64 +} + +#[marine] +pub fn is_quorum(nom: u64, denom: u64, threshold: f64) -> bool { + let div = nom as f64 / denom as f64; + if div >= threshold { + return true; + } + false +}