tomusdrw / rust-web3 Goto Github PK
View Code? Open in Web Editor NEWEthereum JSON-RPC multi-transport client. Rust implementation of web3 library. ENS address: rust-web3.eth
License: MIT License
Ethereum JSON-RPC multi-transport client. Rust implementation of web3 library. ENS address: rust-web3.eth
License: MIT License
Requires #14
Dropping EventLoopHandle
before dropping Web3<T>
causes a hang if at least one request has been issued. Example code:
extern crate web3;
use web3::futures::Future;
fn main() {
let (eloop, http) = web3::transports::Http::new("http://localhost:8545").unwrap();
let web3 = web3::Web3::new(http);
let _accounts = web3.eth().accounts().wait().unwrap();
drop(eloop);
}
This became an issue when I created a struct that owned both EventLoopHandle
and Web3<T>
. If my struct fields were in the wrong order, the program would hang when attempting to drop my struct. If I switched the order of the fields, the program would run to completion.
The current version of JSON RPC includes the following for eth_getTransactionReceipt
It also returns either :
root
:DATA
32 bytes of post-transaction stateroot (pre Byzantium)
status
:QUANTITY
either 1 (success) or 0 (failure)
The Receipt
struct does not include either of these fields.
Trying to capture events from a Smart Contract, I registered a Filter via EthFilter.create_logs_filter(...)
.
The rpc responded with the filter id "0x03" which is internally transformed to a "3" as the id of the BaseFilter struct.
So when the filter changes are queried, it tries to query filter "0x3" instead of "0x03", omitting the leading zero, which results in the rpc error: "FilterSubprovider - no filter with that id: 0x3".
It is possible to fix this by changing the BaseFilter id to type "String", but that might not be wanted.
This is the according output from ganache-cli:
# The library requests a new Filter:
eth_newFilter
> {
> "jsonrpc": "2.0",
> "method": "eth_newFilter",
> "params": [
> {
> ...
> }
> ],
> "id": 1,
> "external": true
> }
...
# Response containing the Filter ID 0x03:
< {
< "id": 1,
< "jsonrpc": "2.0",
< "result": "0x03"
< }
...
# Filter Changes fail because of wrong ID, always returning empty JSON Array in the end
eth_getFilterChanges
> {
> "jsonrpc": "2.0",
> "method": "eth_getFilterChanges",
> "params": [
> "0x3"
> ],
> "id": 4,
> "external": true
> }
FilterSubprovider - no filter with that id: 0x3
< {
< "id": 4,
< "jsonrpc": "2.0",
< "result": []
< }
Best regards,
hardliner93
block number is U256
everywhere (https://tomusdrw.github.io/rust-web3/web3/types/enum.BlockNumber.html?search=block_number) except for BlockNumber::Number(u64)
(https://tomusdrw.github.io/rust-web3/web3/types/enum.BlockNumber.html) where it's a u64
. i think it would be good to have this consistent. if this is a change that's wanted i'll open a PR.
With the simple example below I get an error like Transport("SendError(\"...\")")
. It worked in the beginning but then stopped working. Any idea what could cause that?
extern crate web3;
use web3::futures::Future;
fn main() {
let (_, transport) = web3::transports::Http::new("http://localhost:8545").unwrap();
let web3 = web3::Web3::new(transport);
let accounts = web3.eth().accounts().wait().unwrap();
println!("Accounts: {:#?}", accounts);
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Transport("SendError(\"...\")")', src/libcore/result.rs:906:4
stack backtrace:
0: 0x10ed1fee3 - std::sys::imp::backtrace::tracing::imp::unwind_backtrace::h311e4a395df9fc90
1: 0x10ed1c410 - std::sys_common::backtrace::_print::hebb60342f79f20b6
2: 0x10ed21ce3 - std::panicking::default_hook::{{closure}}::h09124cef4c2cbbd0
3: 0x10ed219e2 - std::panicking::default_hook::hfa171ff8edf516fa
4: 0x10ed221f2 - std::panicking::rust_panic_with_hook::h3c41fb7cc19bbec2
5: 0x10ed220d4 - std::panicking::begin_panic::he2991ed22bf2bf67
6: 0x10ed21fa2 - std::panicking::begin_panic_fmt::hfd4bc5f2019d8a77
7: 0x10ed21f0a - rust_begin_unwind
8: 0x10ed58ec3 - core::panicking::panic_fmt::hae6752e5f963f9a5
9: 0x10eaccb49 - core::result::unwrap_failed::h229ca956bb43bfce
10: 0x10eacbb8b - <core::result::Result<T, E>>::unwrap::h317bd1e8f61b9bdc
11: 0x10ead42d7 - raiden_rs::main::h50693c2b3a30536b
12: 0x10ed2d66c - __rust_maybe_catch_panic
13: 0x10ed226f8 - std::rt::lang_start::heab07b9c4d3b2654
14: 0x10ead4434 - main
It is the continuation of #47.
Thank you for the correspondence of #47.
When I tried it with the latest source, I can compile it, but I get an InvalidOutputType error.
I tried several while changing the type, but it did not work.
contract interface:
function getValues() public constant returns (uint[], byte[64][], address[])
rust source:
let result = contract.query("getValues", (), None, Options::default());
let a = result.wait();
match a {
Ok(_) => {
let (v1, v2, v3): (Vec<U256>, Vec<Vec<u8>>, Vec<Address>) = a.unwrap();
println!("{:?} {:?} {:?}", v1, v2, v3);
}
Err(e) => println!("{:?}", e),
};
Try 1:
let (v1, v2, v3): (Vec<U256>, Vec<Vec<u8>>, Vec<Address>) = a.unwrap();
InvalidOutputType("Expected `bytes`, got FixedArray([FixedBytes([206]), FixedBytes([72]), FixedBytes([241]), FixedBytes([97]), FixedBytes([207]), FixedBytes([128]), FixedBytes([204]), FixedBytes([70]), FixedBytes([118]), FixedBytes([206]), FixedBytes([78]), FixedBytes([231]), FixedBytes([240]), FixedBytes([253]), FixedBytes([6]), FixedBytes([167]), FixedBytes([83]), FixedBytes([97]), FixedBytes([140]), FixedBytes([94]), FixedBytes([69]), FixedBytes([6]), FixedBytes([147]), FixedBytes([168]), FixedBytes([87]), FixedBytes([143]), FixedBytes([48]), FixedBytes([134]), FixedBytes([203]), FixedBytes([234]), FixedBytes([137]), FixedBytes([164]), FixedBytes([184]), FixedBytes([9]), FixedBytes([192]), FixedBytes([144]), FixedBytes([96]), FixedBytes([23]), FixedBytes([52]), FixedBytes([205]), FixedBytes([78]), FixedBytes([122]), FixedBytes([134]), FixedBytes([64]), FixedBytes([80]), FixedBytes([76]), FixedBytes([37]), FixedBytes([106]), FixedBytes([206]), FixedBytes([151]), FixedBytes([106]), FixedBytes([107]), FixedBytes([192]), FixedBytes([75]), FixedBytes([183]), FixedBytes([11]), FixedBytes([217]), FixedBytes([134]), FixedBytes([250]), FixedBytes([98]), FixedBytes([112]), FixedBytes([183]), FixedBytes([106]), FixedBytes([225])])")
Try 2:
let (v1, v2, v3): (Vec<U256>, Vec<Vec<H256>>, Vec<Address>) = a.unwrap();
InvalidOutputType("Expected `H256`, got [206]")
Try 3:
let (v1, v2, v3): (Vec<U256>, Vec<Vec<[H256; 1]>>, Vec<Address>) = a.unwrap();
InvalidOutputType("Expected `FixedArray(1)`, got FixedBytes([206])")
How can I receive the values?
Thank you.
I could deploy contracts using truffle in testrpc without problem.
...with chain-specific types which are decodable from it: (e.g. an EthashSeal
or a TendermintSeal
).
Hi.
I'm getting this when trying to build example:
error[E0432]: unresolved import `self::tokio_uds::UnixStream`
--> C:\Users\Andrey\.cargo\git\checkouts\rust-web3-ebc1a09fd5a9a2a2\c6bd1ab\src\transports\ipc.rs:10:5
|
10 | use self::tokio_uds::UnixStream;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `UnixStream` in the root
error: aborting due to previous error
error: Could not compile `web3`.
Tried both gnu and msvc toolchains, cargo and github versions. Am I missing something?
This problem also occurs on both Windows and Ubuntu.
I am using the following crate.
I am making a server program using jsonrpc-http-server.
When there is a request from the client, the server accesses the parity and returns the acquired value.
When calling BaseFilter's logs function in the program,
If there are a large number of result logs, the connection with Parity will remain and will remain.
Finally, a "Too many open files" error occurs and you can not connect to Parity.
For example, this function works normally if the result is "Logs: 1"
If the result is "Logs: 13530", a zombie connection will occur.
fn get_logs(web3: &Web3<web3::transports::Http>) {
let filter_build = FilterBuilder::default()
.topics(None, Some(vec![H256::from("0x000000000000000000000000a6e345c5f3cc2801f4892b6a67a670d897303d0d")]), None, None)
.from_block(BlockNumber::Number(0))
.build();
let filter = web3.eth_filter().create_logs_filter(filter_build).wait().unwrap();
let result = filter.logs().wait().unwrap();
println!("Logs: {:?}", result.len());
}
However, this problem only occurs when calling the logs function on jsonrpc-http-server, otherwise it does not occur.
I'm sorry if it is not a problem of rust-web3.
I would like to be able to call a function on a contract, wait until the transaction is confirmed, and then do something with the result. I have a feeling this is relatively straight-forward, but the documentation isn't clear.
There is wait_for_confirmations
and send_transaction_with_confirmation
, but neither of these are part of the contract interface, and I'm not sure what I should be passing to these. A simple example would be much appreciated.
Trying out the deployment of a contract, and everything is going smoothly except for the format of the bytecode/solidity contracts are supposed to be in. I'm getting many 'invalid data' and JSON parse errors for a simple 'greeter' contract.
I think it would help to include original solidity code, and maybe even a quick snippet with the process of compiling the solidity code to ABI + JSON with official solc compiler.
While testing parity bridge with nightly version (ok with 1.9.5). The deployment of contract with rust-web3 is stuck on confirmation wait. I believe it might be related with instant sealing running before and no block creation afterward. This kind of modification let me run it : cheme@8af0f34
I think it is a corner case (dev and no confirmation), but I still open this issue for information.
For reference : paritytech/parity-bridge#151
Doesn't bring in much value to have them, and you need to import them :/
Since this library is an LGPL license, I would like to use it with dynamic linking.
How can I do dynamic linking?
Thank you.
Have a look at the list in README
I'm running into a strange runtime error with some fairly simple Solidity code:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error(Abi(Msg("Cannot decode uint256")), State { next_error: Some(Error(InvalidData, State { next_error: None, backtrace: None })), backtrace: None })', /checkout/src/libcore/result.rs:916:5
Using these dependencies:
web3 = "0.2.0"
ethereum-types = "0.2"
Solidity code for context:
function makeDeposit() public payable returns (uint) {
deposits[msg.sender] = deposits[msg.sender].add(msg.value);
DepositMade(msg.sender, msg.value);
return deposits[msg.sender];
}
function getDeposit(address who) constant public returns (uint) {
return deposits[who];
}
Rust code:
use std::env;
use std::fs::File;
use std::io::prelude::*;
extern crate serde_json;
use serde_json::{Value, Error};
extern crate ethereum_types;
use ethereum_types::{H160};
extern crate web3;
use web3::contract::{Contract, Options};
use web3::types::{Address, U256};
use web3::futures::Future;
use std::{thread, time};
fn read_json_file(filename: &str) -> Value {
let file_path = format!("{}{}", env::current_dir().unwrap().display(), filename);
let mut json_file = File::open(file_path).expect(&format!("{} not found", filename));
let mut contents = String::new();
json_file.read_to_string(&mut contents)
.expect("something went wrong reading the file");
let v: Value = serde_json::from_str(&contents).unwrap();
v
}
fn main() {
let (_eloop, transport) = web3::transports::Http::new("http://localhost:8545").unwrap();
let web3 = web3::Web3::new(transport);
let accounts = web3.eth().accounts().wait().unwrap();
let _balance = web3.eth().balance(accounts[0], None).wait().unwrap();
let addresses: Value = read_json_file("/addresses.json");
let incentive_layer_address: H160 = H160::from_slice(addresses["incentiveLayer"].to_string().as_bytes());
let incentive_layer_abi: &Value = &read_json_file("/../build/contracts/IncentiveLayer.json")["abi"];
let il = serde_json::to_string(&incentive_layer_abi).unwrap();
let incentive_layer_contract = Contract::from_json(web3.eth(), incentive_layer_address, il.as_bytes()).unwrap();
incentive_layer_contract.call("makeDeposit", (), accounts[0], Options::with(|opt| opt.value = Some(1000.into())));
let ten_millis = time::Duration::from_millis(2000);
thread::sleep(ten_millis);
let result = incentive_layer_contract.query("getDeposit", (accounts[0], ), None, Options::default(), None);
//ERROR HERE!!!
let balance: U256 = result.wait().unwrap();
println!("{:?}", balance);
}
Seems that contracts can only query the blockchain or call methods.
There should be filter-like logs retrieval.
The contract I'm querying returns a fixed array.
Result::unwrap()on an
Err` value: Error(InvalidOutputType("Expected single element, got a list: [Bool(true), Uint(0x5ada606a), Uint(0x0)]")
I assume that is supported via the FixedArray macro? What signature, type definition has to be used for the query call to trigger/handle this?
As futures-rs
is part of the rust-web3
public API it should be re-exported.
I copied .editorconfig
from some other project and it had 2 spaces in it. We should re-format the code to 4 as per rust guidelines.
Version: 0.1.0
I'm trying to deploy a contract that takes 14 parameters in its constructor, and I get the following compile error:
error[E0277]: the trait bound `(web3::types::H160, web3::types::H160, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256): web3::contract::tokens::Tokenizable` is not satisfied
--> src/main.rs:292:10
|
292 | .execute(
| ^^^^^^^ the trait `web3::contract::tokens::Tokenizable` is not implemented for `(web3::types::H160, web3::types::H160, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256)`
|
= note: required because of the requirements on the impl of `web3::contract::tokens::Tokenize` for `(web3::types::H160, web3::types::H160, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256, web3::types::U256)`
I get a similar error for any more than 5 parameters. I suspect it's because the macro calls here only go up to 5: https://github.com/tomusdrw/rust-web3/blob/master/src/contract/tokens.rs#L88-L92
Support for signing transactions offline for sending to a locked node or potentially Infura would be extremely helpful. Similar functionality can be found in the ethereumjs-tx
for javascript. Much of this functionality exists across the parity codebase and needs to be pieced together. In discussing this with @tomusdrw, the general steps required would be:
ethabi
)ethkey
library)The documentation link on crates.io points to the docs for version 0.2.0
, but version 0.1.0
is currently the latest hosted version. The differences between the two versions are subtle enough that it isn't immediately obvious why things aren't working right if you try to use 0.1.0
based on the 0.2.0
docs.
I am very new to Rust, so there might be something that I'm overlooking; however, I was implementing some Parity-specific methods in a separate fork, and while benchmarking with criterion.rs, I noticed that method calls to parity_pendingTransactions
stalled indefinitely over IPC. This method works 100% of the time with the http transport, so I am assuming the problem isn't with my implementation.
At first I thought it was due to the size of the RPC return (this was when there were around 15k+ pending), but that doesn't quite make sense, since a 20MB buffered transfer shouldn't be an issue over a unix socket.
This issue did make me recall a problem I was having a while back in Java/Scala. We have a microservice that would often stall when polling our Parity node via IPC with the Web3j Java client. We then re-wrote that service from the ground-up in Scala with our own IPC implementation, but still had the same issue. We then switched all calls to http and everything was fine.
So, considering that there might be an issue with IPC calls across three different implementations, in three different languages, and since you work on Parity as well, we wanted to solicit your advice on where you think the issue might reside?
P.S.: You mentioned in another post that you have no issues getting 20k calls/sec using the rust-web3 client. Would you mind sharing the hardware specs used to achieve that? Thanks!
Example:
#[cfg(test)]
mod tests {
use api;
use helpers::tests::TestTransport;
use types::U256;
contract! {
contract Token {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function balanceOf(address _owner) constant returns (uint256 balance);
function transfer(address _to, uint256 _value) returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
function approve(address _spender, uint256 _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
}
}
#[test]
fn should_call_token_contract {
// given
let transport = helpers::tests::TestTransport::default();
let eth = api::Eth::new(transport);
let token = Token::at(1.into(), eth);
// when
let balance = token.balanceOf(5.into());
// then
assert_eq!(balance, U256::from(10));
}
}
The HTTP transport does not support TLS:
let (_eloop, transport) = web3::transports::Http::new("https://sokol.poa.network").unwrap();
leads to
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Transport("Io(Error { repr: Custom(Custom { kind: InvalidInput, error: NotHttp }) })")', src/libcore/result.rs:906:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.
eth_subscribe
takes parameters which appear similar to a web3::types::Filter
, but aren't, their format is described at https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB#logs . Passing filters in the same format as eth_getLogs
et. al. results in no events being delivered.
Probably can port over or publish part of ethcore-rpc
Assuming that this is possible, an example showing how to deploy an instance of a new contract would be great. The example could assume that "solc" is installed on the system and shell out to it to compile the contract.
More generic support for confirmations would be nice.
Currently we have a bunch of methods like "send_transaction_with_confirmations" instead it would be good to have a trait that can be implemented for some return types (e.g. futures resolving to transaction hashes) that allows you to (optionally) wait for confirmations.
According to the JSON RPC, type: String is no longer used and logs now return with removed: bool. https://github.com/ethereum/wiki/wiki/JSON-RPC#returns-42
There is a function of such a contract.
function getValues() public constant returns (uint[], byte[64][], address[])
I wrote the Rust code to receive the value, but this is an error.
let result = contract.query("getValues", (), None, Options::default());
let values: Vec<Token> = result.wait().unwrap();
error[E0277]: the trait bound `std::vec::Vec<ethabi::Token>: web3::contract::tokens::Tokenizable` is not satisfied
It worked when you made changes to crate, but I think this is a bad way.
use ethabi::Token;
-> use web3::contract::tokens::Token;
rust-web3/src/contract/tokens.rs:3
use ethabi::Token;
->pub use ethabi::Token;
ethabi/src/token/token.rs:7
#[derive(Debug, PartialEq, Clone)]
->#[derive(Debug, PartialEq, Clone, Deserialize)]
How is the best way to do it?
Thank you.
hey guys, probably a noob question. but i'd like to convert the U256
gotten from the balance
function to a human readable number. I assume a string u64 is the only way to do this?
i tried using the low_u64
but i'm not even sure what that does, but the number it returns is wrong.
code 👇
extern crate web3;
use web3::*;
use types::{U256, Address};
use futures::{Future};
#[derive(Debug)]
struct Mapping {
address: Address,
balance: u64
}
impl Mapping {
fn new (address: Address, balance: U256) -> Mapping {
Mapping {
address,
balance: balance.low_u64()
}
}
}
fn main() {
let (_eloop, transport) = web3::transports::Http::new("http://localhost:8545").unwrap();
let web3 = web3::Web3::new(transport);
let accounts = web3.eth().accounts().wait().unwrap();
let balances: Vec<Mapping> = accounts.into_iter().fold(Vec::new(),|mut accum, address| {
let balance = web3.eth().balance(address, None).wait();
accum.push(Mapping::new(address, balance.unwrap()));
accum
});
for balance in balances {
println!("Balance : {:?}", balance)
}
}
ganache-cli -e 30 -a 1
Ganache CLI v6.0.3 (ganache-core: 2.0.2)
Available Accounts
==================
(0) 0x6ce23c45eb5b818fdaf76944ba5dd5cf56990a83
Private Keys
==================
(0) 12059b88a7fd4db2e973e4c9670d344b119cd7f9b7f21324bf24245beb9eb4fc
HD Wallet
==================
Mnemonic: image want animal chimney know dune age board world volcano great subway
Base HD Path: m/44'/60'/0'/0/{account_index}
Listening on localhost:8545
eth_accounts
eth_getBalance
cargo run master ✚ ◼
Compiling cryptobot v0.1.0 (file:///home/seunlanlege/Projects/cryptobot)
Finished dev [unoptimized + debuginfo] target(s) in 2.97 secs
Running `target/debug/cryptobot`
Balance : Mapping { address: 0x6ce23c45eb5b818fdaf76944ba5dd5cf56990a83, balance: 7766279631452241920 }
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.