Update dependencies.
This commit is contained in:
parent
6a20b3d91f
commit
0f11a72e2d
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
11
Cargo.toml
|
@ -7,12 +7,13 @@ description = "Read POA voting records and rank voters by how many ballots they
|
|||
[dependencies]
|
||||
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"
|
||||
error-chain = { version = "0.12", default-features = false }
|
||||
ethabi = "6.0.1"
|
||||
ethabi-contract = "6.0.0"
|
||||
ethabi-derive = "6.0.2"
|
||||
parse_duration = "1.0.1"
|
||||
serde = "1.0.36"
|
||||
serde_derive = "1.0.36"
|
||||
serde_json = "1.0.13"
|
||||
web3 = { version = "0.3.0", default-features = false, features = ["http", "tls"] }
|
||||
# TODO: Remove ws once https://github.com/tomusdrw/rust-web3/issues/157 is fixed.
|
||||
web3 = { version = "0.4.0", default-features = false, features = ["http", "tls", "ws"] }
|
||||
|
|
|
@ -1,386 +0,0 @@
|
|||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "pendingList",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getCurrentValidatorsLength",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_newAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setProxyStorage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_validator",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_shouldFireEvent",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "addValidator",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "currentValidatorsLength",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "validatorsState",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "isValidator",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "index",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getPendingList",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address[]"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getVotingToChangeKeys",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "finalizeChange",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_newKey",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_oldKey",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "swapValidatorKey",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "currentValidators",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getKeysManager",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "isMasterOfCeremonyInitialized",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "proxyStorage",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "finalized",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getValidators",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address[]"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "systemAddress",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_validator",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_shouldFireEvent",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "removeValidator",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "masterOfCeremony",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_someone",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "isValidator",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_masterOfCeremony",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "validators",
|
||||
"type": "address[]"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "parentHash",
|
||||
"type": "bytes32"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "newSet",
|
||||
"type": "address[]"
|
||||
}
|
||||
],
|
||||
"name": "InitiateChange",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "newSet",
|
||||
"type": "address[]"
|
||||
}
|
||||
],
|
||||
"name": "ChangeFinalized",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "nameOfContract",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "newAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "ChangeReference",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "proxyStorage",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "MoCInitializedProxyStorage",
|
||||
"type": "event"
|
||||
}
|
||||
]
|
|
@ -1,7 +1,9 @@
|
|||
use colored::{Color, Colorize};
|
||||
use contracts::{key_mgr, val_meta, voting};
|
||||
use contracts::key_mgr::events::voting_key_changed;
|
||||
use contracts::val_meta::functions::{get_mining_by_voting_key, validators as validators_fn};
|
||||
use contracts::voting::events::{ballot_created, vote};
|
||||
use error::{Error, ErrorKind};
|
||||
use ethabi::Address;
|
||||
use ethabi::{Address, Bytes, FunctionOutputDecoder};
|
||||
use stats::Stats;
|
||||
use std::collections::BTreeSet;
|
||||
use std::default::Default;
|
||||
|
@ -84,18 +86,10 @@ impl Counter {
|
|||
// Calls `println!` if `verbose` is `true`.
|
||||
macro_rules! vprintln { ($($arg:tt)*) => { if self.verbose { println!($($arg)*); } } }
|
||||
|
||||
let voting_contract = voting::VotingToChangeKeys::default();
|
||||
let val_meta_contract = val_meta::ValidatorMetadata::default();
|
||||
let key_mgr_contract = key_mgr::KeysManager::default();
|
||||
|
||||
let ballot_event = voting_contract.events().ballot_created();
|
||||
let vote_event = voting_contract.events().vote();
|
||||
let change_event = key_mgr_contract.events().voting_key_changed();
|
||||
|
||||
// Find all ballots and voter changes. We don't filter by contract address, so we can make
|
||||
// a single pass. Contract addresses are checked inside the loop.
|
||||
let ballot_or_change_filter =
|
||||
(ballot_event.create_filter(None, None, None)).or(change_event.create_filter(None));
|
||||
(ballot_created::filter(None, None, None)).or(voting_key_changed::filter(None));
|
||||
|
||||
let mut voters: BTreeSet<Address> = BTreeSet::new();
|
||||
let mut stats = Stats::default();
|
||||
|
@ -107,7 +101,7 @@ impl Counter {
|
|||
for log in ballot_or_change_filter.logs(&self.web3)? {
|
||||
event_found = true;
|
||||
let block_num = log.block_number.expect(ERR_BLOCK_NUM).into();
|
||||
if let Ok(change) = change_event.parse_log(log.clone().into_raw()) {
|
||||
if let Ok(change) = voting_key_changed::parse_log(log.clone().into_raw()) {
|
||||
if log.address != self.key_mgr_addr {
|
||||
continue; // Event from another contract instance.
|
||||
}
|
||||
|
@ -122,7 +116,7 @@ impl Counter {
|
|||
}
|
||||
_ => vprintln!(" Unexpected key change action."),
|
||||
}
|
||||
} else if let Ok(ballot) = ballot_event.parse_log(log.clone().into_raw()) {
|
||||
} else if let Ok(ballot) = ballot_created::parse_log(log.clone().into_raw()) {
|
||||
if log.address != self.voting_addr {
|
||||
continue; // Event from another contract instance.
|
||||
}
|
||||
|
@ -136,8 +130,8 @@ impl Counter {
|
|||
let mut unexpected = BTreeSet::new();
|
||||
let mut voted = BTreeSet::new();
|
||||
let mut votes = Vec::new();
|
||||
for vote_log in vote_event.create_filter(ballot.id, None).logs(&self.web3)? {
|
||||
let vote = vote_event.parse_log(vote_log.into_raw())?;
|
||||
for vote_log in vote::filter(ballot.id, None).logs(&self.web3)? {
|
||||
let vote = vote::parse_log(vote_log.into_raw())?;
|
||||
if voters.insert(vote.voter) {
|
||||
unexpected.insert(vote.voter);
|
||||
} else {
|
||||
|
@ -170,11 +164,8 @@ impl Counter {
|
|||
vprintln!(""); // Add a new line between event log and table.
|
||||
|
||||
// Finally, gather the metadata for all voters.
|
||||
let raw_call = util::raw_call(self.val_meta_addr, self.web3.eth());
|
||||
let get_mining_by_voting_key_fn = val_meta_contract.functions().get_mining_by_voting_key();
|
||||
let validators_fn = val_meta_contract.functions().validators();
|
||||
for voter in voters {
|
||||
let mining_key = match get_mining_by_voting_key_fn.call(voter, &*raw_call) {
|
||||
let mining_key = match self.call_val_meta(get_mining_by_voting_key::call(voter)) {
|
||||
Err(err) => {
|
||||
eprintln!("Failed to find mining key for voter {}: {:?}", voter, err);
|
||||
continue;
|
||||
|
@ -185,12 +176,20 @@ impl Counter {
|
|||
eprintln!("Mining key for voter {} is zero. Skipping.", voter);
|
||||
continue;
|
||||
}
|
||||
let validator = validators_fn.call(mining_key, &*raw_call)?.into();
|
||||
let validator = self.call_val_meta(validators_fn::call(mining_key))?.into();
|
||||
stats.set_metadata(&voter, mining_key, validator);
|
||||
}
|
||||
Ok(stats)
|
||||
}
|
||||
|
||||
/// Calls a function of the `ValidatorMetadata` contract and returns the decoded result.
|
||||
fn call_val_meta<D>(&self, fn_call: (Bytes, D)) -> Result<D::Output, web3::contract::Error>
|
||||
where
|
||||
D: FunctionOutputDecoder,
|
||||
{
|
||||
util::raw_call(self.val_meta_addr, &self.web3.eth(), fn_call)
|
||||
}
|
||||
|
||||
/// Returns `true` if the block with the given number is older than `start_time`.
|
||||
fn is_block_too_old(&self, block_num: u64) -> bool {
|
||||
self.is_block_older_than(
|
||||
|
@ -210,7 +209,8 @@ impl Counter {
|
|||
/// Returns `true` if the block with the given number was created before the given time.
|
||||
fn is_block_older_than(&self, number: web3::types::BlockNumber, time: &SystemTime) -> bool {
|
||||
let id = web3::types::BlockId::Number(number);
|
||||
let block = self.web3.eth().block(id).wait().expect(ERR_BLOCK);
|
||||
let block_result = self.web3.eth().block(id).wait();
|
||||
let block = block_result.expect(ERR_BLOCK).expect(ERR_BLOCK);
|
||||
let seconds = time.duration_since(UNIX_EPOCH).expect(ERR_EPOCH).as_secs();
|
||||
block.timestamp < seconds.into()
|
||||
}
|
||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -30,21 +30,11 @@ use std::time::SystemTime;
|
|||
allow(too_many_arguments, redundant_closure, needless_update)
|
||||
)]
|
||||
mod contracts {
|
||||
use_contract!(
|
||||
voting,
|
||||
"VotingToChangeKeys",
|
||||
"abi/VotingToChangeKeys.abi.json"
|
||||
);
|
||||
use_contract!(
|
||||
val_meta,
|
||||
"ValidatorMetadata",
|
||||
"abi/ValidatorMetadata.abi.json"
|
||||
);
|
||||
use_contract!(key_mgr, "KeysManager", "abi/KeysManager.abi.json");
|
||||
use_contract!(voting, "abi/VotingToChangeKeys.abi.json");
|
||||
use_contract!(val_meta, "abi/ValidatorMetadata.abi.json");
|
||||
use_contract!(key_mgr, "abi/KeysManager.abi.json");
|
||||
}
|
||||
|
||||
use contracts::*;
|
||||
|
||||
fn main() {
|
||||
let matches = cli::get_matches();
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use colored::{Color, Colorize};
|
||||
use contracts::voting;
|
||||
use ethabi::Address;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use validator::Validator;
|
||||
use voting;
|
||||
|
||||
/// The count of ballots and cast votes, as well as metadata for a particular voter.
|
||||
#[derive(Clone, Default)]
|
||||
|
|
41
src/util.rs
41
src/util.rs
|
@ -1,10 +1,10 @@
|
|||
use colored::{Color, Colorize};
|
||||
use ethabi::{self, Address, Bytes};
|
||||
use ethabi::{self, Address, Bytes, FunctionOutputDecoder};
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, u8};
|
||||
use web3;
|
||||
use web3::futures::Future;
|
||||
use web3::helpers::CallResult;
|
||||
use web3::helpers::CallFuture;
|
||||
|
||||
// TODO: Evaluate whether any of these would make sense to include in `web3`.
|
||||
|
||||
|
@ -16,25 +16,24 @@ pub fn parse_address(mut s: &str) -> Option<Address> {
|
|||
Address::from_str(s).ok()
|
||||
}
|
||||
|
||||
/// Returns a wrapper of a contract address, to make function calls using the latest block.
|
||||
pub fn raw_call<T: web3::Transport + 'static>(
|
||||
/// Executes a function call on the latest block and returns the decoded output.
|
||||
pub fn raw_call<T: web3::Transport, D: FunctionOutputDecoder>(
|
||||
to: Address,
|
||||
eth: web3::api::Eth<T>,
|
||||
) -> Box<Fn(Bytes) -> Result<Bytes, String>> {
|
||||
Box::new(move |bytes: Bytes| -> Result<Bytes, String> {
|
||||
let req = web3::types::CallRequest {
|
||||
from: None,
|
||||
to,
|
||||
gas: None,
|
||||
gas_price: None,
|
||||
value: None,
|
||||
data: Some(bytes.into()),
|
||||
};
|
||||
eth.call(req, Some(web3::types::BlockNumber::Latest))
|
||||
.wait()
|
||||
.map(|bytes| bytes.0)
|
||||
.map_err(|err| err.to_string())
|
||||
})
|
||||
eth: &web3::api::Eth<T>,
|
||||
(bytes, decoder): (Bytes, D),
|
||||
) -> Result<D::Output, web3::contract::Error> {
|
||||
let req = web3::types::CallRequest {
|
||||
from: None,
|
||||
to,
|
||||
gas: None,
|
||||
gas_price: None,
|
||||
value: None,
|
||||
data: Some(bytes.into()),
|
||||
};
|
||||
let bytes = eth
|
||||
.call(req, Some(web3::types::BlockNumber::Latest))
|
||||
.wait()?;
|
||||
Ok(decoder.decode(&bytes.0)?)
|
||||
}
|
||||
|
||||
trait TopicExt<T> {
|
||||
|
@ -117,7 +116,7 @@ impl TopicFilterExt for ethabi::TopicFilter {
|
|||
// TODO: Once a version with https://github.com/tomusdrw/rust-web3/pull/122 is available:
|
||||
// self.transport.logs(self.to_filter_builder().build())
|
||||
let filter = web3::helpers::serialize(&self.to_filter_builder().build());
|
||||
CallResult::new(web3.transport().execute("eth_getLogs", vec![filter])).wait()
|
||||
CallFuture::new(web3.transport().execute("eth_getLogs", vec![filter])).wait()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue