mirror of
https://github.com/fluencelabs/examples
synced 2024-12-04 19:20:17 +00:00
feat(eth): Use rust-web3 to serialize and serialize ETH calls (#417)
This commit is contained in:
parent
b537cdf345
commit
8999fcec85
@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "eth-rpc"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "eth-rpc"
|
||||
path = "src/main.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
web3 = { version = "0.18.0", features = [], default-features = false }
|
||||
#async-std = "1.12.0" # async-std does not support wasm32-wasi
|
||||
serde_json = "1.0.91"
|
||||
serde = "1.0.152"
|
||||
jsonrpc-core = "18.0.0"
|
||||
tokio = { version = "1.24.1", default-features = false, features = ["rt"] }
|
||||
eyre = "0.6.8"
|
||||
|
||||
marine-rs-sdk = "0.7.1"
|
||||
|
||||
[dev-dependencies]
|
||||
marine-rs-sdk-test = "0.8.1"
|
@ -0,0 +1,16 @@
|
||||
# Build eth-rpc.wasm
|
||||
```shell
|
||||
marine build --release
|
||||
```
|
||||
|
||||
# Build curl-adapter.wasm
|
||||
```shell
|
||||
cd ../curl-adapter
|
||||
marine build --release
|
||||
```
|
||||
|
||||
# Run tests
|
||||
```shell
|
||||
./test.sh
|
||||
```
|
||||
## It works!~
|
@ -0,0 +1,87 @@
|
||||
data RPCResponse:
|
||||
value: string
|
||||
success: bool
|
||||
error: ?string
|
||||
|
||||
data RPCResult:
|
||||
stdout: RPCResponse -- JSON-RPC result
|
||||
stderr: string -- curl error and other non json-rpc errors
|
||||
|
||||
data Web3Balance:
|
||||
balance: ?string -- hex string bignum
|
||||
success: bool
|
||||
error: ?string
|
||||
|
||||
data Web3GasUsed:
|
||||
gas_used: ?string -- hex string
|
||||
success: bool
|
||||
error: ?string
|
||||
|
||||
data Web3EthCall:
|
||||
result: ?string -- hex string
|
||||
success: bool
|
||||
error: ?string
|
||||
|
||||
service ParseToWeb3Balances("json"):
|
||||
parse(s:string) -> Web3Balance
|
||||
|
||||
-- e.g., https://docs.infura.io/infura/networks/ethereum/json-rpc-methods/eth_getbalance
|
||||
service Web3Services("service-id"):
|
||||
call_eth_get_balance() -> RPCResult
|
||||
call_eth_estimate_gas() -> RPCResult
|
||||
call_eth_call() -> RPCResult
|
||||
|
||||
-- rpc_params: account id, blockheight: ususally "latest"
|
||||
-- or we create a data struct and serialize it in aqua to []string
|
||||
func eth_ getBalance(peerid: string, service_id: string, uri: string, rpc_params: Vec<String>, nonce: u32) -> Web3Balance:
|
||||
result: *Web3Balance
|
||||
on peerid:
|
||||
Web3Services service_id
|
||||
res <- Web3Services.call_eth_get_balance(uri, rpc_params, nonce)
|
||||
if res.stdout.success==true:
|
||||
result.balance <- res.stdout.value
|
||||
result.success <<- true
|
||||
else:
|
||||
result.success <<- false
|
||||
result.error <<- res.stdout.value
|
||||
<- result[0]
|
||||
|
||||
-- here the data struct approach seems to make even more sense as we need the transaction call object:
|
||||
-- data TObject:
|
||||
-- from: ?[]u8 -- optional 20 bytes, address tx is sent from
|
||||
-- to: []u8 -- 20 bytes to address
|
||||
-- gas: ?string -- gas provided for execution of method haxadecimal
|
||||
-- gasPrice: ?string -- gasPrice used, hexadecimal
|
||||
-- maxFeesPerGase: ?string -- maximum fee in wei
|
||||
-- value: ?string -- value sent with tx, hexadecimal
|
||||
-- data: ?string -- hash of method signature and encoded params
|
||||
--func eth_estimateGas(peerid: string, service_id: string, uri: string, t_obj: TObject, nonce: u32) -> Web3GasUsed:
|
||||
-- the "easy" way: Vec<String>
|
||||
func eth_estimateGas(peerid: string, service_id: string, uri: string, rpc_params: []string, nonce: u32) -> Web3GasUsed:
|
||||
result: *Web3Gas
|
||||
on peerid:
|
||||
Web3Services service_id
|
||||
res <- Web3Services.call_eth_estimate_gas(uri, rpc_params, nonce)
|
||||
if res.stdout.success==true:
|
||||
result.gas_used <- res.stdout.value
|
||||
result.success <<- true
|
||||
else:
|
||||
result.success <<- false
|
||||
result.error <<- res.stdout.value
|
||||
<- result
|
||||
|
||||
-- also a big intake object, e.g. https://docs.infura.io/infura/networks/ethereum/json-rpc-methods/eth_call
|
||||
-- easy way -- client serializes to []string
|
||||
func eth_call(peerid: string, service_id: string, uri: string, rpc_params: []string, nonce: u32) -> Web3EthCall:
|
||||
result: *Web3EthCall
|
||||
on peerid:
|
||||
Web3Services service_id
|
||||
res <- Web3Services.call_eth_call(uri, rpc_params, nonce)
|
||||
if res.stdout.success==true:
|
||||
result.result <- res.stdout.value
|
||||
result.success <<- true
|
||||
else:
|
||||
result.success <<- false
|
||||
result.error <<- res.stdout.error ---not sure if this is how Web3 does it if there is a Revert error, e.g. https://docs.infura.io/infura/networks/ethereum/json-rpc-methods/eth_call
|
||||
<- result
|
||||
|
@ -0,0 +1,66 @@
|
||||
|
||||
-- https://www.jsonrpc.org/specification
|
||||
data RPCError:
|
||||
code: i32
|
||||
message: string
|
||||
data: ?string
|
||||
|
||||
data RPCResponse:
|
||||
jsonrpc: string
|
||||
result: string
|
||||
error: ?RPCError
|
||||
id: u32
|
||||
|
||||
data RPCResponse2:
|
||||
value: string
|
||||
success: bool
|
||||
error: ?string
|
||||
|
||||
data RPCResult:
|
||||
stdout: RPCResponse -- JSON-RPC result
|
||||
stderr: string -- curl error and other non json-rpc errors
|
||||
|
||||
|
||||
data RPCResult2:
|
||||
stdout: RPCResponse2 -- JSON-RPC result
|
||||
stderr: string -- curl error and other non json-rpc errors
|
||||
|
||||
|
||||
data Web3Accounts:
|
||||
accounts: []string
|
||||
|
||||
service ParseToAccounts("json"):
|
||||
parse(s:string) -> Web3Accounts
|
||||
|
||||
service Web3Services("service-id"):
|
||||
call_get_accounts() -> [][]u8
|
||||
call_get_accounts_json() -> RPCResult
|
||||
call_get_accounts_json_2() -> RPCResult2
|
||||
|
||||
|
||||
-- the bytestring return which allows you to do nothing until you convert
|
||||
-- the bytes using another service to be deployed and a pita to sort through
|
||||
-- error types
|
||||
func get_accounts(peerid: string, service_id: string) -> [][]u8:
|
||||
on peerid:
|
||||
Web3Services service_id
|
||||
res <- Web3Services.call_get_accounts()
|
||||
<- res
|
||||
|
||||
func get_accounts_jstring(peerid: string, service_id: string) -> Web3Accounts:
|
||||
on peerid:
|
||||
Web3Services service_id
|
||||
res <- Web3Services.call_get_accounts_json()
|
||||
-- if not error ...
|
||||
-- if not rpc error
|
||||
accounts <- ParseToAccounts.parse(res.stdout.result)
|
||||
<- accounts
|
||||
|
||||
func get_accounts_jstring_2(peerid: string, service_id: string) -> Web3Accounts:
|
||||
on peerid:
|
||||
Web3Services service_id
|
||||
res <- Web3Services.call_get_accounts_json_2()
|
||||
-- if not error ....
|
||||
if res.stdout.success == true:
|
||||
accounts <- ParseToAccounts.parse(res.stdout.value)
|
||||
<- accounts
|
@ -0,0 +1,4 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2022-12-06"
|
||||
targets = [ "x86_64-unknown-linux-gnu" ]
|
||||
components = [ "rustfmt" ]
|
@ -0,0 +1,120 @@
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use jsonrpc_core::types::request::Call;
|
||||
use jsonrpc_core::Output;
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
use web3::futures::future::BoxFuture;
|
||||
use web3::{RequestId, Transport};
|
||||
|
||||
use crate::curl_request;
|
||||
|
||||
pub type FutResult = BoxFuture<'static, web3::error::Result<Value>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CurlTransport {
|
||||
pub uri: String,
|
||||
id: Arc<AtomicUsize>,
|
||||
}
|
||||
impl CurlTransport {
|
||||
pub fn new(uri: String) -> Self {
|
||||
Self {
|
||||
uri,
|
||||
id: Arc::new(AtomicUsize::new(0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_id(&self) -> RequestId {
|
||||
self.id.fetch_add(1, Ordering::AcqRel)
|
||||
}
|
||||
}
|
||||
|
||||
impl Transport for CurlTransport {
|
||||
type Out = FutResult;
|
||||
|
||||
fn prepare(&self, method: &str, params: Vec<Value>) -> (RequestId, Call) {
|
||||
let id = self.next_id();
|
||||
let request = web3::helpers::build_request(id, method, params.clone());
|
||||
(id, request)
|
||||
}
|
||||
|
||||
fn send(&self, _: RequestId, call: Call) -> Self::Out {
|
||||
if let Call::MethodCall(call) = call {
|
||||
/*
|
||||
curl --request POST \
|
||||
--url $uri \
|
||||
--header 'accept: application/json' \
|
||||
--header 'content-type: application/json' \
|
||||
--data '
|
||||
{
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_accounts"
|
||||
}
|
||||
'
|
||||
*/
|
||||
let uri = self.uri.clone();
|
||||
Box::pin(async move {
|
||||
let json = json!(call).to_string();
|
||||
let args = vec![
|
||||
"--request",
|
||||
"POST",
|
||||
"--url",
|
||||
&uri,
|
||||
"--header",
|
||||
"accept: application/json",
|
||||
"--header",
|
||||
"content-type: application/json",
|
||||
"--data",
|
||||
json.as_str(),
|
||||
];
|
||||
let args = args.into_iter().map(|s| s.to_string()).collect();
|
||||
let response = curl_request(args);
|
||||
|
||||
/*
|
||||
println!(
|
||||
"response is: \nstdout: {:?}\nstderr: {:?}",
|
||||
String::from_utf8(response.stdout.clone()),
|
||||
String::from_utf8(response.stderr.clone())
|
||||
);
|
||||
|
||||
println!("slice: {:?}", serde_json::from_value::<Output>(serde_json::from_slice(response.stdout.as_slice())?));
|
||||
*/
|
||||
|
||||
// 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())?)?;
|
||||
|
||||
let result = match response {
|
||||
Output::Success(jsonrpc_core::types::Success { result, .. }) => result,
|
||||
|
||||
// no sure if that's enough vs the complete jsonrpc error msg
|
||||
Output::Failure(jsonrpc_core::types::Failure { error, .. }) => {
|
||||
serde_json::to_value(error.message).unwrap()
|
||||
} /*
|
||||
Output::Failure(failure) => panic!(
|
||||
"JSON RPC response was a failure {}",
|
||||
json!(failure).to_string()
|
||||
),
|
||||
*/
|
||||
/*
|
||||
Output::Failure(failure) => {
|
||||
let err = jsonrpc_core::types::error::Error.parse_error()
|
||||
}
|
||||
|
||||
format!("JSON RPC response was a failure {}",
|
||||
json!(failure).to_string()),
|
||||
*/
|
||||
};
|
||||
|
||||
// println!("parsed result is {}", result.to_string());
|
||||
Ok(result)
|
||||
})
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
// Box::pin(async { Ok(json!(["0x407d73d8a49eeb85d32cf465507dd71d507100c1"])) })
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
use marine_rs_sdk::marine;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tokio::runtime::Builder;
|
||||
use web3::Transport;
|
||||
|
||||
use crate::curl_transport::CurlTransport;
|
||||
use crate::values::JsonString;
|
||||
|
||||
#[marine]
|
||||
pub fn eth_call(uri: String, method: &str, json_args: Vec<String>) -> JsonString {
|
||||
let result: eyre::Result<Value> = try {
|
||||
let rt = Builder::new_current_thread().build()?;
|
||||
|
||||
let args: Result<Vec<Value>, _> = json_args
|
||||
.into_iter()
|
||||
.map(|a| serde_json::from_str(&a))
|
||||
.collect();
|
||||
let transport = CurlTransport::new(uri);
|
||||
let result = rt.block_on(transport.execute(method, args?))?;
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
||||
#[marine]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct RPCResult {
|
||||
provider_name: String,
|
||||
stdout: String,
|
||||
stderr: String,
|
||||
}
|
||||
|
||||
pub fn eth_call_2(uri: String, method: &str, json_args: Vec<String>) -> JsonString {
|
||||
let result: eyre::Result<Value> = try {
|
||||
let rt = Builder::new_current_thread().build()?;
|
||||
|
||||
let args: Result<Vec<Value>, _> = json_args
|
||||
.into_iter()
|
||||
.map(|a| serde_json::from_str(&a))
|
||||
.collect();
|
||||
let transport = CurlTransport::new(uri);
|
||||
let result = rt.block_on(transport.execute(method, args?))?;
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use marine_rs_sdk_test::marine_test;
|
||||
|
||||
#[marine_test(
|
||||
config_path = "../tests_artifacts/Config.toml",
|
||||
modules_dir = "../tests_artifacts"
|
||||
)]
|
||||
fn get_accounts_bad_uri(rpc: marine_test_env::eth_rpc::ModuleInterface) {
|
||||
let uri: String = "http://bad_uri.to".into();
|
||||
let method: String = "eth_accounts".into();
|
||||
let json_args: Vec<String> = vec![];
|
||||
|
||||
let accounts = rpc.eth_call(uri, method, json_args);
|
||||
println!("bad uri call: {:?}", accounts);
|
||||
// println!("accounts: {:?}", accounts);
|
||||
// assert_eq!(accounts.len(), 0);
|
||||
}
|
||||
|
||||
#[marine_test(
|
||||
config_path = "../tests_artifacts/Config.toml",
|
||||
modules_dir = "../tests_artifacts"
|
||||
)]
|
||||
fn get_accounts_bad_method(rpc: marine_test_env::eth_rpc::ModuleInterface) {
|
||||
let uri: String = std::fs::read_to_string("./infura_uri.txt").unwrap();
|
||||
let method: String = "eth_getAccounts".into();
|
||||
let json_args: Vec<String> = vec![];
|
||||
|
||||
let accounts = rpc.eth_call(uri, method, json_args);
|
||||
println!("bad method: {:?}", accounts);
|
||||
|
||||
// println!("accounts: {:?}", accounts);
|
||||
// assert_eq!(accounts.len(), 0);
|
||||
}
|
||||
|
||||
#[marine_test(
|
||||
config_path = "../tests_artifacts/Config.toml",
|
||||
modules_dir = "../tests_artifacts"
|
||||
)]
|
||||
fn get_accounts_good_uri(rpc: marine_test_env::eth_rpc::ModuleInterface) {
|
||||
let uri: String = std::fs::read_to_string("./infura_uri.txt").unwrap();
|
||||
let method: String = "eth_accounts".into();
|
||||
let json_args: Vec<String> = vec![];
|
||||
|
||||
let accounts = rpc.eth_call(uri, method, json_args);
|
||||
println!("all good: {:?}", accounts);
|
||||
|
||||
// println!("accounts: {:?}", accounts);
|
||||
// assert_eq!(accounts.len(), 0);
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
#![feature(try_blocks)]
|
||||
|
||||
use marine_rs_sdk::module_manifest;
|
||||
use marine_rs_sdk::{marine, MountedBinaryResult};
|
||||
use tokio::runtime::Builder;
|
||||
use web3::api::Eth;
|
||||
use web3::helpers::CallFuture;
|
||||
use web3::types::Address;
|
||||
use web3::Web3;
|
||||
|
||||
use crate::curl_transport::{CurlTransport, FutResult};
|
||||
|
||||
pub mod curl_transport;
|
||||
pub mod eth_call;
|
||||
pub mod typed;
|
||||
pub mod values;
|
||||
|
||||
module_manifest!();
|
||||
|
||||
pub fn main() {}
|
||||
|
||||
// #[tokio::main(flavor = "current_thread")]
|
||||
// flavor idea comes from https://github.com/rjzak/tokio-echo-test/blob/main/src/main.rs#L42
|
||||
// but seems to require additional tokio futures
|
||||
pub fn get_accounts(uri: String) -> web3::error::Result<Vec<Vec<u8>>> {
|
||||
let rt = Builder::new_current_thread().build()?;
|
||||
|
||||
let web3 = Web3::new(CurlTransport::new(uri));
|
||||
|
||||
let eth = web3.eth();
|
||||
println!("Calling accounts.");
|
||||
let accounts: CallFuture<Vec<Address>, FutResult> = eth.accounts();
|
||||
let accounts: web3::Result<Vec<Address>> = rt.block_on(accounts);
|
||||
println!("Accounts: {:?}", accounts);
|
||||
|
||||
Ok(accounts?
|
||||
.into_iter()
|
||||
.map(|a: Address| a.as_bytes().to_vec())
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn web3_call<
|
||||
Out: serde::de::DeserializeOwned,
|
||||
F: FnOnce(Eth<CurlTransport>) -> CallFuture<Out, FutResult>,
|
||||
>(
|
||||
uri: String,
|
||||
call: F,
|
||||
) -> web3::error::Result<Out> {
|
||||
let rt = Builder::new_current_thread()
|
||||
.build()
|
||||
.expect("error starting tokio runtime");
|
||||
|
||||
let web3 = Web3::new(CurlTransport::new(uri));
|
||||
|
||||
let result: CallFuture<Out, FutResult> = call(web3.eth());
|
||||
let result: web3::error::Result<Out> = rt.block_on(result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[marine]
|
||||
pub fn call_get_accounts(uri: String) -> Vec<Vec<u8>> {
|
||||
get_accounts(uri).expect("error calling main")
|
||||
}
|
||||
|
||||
#[marine]
|
||||
#[link(wasm_import_module = "curl_adapter")]
|
||||
extern "C" {
|
||||
pub fn curl_request(cmd: Vec<String>) -> MountedBinaryResult;
|
||||
}
|
||||
|
||||
#[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",
|
||||
modules_dir = "../tests_artifacts"
|
||||
)]
|
||||
fn get_accounts_generic(rpc: marine_test_env::eth_rpc::ModuleInterface) {
|
||||
let uri: String = std::fs::read_to_string("./infura_uri.txt").unwrap();
|
||||
let method: String = "eth_accounts".into();
|
||||
let json_args: Vec<String> = vec![];
|
||||
|
||||
let accounts = rpc.eth_call(uri, method, json_args);
|
||||
println!("accounts: {:?}", accounts);
|
||||
// assert_eq!(accounts.len(), 0);
|
||||
}
|
||||
}
|
@ -0,0 +1,263 @@
|
||||
#![allow(unused)]
|
||||
|
||||
use marine_rs_sdk::marine;
|
||||
use web3::types::{BlockId, BlockNumber, Bytes, CallRequest};
|
||||
|
||||
use crate::values::{BytesValue, JsonString, U64Value};
|
||||
use crate::web3_call;
|
||||
|
||||
/// Get list of available accounts.
|
||||
#[marine]
|
||||
pub fn accounts(uri: String) -> Vec<JsonString> {
|
||||
web3_call(uri, |w| w.accounts())
|
||||
.into_iter()
|
||||
.map(|a| {
|
||||
let json = serde_json::to_value(&a).map_err(eyre::Report::from);
|
||||
JsonString::from(json)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get current block number
|
||||
#[marine]
|
||||
pub fn block_number(uri: String) -> U64Value {
|
||||
web3_call(uri, |w| w.block_number()).into()
|
||||
}
|
||||
|
||||
/// Call a constant method of contract without changing the state of the blockchain.
|
||||
#[marine]
|
||||
pub fn call(uri: String, req: String, block: u64) -> BytesValue {
|
||||
let result: eyre::Result<Bytes> = try {
|
||||
let req: CallRequest = serde_json::from_str(&req)?;
|
||||
web3_call(uri, move |w| w.call(req, Some(BlockId::Number(BlockNumber::Number(block.into())))))?
|
||||
};
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
||||
/// Get coinbase address
|
||||
// #[marine]
|
||||
pub fn coinbase(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Compile LLL
|
||||
// #[marine]
|
||||
pub fn compile_lll(uri: String, code: String) -> Vec<u8> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Compile Solidity
|
||||
// #[marine]
|
||||
pub fn compile_solidity(uri: String, code: String) -> Vec<u8> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Compile Serpent
|
||||
// #[marine]
|
||||
pub fn compile_serpent(uri: String, code: String) -> Vec<u8> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Call a contract without changing the state of the blockchain to estimate gas usage.
|
||||
// #[marine]
|
||||
pub fn estimate_gas(uri: String, req: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get current recommended gas price
|
||||
// #[marine]
|
||||
pub fn gas_price(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns a collection of historical gas information. This can be used for evaluating the max_fee_per_gas
|
||||
/// and max_priority_fee_per_gas to send the future transactions.
|
||||
// #[marine]
|
||||
pub fn fee_history(
|
||||
uri: String,
|
||||
block_count: String,
|
||||
newest_block: String,
|
||||
reward_percentiles: Vec<f64>,
|
||||
) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get balance of given address
|
||||
// #[marine]
|
||||
pub fn balance(uri: String, address: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get all logs matching a given filter object
|
||||
// #[marine]
|
||||
pub fn logs(uri: String, filter: String) -> Vec<String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get block details with transaction hashes.
|
||||
// #[marine]
|
||||
pub fn block(uri: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get block details with full transaction objects.
|
||||
// #[marine]
|
||||
pub fn block_with_txs(uri: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get number of transactions in block
|
||||
// #[marine]
|
||||
pub fn block_transaction_count(uri: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get code under given address
|
||||
// #[marine]
|
||||
pub fn code(uri: String, address: String, block: String) -> Vec<u8> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get supported compilers
|
||||
// #[marine]
|
||||
pub fn compilers(uri: String) -> Vec<String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get chain id
|
||||
// #[marine]
|
||||
pub fn chain_id(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get available user accounts. This method is only available in the browser. With MetaMask,
|
||||
/// this will cause the popup that prompts the user to allow or deny access to their accounts
|
||||
/// to your app.
|
||||
// #[marine]
|
||||
pub fn request_accounts(uri: String) -> Vec<String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get storage entry
|
||||
// #[marine]
|
||||
pub fn storage(uri: String, address: String, idx: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get nonce
|
||||
// #[marine]
|
||||
pub fn transaction_count(uri: String, address: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get transaction
|
||||
// #[marine]
|
||||
pub fn transaction(uri: String, id: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get transaction receipt
|
||||
// #[marine]
|
||||
pub fn transaction_receipt(uri: String, hash: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get uncle header by block ID and uncle index.
|
||||
///
|
||||
/// This method is meant for TurboGeth compatiblity,
|
||||
/// which is missing transaction hashes in the response.
|
||||
// #[marine]
|
||||
pub fn uncle_header(uri: String, block: String, index: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get uncle by block ID and uncle index -- transactions only has hashes.
|
||||
// #[marine]
|
||||
pub fn uncle(uri: String, block: String, index: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get uncle count in block
|
||||
// #[marine]
|
||||
pub fn uncle_count(uri: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get work package
|
||||
// #[marine]
|
||||
pub fn work(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get hash rate
|
||||
// #[marine]
|
||||
pub fn hashrate(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get mining status
|
||||
// #[marine]
|
||||
pub fn mining(uri: String) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Start new block filter
|
||||
// #[marine]
|
||||
pub fn new_block_filter(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Start new pending transaction filter
|
||||
// #[marine]
|
||||
pub fn new_pending_transaction_filter(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Start new pending transaction filter
|
||||
// #[marine]
|
||||
pub fn protocol_version(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Sends a rlp-encoded signed transaction
|
||||
// #[marine]
|
||||
pub fn send_raw_transaction(uri: String, rlp: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Sends a transaction transaction
|
||||
// #[marine]
|
||||
pub fn send_transaction(uri: String, tx: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Signs a hash of given data
|
||||
// #[marine]
|
||||
pub fn sign(uri: String, address: String, data: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Submit hashrate of external miner
|
||||
// #[marine]
|
||||
pub fn submit_hashrate(uri: String, rate: String, id: String) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Submit work of external miner
|
||||
// #[marine]
|
||||
pub fn submit_work(uri: String, nonce: String, pow_hash: String, mix_hash: String) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get syncing status
|
||||
// #[marine]
|
||||
pub fn syncing(uri: String) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns the account- and storage-values of the specified account including the Merkle-proof.
|
||||
// #[marine]
|
||||
pub fn proof(uri: String, address: String, keys: String, block: String) -> String {
|
||||
todo!()
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
use marine_rs_sdk::marine;
|
||||
use serde_json::Value;
|
||||
use web3::types::Bytes;
|
||||
use web3::types::U64;
|
||||
|
||||
#[marine]
|
||||
pub struct JsonString {
|
||||
value: String,
|
||||
success: bool,
|
||||
error: String,
|
||||
}
|
||||
|
||||
impl From<eyre::Result<Value>> for JsonString {
|
||||
fn from(value: eyre::Result<Value>) -> Self {
|
||||
match value {
|
||||
Ok(value) => JsonString {
|
||||
value: value.to_string(),
|
||||
success: true,
|
||||
error: String::new(),
|
||||
},
|
||||
Err(err) => JsonString {
|
||||
value: String::new(),
|
||||
success: false,
|
||||
error: format!("{}\n{:?}", err, err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[marine]
|
||||
pub struct U64Value {
|
||||
value: u64,
|
||||
success: bool,
|
||||
error: String,
|
||||
}
|
||||
|
||||
impl From<web3::error::Result<U64>> for U64Value {
|
||||
fn from(value: web3::error::Result<U64>) -> Self {
|
||||
match value {
|
||||
Ok(value) => U64Value {
|
||||
value: value.as_u64(),
|
||||
success: true,
|
||||
error: String::new(),
|
||||
},
|
||||
Err(err) => U64Value {
|
||||
value: u64::default(),
|
||||
success: false,
|
||||
error: format!("{}\n{:?}", err, err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[marine]
|
||||
pub struct BytesValue {
|
||||
value: Vec<u8>,
|
||||
success: bool,
|
||||
error: String,
|
||||
}
|
||||
|
||||
impl From<eyre::Result<Bytes>> for BytesValue {
|
||||
fn from(value: eyre::Result<Bytes>) -> Self {
|
||||
match value {
|
||||
Ok(value) => BytesValue {
|
||||
value: value.0,
|
||||
success: true,
|
||||
error: String::new(),
|
||||
},
|
||||
Err(err) => BytesValue {
|
||||
value: vec![],
|
||||
success: false,
|
||||
error: format!("{}\n{:?}", err, err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
25
aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/test.sh
Executable file
25
aqua-examples/decentralized-blockchain-gateway/wasm-modules/eth-rpc/test.sh
Executable file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
mkdir -p tests_artifacts
|
||||
|
||||
# build eth-rpc.wasm
|
||||
marine build --release
|
||||
cp ./target/wasm32-wasi/release/eth-rpc.wasm tests_artifacts/
|
||||
|
||||
# build curl-adapter.wasm
|
||||
(cd ../curl-adapter; marine build --release)
|
||||
cp ../curl-adapter/target/wasm32-wasi/release/curl_adapter.wasm tests_artifacts/
|
||||
|
||||
#if [[ ! -f "tests_artifacts/sqlite3.wasm" ]]; then
|
||||
# # download SQLite 3
|
||||
# curl -L https://github.com/fluencelabs/sqlite/releases/download/v0.15.0_w/sqlite3.wasm -o tests_artifacts/sqlite3.wasm
|
||||
#fi
|
||||
|
||||
# run tests
|
||||
cargo nextest run --release --no-fail-fast --nocapture
|
@ -0,0 +1,23 @@
|
||||
modules_dir = "."
|
||||
|
||||
#[[module]]
|
||||
#name = "sqlite3"
|
||||
#mem_pages_count = 100
|
||||
#logger_enabled = false
|
||||
|
||||
#[module.wasi]
|
||||
#preopened_files = ["/tmp"]
|
||||
#mapped_dirs = { "tmp" = "." }
|
||||
|
||||
[[module]]
|
||||
name = "curl_adapter"
|
||||
max_heap_size = "2 MiB"
|
||||
logger_enabled = true
|
||||
|
||||
[module.mounted_binaries]
|
||||
curl = "/usr/bin/curl"
|
||||
|
||||
[[module]]
|
||||
name = "eth-rpc"
|
||||
|
||||
logger_enabled = true
|
Binary file not shown.
@ -0,0 +1,29 @@
|
||||
# Fluence decentralized RPC Workshop
|
||||
|
||||
ETHDenver 2/27/2023
|
||||
|
||||
|
||||
##Outline
|
||||
|
||||
## Intended bounty user experience
|
||||
|
||||
* embedd a the already created Fluence client peer into your dApp
|
||||
|
||||
|
||||
|
||||
## Deployment and code
|
||||
|
||||
* deploy eth-rpc service to each KRAS (?) peer at least once
|
||||
* create Registry instance for deployed services
|
||||
* create Aqua scaffold to interct with registry and modules
|
||||
* create Fluence JS reference client to embed into dApp
|
||||
|
||||
|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||
Fluence decentralized RPC (fRPC) is a ready to use ???
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user