Use ethabi-contract.
This commit is contained in:
parent
85bb8d26e3
commit
78f2da0a4a
|
@ -206,6 +206,22 @@ dependencies = [
|
|||
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ethabi-contract"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ethabi-derive"
|
||||
version = "5.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ethbloom"
|
||||
version = "0.5.0"
|
||||
|
@ -300,6 +316,14 @@ dependencies = [
|
|||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.2.4"
|
||||
|
@ -619,6 +643,8 @@ dependencies = [
|
|||
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1120,6 +1146,11 @@ name = "unicode-normalization"
|
|||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.4"
|
||||
|
@ -1267,6 +1298,8 @@ dependencies = [
|
|||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||
"checksum ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05e33a914b94b763f0a92333e4e5c95c095563f06ef7d6b295b3d3c2cf31e21f"
|
||||
"checksum ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "210c9e21d164c15b6ef64fe601e0e12a3c84a031d5ef558e38463e53edbd22ed"
|
||||
"checksum ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2bc7099baa147187aedaecd9fe04a6c0541c82bc43ff317cb6900fe2b983d74"
|
||||
"checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386"
|
||||
"checksum ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3ae691a36ce5d25b433e63128ce5579f4a18457b6a9c849832b2c9e0fec92a"
|
||||
"checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002"
|
||||
|
@ -1278,6 +1311,7 @@ dependencies = [
|
|||
"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
|
||||
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
|
||||
"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461"
|
||||
"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82"
|
||||
"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37"
|
||||
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
|
||||
"checksum hyper 0.11.26 (registry+https://github.com/rust-lang/crates.io-index)" = "66b16eb6213713f3c72d0ed14ce56423ae84dced8df73d2a2c8675f0495ae7ea"
|
||||
|
@ -1370,6 +1404,7 @@ dependencies = [
|
|||
"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90d662d111b0dbb08a180f2761026cba648c258023c355954a7c00e00e354636"
|
||||
"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"
|
||||
|
|
|
@ -9,6 +9,8 @@ clap = "2.31.2"
|
|||
colored = "1.6.0"
|
||||
error-chain = { version = "0.11", default-features = false }
|
||||
ethabi = "5.1.1"
|
||||
ethabi-contract = "5.1.0"
|
||||
ethabi-derive = "5.1.2"
|
||||
serde = "1.0.36"
|
||||
serde_derive = "1.0.36"
|
||||
serde_json = "1.0.13"
|
||||
|
|
|
@ -1,83 +1,7 @@
|
|||
use error::{ErrorKind, Result};
|
||||
use ethabi::{Address, FixedBytes, Log, RawTopicFilter, Token, Topic, Uint};
|
||||
use ethabi::{Address, Log, RawTopicFilter, Token, Topic, Uint};
|
||||
use std::fmt;
|
||||
use util::{HexBytes, LogExt};
|
||||
|
||||
/// An event that is logged when the current set of validators has changed.
|
||||
#[derive(Debug)]
|
||||
pub struct ChangeFinalized {
|
||||
/// The new set of validators.
|
||||
pub new_set: Vec<Address>,
|
||||
}
|
||||
|
||||
impl ChangeFinalized {
|
||||
/// Parses the log and returns a `ChangeFinalized`, if the log corresponded to such an event.
|
||||
pub fn from_log(log: &Log) -> Result<ChangeFinalized> {
|
||||
log.param(0, "newSet")
|
||||
.cloned()
|
||||
.and_then(Token::to_array)
|
||||
.map(|tokens| ChangeFinalized {
|
||||
new_set: tokens.into_iter().filter_map(Token::to_address).collect(),
|
||||
})
|
||||
.ok_or_else(|| ErrorKind::UnexpectedLogParams.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ChangeFinalized {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "ChangeFinalized {{ new_set: [",)?;
|
||||
for (i, voter) in self.new_set.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{}", voter)?;
|
||||
}
|
||||
write!(f, "] }}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InitiateChange {
|
||||
/// The previous voter set's hash.
|
||||
parent_hash: FixedBytes,
|
||||
/// The new set of validators.
|
||||
pub new_set: Vec<Address>,
|
||||
}
|
||||
|
||||
impl InitiateChange {
|
||||
/// Parses the log and returns a `InitiateChange`, if the log corresponded to such an event.
|
||||
pub fn from_log(log: &Log) -> Result<InitiateChange> {
|
||||
match (
|
||||
log.param(0, "parentHash")
|
||||
.cloned()
|
||||
.and_then(Token::to_fixed_bytes),
|
||||
log.param(1, "newSet").cloned().and_then(Token::to_array),
|
||||
) {
|
||||
(Some(parent_hash), Some(tokens)) => Ok(InitiateChange {
|
||||
parent_hash,
|
||||
new_set: tokens.into_iter().filter_map(Token::to_address).collect(),
|
||||
}),
|
||||
_ => Err(ErrorKind::UnexpectedLogParams.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InitiateChange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"InitiateChange {{ parent_hash: {}, new_set: [",
|
||||
HexBytes(&self.parent_hash)
|
||||
)?;
|
||||
for (i, voter) in self.new_set.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{}", voter)?;
|
||||
}
|
||||
write!(f, "] }}")
|
||||
}
|
||||
}
|
||||
use util::LogExt;
|
||||
|
||||
/// An event that is logged when a new ballot is started.
|
||||
#[derive(Debug)]
|
||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -3,6 +3,10 @@ extern crate colored;
|
|||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
extern crate ethabi;
|
||||
#[macro_use]
|
||||
extern crate ethabi_derive;
|
||||
#[macro_use]
|
||||
extern crate ethabi_contract;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
@ -17,19 +21,23 @@ mod util;
|
|||
mod validator;
|
||||
|
||||
use error::{Error, ErrorKind};
|
||||
use events::{BallotCreated, ChangeFinalized, InitiateChange, Vote};
|
||||
use events::{BallotCreated, Vote};
|
||||
use stats::Stats;
|
||||
use std::default::Default;
|
||||
use std::fs::File;
|
||||
use util::{ContractExt, TopicFilterExt, Web3LogExt};
|
||||
use util::{ContractExt, HexBytes, HexList, TopicFilterExt, Web3LogExt};
|
||||
use web3::futures::Future;
|
||||
|
||||
// TODO: `ethabi_derive` produces unparseable tokens.
|
||||
// mod voting_to_change_keys {
|
||||
// #[derive(EthabiContract)]
|
||||
// #[ethabi_contract_options(name = "VotingToChangeKeys", path = "abi/VotingToChangeKeys.json")]
|
||||
// struct _Dummy;
|
||||
// }
|
||||
use_contract!(
|
||||
net_con,
|
||||
"NetworkConsensus",
|
||||
"abi/PoaNetworkConsensus.abi.json"
|
||||
);
|
||||
// use_contract!(
|
||||
// voting,
|
||||
// "VotingToChangeKeys",
|
||||
// "abi/VotingToChangeKeys.abi.json"
|
||||
// );
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
|
@ -48,12 +56,11 @@ fn count_votes(
|
|||
let web3 = web3::Web3::new(transport);
|
||||
|
||||
let voting_abi = File::open("abi/VotingToChangeKeys.abi.json").expect("read voting abi");
|
||||
let net_con_abi = File::open("abi/PoaNetworkConsensus.abi.json").expect("read consensus abi");
|
||||
let val_meta_abi = File::open("abi/ValidatorMetadata.abi.json").expect("read val meta abi");
|
||||
let key_mgr_abi = File::open("abi/KeysManager.abi.json").expect("read key mgr abi");
|
||||
|
||||
let voting_contract = ethabi::Contract::load(voting_abi)?;
|
||||
let net_con_contract = ethabi::Contract::load(net_con_abi)?;
|
||||
let net_con_contract = net_con::NetworkConsensus::default();
|
||||
let val_meta_contract = ethabi::Contract::load(val_meta_abi)?;
|
||||
let key_mgr_contract = ethabi::Contract::load(key_mgr_abi)?;
|
||||
|
||||
|
@ -64,18 +71,16 @@ fn count_votes(
|
|||
|
||||
let ballot_event = voting_contract.event("BallotCreated")?;
|
||||
let vote_event = voting_contract.event("Vote")?;
|
||||
let change_event = net_con_contract.event("ChangeFinalized")?;
|
||||
let init_change_event = net_con_contract.event("InitiateChange")?;
|
||||
let change_event = net_con_contract.events().change_finalized();
|
||||
let init_change_event = net_con_contract.events().initiate_change();
|
||||
|
||||
// Find all ballots and voter changes.
|
||||
let ballot_or_change_filter = ethabi::TopicFilter {
|
||||
topic0: ethabi::Topic::OneOf(vec![
|
||||
ballot_event.signature(),
|
||||
change_event.signature(),
|
||||
init_change_event.signature(),
|
||||
]),
|
||||
..ethabi::TopicFilter::default()
|
||||
}.to_filter_builder()
|
||||
let ballot_or_change_filter = ballot_event
|
||||
.create_filter(ethabi::RawTopicFilter::default())
|
||||
.expect("create ballot event filter")
|
||||
.or(change_event.create_filter())
|
||||
.or(init_change_event.create_filter(ethabi::Topic::Any))
|
||||
.to_filter_builder()
|
||||
.build();
|
||||
let ballot_change_logs_filter = web3.eth_filter()
|
||||
.create_logs_filter(ballot_or_change_filter)
|
||||
|
@ -84,7 +89,7 @@ fn count_votes(
|
|||
// FIXME: Find out why we see no `ChangeFinalized` events, and how to obtain the initial voters.
|
||||
let mut voters: Vec<ethabi::Address> = Vec::new();
|
||||
let mut stats = Stats::default();
|
||||
let mut prev_init_change: Option<InitiateChange> = None;
|
||||
let mut prev_init_change: Option<net_con::logs::InitiateChange> = None;
|
||||
|
||||
if verbose {
|
||||
println!("Collecting events…");
|
||||
|
@ -94,18 +99,23 @@ fn count_votes(
|
|||
// Iterate over all ballot and voter change events.
|
||||
for log in ballot_change_logs_filter.logs().wait()? {
|
||||
event_found = true;
|
||||
if let Ok(change_log) = change_event.parse_log(log.clone().into_raw()) {
|
||||
if let Ok(change) = change_event.parse_log(log.clone().into_raw()) {
|
||||
// If it is a `ChangeFinalized`, update the current set of voters.
|
||||
let change = ChangeFinalized::from_log(&change_log)?;
|
||||
if verbose {
|
||||
println!("• {}", change);
|
||||
println!(
|
||||
"• ChangeFinalized {{ new_set: {} }}",
|
||||
HexList(&change.new_set)
|
||||
);
|
||||
}
|
||||
voters = change.new_set;
|
||||
} else if let Ok(init_change_log) = init_change_event.parse_log(log.clone().into_raw()) {
|
||||
} else if let Ok(init_change) = init_change_event.parse_log(log.clone().into_raw()) {
|
||||
// If it is an `InitiateChange`, update the current set of voters.
|
||||
let init_change = InitiateChange::from_log(&init_change_log)?;
|
||||
if verbose {
|
||||
println!("• {}", init_change);
|
||||
println!(
|
||||
"• InitiateChange {{ parent_hash: {}, new_set: {} }}",
|
||||
HexBytes(&init_change.parent_hash),
|
||||
HexList(&init_change.new_set)
|
||||
);
|
||||
}
|
||||
if let Some(prev) = prev_init_change.take() {
|
||||
voters = vec![];
|
||||
|
|
88
src/util.rs
88
src/util.rs
|
@ -53,23 +53,73 @@ impl ContractExt for web3::contract::Contract<web3::transports::Http> {
|
|||
}
|
||||
}
|
||||
|
||||
trait TopicExt<T> {
|
||||
/// Returns the union of the two topics.
|
||||
fn or(self, other: Self) -> Self;
|
||||
|
||||
/// Converts this topic into an `Option<Vec<T>>`, where `Any` corresponds to `None`,
|
||||
/// `This` to a vector with one element, and `OneOf` to any vector.
|
||||
fn to_opt_vec(self) -> Option<Vec<T>>;
|
||||
}
|
||||
|
||||
impl<T: Ord> TopicExt<T> for ethabi::Topic<T> {
|
||||
fn or(self, other: Self) -> Self {
|
||||
match (self.to_opt_vec(), other.to_opt_vec()) {
|
||||
(Some(mut v0), Some(v1)) => {
|
||||
for e in v1 {
|
||||
if !v0.contains(&e) {
|
||||
v0.push(e);
|
||||
}
|
||||
}
|
||||
if v0.len() == 1 {
|
||||
ethabi::Topic::This(v0.into_iter().next().expect("has a single element; qed"))
|
||||
} else {
|
||||
ethabi::Topic::OneOf(v0)
|
||||
}
|
||||
}
|
||||
(_, _) => ethabi::Topic::Any,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_opt_vec(self) -> Option<Vec<T>> {
|
||||
match self {
|
||||
ethabi::Topic::Any => None,
|
||||
ethabi::Topic::OneOf(v) => Some(v),
|
||||
ethabi::Topic::This(t) => Some(vec![t]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TopicFilterExt {
|
||||
/// Returns a `web3::types::FilterBuilder` with these topics, starting from the first block.
|
||||
fn to_filter_builder(self) -> web3::types::FilterBuilder;
|
||||
|
||||
/// Returns the "disjunction" of the two filters, i.e. it filters for everything that matches
|
||||
/// at least one of the two in every topic.
|
||||
fn or(self, other: ethabi::TopicFilter) -> ethabi::TopicFilter;
|
||||
}
|
||||
|
||||
impl TopicFilterExt for ethabi::TopicFilter {
|
||||
fn to_filter_builder(self) -> web3::types::FilterBuilder {
|
||||
web3::types::FilterBuilder::default()
|
||||
.topics(
|
||||
to_topic(self.topic0),
|
||||
to_topic(self.topic1),
|
||||
to_topic(self.topic2),
|
||||
to_topic(self.topic3),
|
||||
self.topic0.to_opt_vec(),
|
||||
self.topic1.to_opt_vec(),
|
||||
self.topic2.to_opt_vec(),
|
||||
self.topic3.to_opt_vec(),
|
||||
)
|
||||
.from_block(web3::types::BlockNumber::Earliest)
|
||||
.to_block(web3::types::BlockNumber::Latest)
|
||||
}
|
||||
|
||||
fn or(self, other: ethabi::TopicFilter) -> ethabi::TopicFilter {
|
||||
ethabi::TopicFilter {
|
||||
topic0: self.topic0.or(other.topic0),
|
||||
topic1: self.topic1.or(other.topic1),
|
||||
topic2: self.topic2.or(other.topic2),
|
||||
topic3: self.topic3.or(other.topic3),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Web3LogExt {
|
||||
|
@ -82,16 +132,6 @@ impl Web3LogExt for web3::types::Log {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts an `ethabi::Topic<T>` into an `Option<Vec<T>>`, where `Any` corresponds to `None`,
|
||||
/// `This` to a vector with one element, and `OneOf` to any vector.
|
||||
fn to_topic<T>(topic: ethabi::Topic<T>) -> Option<Vec<T>> {
|
||||
match topic {
|
||||
ethabi::Topic::Any => None,
|
||||
ethabi::Topic::OneOf(v) => Some(v),
|
||||
ethabi::Topic::This(t) => Some(vec![t]),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LogExt {
|
||||
/// Returns the `i`-th parameter, if it has the given name, otherwise `None`.
|
||||
fn param(&self, i: usize, name: &str) -> Option<ðabi::Token>;
|
||||
|
@ -146,3 +186,23 @@ impl<'a> fmt::Display for HexBytes<'a> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for a list of byte arrays, whose `Display` implementation outputs shortened hexadecimal
|
||||
/// strings.
|
||||
pub struct HexList<'a, T: 'a>(pub &'a [T]);
|
||||
|
||||
impl<'a, T: 'a> fmt::Display for HexList<'a, T>
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "[")?;
|
||||
for (i, item) in self.0.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{}", HexBytes(item.as_ref()))?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue