diff --git a/CHANGELOG.md b/CHANGELOG.md index 9933887..cb67306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog All notable changes to the project will be documented in this file. + +## Unreleased + +- Migrate to Rust 2018. At least version 1.31.0 required. +- Show new validators in the list, even if there was no ballot since they were added. + + ## [0.4.0] - 2018-10-15 - Support new contracts (hard fork 2). diff --git a/abi/v2/PoaNetworkConsensus.abi.json b/abi/v2/PoaNetworkConsensus.abi.json new file mode 100644 index 0000000..113ac6b --- /dev/null +++ b/abi/v2/PoaNetworkConsensus.abi.json @@ -0,0 +1,462 @@ +[ + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "pendingList", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x03aca792" + }, + { + "constant": true, + "inputs": [], + "name": "getCurrentValidatorsLength", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x0eaba26a" + }, + { + "constant": false, + "inputs": [ + { + "name": "_newAddress", + "type": "address" + } + ], + "name": "setProxyStorage", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x10855269" + }, + { + "constant": false, + "inputs": [ + { + "name": "_validator", + "type": "address" + }, + { + "name": "_shouldFireEvent", + "type": "bool" + } + ], + "name": "addValidator", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x21a3fb85" + }, + { + "constant": true, + "inputs": [], + "name": "isMasterOfCeremonyRemovedPending", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x273cb593" + }, + { + "constant": true, + "inputs": [], + "name": "isMasterOfCeremonyRemoved", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x379fed9a" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "validatorsState", + "outputs": [ + { + "name": "isValidator", + "type": "bool" + }, + { + "name": "isValidatorFinalized", + "type": "bool" + }, + { + "name": "index", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4110a489" + }, + { + "constant": true, + "inputs": [], + "name": "getPendingList", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x45199e0a" + }, + { + "constant": false, + "inputs": [], + "name": "finalizeChange", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x75286211" + }, + { + "constant": false, + "inputs": [ + { + "name": "_newKey", + "type": "address" + }, + { + "name": "_oldKey", + "type": "address" + } + ], + "name": "swapValidatorKey", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x879736b2" + }, + { + "constant": true, + "inputs": [ + { + "name": "_someone", + "type": "address" + } + ], + "name": "isValidatorFinalized", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f2eabe1" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "currentValidators", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x900eb5a8" + }, + { + "constant": true, + "inputs": [], + "name": "getKeysManager", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x9a573786" + }, + { + "constant": true, + "inputs": [], + "name": "wasProxyStorageSet", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa5f8b874" + }, + { + "constant": true, + "inputs": [], + "name": "getCurrentValidatorsLengthWithoutMoC", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa8756337" + }, + { + "constant": true, + "inputs": [], + "name": "proxyStorage", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae4b1b5b" + }, + { + "constant": true, + "inputs": [], + "name": "finalized", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xb3f05b97" + }, + { + "constant": true, + "inputs": [], + "name": "getValidators", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xb7ab4db5" + }, + { + "constant": true, + "inputs": [], + "name": "systemAddress", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xd3e848f1" + }, + { + "constant": true, + "inputs": [], + "name": "masterOfCeremonyPending", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xec7de1e9" + }, + { + "constant": false, + "inputs": [ + { + "name": "_validator", + "type": "address" + }, + { + "name": "_shouldFireEvent", + "type": "bool" + } + ], + "name": "removeValidator", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf89a77b1" + }, + { + "constant": true, + "inputs": [], + "name": "masterOfCeremony", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfa81b200" + }, + { + "constant": true, + "inputs": [ + { + "name": "_someone", + "type": "address" + } + ], + "name": "isValidator", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfacd743b" + }, + { + "inputs": [ + { + "name": "_masterOfCeremony", + "type": "address" + }, + { + "name": "validators", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "parentHash", + "type": "bytes32" + }, + { + "indexed": false, + "name": "newSet", + "type": "address[]" + } + ], + "name": "InitiateChange", + "type": "event", + "signature": "0x55252fa6eee4741b4e24a74a70e9c11fd2c2281df8d6ea13126ff845f7825c89" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "newSet", + "type": "address[]" + } + ], + "name": "ChangeFinalized", + "type": "event", + "signature": "0x8564cd629b15f47dc310d45bcbfc9bcf5420b0d51bf0659a16c67f91d2763253" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "proxyStorage", + "type": "address" + } + ], + "name": "MoCInitializedProxyStorage", + "type": "event", + "signature": "0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22" + } +] \ No newline at end of file diff --git a/src/contracts.rs b/src/contracts.rs index f310f9a..09549ae 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -11,6 +11,7 @@ pub mod v2 { use_contract!(key_mgr, "abi/v2/KeysManager.abi.json"); use_contract!(val_meta, "abi/v2/ValidatorMetadata.abi.json"); use_contract!(voting, "abi/v2/VotingToChangeKeys.abi.json"); + use_contract!(consensus, "abi/v2/PoaNetworkConsensus.abi.json"); } // The `use_contract!` macro triggers several Clippy warnings. @@ -25,6 +26,7 @@ pub struct ContractV1V2Addresses { pub metadata_address: Address, pub keys_manager_address: Address, pub voting_to_change_keys_address: Address, + pub poa_address: Address, } #[derive(Deserialize)] diff --git a/src/counter.rs b/src/counter.rs index 32db3a6..bb2cac5 100644 --- a/src/counter.rs +++ b/src/counter.rs @@ -1,6 +1,10 @@ use crate::contracts::v1::voting::events::{ballot_created as ballot_created_v1, vote as vote_v1}; +use crate::contracts::v2::consensus::functions::get_validators as get_validators_fn; use crate::contracts::v2::key_mgr::events::voting_key_changed; -use crate::contracts::v2::key_mgr::functions::get_mining_key_by_voting; +use crate::contracts::v2::key_mgr::functions::{ + get_mining_key_by_voting as get_mining_key_by_voting_fn, + get_voting_by_mining as get_voting_by_mining_fn, +}; use crate::contracts::v2::val_meta::functions::validators as validators_fn; use crate::contracts::v2::voting::events::{ballot_created, vote}; use crate::contracts::ContractAddresses; @@ -132,11 +136,22 @@ impl Counter { return Err(ErrorKind::NoEventsFound.into()); } + // Add all voters we haven't encountered so far. + let mining_keys: Vec
= self.call_poa(get_validators_fn::call())?; + for mining_key in mining_keys { + let voter = self.call_key_mgr(get_voting_by_mining_fn::call(mining_key))?; + if voter.is_zero() { + vprintln!("Voting key for {} is zero. Skipping.", mining_key); + } else if voters.insert(voter) { + eprintln!("Unexpected voter {} (mining key {})", voter, mining_key); + } + } + vprintln!(""); // Add a new line between event log and table. // Finally, gather the metadata for all voters. for voter in voters { - let mining_key = match self.call_key_mgr(get_mining_key_by_voting::call(voter)) { + let mining_key = match self.call_key_mgr(get_mining_key_by_voting_fn::call(voter)) { Err(err) => { eprintln!("Failed to find mining key for voter {}: {:?}", voter, err); continue; @@ -196,6 +211,14 @@ impl Counter { ) } + /// Calls a function of the `PoaNetworkConsensus` contract and returns the decoded result. + fn call_poa(&self, fn_call: (Bytes, D)) -> Result + where + D: FunctionOutputDecoder, + { + util::raw_call(self.addrs.v2.poa_address, &self.web3.eth(), fn_call) + } + fn voters_for_ballot(&self, id: Uint) -> Result, Error> { let vote_filter = vote::filter(id, None).or(vote_v1::filter(id, None)); let is_voting = |log: &web3::types::Log| self.addrs.is_voting(&log.address); diff --git a/src/stats.rs b/src/stats.rs index 142dc43..6435c19 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -43,20 +43,10 @@ impl Stats { } /// Inserts metadata about a voter: the mining key and the `Validator` information. - pub fn set_metadata( - &mut self, - voter: &Address, - mining_key: Address, - validator: Validator, - ) -> bool { - match self.voter_stats.get_mut(voter) { - None => false, - Some(vs) => { - vs.validator = Some(validator); - vs.mining_key = Some(mining_key); - true - } - } + pub fn set_metadata(&mut self, voter: &Address, mining_key: Address, validator: Validator) { + let vs = self.voter_stats.entry(*voter).or_default(); + vs.validator = Some(validator); + vs.mining_key = Some(mining_key); } }