// Copyright 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 . use client::MiningBlockChainClient; use transaction::SignedTransaction; use util::{U256, Uint, Mutex}; const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker"; /// Service transactions checker. #[derive(Default)] pub struct ServiceTransactionChecker { contract: Mutex>, } impl ServiceTransactionChecker { /// Try to create instance, reading contract address from given chain client. pub fn update_from_chain_client(&self, client: &MiningBlockChainClient) { let mut contract = self.contract.lock(); if contract.is_none() { *contract = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned()) .and_then(|contract_addr| { trace!(target: "txqueue", "Configuring for service transaction checker contract from {}", contract_addr); Some(provider::Contract::new(contract_addr)) }) } } /// Checks if service transaction can be appended to the transaction queue. pub fn check(&self, client: &MiningBlockChainClient, tx: &SignedTransaction) -> Result { debug_assert_eq!(tx.gas_price, U256::zero()); if let Some(ref contract) = *self.contract.lock() { let do_call = |a, d| client.call_contract(a, d); contract.certified(&do_call, &tx.sender()) } 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::{FixedHash, 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()) })) } } }