openethereum/ethcore/src/miner/service_transaction_checker.rs

213 lines
12 KiB
Rust

// 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 <http://www.gnu.org/licenses/>.
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<Option<provider::Contract>>,
}
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<bool, String> {
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<T: fmt::Debug>(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<F>(&self, do_call: &F, _new: &util::Address) -> Result<(), String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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<F>(&self, do_call: &F, _who: &util::Address) -> Result<(), String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::Address, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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::<Vec<_>>();
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<F>(&self, do_call: &F, _who: &util::Address) -> Result<(), String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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<F>(&self, do_call: &F) -> Result<util::Address, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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::<Vec<_>>();
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<F>(&self, do_call: &F) -> Result<util::Address, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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::<Vec<_>>();
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<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::U256, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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::<Vec<_>>();
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<F>(&self, do_call: &F, _new: &util::Address) -> Result<(), String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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<F>(&self, do_call: &F, _who: &util::Address) -> Result<bool, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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::<Vec<_>>();
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<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::H256, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, 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::<Vec<_>>();
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()) }))
}
}
}