Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
Pass additional data when reporting (#5527)
Browse files Browse the repository at this point in the history
* pass additional data when reporting

* checkout correct tests
  • Loading branch information
keorn authored and gavofyork committed May 3, 2017
1 parent 60bb0de commit a3d9cce
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 40 deletions.
2 changes: 1 addition & 1 deletion ethcore/native_contracts/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const SECRETSTORE_ACL_STORAGE_ABI: &'static str = r#"[{"constant":true,"inputs":
// changes.
const VALIDATOR_SET_ABI: &'static str = r#"[{"constant":true,"inputs":[],"name":"transitionNonce","outputs":[{"name":"nonce","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"validators","type":"address[]"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":true,"name":"_nonce","type":"uint256"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"ValidatorsChanged","type":"event"}]"#;

const VALIDATOR_REPORT_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"}]"#;
const VALIDATOR_REPORT_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"},{"name":"proof","type":"bytes"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"}]"#;

fn build_file(name: &str, abi: &str, filename: &str) {
let code = ::native_contract_generator::generate_module(name, abi).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion ethcore/res/validator_contract.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0000000000000000000000000000000000000005": {
"balance": "1",
"constructor": "6060604052604060405190810160405280737d577a597b2742b498cb5cf0c26cdcd726d39e6e73ffffffffffffffffffffffffffffffffffffffff1681526020017382a978b3f5962a5b0957d9ee9eef472ee55b42f173ffffffffffffffffffffffffffffffffffffffff1681525060009060028280548282559060005260206000209081019282156100ec579160200282015b828111156100eb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610093565b5b50905061012f91905b8082111561012b57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506001016100f5565b5090565b505034610000575b6000600090505b6000805490508110156101d5578060016000600084815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b808060010191505061013e565b5b505b6105f2806101e76000396000f30060606040523615610076576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806335aa2e441461007b5780634d238c8e146100d8578063b7ab4db51461010b578063bfc708a01461017d578063d8f2e0bf146101b0578063fd6e1b50146101ff575b610000565b34610000576100966004808035906020019091905050610232565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610109600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061026f565b005b346100005761011861030f565b604051808060200182810382528381815181526020019150805190602001906020028083836000831461016a575b80518252602083111561016a57602082019150602081019050602083039250610146565b5050509050019250505060405180910390f35b34610000576101ae600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506103ad565b005b34610000576101bd61055b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610230600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610581565b005b600081815481101561000057906000526020600020900160005b915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080548060010182818154818355818115116102b8578183600052602060002091820191016102b791905b808211156102b357600081600090555060010161029b565b5090565b5b505050916000526020600020900160005b83909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b50565b602060405190810160405280600081525060008054806020026020016040519081016040528092919081815260200182805480156103a257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610358575b505050505090505b90565b6000600160008054905003815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815481101561000057906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600090556000600160008054905003815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905560008054809190600190038154818355818115116105535781836000526020600020918201910161055291905b8082111561054e576000816000905550600101610536565b5090565b5b505050505b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505600a165627a7a7230582063a0123d8e8f5dde980af6b47e20acc5b7a1acac3e3101fa1c933471ef4b405c0029"
"constructor": "60a06040819052737d577a597b2742b498cb5cf0c26cdcd726d39e6e60609081527382a978b3f5962a5b0957d9ee9eef472ee55b42f1608052600080546002825581805290927f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639182019291905b828111156100a25782518254600160a060020a031916600160a060020a0390911617825560209092019160019091019061006d565b5b506100cd9291505b808211156100c9578054600160a060020a03191681556001016100ab565b5090565b505034610000575b60005b60005481101561012f578060016000600084815481101561000057906000526020600020900160005b9054600160a060020a036101009290920a90041681526020810191909152604001600020555b6001016100d8565b5b505b610453806101416000396000f3006060604052361561005c5763ffffffff60e060020a60003504166335aa2e4481146100615780634d238c8e1461008d578063b7ab4db5146100a8578063c476dd4014610110578063d69f13bb14610172578063d8f2e0bf14610190575b610000565b34610000576100716004356101b9565b60408051600160a060020a039092168252519081900360200190f35b34610000576100a6600160a060020a03600435166101e9565b005b34610000576100b5610260565b60408051602080825283518183015283519192839290830191858101910280838382156100fd575b8051825260208311156100fd57601f1990920191602091820191016100dd565b5050509050019250505060405180910390f35b3461000057604080516020600460443581810135601f81018490048402850184019095528484526100a6948235600160a060020a03169460248035956064949293919092019181908401838280828437509496506102ca95505050505050565b005b34610000576100a6600160a060020a03600435166024356103eb565b005b3461000057610071610418565b60408051600160a060020a039092168252519081900360200190f35b600081815481101561000057906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000805480600101828181548183558181151161022b5760008381526020902061022b9181019083015b808211156102275760008155600101610213565b5090565b5b505050916000526020600020900160005b8154600160a060020a038086166101009390930a92830292021916179055505b50565b60408051602081810183526000808352805484518184028101840190955280855292939290918301828280156102bf57602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116102a1575b505050505090505b90565b6000805460001981019081101561000057906000526020600020900160005b9054906101000a9004600160a060020a031660006001600086600160a060020a0316600160a060020a0316815260200190815260200160002054815481101561000057906000526020600020900160005b8154600160a060020a039384166101009290920a918202918402191617905583166000908152600160205260408120819055805460001981019081101561000057906000526020600020900160005b6101000a815490600160a060020a03021916905560008054809190600190038154818355818115116103e0576000838152602090206103e09181019083015b808211156102275760008155600101610213565b5090565b5b505050505b505050565b6002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5050565b600254600160a060020a0316815600a165627a7a72305820f7876e17abd5f0927fff16788b4b3c9028ed64e6db740d788b07fc5f0a8f10920029"
},
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
Expand Down
4 changes: 2 additions & 2 deletions ethcore/src/engines/authority_round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ fn verify_external(header: &Header, validators: &ValidatorSet, step: &Step) -> R
// Give one step slack if step is lagging, double vote is still not possible.
if step.is_future(header_step) {
trace!(target: "engine", "verify_block_unordered: block from the future");
validators.report_benign(header.author());
validators.report_benign(header.author(), header.number());
Err(BlockError::InvalidSeal)?
} else {
let proposer_signature = header_signature(header)?;
Expand Down Expand Up @@ -381,7 +381,7 @@ impl Engine for AuthorityRound {
let parent_step = header_step(parent)?;
if step <= parent_step {
trace!(target: "engine", "Multiple blocks proposed for step {}.", parent_step);
self.validators.report_malicious(header.author());
self.validators.report_malicious(header.author(), header.number(), Default::default());
Err(EngineError::DoubleVote(header.author().clone()))?;
}

Expand Down
11 changes: 6 additions & 5 deletions ethcore/src/engines/tendermint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,8 @@ impl Engine for Tendermint {
return Err(EngineError::NotAuthorized(sender).into());
}
self.broadcast_message(rlp.as_raw().to_vec());
if self.votes.vote(message.clone(), &sender).is_some() {
self.validators.report_malicious(&sender);
if let Some(double) = self.votes.vote(message.clone(), &sender) {
self.validators.report_malicious(&sender, message.vote_step.height as BlockNumber, ::rlp::encode(&double).to_vec());
return Err(EngineError::DoubleVote(sender).into());
}
trace!(target: "engine", "Handling a valid {:?} from {}.", message, sender);
Expand Down Expand Up @@ -560,7 +560,7 @@ impl Engine for Tendermint {
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
self.validators.report_malicious(header.author());
self.validators.report_malicious(header.author(), header.number(), Default::default());
return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
}

Expand Down Expand Up @@ -610,8 +610,9 @@ impl Engine for Tendermint {
trace!(target: "engine", "Propose timeout.");
if self.proposal.read().is_none() {
// Report the proposer if no proposal was received.
let current_proposer = self.view_proposer(&*self.proposal_parent.read(), self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst));
self.validators.report_benign(&current_proposer);
let height = self.height.load(AtomicOrdering::SeqCst);
let current_proposer = self.view_proposer(&*self.proposal_parent.read(), height, self.view.load(AtomicOrdering::SeqCst));
self.validators.report_benign(&current_proposer, height as BlockNumber);
}
Step::Prevote
},
Expand Down
10 changes: 5 additions & 5 deletions ethcore/src/engines/validator_set/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use native_contracts::ValidatorReport as Provider;

use client::{Client, BlockChainClient};
use engines::Call;
use header::Header;
use header::{Header, BlockNumber};

use super::ValidatorSet;
use super::safe_contract::ValidatorSafeContract;
Expand Down Expand Up @@ -92,15 +92,15 @@ impl ValidatorSet for ValidatorContract {
self.validators.count_with_caller(bh, caller)
}

fn report_malicious(&self, address: &Address) {
match self.provider.report_malicious(&*self.transact(), *address).wait() {
fn report_malicious(&self, address: &Address, block: BlockNumber, proof: Bytes) {
match self.provider.report_malicious(&*self.transact(), *address, block.into(), proof).wait() {
Ok(_) => warn!(target: "engine", "Reported malicious validator {}", address),
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
}
}

fn report_benign(&self, address: &Address) {
match self.provider.report_benign(&*self.transact(), *address).wait() {
fn report_benign(&self, address: &Address, block: BlockNumber) {
match self.provider.report_benign(&*self.transact(), *address, block.into()).wait() {
Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address),
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
}
Expand Down
8 changes: 4 additions & 4 deletions ethcore/src/engines/validator_set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ mod multi;

use std::sync::Weak;
use ids::BlockId;
use util::{Address, H256};
use util::{Bytes, Address, H256};
use ethjson::spec::ValidatorSet as ValidatorSpec;
use client::Client;
use header::Header;
use header::{Header, BlockNumber};

pub use self::simple_list::SimpleList;
use self::contract::ValidatorContract;
Expand Down Expand Up @@ -111,9 +111,9 @@ pub trait ValidatorSet: Send + Sync {
fn count_with_caller(&self, parent_block_hash: &H256, caller: &Call) -> usize;

/// Notifies about malicious behaviour.
fn report_malicious(&self, _validator: &Address) {}
fn report_malicious(&self, _validator: &Address, _block: BlockNumber, _proof: Bytes) {}
/// Notifies about benign misbehaviour.
fn report_benign(&self, _validator: &Address) {}
fn report_benign(&self, _validator: &Address, _block: BlockNumber) {}
/// Allows blockchain state access.
fn register_contract(&self, _client: Weak<Client>) {}
}
14 changes: 5 additions & 9 deletions ethcore/src/engines/validator_set/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use std::collections::BTreeMap;
use std::sync::Weak;
use engines::{Call, EpochChange};
use util::{H256, Address, RwLock};
use util::{Bytes, H256, Address, RwLock};
use ids::BlockId;
use header::{BlockNumber, Header};
use client::{Client, BlockChainClient};
Expand Down Expand Up @@ -110,16 +110,12 @@ impl ValidatorSet for Multi {
.map_or_else(usize::max_value, |set| set.count_with_caller(bh, caller))
}

fn report_malicious(&self, validator: &Address) {
for set in self.sets.values() {
set.report_malicious(validator);
}
fn report_malicious(&self, validator: &Address, block: BlockNumber, proof: Bytes) {
self.correct_set_by_number(block).1.report_malicious(validator, block, proof);
}

fn report_benign(&self, validator: &Address) {
for set in self.sets.values() {
set.report_benign(validator);
}
fn report_benign(&self, validator: &Address, block: BlockNumber) {
self.correct_set_by_number(block).1.report_benign(validator, block);
}

fn register_contract(&self, client: Weak<Client>) {
Expand Down
45 changes: 32 additions & 13 deletions ethcore/src/engines/vote_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use std::fmt::Debug;
use util::*;
use rlp::Encodable;
use rlp::{Encodable, RlpStream};

pub trait Message: Clone + PartialEq + Eq + Hash + Encodable + Debug {
type Round: Clone + PartialEq + Eq + Hash + Default + Debug + Ord;
Expand All @@ -40,25 +40,44 @@ pub struct VoteCollector<M: Message> {

#[derive(Debug, Default)]
struct StepCollector<M: Message> {
voted: HashSet<Address>,
voted: HashMap<Address, M>,
pub block_votes: HashMap<Option<H256>, HashMap<H520, Address>>,
messages: HashSet<M>,
}

#[derive(Debug)]
pub struct DoubleVote<'a, M: Message> {
pub author: &'a Address,
vote_one: M,
vote_two: M,
}

impl<'a, M: Message> Encodable for DoubleVote<'a, M> {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2)
.append(&self.vote_one)
.append(&self.vote_two);
}
}

impl <M: Message> StepCollector<M> {
/// Returns Some(&Address) when validator is double voting.
fn insert<'a>(&mut self, message: M, address: &'a Address) -> Option<&'a Address> {
fn insert<'a>(&mut self, message: M, address: &'a Address) -> Option<DoubleVote<'a, M>> {
// Do nothing when message was seen.
if self.messages.insert(message.clone()) {
if self.voted.insert(address.clone()) {
if let Some(previous) = self.voted.insert(address.clone(), message.clone()) {
// Bad validator sent a different message.
return Some(DoubleVote {
author: address,
vote_one: previous,
vote_two: message
});
} else {
self
.block_votes
.entry(message.block_hash())
.or_insert_with(HashMap::new)
.insert(message.signature(), address.clone());
} else {
// Bad validator sent a different message.
return Some(address);
}
}
None
Expand Down Expand Up @@ -101,7 +120,7 @@ impl <M: Message + Default> Default for VoteCollector<M> {

impl <M: Message + Default + Encodable + Debug> VoteCollector<M> {
/// Insert vote if it is newer than the oldest one.
pub fn vote<'a>(&self, message: M, voter: &'a Address) -> Option<&'a Address> {
pub fn vote<'a>(&self, message: M, voter: &'a Address) -> Option<DoubleVote<'a, M>> {
self
.votes
.write()
Expand Down Expand Up @@ -220,11 +239,11 @@ mod tests {
}

fn random_vote(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>) -> bool {
full_vote(collector, signature, step, block_hash, &H160::random()).is_none()
full_vote(collector, signature, step, block_hash, &H160::random())
}

fn full_vote<'a>(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>, address: &'a Address) -> Option<&'a Address> {
collector.vote(TestMessage { signature: signature, step: step, block_hash: block_hash }, address)
fn full_vote<'a>(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>, address: &'a Address) -> bool {
collector.vote(TestMessage { signature: signature, step: step, block_hash: block_hash }, address).is_none()
}

#[test]
Expand Down Expand Up @@ -319,9 +338,9 @@ mod tests {
let collector = VoteCollector::default();
let round = 3;
// Vote is inserted fine.
assert!(full_vote(&collector, H520::random(), round, Some("0".sha3()), &Address::default()).is_none());
assert!(full_vote(&collector, H520::random(), round, Some("0".sha3()), &Address::default()));
// Returns the double voting address.
full_vote(&collector, H520::random(), round, Some("1".sha3()), &Address::default()).unwrap();
assert!(!full_vote(&collector, H520::random(), round, Some("1".sha3()), &Address::default()));
assert_eq!(collector.count_round_votes(&round), 1);
}
}

0 comments on commit a3d9cce

Please sign in to comment.