From c9c8f920d2b7b8cd636e490a3b10aea17a464249 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 3 Apr 2017 09:40:18 +0200 Subject: [PATCH] Futures-based native wrappers for contract ABIs (#5341) * initial native contract generator * get generated code compiling * unit tests for type codegen * autogenerate registry contract * native_contracts entry for registry * service_transaction_checker * fixed indentation --- Cargo.lock | 46 ++- ethcore/Cargo.toml | 74 ++-- ethcore/native_contracts/Cargo.toml | 15 + ethcore/native_contracts/build.rs | 40 ++ ethcore/native_contracts/generator/Cargo.toml | 9 + ethcore/native_contracts/generator/src/lib.rs | 346 ++++++++++++++++++ ethcore/native_contracts/src/lib.rs | 30 ++ ethcore/native_contracts/src/registry.rs | 22 ++ .../src/service_transaction.rs | 22 ++ ethcore/src/client/client.rs | 77 ++-- ethcore/src/client/mod.rs | 1 - ethcore/src/client/registry.rs | 338 ----------------- ethcore/src/lib.rs | 54 +-- .../src/miner/service_transaction_checker.rs | 173 +-------- 14 files changed, 642 insertions(+), 605 deletions(-) create mode 100644 ethcore/native_contracts/Cargo.toml create mode 100644 ethcore/native_contracts/build.rs create mode 100644 ethcore/native_contracts/generator/Cargo.toml create mode 100644 ethcore/native_contracts/generator/src/lib.rs create mode 100644 ethcore/native_contracts/src/lib.rs create mode 100644 ethcore/native_contracts/src/registry.rs create mode 100644 ethcore/native_contracts/src/service_transaction.rs delete mode 100644 ethcore/src/client/registry.rs diff --git a/Cargo.lock b/Cargo.lock index c0c904fe3..8a70f35a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -361,7 +361,7 @@ dependencies = [ [[package]] name = "ethabi" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -392,7 +392,7 @@ dependencies = [ "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.7.0", "ethcore-bloom-journal 0.1.0", "ethcore-devtools 1.7.0", @@ -407,6 +407,7 @@ dependencies = [ "ethkey 0.2.0", "ethstore 0.1.0", "evmjit 1.7.0", + "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "hardware-wallet 1.7.0", "hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -414,6 +415,7 @@ dependencies = [ "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "native-contracts 0.1.0", "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -944,6 +946,14 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "heck" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hidapi" version = "0.3.1" @@ -1394,6 +1404,25 @@ dependencies = [ "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "native-contract-generator" +version = "0.1.0" +dependencies = [ + "ethabi 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "heck 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "native-contracts" +version = "0.1.0" +dependencies = [ + "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-util 1.7.0", + "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "native-contract-generator 0.1.0", +] + [[package]] name = "native-tls" version = "0.1.0" @@ -1593,7 +1622,7 @@ dependencies = [ name = "parity-hash-fetch" version = "1.7.0" dependencies = [ - "ethabi 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-util 1.7.0", "fetch 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1703,7 +1732,7 @@ dependencies = [ name = "parity-updater" version = "1.7.0" dependencies = [ - "ethabi 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.7.0", "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", @@ -2503,6 +2532,11 @@ name = "unicode-normalization" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-segmentation" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.0.4" @@ -2678,7 +2712,7 @@ dependencies = [ "checksum elastic-array 0.6.0 (git+https://github.com/paritytech/elastic-array)" = "" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)" = "" -"checksum ethabi 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d8f6cc4c1acd005f48e1d17b06a461adac8fb6eeeb331fbf19a0e656fba91cd" +"checksum ethabi 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63df67d0af5e3cb906b667ca1a6e00baffbed87d0d8f5f78468a1f5eb3a66345" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb" "checksum futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8e51e7f9c150ba7fd4cee9df8bf6ea3dea5b63b68955ddad19ccd35b71dcfb4d" @@ -2688,6 +2722,7 @@ dependencies = [ "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1" "checksum heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "abb306abb8d398e053cfb1b3e7b72c2f580be048b85745c52652954f8ad1439c" +"checksum heck 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f807d2f64cc044a6bcf250ff23e59be0deec7a16612c014f962a06fa7e020f9" "checksum hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)" = "" "checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae" "checksum hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)" = "" @@ -2848,6 +2883,7 @@ dependencies = [ "checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764" "checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" "checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" +"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum untrusted 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "193df64312e3515fd983ded55ad5bcaa7647a035804828ed757e832ce6029ef3" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 86d623e93..697ac2e1c 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -11,44 +11,46 @@ build = "build.rs" "ethcore-ipc-codegen" = { path = "../ipc/codegen" } [dependencies] -log = "0.3" -env_logger = "0.4" -rustc-serialize = "0.3" -rust-crypto = "0.2.34" -num_cpus = "1.2" -crossbeam = "0.2.9" -lazy_static = "0.2" -bloomchain = "0.1" -semver = "0.6" bit-set = "0.4" -time = "0.1" -rand = "0.3" -byteorder = "1.0" -transient-hashmap = "0.4" -linked-hash-map = "0.3.0" -lru-cache = "0.1.0" -itertools = "0.5" -ethabi = "1.0.0" -evmjit = { path = "../evmjit", optional = true } -clippy = { version = "0.0.103", optional = true} -ethash = { path = "../ethash" } -ethcore-util = { path = "../util" } -ethcore-io = { path = "../util/io" } -ethcore-devtools = { path = "../devtools" } -ethjson = { path = "../json" } -ethcore-ipc = { path = "../ipc/rpc" } -ethstore = { path = "../ethstore" } -ethkey = { path = "../ethkey" } -ethcore-ipc-nano = { path = "../ipc/nano" } -rlp = { path = "../util/rlp" } -ethcore-stratum = { path = "../stratum" } -ethcore-bloom-journal = { path = "../util/bloom" } -hardware-wallet = { path = "../hw" } -ethcore-logger = { path = "../logger" } -stats = { path = "../util/stats" } -hyper = { git = "https://github.com/paritytech/hyper", default-features = false } -num = "0.1" +bloomchain = "0.1" bn = { git = "https://github.com/paritytech/bn" } +byteorder = "1.0" +clippy = { version = "0.0.103", optional = true} +crossbeam = "0.2.9" +env_logger = "0.4" +ethabi = "1.0.0" +ethash = { path = "../ethash" } +ethcore-bloom-journal = { path = "../util/bloom" } +ethcore-devtools = { path = "../devtools" } +ethcore-io = { path = "../util/io" } +ethcore-ipc = { path = "../ipc/rpc" } +ethcore-ipc-nano = { path = "../ipc/nano" } +ethcore-logger = { path = "../logger" } +ethcore-stratum = { path = "../stratum" } +ethcore-util = { path = "../util" } +ethjson = { path = "../json" } +ethkey = { path = "../ethkey" } +ethstore = { path = "../ethstore" } +evmjit = { path = "../evmjit", optional = true } +futures = "0.1" +hardware-wallet = { path = "../hw" } +hyper = { git = "https://github.com/paritytech/hyper", default-features = false } +itertools = "0.5" +lazy_static = "0.2" +linked-hash-map = "0.3.0" +log = "0.3" +lru-cache = "0.1.0" +native-contracts = { path = "native_contracts" } +num = "0.1" +num_cpus = "1.2" +rand = "0.3" +rlp = { path = "../util/rlp" } +rust-crypto = "0.2.34" +rustc-serialize = "0.3" +semver = "0.6" +stats = { path = "../util/stats" } +time = "0.1" +transient-hashmap = "0.4" [features] jit = ["evmjit"] diff --git a/ethcore/native_contracts/Cargo.toml b/ethcore/native_contracts/Cargo.toml new file mode 100644 index 000000000..085908509 --- /dev/null +++ b/ethcore/native_contracts/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "native-contracts" +description = "Generated Rust code for Ethereum contract ABIs" +version = "0.1.0" +authors = ["Parity Technologies "] +build = "build.rs" + +[dependencies] +ethabi = "1.0" +futures = "0.1" +byteorder = "1.0" +ethcore-util = { path = "../../util" } + +[build-dependencies] +native-contract-generator = { path = "generator" } diff --git a/ethcore/native_contracts/build.rs b/ethcore/native_contracts/build.rs new file mode 100644 index 000000000..a8488617a --- /dev/null +++ b/ethcore/native_contracts/build.rs @@ -0,0 +1,40 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate native_contract_generator; + +use std::path::Path; +use std::fs::File; +use std::io::Write; + +// TODO: `include!` these from files where they're pretty-printed? +const REGISTRY_ABI: &'static str = r#"[{"constant":true,"inputs":[{"name":"_data","type":"address"}],"name":"canReverse","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"bytes32"}],"name":"setData","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"}],"name":"confirmReverse","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[{"name":"success","type":"bool"}],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"drop","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"setFee","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_to","type":"address"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getData","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserved","outputs":[{"name":"reserved","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"proposeReverse","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"hasReverse","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"getOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"getReverse","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_data","type":"address"}],"name":"reverse","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"uint256"}],"name":"setUint","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"confirmReverseAs","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"removeReverse","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"address"}],"name":"setAddress","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}]"#; +const SERVICE_TRANSACTION_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"}]"#; + +fn build_file(name: &str, abi: &str, filename: &str) { + let code = ::native_contract_generator::generate_module(name, abi).unwrap(); + + let out_dir = ::std::env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join(filename); + let mut f = File::create(&dest_path).unwrap(); + + f.write_all(code.as_bytes()).unwrap(); +} + +fn main() { + build_file("Registry", REGISTRY_ABI, "registry.rs"); + build_file("ServiceTransactionChecker", SERVICE_TRANSACTION_ABI, "service_transaction.rs"); +} diff --git a/ethcore/native_contracts/generator/Cargo.toml b/ethcore/native_contracts/generator/Cargo.toml new file mode 100644 index 000000000..26e9a6611 --- /dev/null +++ b/ethcore/native_contracts/generator/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "native-contract-generator" +description = "Generates Rust code for ethereum contract ABIs" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +ethabi = "1.0.2" +heck = "0.2" diff --git a/ethcore/native_contracts/generator/src/lib.rs b/ethcore/native_contracts/generator/src/lib.rs new file mode 100644 index 000000000..f49caf227 --- /dev/null +++ b/ethcore/native_contracts/generator/src/lib.rs @@ -0,0 +1,346 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Rust code contract generator. +//! The code generated will require a dependence on the `ethcore-util`, +//! `ethabi`, `byteorder`, and `futures` crates. +//! This currently isn't hygienic, so compilation of generated code may fail +//! due to missing crates or name collisions. This will change when +//! it can be ported to a procedural macro. + +use ethabi::Contract; +use ethabi::spec::{Interface, ParamType, Error as AbiError}; +use heck::SnakeCase; + +extern crate ethabi; +extern crate heck; + +/// Errors in generation. +#[derive(Debug)] +pub enum Error { + /// Bad ABI. + Abi(AbiError), + /// Unsupported parameter type in given function. + UnsupportedType(String, ParamType), +} + +/// Given an ABI string, generate code for a a Rust module containing +/// a struct which can be used to call it. +// TODO: make this a proc macro when that's possible. +pub fn generate_module(struct_name: &str, abi: &str) -> Result { + let contract = Contract::new(Interface::load(abi.as_bytes()).map_err(Error::Abi)?); + let functions = generate_functions(&contract)?; + + Ok(format!(r##" +use byteorder::{{BigEndian, ByteOrder}}; +use futures::{{future, Future, BoxFuture}}; +use ethabi::{{Contract, Interface, Token}}; +use util::{{self, Uint}}; + +pub struct {name} {{ + contract: Contract, + /// Address to make calls to. + pub address: util::Address, +}} + +const ABI: &'static str = r#"{abi_str}"#; + +impl {name} {{ + /// Create a new instance of `{name}` with an address. + /// Calls can be made, given a callback for dispatching calls asynchronously. + pub fn new(address: util::Address) -> Self {{ + let contract = Contract::new(Interface::load(ABI.as_bytes()) + .expect("ABI checked at generation-time; qed")); + {name} {{ + contract: contract, + address: address, + }} + }} + + {functions} +}} +"##, + name = struct_name, + abi_str = abi, + functions = functions, + )) +} + +// generate function bodies from the ABI. +fn generate_functions(contract: &Contract) -> Result { + let mut functions = String::new(); + for function in contract.functions() { + let name = function.name(); + let snake_name = name.to_snake_case(); + let inputs = function.input_params(); + let outputs = function.output_params(); + + let (input_params, to_tokens) = input_params_codegen(&inputs) + .map_err(|bad_type| Error::UnsupportedType(name.into(), bad_type))?; + + let (output_type, decode_outputs) = output_params_codegen(&outputs) + .map_err(|bad_type| Error::UnsupportedType(name.into(), bad_type))?; + + functions.push_str(&format!(r##" +/// Call the function "{abi_name}" on the contract. +/// Inputs: {abi_inputs:?} +/// Outputs: {abi_outputs:?} +pub fn {snake_name}(&self, call: F, {params}) -> BoxFuture<{output_type}, String> + where F: Fn(util::Address, Vec) -> U, U: Future, Error=String> + Send + 'static +{{ + let function = self.contract.function(r#"{abi_name}"#.to_string()) + .expect("function existence checked at compile-time; qed"); + let call_addr = self.address; + + let call_future = match function.encode_call({to_tokens}) {{ + Ok(call_data) => (call)(call_addr, call_data), + Err(e) => return future::err(format!("Error encoding call: {{:?}}", e)).boxed(), + }}; + + call_future + .and_then(move |out| function.decode_output(out).map_err(|e| format!("{{:?}}", e))) + .map(::std::collections::VecDeque::from) + .and_then(|mut outputs| {decode_outputs}) + .boxed() +}} + "##, + abi_name = name, + abi_inputs = inputs, + abi_outputs = outputs, + snake_name = snake_name, + params = input_params, + output_type = output_type, + to_tokens = to_tokens, + decode_outputs = decode_outputs, + )) + } + + Ok(functions) +} + +// generate code for params in function signature and turning them into tokens. +// +// two pieces of code are generated: the first gives input types for the function signature, +// and the second gives code to tokenize those inputs. +// +// params of form `param_0: type_0, param_1: type_1, ...` +// tokenizing code of form `{let mut tokens = Vec::new(); tokens.push({param_X}); tokens }` +// +// returns any unsupported param type encountered. +fn input_params_codegen(inputs: &[ParamType]) -> Result<(String, String), ParamType> { + let mut params = String::new(); + let mut to_tokens = "{ let mut tokens = Vec::new();".to_string(); + + for (index, param_type) in inputs.iter().enumerate() { + let param_name = format!("param_{}", index); + let rust_type = rust_type(param_type.clone())?; + let (needs_mut, tokenize_code) = tokenize(¶m_name, param_type.clone()); + + params.push_str(&format!("{}{}: {}, ", + if needs_mut { "mut " } else { "" }, param_name, rust_type)); + + to_tokens.push_str(&format!("tokens.push({{ {} }});", tokenize_code)); + } + + to_tokens.push_str(" tokens }"); + Ok((params, to_tokens)) +} + +// generate code for outputs of the function and detokenizing them. +// +// two pieces of code are generated: the first gives an output type for the function signature +// as a tuple, and the second gives code to get that tuple from a deque of tokens. +// +// produce output type of the form (type_1, type_2, ...) without trailing comma. +// produce code for getting this output type from `outputs: VecDeque`, where +// an `Err(String)` can be returned. +// +// returns any unsupported param type encountered. +fn output_params_codegen(outputs: &[ParamType]) -> Result<(String, String), ParamType> { + let mut output_type = "(".to_string(); + let mut decode_outputs = "Ok((".to_string(); + + for (index, output) in outputs.iter().cloned().enumerate() { + let rust_type = rust_type(output.clone())?; + + output_type.push_str(&rust_type); + + decode_outputs.push_str(&format!( + r#" + outputs + .pop_front() + .and_then(|output| {{ {} }}) + .ok_or_else(|| "Wrong output type".to_string())? + "#, + detokenize("output", output) + )); + + // don't append trailing commas for the last element + // so we can reuse the same code for single-output contracts, + // since T == (T) != (T,) + if index < outputs.len() - 1 { + output_type.push_str(", "); + decode_outputs.push_str(", "); + } + } + + output_type.push_str(")"); + decode_outputs.push_str("))"); + Ok((output_type, decode_outputs)) +} + +// create code for an argument type from param type. +fn rust_type(input: ParamType) -> Result { + Ok(match input { + ParamType::Address => "util::Address".into(), + ParamType::FixedBytes(len) if len <= 32 => format!("util::H{}", len * 8), + ParamType::Bytes | ParamType::FixedBytes(_) => "Vec".into(), + ParamType::Int(width) => match width { + 8 | 16 | 32 | 64 => format!("i{}", width), + _ => return Err(ParamType::Int(width)), + }, + ParamType::Uint(width) => match width { + 8 | 16 | 32 | 64 => format!("u{}", width), + 128 | 160 | 256 => format!("util::U{}", width), + _ => return Err(ParamType::Uint(width)), + }, + ParamType::Bool => "bool".into(), + ParamType::String => "String".into(), + ParamType::Array(kind) => format!("Vec<{}>", rust_type(*kind)?), + other => return Err(other), + }) +} + +// create code for tokenizing this parameter. +// returns (needs_mut, code), where needs_mut indicates mutability required. +// panics on unsupported types. +fn tokenize(name: &str, input: ParamType) -> (bool, String) { + let mut needs_mut = false; + let code = match input { + ParamType::Address => format!("Token::Address({}.0)", name), + ParamType::Bytes => format!("Token::Bytes({})", name), + ParamType::FixedBytes(len) if len <= 32 => + format!("Token::FixedBytes({}.0.to_vec())", name), + ParamType::FixedBytes(len) => { + needs_mut = true; + format!("{}.resize({}, 0); Token::FixedBytes({})", name, len, name) + } + ParamType::Int(width) => match width { + 8 => format!("let mut r = [0xff; 32]; r[31] = {}; Token::Int(r)", name), + 16 | 32 | 64 => + format!("let mut r = [0xff; 32]; BigEndian::write_i{}(&mut r[{}..], {}); Token::Int(r))", + width, 32 - (width / 8), name), + _ => panic!("Signed int with more than 64 bits not supported."), + }, + ParamType::Uint(width) => format!( + "let mut r = [0; 32]; {}.to_big_endian(&mut r); Token::Uint(r)", + if width <= 64 { format!("util::U256::from({} as u64)", name) } + else { format!("util::U256::from({})", name) } + ), + ParamType::Bool => format!("Token::Bool({})", name), + ParamType::String => format!("Token::String({})", name), + ParamType::Array(kind) => { + let (needs_mut, code) = tokenize("i", *kind); + format!("Token::Array({}.into_iter().map(|{}i| {{ {} }}).collect())", + name, if needs_mut { "mut " } else { "" }, code) + } + ParamType::FixedArray(_, _) => panic!("Fixed-length arrays not supported."), + }; + + (needs_mut, code) +} + +// create code for detokenizing this parameter. +// takes an output type and the identifier of a token. +// expands to code that evaluates to a Option +// panics on unsupported types. +fn detokenize(name: &str, output_type: ParamType) -> String { + match output_type { + ParamType::Address => format!("{}.to_address().map(util::H160)", name), + ParamType::Bytes => format!("{}.to_bytes()", name), + ParamType::FixedBytes(len) if len <= 32 => { + // ensure no panic on slice too small. + let read_hash = format!("b.resize({}, 0); util::H{}::from_slice(&b[..{}])", + len, len * 8, len); + + format!("{}.to_fixed_bytes().map(|mut b| {{ {} }})", + name, read_hash) + } + ParamType::FixedBytes(_) => format!("{}.to_fixed_bytes()", name), + ParamType::Int(width) => { + let read_int = match width { + 8 => "i[31] as i8".into(), + 16 | 32 | 64 => format!("BigEndian::read_i{}(&i[{}..])", width, 32 - (width / 8)), + _ => panic!("Signed integers over 64 bytes not allowed."), + }; + format!("{}.to_int().map(|i| {})", name, read_int) + } + ParamType::Uint(width) => { + let read_uint = match width { + 8 | 16 | 32 | 64 => format!("util::U256(u).low_u64() as u{}", width), + _ => format!("util::U{}::from(&u[..])", width), + }; + + format!("{}.to_uint().map(|u| {})", name, read_uint) + } + ParamType::Bool => format!("{}.to_bool()", name), + ParamType::String => format!("{}.to_string()", name), + ParamType::Array(kind) => { + let read_array = format!("x.into_iter().map(|a| {{ {} }}).collect::>()", + detokenize("a", *kind)); + + format!("{}.to_array().and_then(|x| {})", + name, read_array) + } + ParamType::FixedArray(_, _) => panic!("Fixed-length arrays not supported.") + } +} + +#[cfg(test)] +mod tests { + use ethabi::spec::ParamType; + + #[test] + fn input_types() { + assert_eq!(::input_params_codegen(&[]).unwrap().0, ""); + assert_eq!(::input_params_codegen(&[ParamType::Address]).unwrap().0, "param_0: util::Address, "); + assert_eq!(::input_params_codegen(&[ParamType::Address, ParamType::Bytes]).unwrap().0, + "param_0: util::Address, param_1: Vec, "); + } + + #[test] + fn output_types() { + assert_eq!(::output_params_codegen(&[]).unwrap().0, "()"); + assert_eq!(::output_params_codegen(&[ParamType::Address]).unwrap().0, "(util::Address)"); + assert_eq!(::output_params_codegen(&[ParamType::Address, ParamType::Array(Box::new(ParamType::Bytes))]).unwrap().0, + "(util::Address, Vec>)"); + } + + #[test] + fn rust_type() { + assert_eq!(::rust_type(ParamType::FixedBytes(32)).unwrap(), "util::H256"); + assert_eq!(::rust_type(ParamType::Array(Box::new(ParamType::FixedBytes(32)))).unwrap(), + "Vec"); + + assert_eq!(::rust_type(ParamType::Uint(64)).unwrap(), "u64"); + assert!(::rust_type(ParamType::Uint(63)).is_err()); + + assert_eq!(::rust_type(ParamType::Int(32)).unwrap(), "i32"); + assert_eq!(::rust_type(ParamType::Uint(256)).unwrap(), "util::U256"); + } + + // codegen tests will need bootstrapping of some kind. +} diff --git a/ethcore/native_contracts/src/lib.rs b/ethcore/native_contracts/src/lib.rs new file mode 100644 index 000000000..55c6446b7 --- /dev/null +++ b/ethcore/native_contracts/src/lib.rs @@ -0,0 +1,30 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Native contracts useful for Parity. These are type-safe wrappers +//! autogenerated at compile-time from Ethereum ABIs, and can be instantiated +//! given any closure which can dispatch calls to them asynchronously. + +extern crate futures; +extern crate byteorder; +extern crate ethabi; +extern crate ethcore_util as util; + +mod registry; +mod service_transaction; + +pub use self::registry::Registry; +pub use self::service_transaction::ServiceTransactionChecker; diff --git a/ethcore/native_contracts/src/registry.rs b/ethcore/native_contracts/src/registry.rs new file mode 100644 index 000000000..3b3a6414d --- /dev/null +++ b/ethcore/native_contracts/src/registry.rs @@ -0,0 +1,22 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +#![allow(unused_mut, unused_variables, unused_imports)] + +//! Registrar contract: maps names to addresses and data. +// TODO: testing. + +include!(concat!(env!("OUT_DIR"), "/registry.rs")); diff --git a/ethcore/native_contracts/src/service_transaction.rs b/ethcore/native_contracts/src/service_transaction.rs new file mode 100644 index 000000000..ee3b17552 --- /dev/null +++ b/ethcore/native_contracts/src/service_transaction.rs @@ -0,0 +1,22 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +#![allow(unused_mut, unused_variables, unused_imports)] + +//! Service transaction contract. +// TODO: testing. + +include!(concat!(env!("OUT_DIR"), "/service_transaction.rs")); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 9da044573..3accc777f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -30,47 +30,48 @@ use util::trie::TrieSpec; use util::kvdb::*; // other -use io::*; -use views::BlockView; -use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; -use header::BlockNumber; -use state::{self, State, CleanupMode}; -use spec::Spec; use basic_types::Seal; -use engines::Engine; -use service::ClientIoMessage; -use env_info::LastHashes; -use verification; -use verification::{PreverifiedBlock, Verifier}; use block::*; -use transaction::{LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, PendingTransaction, Action}; -use blockchain::extras::TransactionAddress; -use types::filter::Filter; -use types::mode::Mode as IpcMode; -use log_entry::LocalizedLogEntry; -use verification::queue::BlockQueue; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; +use blockchain::extras::TransactionAddress; +use client::Error as ClientError; use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, MiningBlockChainClient, EngineClient, TraceFilter, CallAnalytics, BlockImportError, Mode, ChainNotify, PruningInfo, }; -use client::Error as ClientError; -use env_info::EnvInfo; -use executive::{Executive, Executed, TransactOptions, contract_address}; -use receipt::{Receipt, LocalizedReceipt}; -use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; -use trace; -use trace::FlatTransactionTraces; -use evm::{Factory as EvmFactory, Schedule}; -use miner::{Miner, MinerService, TransactionImportResult}; -use snapshot::{self, io as snapshot_io}; -use factory::Factories; -use rlp::UntrustedRlp; -use state_db::StateDB; -use rand::OsRng; -use client::registry::Registry; use encoded; +use engines::Engine; +use env_info::EnvInfo; +use env_info::LastHashes; +use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; +use evm::{Factory as EvmFactory, Schedule}; +use executive::{Executive, Executed, TransactOptions, contract_address}; +use factory::Factories; +use futures::{future, Future}; +use header::BlockNumber; +use io::*; +use log_entry::LocalizedLogEntry; +use miner::{Miner, MinerService, TransactionImportResult}; +use native_contracts::Registry; +use rand::OsRng; +use receipt::{Receipt, LocalizedReceipt}; +use rlp::UntrustedRlp; +use service::ClientIoMessage; +use snapshot::{self, io as snapshot_io}; +use spec::Spec; +use state_db::StateDB; +use state::{self, State, CleanupMode}; +use trace; +use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; +use trace::FlatTransactionTraces; +use transaction::{LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, PendingTransaction, Action}; +use types::filter::Filter; +use types::mode::Mode as IpcMode; +use verification; +use verification::{PreverifiedBlock, Verifier}; +use verification::queue::BlockQueue; +use views::BlockView; // re-export pub use types::blockchain_info::BlockChainInfo; @@ -254,8 +255,7 @@ impl Client { if let Some(reg_addr) = client.additional_params().get("registrar").and_then(|s| Address::from_str(s).ok()) { trace!(target: "client", "Found registrar at {}", reg_addr); - let weak = Arc::downgrade(&client); - let registrar = Registry::new(reg_addr, move |a, d| weak.upgrade().ok_or("No client!".into()).and_then(|c| c.call_contract(BlockId::Latest, a, d))); + let registrar = Registry::new(reg_addr); *client.registrar.lock() = Some(registrar); } Ok(client) @@ -1488,12 +1488,17 @@ impl BlockChainClient for Client { } fn registrar_address(&self) -> Option
{ - self.registrar.lock().as_ref().map(|r| r.address.clone()) + self.registrar.lock().as_ref().map(|r| r.address) } fn registry_address(&self, name: String) -> Option
{ self.registrar.lock().as_ref() - .and_then(|r| r.get_address(&(name.as_bytes().sha3()), "A").ok()) + .and_then(|r| { + let dispatch = move |reg_addr, data| { + future::done(self.call_contract(BlockId::Latest, reg_addr, data)) + }; + r.get_address(dispatch, name.as_bytes().sha3(), "A".to_string()).wait().ok() + }) .and_then(|a| if a.is_zero() { None } else { Some(a) }) } } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index f2479b17e..6c1280de7 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -16,7 +16,6 @@ //! Blockchain database client. -mod registry; mod config; mod error; mod test_client; diff --git a/ethcore/src/client/registry.rs b/ethcore/src/client/registry.rs deleted file mode 100644 index fb74ec36b..000000000 --- a/ethcore/src/client/registry.rs +++ /dev/null @@ -1,338 +0,0 @@ -// Autogenerated from JSON contract definition using Rust contract convertor. -// Command line: --name=Registry --jsonabi=/Users/gav/registry.abi -#![allow(unused_imports)] -use std::string::String; -use std::result::Result; -use std::fmt; -use {util, ethabi}; -use util::{Uint}; - -pub struct Registry { - contract: ethabi::Contract, - pub address: util::Address, - do_call: Box) -> Result, String> + Send + Sync + 'static>, -} -impl Registry { - pub fn new(address: util::Address, do_call: F) -> Self - where F: Fn(util::Address, Vec) -> Result, String> + Send + Sync + 'static { - Registry { - contract: ethabi::Contract::new(ethabi::Interface::load(b"[{\"constant\":true,\"inputs\":[{\"name\":\"_data\",\"type\":\"address\"}],\"name\":\"canReverse\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_new\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_key\",\"type\":\"string\"},{\"name\":\"_value\",\"type\":\"bytes32\"}],\"name\":\"setData\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"string\"}],\"name\":\"confirmReverse\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"reserve\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":true,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"drop\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_key\",\"type\":\"string\"}],\"name\":\"getAddress\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"setFee\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_to\",\"type\":\"address\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_key\",\"type\":\"string\"}],\"name\":\"getData\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"reserved\",\"outputs\":[{\"name\":\"reserved\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"drain\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"proposeReverse\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"hasReverse\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_key\",\"type\":\"string\"}],\"name\":\"getUint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"getOwner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"getReverse\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_data\",\"type\":\"address\"}],\"name\":\"reverse\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_key\",\"type\":\"string\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"setUint\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"confirmReverseAs\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"removeReverse\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_key\",\"type\":\"string\"},{\"name\":\"_value\",\"type\":\"address\"}],\"name\":\"setAddress\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"}]").expect("JSON is autogenerated; qed")), - address: address, - do_call: Box::new(do_call), - } - } - fn as_string(e: T) -> String { format!("{:?}", e) } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_data","type":"address"}],"name":"canReverse","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn can_reverse(&self, _data: &util::Address) -> Result - { - let call = self.contract.function("canReverse".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_data.clone().0)] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn set_owner(&self, _new: &util::Address) -> Result<(), String> - { - let call = self.contract.function("setOwner".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_new.clone().0)] - ).map_err(Self::as_string)?; - call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - - Ok(()) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"bytes32"}],"name":"setData","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn set_data(&self, _name: &util::H256, _key: &str, _value: &util::H256) -> Result - { - let call = self.contract.function("setData".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned()), ethabi::Token::String(_key.to_owned()), ethabi::Token::FixedBytes(_value.as_ref().to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"string"}],"name":"confirmReverse","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn confirm_reverse(&self, _name: &str) -> Result - { - let call = self.contract.function("confirmReverse".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::String(_name.to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[{"name":"success","type":"bool"}],"payable":true,"type":"function"}` - #[allow(dead_code)] - pub fn reserve(&self, _name: &util::H256) -> Result - { - let call = self.contract.function("reserve".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"drop","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn drop(&self, _name: &util::H256) -> Result - { - let call = self.contract.function("drop".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn get_address(&self, _name: &util::H256, _key: &str) -> Result - { - let call = self.contract.function("getAddress".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned()), ethabi::Token::String(_key.to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"setFee","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn set_fee(&self, _amount: util::U256) -> Result - { - let call = self.contract.function("setFee".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Uint({ let mut r = [0u8; 32]; _amount.to_big_endian(&mut r); r })] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_to","type":"address"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn transfer(&self, _name: &util::H256, _to: &util::Address) -> Result - { - let call = self.contract.function("transfer".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned()), ethabi::Token::Address(_to.clone().0)] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn owner(&self) -> Result - { - let call = self.contract.function("owner".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getData","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn get_data(&self, _name: &util::H256, _key: &str) -> Result - { - let call = self.contract.function("getData".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned()), ethabi::Token::String(_key.to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_fixed_bytes().ok_or("Invalid type returned")?; util::H256::from_slice(r.as_ref()) })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserved","outputs":[{"name":"reserved","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn reserved(&self, _name: &util::H256) -> Result - { - let call = self.contract.function("reserved".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[],"name":"drain","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn drain(&self) -> Result - { - let call = self.contract.function("drain".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"proposeReverse","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn propose_reverse(&self, _name: &str, _who: &util::Address) -> Result - { - let call = self.contract.function("proposeReverse".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::String(_name.to_owned()), ethabi::Token::Address(_who.clone().0)] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"hasReverse","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn has_reverse(&self, _name: &util::H256) -> Result - { - let call = self.contract.function("hasReverse".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn get_uint(&self, _name: &util::H256, _key: &str) -> Result - { - let call = self.contract.function("getUint".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned()), ethabi::Token::String(_key.to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_uint().ok_or("Invalid type returned")?; util::U256::from(r.as_ref()) })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn fee(&self) -> Result - { - let call = self.contract.function("fee".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_uint().ok_or("Invalid type returned")?; util::U256::from(r.as_ref()) })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"getOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn get_owner(&self, _name: &util::H256) -> Result - { - let call = self.contract.function("getOwner".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"getReverse","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn get_reverse(&self, _name: &util::H256) -> Result - { - let call = self.contract.function("getReverse".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_data","type":"address"}],"name":"reverse","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn reverse(&self, _data: &util::Address) -> Result - { - let call = self.contract.function("reverse".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_data.clone().0)] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_string().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"uint256"}],"name":"setUint","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn set_uint(&self, _name: &util::H256, _key: &str, _value: util::U256) -> Result - { - let call = self.contract.function("setUint".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned()), ethabi::Token::String(_key.to_owned()), ethabi::Token::Uint({ let mut r = [0u8; 32]; _value.to_big_endian(&mut r); r })] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"confirmReverseAs","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn confirm_reverse_as(&self, _name: &str, _who: &util::Address) -> Result - { - let call = self.contract.function("confirmReverseAs".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::String(_name.to_owned()), ethabi::Token::Address(_who.clone().0)] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[],"name":"removeReverse","outputs":[],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn remove_reverse(&self) -> Result<(), String> - { - let call = self.contract.function("removeReverse".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![] - ).map_err(Self::as_string)?; - call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - - Ok(()) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"address"}],"name":"setAddress","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn set_address(&self, _name: &util::H256, _key: &str, _value: &util::Address) -> Result - { - let call = self.contract.function("setAddress".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::FixedBytes(_name.as_ref().to_owned()), ethabi::Token::String(_key.to_owned()), ethabi::Token::Address(_value.clone().0)] - ).map_err(Self::as_string)?; - let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } -} - diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index c4790f4d2..8f9ed2e5f 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -79,37 +79,39 @@ //! cargo build --release //! ``` -extern crate ethcore_io as io; -extern crate rustc_serialize; -extern crate crypto; -extern crate time; -extern crate env_logger; -extern crate num_cpus; -extern crate crossbeam; -extern crate ethjson; -extern crate bloomchain; -extern crate hyper; -extern crate ethash; -extern crate ethkey; -extern crate semver; -extern crate ethcore_ipc_nano as nanoipc; -extern crate ethcore_devtools as devtools; -extern crate rand; extern crate bit_set; -extern crate rlp; -extern crate ethcore_bloom_journal as bloom_journal; +extern crate bloomchain; +extern crate bn; extern crate byteorder; -extern crate transient_hashmap; +extern crate crossbeam; +extern crate crypto; +extern crate env_logger; +extern crate ethabi; +extern crate ethash; +extern crate ethcore_bloom_journal as bloom_journal; +extern crate ethcore_devtools as devtools; +extern crate ethcore_io as io; +extern crate ethcore_ipc_nano as nanoipc; +extern crate ethcore_logger; +extern crate ethcore_stratum; +extern crate ethjson; +extern crate ethkey; +extern crate futures; +extern crate hardware_wallet; +extern crate hyper; +extern crate itertools; extern crate linked_hash_map; extern crate lru_cache; -extern crate ethcore_stratum; -extern crate ethabi; -extern crate hardware_wallet; -extern crate stats; -extern crate ethcore_logger; +extern crate native_contracts; +extern crate num_cpus; extern crate num; -extern crate bn; -extern crate itertools; +extern crate rand; +extern crate rlp; +extern crate rustc_serialize; +extern crate semver; +extern crate stats; +extern crate time; +extern crate transient_hashmap; #[macro_use] extern crate log; diff --git a/ethcore/src/miner/service_transaction_checker.rs b/ethcore/src/miner/service_transaction_checker.rs index 8a97ed9dc..a0a75647f 100644 --- a/ethcore/src/miner/service_transaction_checker.rs +++ b/ethcore/src/miner/service_transaction_checker.rs @@ -14,9 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use types::ids::BlockId; use client::MiningBlockChainClient; use transaction::SignedTransaction; +use types::ids::BlockId; + +use futures::{future, Future}; +use native_contracts::ServiceTransactionChecker as Contract; use util::{U256, Uint, Mutex}; const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker"; @@ -24,7 +27,7 @@ const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transa /// Service transactions checker. #[derive(Default)] pub struct ServiceTransactionChecker { - contract: Mutex>, + contract: Mutex>, } impl ServiceTransactionChecker { @@ -36,7 +39,7 @@ impl ServiceTransactionChecker { .and_then(|contract_addr| { trace!(target: "txqueue", "Configuring for service transaction checker contract from {}", contract_addr); - Some(provider::Contract::new(contract_addr)) + Some(Contract::new(contract_addr)) }) } } @@ -46,168 +49,12 @@ impl ServiceTransactionChecker { debug_assert_eq!(tx.gas_price, U256::zero()); if let Some(ref contract) = *self.contract.lock() { - let do_call = |a, d| client.call_contract(BlockId::Latest, a, d); - contract.certified(&do_call, &tx.sender()) + contract.certified( + |addr, data| future::done(client.call_contract(BlockId::Latest, addr, data)), + tx.sender() + ).wait() } else { Err("contract is not configured".to_owned()) } } } - -mod provider { - // Autogenerated from JSON contract definition using Rust contract convertor. - // Command line: --jsonabi=SimpleCertifier.abi --explicit-do-call - #![allow(unused_imports)] - use std::string::String; - use std::result::Result; - use std::fmt; - use {util, ethabi}; - use util::{Uint}; - - pub struct Contract { - contract: ethabi::Contract, - address: util::Address, - - } - impl Contract { - pub fn new(address: util::Address) -> Self - { - Contract { - contract: ethabi::Contract::new(ethabi::Interface::load(b"[{\"constant\":false,\"inputs\":[{\"name\":\"_new\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"certify\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"getAddress\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"revoke\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"delegate\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"getUint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_new\",\"type\":\"address\"}],\"name\":\"setDelegate\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"certified\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"type\":\"function\"}]").expect("JSON is autogenerated; qed")), - address: address, - - } - } - fn as_string(e: T) -> String { format!("{:?}", e) } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn set_owner(&self, do_call: &F, _new: &util::Address) -> Result<(), String> - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("setOwner".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_new.clone().0)] - ).map_err(Self::as_string)?; - call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - - Ok(()) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn certify(&self, do_call: &F, _who: &util::Address) -> Result<(), String> - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("certify".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_who.clone().0)] - ).map_err(Self::as_string)?; - call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - - Ok(()) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn get_address(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("getAddress".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn revoke(&self, do_call: &F, _who: &util::Address) -> Result<(), String> - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("revoke".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_who.clone().0)] - ).map_err(Self::as_string)?; - call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - - Ok(()) - } - - /// Auto-generated from: `{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn owner(&self, do_call: &F) -> Result - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("owner".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![] - ).map_err(Self::as_string)?; - let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn delegate(&self, do_call: &F) -> Result - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("delegate".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![] - ).map_err(Self::as_string)?; - let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn get_uint(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("getUint".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_uint().ok_or("Invalid type returned")?; util::U256::from(r.as_ref()) })) - } - - /// Auto-generated from: `{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn set_delegate(&self, do_call: &F, _new: &util::Address) -> Result<(), String> - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("setDelegate".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_new.clone().0)] - ).map_err(Self::as_string)?; - call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - - Ok(()) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn certified(&self, do_call: &F, _who: &util::Address) -> Result - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("certified".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_who.clone().0)] - ).map_err(Self::as_string)?; - let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r })) - } - - /// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"}` - #[allow(dead_code)] - pub fn get(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result - where F: Fn(util::Address, Vec) -> Result, String> + Send { - let call = self.contract.function("get".into()).map_err(Self::as_string)?; - let data = call.encode_call( - vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())] - ).map_err(Self::as_string)?; - let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; - let mut result = output.into_iter().rev().collect::>(); - Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_fixed_bytes().ok_or("Invalid type returned")?; util::H256::from_slice(r.as_ref()) })) - } - } -}