From 3c933c28fb3a42d25251efdaaab9ecd034112fda Mon Sep 17 00:00:00 2001 From: folex <0xdxdy@gmail.com> Date: Wed, 8 Feb 2023 17:07:38 +0700 Subject: [PATCH] chore: deploy eth gateway via fluence cli (#418) --- .../.gitignore | 10 + .../configs/deployment_cfg.json | 17 ++ .../configs/services/eth-rpc/service.yaml | 13 + .../services/ipfs-package/service.yaml | 13 + .../multi-provider-query/service.yaml | 13 + .../services/simple-quorum/service.yaml | 11 + .../configs/services/utilities/service.yaml | 11 + .../fluence-lock.yaml | 11 + .../fluence.yaml | 37 +++ .../scripts/build.sh | 10 +- .../wasm-modules/curl-adapter/module.yaml | 11 + .../wasm-modules/eth-rpc/Cargo.toml | 4 +- .../wasm-modules/eth-rpc/module.yaml | 9 + .../eth-rpc/src/curl_transport.rs | 15 +- .../wasm-modules/eth-rpc/src/eth_call.rs | 48 +++- .../wasm-modules/eth-rpc/src/main.rs | 16 -- .../wasm-modules/eth-rpc/src/typed.rs | 7 +- .../wasm-modules/eth-rpc/src/values.rs | 20 +- .../eth-rpc/tests_artifacts/Config.toml | 5 +- .../eth-rpc/tests_artifacts/curl_adapter.wasm | Bin 75335 -> 70366 bytes .../wasm-modules/ipfs-adapter/module.yaml | 11 + .../wasm-modules/ipfs-cli/module.yaml | 9 + .../multi-provider-query/Cargo.toml | 18 +- .../multi-provider-query/module.yaml | 9 + .../multi-provider-query/src/main.rs | 248 +++++++++--------- .../wasm-modules/simple-quorum/module.yaml | 9 + .../wasm-modules/simple-quorum/src/main.rs | 1 + .../wasm-modules/utilities/module.yaml | 9 + 28 files changed, 409 insertions(+), 186 deletions(-) create mode 100644 aqua-examples/decentralized-blockchain-gateway/configs/services/eth-rpc/service.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/configs/services/ipfs-package/service.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/configs/services/multi-provider-query/service.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/configs/services/simple-quorum/service.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/configs/services/utilities/service.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/fluence-lock.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/fluence.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/module.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/module.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/wasm-modules/ipfs-adapter/module.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/wasm-modules/ipfs-cli/module.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/module.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/module.yaml create mode 100644 aqua-examples/decentralized-blockchain-gateway/wasm-modules/utilities/module.yaml diff --git a/aqua-examples/decentralized-blockchain-gateway/.gitignore b/aqua-examples/decentralized-blockchain-gateway/.gitignore index 8bef1dc..c561d39 100644 --- a/aqua-examples/decentralized-blockchain-gateway/.gitignore +++ b/aqua-examples/decentralized-blockchain-gateway/.gitignore @@ -4,3 +4,13 @@ target/ Cargo.lock **/*.bk **/*.bak + +# recommended by Fluence Labs: +.idea +.fluence +**/node_modules +**/target/ +.repl_history +.vscode/settings.json +src/ts/src/aqua +src/js/src/aqua diff --git a/aqua-examples/decentralized-blockchain-gateway/configs/deployment_cfg.json b/aqua-examples/decentralized-blockchain-gateway/configs/deployment_cfg.json index 082937e..bc34ad2 100644 --- a/aqua-examples/decentralized-blockchain-gateway/configs/deployment_cfg.json +++ b/aqua-examples/decentralized-blockchain-gateway/configs/deployment_cfg.json @@ -52,5 +52,22 @@ "logger_enabled": true } ] + }, + "eth-rpc": { + "modules": [ + { + "name": "curl_adapter", + "path": "./artifacts/curl_adapter.wasm", + "max_heap_size": "2 MiB", + "mounted_binaries": [["curl", "/usr/bin/curl"]], + "logger_enabled": true + }, + { + "name": "eth-rpc", + "path": "./artifacts/eth-rpc.wasm", + "logger_enabled": true, + "max_heap_size": "100 MiB" + } + ] } } diff --git a/aqua-examples/decentralized-blockchain-gateway/configs/services/eth-rpc/service.yaml b/aqua-examples/decentralized-blockchain-gateway/configs/services/eth-rpc/service.yaml new file mode 100644 index 0000000..87e22ad --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/configs/services/eth-rpc/service.yaml @@ -0,0 +1,13 @@ +# yaml-language-server: $schema=../../../.fluence/schemas/service.yaml.json + +# Defines a [Marine service](https://fluence.dev/docs/build/concepts/#services), most importantly the modules that the service consists of. For Fluence CLI, **service** - is a directory which contains this config. You can use `fluence service new` command to generate a template for new service + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/service.md + +version: 0 +name: eth_rpc +modules: + facade: + get: ../../../wasm-modules/eth-rpc + curl-adapter: + get: ../../../wasm-modules/curl-adapter diff --git a/aqua-examples/decentralized-blockchain-gateway/configs/services/ipfs-package/service.yaml b/aqua-examples/decentralized-blockchain-gateway/configs/services/ipfs-package/service.yaml new file mode 100644 index 0000000..c526a94 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/configs/services/ipfs-package/service.yaml @@ -0,0 +1,13 @@ +# yaml-language-server: $schema=../../../.fluence/schemas/service.yaml.json + +# Defines a [Marine service](https://fluence.dev/docs/build/concepts/#services), most importantly the modules that the service consists of. For Fluence CLI, **service** - is a directory which contains this config. You can use `fluence service new` command to generate a template for new service + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/service.md + +version: 0 +name: ipfs_package +modules: + facade: + get: ../../../wasm-modules/ipfs-cli + ipfs-adapter: + get: ../../../wasm-modules/ipfs-adapter diff --git a/aqua-examples/decentralized-blockchain-gateway/configs/services/multi-provider-query/service.yaml b/aqua-examples/decentralized-blockchain-gateway/configs/services/multi-provider-query/service.yaml new file mode 100644 index 0000000..8fc1dad --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/configs/services/multi-provider-query/service.yaml @@ -0,0 +1,13 @@ +# yaml-language-server: $schema=../../../.fluence/schemas/service.yaml.json + +# Defines a [Marine service](https://fluence.dev/docs/build/concepts/#services), most importantly the modules that the service consists of. For Fluence CLI, **service** - is a directory which contains this config. You can use `fluence service new` command to generate a template for new service + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/service.md + +version: 0 +name: multi_provider_query +modules: + facade: + get: ../../../wasm-modules/multi-provider-query + curl-adapter: + get: ../../../wasm-modules/curl-adapter diff --git a/aqua-examples/decentralized-blockchain-gateway/configs/services/simple-quorum/service.yaml b/aqua-examples/decentralized-blockchain-gateway/configs/services/simple-quorum/service.yaml new file mode 100644 index 0000000..53418be --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/configs/services/simple-quorum/service.yaml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=../../../.fluence/schemas/service.yaml.json + +# Defines a [Marine service](https://fluence.dev/docs/build/concepts/#services), most importantly the modules that the service consists of. For Fluence CLI, **service** - is a directory which contains this config. You can use `fluence service new` command to generate a template for new service + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/service.md + +version: 0 +name: simple_quorum +modules: + facade: + get: ../../../wasm-modules/simple-quorum diff --git a/aqua-examples/decentralized-blockchain-gateway/configs/services/utilities/service.yaml b/aqua-examples/decentralized-blockchain-gateway/configs/services/utilities/service.yaml new file mode 100644 index 0000000..b202547 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/configs/services/utilities/service.yaml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=../../../.fluence/schemas/service.yaml.json + +# Defines a [Marine service](https://fluence.dev/docs/build/concepts/#services), most importantly the modules that the service consists of. For Fluence CLI, **service** - is a directory which contains this config. You can use `fluence service new` command to generate a template for new service + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/service.md + +version: 0 +name: utilities +modules: + facade: + get: ../../../wasm-modules/utilities diff --git a/aqua-examples/decentralized-blockchain-gateway/fluence-lock.yaml b/aqua-examples/decentralized-blockchain-gateway/fluence-lock.yaml new file mode 100644 index 0000000..b53d3a0 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/fluence-lock.yaml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=.fluence/schemas/fluence-lock.yaml.json + +# Defines a lock file for Fluence Project dependencies. When dependencies are installed - their exact versions are saved here. + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/fluence-lock.md + +version: 0 +cargo: + marine: 0.12.5 +npm: + "@fluencelabs/aqua": 0.9.1-374 diff --git a/aqua-examples/decentralized-blockchain-gateway/fluence.yaml b/aqua-examples/decentralized-blockchain-gateway/fluence.yaml new file mode 100644 index 0000000..2c24708 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/fluence.yaml @@ -0,0 +1,37 @@ +# yaml-language-server: $schema=.fluence/schemas/fluence.yaml.json + +# Defines Fluence Project, most importantly - what exactly you want to deploy and how. You can use `fluence init` command to generate a template for new Fluence project + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/fluence.md + +version: 2 +aquaInputPath: src/aqua/main.aqua +dependencies: + npm: + "@fluencelabs/aqua-lib": 0.6.0 + "@fluencelabs/spell": 0.0.1 + "@fluencelabs/aqua": 0.9.1-374 + cargo: + marine: 0.12.5 + mrepl: 0.18.8 +services: + ipfs_package: + get: ./configs/services/ipfs-package + deploy: + - deployId: default + multi_provider_query: + get: configs/services/multi-provider-query + deploy: + - deployId: default + simple_quorum: + get: configs/services/simple-quorum + deploy: + - deployId: default + utilities: + get: configs/services/utilities + deploy: + - deployId: default + eth_rpc: + get: configs/services/eth-rpc + deploy: + - deployId: default diff --git a/aqua-examples/decentralized-blockchain-gateway/scripts/build.sh b/aqua-examples/decentralized-blockchain-gateway/scripts/build.sh index 20bac77..7314008 100755 --- a/aqua-examples/decentralized-blockchain-gateway/scripts/build.sh +++ b/aqua-examples/decentralized-blockchain-gateway/scripts/build.sh @@ -8,33 +8,31 @@ rm -f artifacts/*.wasm cd wasm-modules cd curl-adapter -cargo update --aggressive marine build --release cp target/wasm32-wasi/release/curl_adapter.wasm ../../artifacts/ cd ../ipfs-adapter -cargo update --aggressive marine build --release cp target/wasm32-wasi/release/ipfs_adapter.wasm ../../artifacts/ cd ../multi-provider-query -cargo update --aggressive marine build --release cp target/wasm32-wasi/release/multi_provider_query.wasm ../../artifacts/ cd ../simple-quorum -cargo update --aggressive marine build --release cp target/wasm32-wasi/release/simple_quorum.wasm ../../artifacts/ cd ../ipfs-cli -cargo update --aggressive marine build --release cp target/wasm32-wasi/release/ipfs_cli.wasm ../../artifacts/ cd ../utilities -cargo update --aggressive marine build --release cp target/wasm32-wasi/release/utilities.wasm ../../artifacts/ +cd ../eth-rpc +marine build --release +cp target/wasm32-wasi/release/eth_rpc.wasm ../../artifacts/ + cd .. \ No newline at end of file diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/module.yaml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/module.yaml new file mode 100644 index 0000000..07800bc --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/curl-adapter/module.yaml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=../../.fluence/schemas/module.yaml.json + +# Defines [Marine Module](https://fluence.dev/docs/build/concepts/#modules). For Fluence CLI, **module** - is a directory which contains this config and either a precompiled .wasm Marine module or a source code of the module written in Rust which can be compiled into a .wasm Marine module. You can use `fluence module new` command to generate a template for new module + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/module.md + +version: 0 +type: rust +name: curl_adapter +mountedBinaries: + curl: /usr/bin/curl diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/Cargo.toml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/Cargo.toml index 08235d2..33f6809 100644 --- a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/Cargo.toml +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "eth-rpc" +name = "eth_rpc" version = "0.1.0" edition = "2021" [[bin]] -name = "eth-rpc" +name = "eth_rpc" path = "src/main.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/module.yaml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/module.yaml new file mode 100644 index 0000000..2b6392c --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/module.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=../../.fluence/schemas/module.yaml.json + +# Defines [Marine Module](https://fluence.dev/docs/build/concepts/#modules). For Fluence CLI, **module** - is a directory which contains this config and either a precompiled .wasm Marine module or a source code of the module written in Rust which can be compiled into a .wasm Marine module. You can use `fluence module new` command to generate a template for new module + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/module.md + +version: 0 +type: rust +name: eth_rpc diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/curl_transport.rs b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/curl_transport.rs index eca119c..290a29f 100644 --- a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/curl_transport.rs +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/curl_transport.rs @@ -84,9 +84,20 @@ impl Transport for CurlTransport { // FIX: if there's a bad uri, the panic kicks in here. - let response: Output = - serde_json::from_value(serde_json::from_slice(response.stdout.as_slice())?)?; + if response.ret_code != 0 { + let stdout = String::from_utf8_lossy(&response.stdout); + let error = if response.error.is_empty() { + stdout.to_string() + } else { + format!("error: {}\nstdout: {stdout}", response.error) + }; + return Err(web3::error::Error::Transport( + web3::error::TransportError::Message(format!("error: {}", error)), + )); + } + let response = serde_json::from_slice(response.stdout.as_slice())?; + let response: Output = serde_json::from_value(response)?; let result = match response { Output::Success(jsonrpc_core::types::Success { result, .. }) => result, diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/eth_call.rs b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/eth_call.rs index 48985b0..c6cf41f 100644 --- a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/eth_call.rs +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/eth_call.rs @@ -1,3 +1,4 @@ +use eyre::eyre; use marine_rs_sdk::marine; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -12,12 +13,13 @@ pub fn eth_call(uri: String, method: &str, json_args: Vec) -> JsonString let result: eyre::Result = try { let rt = Builder::new_current_thread().build()?; - let args: Result, _> = json_args - .into_iter() - .map(|a| serde_json::from_str(&a)) - .collect(); + let args: Result, _> = + json_args.iter().map(|a| serde_json::from_str(a)).collect(); + let args = args.map_err(|err| { + eyre!("Invalid arguments. Expected JSON serialized to string, got {json_args:?}: {err}") + })?; let transport = CurlTransport::new(uri); - let result = rt.block_on(transport.execute(method, args?))?; + let result = rt.block_on(transport.execute(method, args))?; result }; @@ -80,9 +82,6 @@ mod tests { let accounts = rpc.eth_call(uri, method, json_args); println!("bad method: {:?}", accounts); - - // println!("accounts: {:?}", accounts); - // assert_eq!(accounts.len(), 0); } #[marine_test( @@ -100,4 +99,37 @@ mod tests { // println!("accounts: {:?}", accounts); // assert_eq!(accounts.len(), 0); } + + #[marine_test( + config_path = "../tests_artifacts/Config.toml", + modules_dir = "../tests_artifacts" + )] + fn get_transaction(rpc: marine_test_env::eth_rpc::ModuleInterface) { + use serde_json::json; + + let uri: String = todo!("put Goerli ETH RPC URL here"); + let method: String = "eth_getTransactionByHash".into(); + let json_args: Vec = + vec![ + json!("0x3ffaa16b93ef90b9385b6f6a140d8297c43b6551bf8e8b804d9eecff7bc1509f") + .to_string(), + ]; + + let result = rpc.eth_call(uri.clone(), method.clone(), json_args); + assert!(result.success, "{}", result.error); + assert_eq!(result.value, "null", "{}", result.value); + + let json_args: Vec = + vec!["0x3ffaa16b93ef90b9385b6f6a140d8297c43b6551bf8e8b804d9eecff7bc1509f".into()]; + + let result = rpc.eth_call(uri, method, json_args); + assert!(!result.success); + assert!( + result + .error + .starts_with("Invalid arguments. Expected JSON serialized to string"), + "{}", + result.error + ); + } } diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/main.rs b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/main.rs index 1cff43a..4df22c0 100644 --- a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/main.rs +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/main.rs @@ -72,21 +72,6 @@ extern "C" { #[cfg(test)] mod tests { use marine_rs_sdk_test::marine_test; - // use web3::types::Address; - - #[marine_test( - config_path = "../tests_artifacts/Config.toml", - modules_dir = "../tests_artifacts" - )] - fn get_accounts(rpc: marine_test_env::eth_rpc::ModuleInterface) { - let uri: String = std::fs::read_to_string("./infura_uri.txt").unwrap(); - let accounts = rpc.call_get_accounts(uri); - // let addr: Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - // .parse() - // .unwrap(); - // assert_eq!(accounts, vec![addr.as_bytes().to_vec()]); - assert_eq!(accounts.len(), 0); - } #[marine_test( config_path = "../tests_artifacts/Config.toml", @@ -99,6 +84,5 @@ mod tests { let accounts = rpc.eth_call(uri, method, json_args); println!("accounts: {:?}", accounts); - // assert_eq!(accounts.len(), 0); } } diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/typed.rs b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/typed.rs index 80ab387..c8b1c24 100644 --- a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/typed.rs +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/typed.rs @@ -29,7 +29,12 @@ pub fn block_number(uri: String) -> U64Value { pub fn call(uri: String, req: String, block: u64) -> BytesValue { let result: eyre::Result = try { let req: CallRequest = serde_json::from_str(&req)?; - web3_call(uri, move |w| w.call(req, Some(BlockId::Number(BlockNumber::Number(block.into())))))? + web3_call(uri, move |w| { + w.call( + req, + Some(BlockId::Number(BlockNumber::Number(block.into()))), + ) + })? }; result.into() diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/values.rs b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/values.rs index 5875af7..f52608c 100644 --- a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/values.rs +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/src/values.rs @@ -5,9 +5,9 @@ use web3::types::U64; #[marine] pub struct JsonString { - value: String, - success: bool, - error: String, + pub value: String, + pub success: bool, + pub error: String, } impl From> for JsonString { @@ -29,9 +29,9 @@ impl From> for JsonString { #[marine] pub struct U64Value { - value: u64, - success: bool, - error: String, + pub value: u64, + pub success: bool, + pub error: String, } impl From> for U64Value { @@ -53,9 +53,9 @@ impl From> for U64Value { #[marine] pub struct BytesValue { - value: Vec, - success: bool, - error: String, + pub value: Vec, + pub success: bool, + pub error: String, } impl From> for BytesValue { @@ -73,4 +73,4 @@ impl From> for BytesValue { }, } } -} \ No newline at end of file +} diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/tests_artifacts/Config.toml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/tests_artifacts/Config.toml index ff62c27..3848843 100644 --- a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/tests_artifacts/Config.toml +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/tests_artifacts/Config.toml @@ -18,6 +18,5 @@ logger_enabled = true curl = "/usr/bin/curl" [[module]] -name = "eth-rpc" - -logger_enabled = true \ No newline at end of file +name = "eth_rpc" +logger_enabled = true diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/tests_artifacts/curl_adapter.wasm b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/tests_artifacts/curl_adapter.wasm index 4843757f39d0a5787dc21382f2cced7012b57c76..daec79fd464812e6d7110b3a15b54dfe1f490dc4 100755 GIT binary patch delta 20414 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 Vs!xvS6JrPv)bJBi>R6%g{{jrc(Ch#J delta 25455 zcmd^od7Kp0wSV2}?%8?uC9g|Ua_-sBshalf4dEZ|3_mo6<^O)|k|okX7Lp@nWhIfaXi0fhv_vi|FD)&V%1X*3 zl|9NLkaoU4lL|6Mf|J5;-DcQMp_$3*nn@V$<^xfMmubNh%G6LNbn!6fOzVhniAYk|mk` z3*WE=XtVk3l1n1ji>B18OTP3sR_4x~+vd5Qz7+4-HA!bv2i^Sz>)CA@0s0y1+3wHv-44I0Ez{zAogLCI zS@~B9O(xkadhti>8!Z2I_A$Hi4{SZ#$2PF{*+F&}yPw_1W-rp7XSFY}M_BzQ>?vl> zU&4OO+OA{6Tkm8)Vo$Oi>`OPWL`O2+elM$8d{y>}{p>Y1rSGJT?3zJ;X0NiPtmlb; zVjr+I%sBs6ww3*neU*KUeacp{RczLC>`|6`fIY-MW4Qxt;DpZY%vw-!=(g)gG@jI0 zG(SwTV{>X*og_EfQoVd|V`G(MOR;O2y?66AX-=(dzagDTpqfz7Y6?Cpe4|K!jGI1H9%aDDi=u^0uu)Z*2)!{A?nwolU zDcoBl?iFS$47_g>|6aI%A41N)G9ZB6a{;i~yP5wXJZkWc&5efqnLspT$R89j2GOWT zBBIKBH*yb?t=PoB5vd*!peUVAoe{V$vF!xOHG-V@+6Ylp8TQQ_4DP%N7JnDP`@V|EZ;^zUYM2 zfz-Z@jg^()LcRRnM!vk%msfn7|Fv|HyniE~TXr)650>2p;MUvAs~O$gQgJz9*(0h@ zpG34XhADueEChm<=Z{9~qX1$7uoKt6i%u9P79{TDMpOygWi2(K%8F9(N7xl07FFxNS3bUdgbV-7o zxKat566X6V#|+xNxv>k$Rgm!zRti>Kv6+vr8aguQU`yj92(uktP$eiIbb$oah6%Mb zoB6`3MBi&!EkyXVs)$lnQxbH6YCKgnp+|9Q+C3&_JqF0vGCr_}LZ^v6G)!9sG&f8rdJWoiP?an zRfE|S$fnS00tYG`XfN4-dLnyKsd0bH=Ee}=@b4?NT~N;Tq_7zIKT_&`yd{=A;h*X+ ze=K$?^qGGetC`-d6IKpH6NrPwU`DjXwji32JWx_>kEl~NU8o&;;YyKe%A%kZ_!c2~ znA6JwRrrQpcTOckAqHVqB_eo2Eg8FFB=MD@f|fvql#;+~z+@H_s-6_8FbryWLwwrk zf`K`0Ah0Q^mn)&1VKIydzZa`rqm&g)&OhRhk6ZC=vY;VY8!TL+KA1RaAz$P09#RDR|8XXf1ihYiuuVR(ejvKPT#?Fy1DO% zU+6~FF4Gwes9I*nT5M^QeBb6q6WEkd8)9V2XyK}?#h_bgA1h}T zvo;bS3RD9`zu5oL0-}*FM28L#h@Ldy!x$JsCho9-I{Ad^Xdnd;2N*2>grN%A0+~c0 zDy#$=WlCASJP5>*J8hWG^(WNP&R;s=hsVS0pOEnBfe(|}omV}K#(uT>HM(jZR7+R4 z4%%LIgyrX#4IV_U8UXg}ChUjjJVMxmIZ5n;Ir&|RNjuo39KC~&6jDCkP;-4j z%4L#rnifQW;6QqgFXeC7Eb1XJ1g@kGAfZ=l7PuyL7yK~fN$#wb19=K7av)DH)^6?9 zCHP$ub<;2*Q5%Q7&3ED3*T zWHmo^xNz0?4?mhYuMfY5(7j;9$$~F(z!&V{2s^{DbifyKi2+~0i+_(Vhvz(kFTtF| zmtaobXQbfE*&~nU%fgX@FW(tiD=y9;%398fonn+jSQY~@FWL#&UPMS4XGX4*0Z zz2=)mdNGn?nh7dUMsi$sq#O$s2JVX0&e+48rx&o3d1S&g_5?p~!X-T)W;J01VO25^ zE{W~r&rZ04HS#Y{9L+DAI7qZ6_20>)sC^#-czcY!7pK@Q0K``CT@xECA7-@?82U;( zjKKpZ)y99wK(9~?Y6Y_$dxOP1K5f!itoG$eO63y_u_D38$6n@}Cba{hfhSI-F|xg1 zYN?ZYM(uiow?K=vcih}3}<#HJ@wA?;tj4KBmpEw#k@AOMSulls&k7;|7%!}cMzzz&~Q6%t?@Rwl&n zovh?b>~M<+<>3{S2r&*L;K0y|5oscVj!&@In?!N3+c)8Ip-s>Pw9py*f!9*79|b4u zXAn-<&j1V#_R|NgU_UV;*L~!#?EKWKh}{c1B?t!?-Fj#vpLObxJfTTE>0L>ZAaDo9 zScSGJkgG-P0Gigz$U&rD$ismNE^5Pt{ZK4S5YkzS=ezb(FAwOxB}@s#L2xwo5iN=0 zyy=wENddwj?PO-k=K=bG;0?$QMjVIM8buLAZIFSN0m$x@ScPrq{l@rb|cDxqAUVu z+y@EqO%gb%9F0UvEFXK5A2_wXZp}?adG0CXxgZeTraE{xZ*<1?hBnysVjLt+fendW zur=>23FTibVHKo$%ADG89T*<`Qv|1Fu)PMtXNNi|^}tqywn64uOHC<){xZ2Sgxy07 zgcu=9L!v`B%dpuiA3+LH|^W`n|d2!>S0$@hre1IJBhOP~j>fEfny?$_9#=k@z8MMQ{q7YRi-=_z^-ql*h`F{Sa*2cP1-0 zPL`J<@<#RniW2LI#W;|;7B_}@kfjLQRNS3lw+sQPB$iha%jqgg*-yDrb|%bDh2U+i zj44UJ2wZUd$Zg4v4l3wExFEm-lrR~HO5FMY!a|sny|E9F&bk8MkDYZZzE7EQJHB6;auNU5^j{B71=)dATPm!AMEtZFQKBri zkbi5&=$cnib_>BFAa6!92qO2uu$RL1Dt1}yVg9EXL*;E7dCznD_u7UVl}e>jaZYVn zwHX4`JZGr9XCuGpocan37cSscq+RDU=ND3GAOtswT0&(s8nxGd9d3RbtdVf?kkuj! zislH8CSXCtUh$1!yCl#UK=c=UvSS#x6E4;MYz1iG0!&C!7!kW2Us5#G7(0P{BX6JC zzuyi_6Pt%lOK!lBG4>w1zJ=dAa}-<1e>AgcG-3?7szM>_L~|&h!&$Y=DS*V?^58C? zdF~_%X<$j^sxnBpgs9}3-C(5!*uHZojVtym31Ho4E)mm-nInan&pGe#%;CZ;tGmHM z1=#Pp!Q=ugdH&(CtN^?E{7I7w7&v74<(>$s2nR+;qj7tQ9L}?AV1xG}{9$#HjeW_D zUzDqDPDFi{07Inc8!jXDv)c_O#`Ij$j z$Rh+RL|Q-~_6mb}V{j;75o&8oIT+bb2~{y9!^gnIj7N_bW(SLxQ}`1ghPk8(5?o3* z{FDGKdywb^OcA;i5rm!uxA{pI4b5NA2={_yZ6Smxcm*<;;XIszz+;BONT^Q*VENr7 z)QxDJ+=4Hd_t;!90J~!L9(dI+3B-3M z19UxHVNE54NtNUd5iK9~HUft^wQy?%Z$mz%o427V6=IE=yg(Qpu)DYU-*Yz6x56w! zaT`6G3Dr@+j}Wv^i;YZyF6zM|T=faAv=+OsXiW~AFdQL!4-~|ZV`u?B7NP>BM^b48 zEfkOvK?|Mg(ZYP#mVz@Z4iaaqMaocD8}3yqK|ey{BzPC$(n)40AmlHc(tA`f4}uVZ zCV&zHF$Y>lXsR+uEJMZ(HS3dT&U%^?;YPhYmfw4}HilBCAO(FwSQwAx9G$2M+A$~ySc2P3+!nWF%qElbhuIz{ z!JLKdkN|}WAjJDf@&w2e2`#$eK}Oh)2w0@hEdmfG5=w{@O;%DHu124*1H@pQx8Jjk zeEW)f3l=!=btstyE**%_7Wk8wsca1Y!(}xr!YiAqd;kAQr8WOODh-aVE@(Ymic}{R z4K|%)6M44j+@44IS^k5jbB=+HxV(YlK}3{6A%-sl%ifmk6<-0*UI@Y?$owGm2)yP1 zMG8Veso*usa0`L91XUJJ6TV`CR0(?t>r-YwbR*^)BktP!5aZcfR%2op245;hnRzsi znfq0Aqe!2owcn&MBGQN4|1)I1SsYM6#=a8}3Na6_bi9RDuj*ACNGq+PmAL1An~mdD znIFpg*YejhkE8y#^)~MumR}ZP;XIKT0S@UPJ@kRfcKJYh5Q4|il$s(@Lbr%rDxL$8 zIzlr=DNN+2;bMMDxpNrqSD3_qnV-s19`hYPKMi-~r(yJgv4I+vl5<72Koy2!ek!Ub zsL0@caZR*ojL1(>NeeP{igYOVCOb{JDW#_2>69T-ZW@lAhHaC*q{md0sl%3#fucz% zGO8)3k^47b0k}LHl|=i|TXAs^OU8N;TSWa+DM1==JHK^S za#&EqsmC4Ea83=fE|eziJs4rgXP_11@6I||lyH<{3C9+R7T0EiG>NmiaYh(() zOYQG<13>sn?I+jpdu9)-dKul|f$i1Doa_MqtcwKVi1z;^M!&DPl+d`$BhDWE~! zED=E*F({aTf`~7o!;)^JH#VQl?%4X<=4V*`;D$yUZUu5;_iTxMS;Wudq@MH?U2Y^A zeTELZH*S;Ahg|Y1P(Ea{8eC8&fJ?|1TOd*v>V`KhHZ+Py{Ppq@k=541ZBwG6;2uFR z=hCjkxtiLv&^YN%N^*b(yz4Sd6dTMZ%{?W5gqIF5S`H3VC_pnU!}>sk;uE}7fOlDN zlQ1*r4jRE?BDcmu0f3Nz5*5**JO*nk63s{#*b_CxPVz_riGTV*#KK4-&6e!}EkUNe>=xXDEnQKFD#W`vxewr;U#!oE68Wo zgt{Ub%y|fv>L7$s7(y7-n?$H2Bcefp1s5wq^t7HLMi4DFN(OuJ$^+TbaE%D=?hM5c z2cQqoLwQgEsVhm6L!^BBZ)>bQrNj)OqPPhHE=;coLgm=yBJM;DfCP*F5jH_VUZPcw z2uk^aTL<9Hv2JyFvRSChQx=Vuh(|#wn1z5WAfANf0(2{>41q~;#bUpvG6f_e@B}gy zDG(RoS+Np{p_D*j6YA>_s3@M{EXrF6B!V?Fv5>2yn>np9V zGj;~wJpcRbG(LYpd&RUCdZa|6$s612c&z|=gWrvm%6xU)L;6;{OpDv*TY+10l? zCkzzTL-&i)+FsHXoPh_}98WDAgGrkf_U|J)1X$7AIH=Uc zzQb=`crx3`Us|ZhOV;oY7B-;taN8Bbj7CT=pZTuasK`l z1BdRyzWb0Hp%er!`Ow1}d2)yXZrR>L?zgrF>XS|q(6h}}W&VdTPAqo*d zNszb@E#oaA;fw;71<`U484Dh=VzeAY(9mrr3dqY&P7Rz?2dT9DL@yjf*#T2LUtD@XR-gOC)I4cXfUYI~A=p_TfL9g4UC@4je*G9|C7`R1fmQ)}&oR(CK-U}t9bwno>j3SI z`bLqw)iuPO=!^VN`@S#iUJw64&t4!L6tF>WgshU~q)-kZ8H|UzC=p8NkrUdirj(uu zP~C+h-5@YS{#cMLvT3CdF@EirXOw<~puoO$9pCfiiSjM$c;Bni@}9MP##IaC18ez< zS2?gO1`As77?k|vlD?3*4b zQb`ZxFus4uXbL2&ueGCl4_AcvtZQ3F2zPkcBPb=N3=~{v9g6n( zOUJM$wqComjNy^~%{L6g_X9Uv$JTT8#>?ns04gp7F9Uqz#=&g=)~9X+Hq_LW~&1h-itBN@STksePP> z7yJjed_ms7oDaIS8ouu2r1P>Dn2*{sae!0A-+kFvL9=;D!hwz*h)t?&+J`B~L zFbUr{X$`hXI#mLKAl}6#lrVzl{E$i*e!1~DY(#Gg8|x@isX;DA%%d=(>oHm0eh-;W z@SLodA=i;!Pmspr6h^Q~uMJRZyr|-VMrgxFM1txa<%h>xlc0p*TJeS_g>wQ|v9F#a zOIU9ZPDD^eED=-*!d+DYT3aj?o6Em@>+Ng?e`}>(61Wil)!SAb324846`R?;$IKNM zGn;Q&(PBV$?G>;H_74iae-B+ed0n6<_6{__QV|vGq4t~C(;Ytbj#ZG`-`vqy4Q(p+ z5_%?j?F@Pi=Vz8SK)gy~4SXR#U%m}~aaFav=U)DM{L#WW{Ej=jaNcs)a(3=f0G_>T za&b>fzIHS2ciZI5l{fQ>m0kDiR?TD$e9@}zi@d*TME>VYmXCf|pir`XM8&=&M52Ol z3C~4?pfU`xwqdWy%CMtK_%X8HcpZU)Q}|{jawgSMmB<`Y9lSn@Xc~qLVlkfO;}h8s z%rfM^E{j7BC9;H~EDn_{SV5R&DvwaY9z0mZY*b!~{*|G6g6bz?I7t{^1Ovr?By_7c zHueZ7LScqT*uI}04A$FgZUy(~@eQbsAlisRVo&hz-<`zV{FA$9DfIMB*sAp|~n z^h&7h0fdSG5OXx43uvGh25qCl?qO3xPr`!iZ228R?*90V5%D!Q1^UP+t*^tNXZY~d zR_P?HPH%5yS6?^)ScC{Mm_bEGlMq5g`!GM}o=yLEZl24%do}sGb^PvoN6DY9<=gK~ z#}BRr8AGvwKmrDAfc@!O-gC`8u=EeC8G%IcwKXRDkXNm(FBB>UfP~nQrpTo22;A+} z;%T^rR-9k7_QVQ;;WZ=L<-Kd$>KN_lWj~)qm%tr^xyWWL` z`+*dDofL_#pGLwNz#%Yn^M}FBf`{A8n>MVic#zR5_KC3(yka9B{cq-DHrBCA`HYRH z#|wEEC0&HDj1tecH`+4Ns}D8~%iqL;H|~Pe3TA->ufN=g`5*)!07(Pt2IOxt2on8AOr~Pt0fr(!7GE2B|x}$4yol(})5K@tr!A2?q(6%&Rt?I54O&MJCH8 zz2#=_fItQ>y6xiGO`}njx_#5+ny&LQ@OtD2yZS2IjHr2_g1IPEc4mPi8RRc(SwVz6+Sb|9sy{ z>mK3_nQ$2GBT6y$2Nd4D$OaNAT55;%EH5K*KO_wU>g*pd)5 z?2XMM*d1TJzu~AZj~>~jmP$6QU6hdPNCMu3qo(}{bR>Sx0}1}U`y&ne$$vu@@%~-V zf-~8Pr{l4qQglw&6v0ErRo~!$x!)eJmpYX2o;C0RQQ8P1SS&Q5NXnr94HcxJTgUu&tzE(;qzsWj6>?S{E;uj@D~(z9?>Ks zgie&i|H40hWVE|4l8#k!h06%zaP;DXE!W)0VBUHg&azui!$dvEmqaSbSNOtFxUCq-^3_d22^`9_8Qfvsn z=ZS&&#{&1qVvkc~17{g~9>fuiOA6bqsVCNo8(KdRHlX+LFRV+ z0rx@Kx(zsw2IPw)l31KXR06wL>{zV6U&QLd0#+AA|EnR#*@%UW*eob=p$J$d@yDO+ zA>Xl%|KQ0nu{|vCkv(z3(~w_r_LOogP<_f|U*OG8ohYwZ$M1XUOjg7H@)W&GKlJGl z>E+PdVb}s~!Y-p?J5!{y@%MLhj%^luh`qz2!{E`;M-p-gZ~YFx=IInUM06B74Q&*T zm`d4#Fqls~=lHKX(E5rrP9lY1_I>L?^hm4{RAcsfx(LTAqjf}wy|7zE3W}fK#M6i| z$i)BxR(eo{8jM~FO@a>V@z_PSdnZ5w8-l7-?2G(2-&JbXA-Jc4QLn--$?kyvyIHh1AfzuN zo;juFZ4jFgw-m3@b&e!P z>ZrJa-LcWpO3@Q{)?!%Kg{lPo#B#VfP>fQg;;4#X{#`%}naBr7PQ`kYsT;HRU5_s*r_>is+TV;}9=y6yncdGf)ZzyJ4J_y6V(SJOq;yO7Z^C>(r+fG!$z&e%w}CT;UyDE zSIef1gytvHnVg?7czoL^wvkWT))3D4nKs_G?V`Lio5iGzBuS^>7>1*GJ+*M%1Lyit zlGGpPaN!t$^9eWx;^+>q#`Pc^gO7p_!Szra3J!N}yYFTfE19O^f^bu>iCr}3@u-VKRN1)yWiw%UKr0F;=5lM%J%a8FRUzI z5RM5Nyv0|%cyg~bxH8eN2)%&sebHo}^8wpay~ajjQa$e7iX)C=693}%VO4VhC0cgK zlGK|k+xuk-_)5|$+#=G~MI@;o&TjS!x7BNIouxFlDIIg0J-0?Gvr6Y|zqwtR z>$lG8oGop~xRK~z96ti%iQ2{MD*ov9VdwWLi3tW0y>o5t^W4r(zg_Xcsdi}+?)3zm z&>fDW5(f#y2plx?(QwF&G#bYkuIw044{9&N1SC28anN3K3+K-5&e*YljpOsbKQzCi zfX3~B&@|n9HQ;(Yj$)se(C%~8HK8)2t+}JE73^$l&o$5Wl~#A2uXt^(o%neTKdZQ{ z%EDIv%K7+d3|vh+f2xvMj33vKq*Q5aw7{Dtr4M)@U0xcK@RJ_i93_LV&UV-HCsY7_ z<<@0C_$j-D@S_ijZ~_Mmsg%T#!lB{NaTqvE97VEOXs2-?y^|*5n1tg*94FzZFAv!8 zH;KDDYEO6umt_EN$C)_r3eGSc5WLkpE}VA|SJS!;f;|rS1UM<HdNK|&2;KXfife~o{v)&RlNB+sJ-SOD+V*LD%a6>8Nzf(O@@pa0UJKFw{Uq0(*u$bQgbReb78 zLs9SJ^Ikfsysk1P5fS_GM_(E#&#mNd0eB~XMCpFK?#IK}oBWI)kKwO;e{OlUDkhjJ z^CdqXa#CBX=Z~M|xBBhPo>*jc;r2lcEyq#3j$muF_~|%`v^oP*nDW6Y{?w00R7~m- z6PV%h_djl^n2Sp?bhxb9IXb-_m&AgDn4V-|E)J6X;`Nu%Ci_bAd?pSeJsoH9r8`p< z1A4|JI5p|B9{l;8m*m@UNw|y!P6RGqCkxlp7S0vY-hHAe=-2&vDy~OO7MAzyg`J}N zgguy-KEJ~mQ+1u^yRFUM98#4|W#q`QBb3Tm(4h)v62F-=3LhGDE)Fpf-}aL!`BTt? zjMNu#rv0|!OmhFF!pO_f{%3vGpbyPBK`G3L_IAJ^#bU*x{+x&F^Ko2&L&0Zk#aN}G zq2g+M^P6|6a=aIRcGoZZ5|Tx-UWoQZI4A6EomPlc;G;Aw1|G^jRPRFdQ zrsYzWXZmU)oi>yF>D?#wM$<4ezH3>TY|=Gyjy#UHyE(d4zwo7dK=ks6r=HPWWzLi4Z;W>2J3s++U4ObWY8=oX*) z%J_UHWh8ymGz>LixK`G8`i#J&ng@(hxp|$sz>`ojayc)Z*0e-UO(j&{>HF_)%5XD@ z1nA*e5c%iUGBZom;d@_HE~2qdMXXdYih>T(5pXx?3L!Yn#^gQj`dOr zKV_z}&H$cx_40{YCTFUakxr}WbV}3G&Iuz6a~hqqDU#9VyX|v;wq_bh%Qv;0p(os| zmv#p7AHRB`t6RQnWU~o;XY`Dfa;keZx5BBmx^tWGb5Zztr&+ComaxK{#J1*n^XGP$ zT2tNB^XjNww=kKg14|nkU=bSxQw0eAna+I4$9Q+OXbQ)>6}{oSsTzlxJGb(24x{ zeZBcRul29iG}SPDFRSWFBbT<4jzYhBg`c0QnaOATu^%7x`k1(7_({Vz5Pj-d)ljoe zEzi9^<}@{v%lcT#R5NKE^l*k1NtyCnuP~dgaNC>OIzUQK^HdjnG6&I)X(z$gzF8ZG&?GDka;y2K0n6p6m~2cug&n%CtNOl?@GQ@D zlKg=;ym%(Z@KVs_m0G7yENuj!ti zOPQvl^Y?#Y_sXT*OeUQ&lPRE)$v6f-@t1RZr&V;xxfvBgse1|2F}sAIcN($=;Y}J= z+R(kU=~&|4%BhUSdZ{@h>-nCS&81Z%mvYi#TfVNDng$U|BuzbGy3Pav)+|-aCNpX_ zV|Zy#O*<3$Yj0|CE0tCgIvAC7bvLCZok_gc9LIr$PcTVI}-WnQDrPE1E zH?q)>Y%c3LCz*Wt-v$rT=eI-WAs&Py6iPEplWbeYIe99N?H$4Qzty+5Wms7c?1A-2 z<}yj$Y3z2-cY$-lOsL6>1#9HkUH9THj2_G+Hl=GIfbLA@o8C^uGg(th=XAIpE0@+& z8RrxN_s&_mju|p(E#s+LF72G^!0z|sgWu`RC;ciKH(@soGY9rqURDP^9o}>AnQ_f@ zkyWZ0Bb)KO9Efw804H-PElYM@HFFT-lyf?PduOsn!th;B*L^LeL%q)ELbrD=rzT(o z5^lyPdM2DR58q2?Ow3|hhL+ZI*@WkuRYY#cWEVnZm|53PxC!`{v@@llo6QtfF&&t_ zzy%pF#hRsOeATm%0;|qce)c;fVrkFFrYs0FgvQcSE`Q+Nx`EIM*rSZ$>q#r6`?@o& z1d5KtX*z%Yo%*;6ZC2GRyc>M5p46Nf{GoSiduMXFRN8|8z(qg?T<4rA{NZd>Ke%WtpdFijK<2lR9SzaawF;(@1<($8WpY+S7;VJwsAQ`um;pWtA z3cfI-BkFK2sAyl z(nzOV=VJcGdt>?f_lCvOh+Z;j*UyBh`(lcC$ zxpVo9qV-0&VFclZs&&9!&TSG_7zuAuYhTzJ7+(*wQiMZ4kcc}Vf``B+rNPMObQl;n z;kbO%Z)@XP!ZP8Ql4c?S9wmJz!!P~qxVW3OQivI>td%sfIX&rkeD!ZH$YT;6mKZ!k zpp?{AC))(HjKDPuj|}V@8Wy=7%?%B>CjWeHXBO$QaL{gtIEjvjT{j$bSEvIdV0%-E zEJ$mCT8>{r5mcL(I};1>5C5*meZ*2m#!MIxTI8OVGmGE;nHf*%h#xihs&vxN!3;aI z`I_II(HrF+4>DvWG{f*L-*TEYQtzP!)j*g9+9VAZ9y6z!76dwNWt|qD*k|^JEryrU zT}w61G=frRj>FY`efjPChQ@V0t6Qn8m&m$F7eRzGmv7rQqF2s^x6!>ENh0iwGY`<= z@sz9k5FZ_M!wBHk%5VSE$peDLQ!s$ZWGZ1~-CPzv$7$j6mrLu;WP&GG^@|^|UZn`c48_bu5KqqoQrJeuj4+_kg4%1}#z6%=bDbMK;U<(K& z69|1Wu93`Yrqe0FuoiksL+q#Ph*hAv3%ThYQEtt@|yT%@1GkplF3}!L@1hpjnthh`Sb5z90$LU5@b>^vWb+HHJrtK z`bTHQAq1|W`q(kTyOf%9zQmV(&=U7OBc0WeNBGHPT1{r1FZ1vp)A5w0=hE4f3ZtdE znyWfj@#%k@avAz1axgtsMoas?b9FCaLo)uX=GLZ#t&5NlU2{c2NB@UGYyA;H>tUUs zl*dKH=6Nn$x9{Znvw!q@XFNBPO(T!WQe>u1aha@D2 zJTYM)00D`eyyiwWO)t5TxQbE`mD;ej!IU_xPH zL1Y-xB&?G2b(Z0e9xxkxpq$fvWF;mtcnZLU_g9g(TL!`&3cgUShiOcFgLU#5ADuZC zekzkO3=94T@lYc1FNUn^SAN2r>5WB!hxM>SfV^($U<x#5B@%(A+0BooLF!skOm~j&V%fPrY4FB@Z`a3@>@F=w);3;(cIqF`Va|K4b;#~ zAt&@wC>W$O3Fl!}S(sXo?Gc(7F*o!CIU`&v`obS?<<_TjKtwlTc}UR_^Sc>SbsiPH zja&v2sX?Sw-_?zj^B8BJjfLY@O%FK}h5Rm}Zs&1;72fn&(EyK4ZVj1_awL?pgds zbw?9y)H5vXU)kLGtdI&M^Uv}5{}|K9gf%CNpdrM@Msv>h*r_7$*#3_peOw>NXH~Go zO=W%GbGEU`;%4;oL2)fZxsPEbQYc}hG~Icgr$0Y8Zb99X7IGB|0CR@vyuk1Id{`Vd zBCF=~w4XCnBjH-ki~N<(NA*TF0JDq&59R^Kv(ENldx=y|L)54FIarZgR&&13bBAWe z)s%;XID^`mZ|c73J3rtr9U8=b$bWZeLfp@waDeG3M@k_Vc6JCOVn8)i)Kj2PNRcz1 z^P|AFKr~?sQzn>;yvuW5B2MK_CQjAP~eoU?P~ zJjUw#_%JM}1?m}Oj!0}1&QDn5$~MM^t=!32IWGgUbX>d=J?(jPCB0mdxOJkbT2Lq%ldtw^B*x<)eSQ96vdJ)US}g zvT}pWjA_Im=)ILjUX41a=Df=O!_XmrgtOIia~F2ZhQ0ICrmIK#S*#%T^V{2?_5kf+(~-q%ITClA>T%P zhj7DnO$WdI4wVRg3|{>9JATEz8-RYr{g=o5i2Iu>Zx6BI)2J|}tG&t`|7%9Y;p0`wEKwxG&)TQq1&~fR34~A( zMtua)bQWcyB;xq@iURmx7y?MKiQz%s;LY&NI_vyq<<2lm#$ow27vU4?;-02uGtO^U z#v)7~p(0;JWeZAadZ?pkoZqotf)n$aD3@xYl6S|xl}|^QaRQlxR2s=K40T4&`Ofc| z___T*h}&@#>P=*=DP2eHB7tD>{URKW0M+Om%1|A&>|BQ-%an^BGw_5NoA}=%1eJ)tu!s=R zzpgY(*+_O^0qAr8(ZkY*>c5W~N-NOs}8d5b??d38B!h{M7m6tIw;=Ta%d z$T**^e72l@xpxxD2kL4n9=@PtX?c#cZ{?H<);M^u+F%$Bs&e=(4h3&+q{b!Gacbg; yhbmZ)NDZ3Sd8#!bk({6=8c-e>cRRy@lj8"] +name = "multi-provider-query" +version = "0.1.0" edition = "2018" -description = "multi-provider-query, a Marine wasi module" -license = "Apache-2.0" [[bin]] -name = "multi_provider_query" +name = "multi-provider-query" path = "src/main.rs" [dependencies] -marine-rs-sdk = { version = "0.7.1", features = ["logger"] } -log = "0.4.14" -serde_json = "1.0.81" -serde = "1.0.137" +marine-rs-sdk = "0.7.1" [dev-dependencies] marine-rs-sdk-test = "0.8.1" - -[dev] -[profile.release] -opt-level = "s" diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/module.yaml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/module.yaml new file mode 100644 index 0000000..65dc352 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/multi-provider-query/module.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=../../.fluence/schemas/module.yaml.json + +# Defines [Marine Module](https://fluence.dev/docs/build/concepts/#modules). For Fluence CLI, **module** - is a directory which contains this config and either a precompiled .wasm Marine module or a source code of the module written in Rust which can be compiled into a .wasm Marine module. You can use `fluence module new` command to generate a template for new module + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/module.md + +version: 0 +type: rust +name: multi_provider_query 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 index 7a2362b..a2e578a 100644 --- 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 @@ -14,146 +14,146 @@ * 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}; + 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); + pub static NONCE_COUNTER: AtomicUsize = AtomicUsize::new(1); -module_manifest!(); + module_manifest!(); -fn main() {} + fn main() {} -fn get_nonce() -> u64 { - NONCE_COUNTER.fetch_add(1, Ordering::SeqCst) as u64 -} + 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 ProviderInfo { + pub url: String, + pub name: String, + } -#[marine] -pub struct EVMResult { - pub provider: String, - pub stdout: String, - pub stderr: 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)] + 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, -} + #[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, - } - } -} + 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, - ]; + 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 -} + 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, - }, - } -} + 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; + #[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 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); + 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); + 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; - } + 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(), - } -} + 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; -} + #[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/module.yaml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/module.yaml new file mode 100644 index 0000000..a64b8eb --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/simple-quorum/module.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=../../.fluence/schemas/module.yaml.json + +# Defines [Marine Module](https://fluence.dev/docs/build/concepts/#modules). For Fluence CLI, **module** - is a directory which contains this config and either a precompiled .wasm Marine module or a source code of the module written in Rust which can be compiled into a .wasm Marine module. You can use `fluence module new` command to generate a template for new module + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/module.md + +version: 0 +type: rust +name: simple_quorum 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 index 7b2b69c..860a107 100644 --- 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 @@ -47,6 +47,7 @@ fn mode<'a>(data: impl ExactSizeIterator) -> (u32, u64) { (*frequencies.get(&mode).unwrap(), *mode) } +#[allow(unused)] fn mean<'a>(data: impl ExactSizeIterator) -> Option { let n = data.len() as u64; if n < 1 { diff --git a/aqua-examples/decentralized-blockchain-gateway/wasm-modules/utilities/module.yaml b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/utilities/module.yaml new file mode 100644 index 0000000..f4ee9e1 --- /dev/null +++ b/aqua-examples/decentralized-blockchain-gateway/wasm-modules/utilities/module.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=../../.fluence/schemas/module.yaml.json + +# Defines [Marine Module](https://fluence.dev/docs/build/concepts/#modules). For Fluence CLI, **module** - is a directory which contains this config and either a precompiled .wasm Marine module or a source code of the module written in Rust which can be compiled into a .wasm Marine module. You can use `fluence module new` command to generate a template for new module + +# Documentation: https://github.com/fluencelabs/fluence-cli/tree/main/docs/configs/module.md + +version: 0 +type: rust +name: utilities