Pass additional data when reporting (#5527)

* pass additional data when reporting

* checkout correct tests
This commit is contained in:
keorn 2017-05-03 09:01:24 +02:00 committed by Gav Wood
parent 60bb0de9d6
commit a3d9cce7c5
8 changed files with 56 additions and 40 deletions

View File

@ -31,7 +31,7 @@ const SECRETSTORE_ACL_STORAGE_ABI: &'static str = r#"[{"constant":true,"inputs":
// changes. // 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_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) { fn build_file(name: &str, abi: &str, filename: &str) {
let code = ::native_contract_generator::generate_module(name, abi).unwrap(); let code = ::native_contract_generator::generate_module(name, abi).unwrap();

View File

@ -36,7 +36,7 @@
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0000000000000000000000000000000000000005": { "0000000000000000000000000000000000000005": {
"balance": "1", "balance": "1",
"constructor": "6060604052604060405190810160405280737d577a597b2742b498cb5cf0c26cdcd726d39e6e73ffffffffffffffffffffffffffffffffffffffff1681526020017382a978b3f5962a5b0957d9ee9eef472ee55b42f173ffffffffffffffffffffffffffffffffffffffff1681525060009060028280548282559060005260206000209081019282156100ec579160200282015b828111156100eb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610093565b5b50905061012f91905b8082111561012b57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506001016100f5565b5090565b505034610000575b6000600090505b6000805490508110156101d5578060016000600084815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b808060010191505061013e565b5b505b6105f2806101e76000396000f30060606040523615610076576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806335aa2e441461007b5780634d238c8e146100d8578063b7ab4db51461010b578063bfc708a01461017d578063d8f2e0bf146101b0578063fd6e1b50146101ff575b610000565b34610000576100966004808035906020019091905050610232565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610109600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061026f565b005b346100005761011861030f565b604051808060200182810382528381815181526020019150805190602001906020028083836000831461016a575b80518252602083111561016a57602082019150602081019050602083039250610146565b5050509050019250505060405180910390f35b34610000576101ae600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506103ad565b005b34610000576101bd61055b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610230600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610581565b005b600081815481101561000057906000526020600020900160005b915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080548060010182818154818355818115116102b8578183600052602060002091820191016102b791905b808211156102b357600081600090555060010161029b565b5090565b5b505050916000526020600020900160005b83909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b50565b602060405190810160405280600081525060008054806020026020016040519081016040528092919081815260200182805480156103a257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610358575b505050505090505b90565b6000600160008054905003815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815481101561000057906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600090556000600160008054905003815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905560008054809190600190038154818355818115116105535781836000526020600020918201910161055291905b8082111561054e576000816000905550600101610536565b5090565b5b505050505b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505600a165627a7a7230582063a0123d8e8f5dde980af6b47e20acc5b7a1acac3e3101fa1c933471ef4b405c0029" "constructor": "60a06040819052737d577a597b2742b498cb5cf0c26cdcd726d39e6e60609081527382a978b3f5962a5b0957d9ee9eef472ee55b42f1608052600080546002825581805290927f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639182019291905b828111156100a25782518254600160a060020a031916600160a060020a0390911617825560209092019160019091019061006d565b5b506100cd9291505b808211156100c9578054600160a060020a03191681556001016100ab565b5090565b505034610000575b60005b60005481101561012f578060016000600084815481101561000057906000526020600020900160005b9054600160a060020a036101009290920a90041681526020810191909152604001600020555b6001016100d8565b5b505b610453806101416000396000f3006060604052361561005c5763ffffffff60e060020a60003504166335aa2e4481146100615780634d238c8e1461008d578063b7ab4db5146100a8578063c476dd4014610110578063d69f13bb14610172578063d8f2e0bf14610190575b610000565b34610000576100716004356101b9565b60408051600160a060020a039092168252519081900360200190f35b34610000576100a6600160a060020a03600435166101e9565b005b34610000576100b5610260565b60408051602080825283518183015283519192839290830191858101910280838382156100fd575b8051825260208311156100fd57601f1990920191602091820191016100dd565b5050509050019250505060405180910390f35b3461000057604080516020600460443581810135601f81018490048402850184019095528484526100a6948235600160a060020a03169460248035956064949293919092019181908401838280828437509496506102ca95505050505050565b005b34610000576100a6600160a060020a03600435166024356103eb565b005b3461000057610071610418565b60408051600160a060020a039092168252519081900360200190f35b600081815481101561000057906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000805480600101828181548183558181151161022b5760008381526020902061022b9181019083015b808211156102275760008155600101610213565b5090565b5b505050916000526020600020900160005b8154600160a060020a038086166101009390930a92830292021916179055505b50565b60408051602081810183526000808352805484518184028101840190955280855292939290918301828280156102bf57602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116102a1575b505050505090505b90565b6000805460001981019081101561000057906000526020600020900160005b9054906101000a9004600160a060020a031660006001600086600160a060020a0316600160a060020a0316815260200190815260200160002054815481101561000057906000526020600020900160005b8154600160a060020a039384166101009290920a918202918402191617905583166000908152600160205260408120819055805460001981019081101561000057906000526020600020900160005b6101000a815490600160a060020a03021916905560008054809190600190038154818355818115116103e0576000838152602090206103e09181019083015b808211156102275760008155600101610213565b5090565b5b505050505b505050565b6002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5050565b600254600160a060020a0316815600a165627a7a72305820f7876e17abd5f0927fff16788b4b3c9028ed64e6db740d788b07fc5f0a8f10920029"
}, },
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1": { "balance": "1606938044258990275541962092341162602522202993782792835301376" } "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }

View File

@ -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. // Give one step slack if step is lagging, double vote is still not possible.
if step.is_future(header_step) { if step.is_future(header_step) {
trace!(target: "engine", "verify_block_unordered: block from the future"); 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)? Err(BlockError::InvalidSeal)?
} else { } else {
let proposer_signature = header_signature(header)?; let proposer_signature = header_signature(header)?;
@ -381,7 +381,7 @@ impl Engine for AuthorityRound {
let parent_step = header_step(parent)?; let parent_step = header_step(parent)?;
if step <= parent_step { if step <= parent_step {
trace!(target: "engine", "Multiple blocks proposed for 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()))?; Err(EngineError::DoubleVote(header.author().clone()))?;
} }

View File

@ -471,8 +471,8 @@ impl Engine for Tendermint {
return Err(EngineError::NotAuthorized(sender).into()); return Err(EngineError::NotAuthorized(sender).into());
} }
self.broadcast_message(rlp.as_raw().to_vec()); self.broadcast_message(rlp.as_raw().to_vec());
if self.votes.vote(message.clone(), &sender).is_some() { if let Some(double) = self.votes.vote(message.clone(), &sender) {
self.validators.report_malicious(&sender); self.validators.report_malicious(&sender, message.vote_step.height as BlockNumber, ::rlp::encode(&double).to_vec());
return Err(EngineError::DoubleVote(sender).into()); return Err(EngineError::DoubleVote(sender).into());
} }
trace!(target: "engine", "Handling a valid {:?} from {}.", message, sender); trace!(target: "engine", "Handling a valid {:?} from {}.", message, sender);
@ -560,7 +560,7 @@ impl Engine for Tendermint {
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor; 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; 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 { 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()); return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
} }
@ -610,8 +610,9 @@ impl Engine for Tendermint {
trace!(target: "engine", "Propose timeout."); trace!(target: "engine", "Propose timeout.");
if self.proposal.read().is_none() { if self.proposal.read().is_none() {
// Report the proposer if no proposal was received. // 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)); let height = self.height.load(AtomicOrdering::SeqCst);
self.validators.report_benign(&current_proposer); 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 Step::Prevote
}, },

View File

@ -25,7 +25,7 @@ use native_contracts::ValidatorReport as Provider;
use client::{Client, BlockChainClient}; use client::{Client, BlockChainClient};
use engines::Call; use engines::Call;
use header::Header; use header::{Header, BlockNumber};
use super::ValidatorSet; use super::ValidatorSet;
use super::safe_contract::ValidatorSafeContract; use super::safe_contract::ValidatorSafeContract;
@ -92,15 +92,15 @@ impl ValidatorSet for ValidatorContract {
self.validators.count_with_caller(bh, caller) self.validators.count_with_caller(bh, caller)
} }
fn report_malicious(&self, address: &Address) { fn report_malicious(&self, address: &Address, block: BlockNumber, proof: Bytes) {
match self.provider.report_malicious(&*self.transact(), *address).wait() { match self.provider.report_malicious(&*self.transact(), *address, block.into(), proof).wait() {
Ok(_) => warn!(target: "engine", "Reported malicious validator {}", address), Ok(_) => warn!(target: "engine", "Reported malicious validator {}", address),
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s), Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
} }
} }
fn report_benign(&self, address: &Address) { fn report_benign(&self, address: &Address, block: BlockNumber) {
match self.provider.report_benign(&*self.transact(), *address).wait() { match self.provider.report_benign(&*self.transact(), *address, block.into()).wait() {
Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address), Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address),
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s), Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
} }

View File

@ -23,10 +23,10 @@ mod multi;
use std::sync::Weak; use std::sync::Weak;
use ids::BlockId; use ids::BlockId;
use util::{Address, H256}; use util::{Bytes, Address, H256};
use ethjson::spec::ValidatorSet as ValidatorSpec; use ethjson::spec::ValidatorSet as ValidatorSpec;
use client::Client; use client::Client;
use header::Header; use header::{Header, BlockNumber};
pub use self::simple_list::SimpleList; pub use self::simple_list::SimpleList;
use self::contract::ValidatorContract; use self::contract::ValidatorContract;
@ -111,9 +111,9 @@ pub trait ValidatorSet: Send + Sync {
fn count_with_caller(&self, parent_block_hash: &H256, caller: &Call) -> usize; fn count_with_caller(&self, parent_block_hash: &H256, caller: &Call) -> usize;
/// Notifies about malicious behaviour. /// Notifies about malicious behaviour.
fn report_malicious(&self, _validator: &Address) {} fn report_malicious(&self, _validator: &Address, _block: BlockNumber, _proof: Bytes) {}
/// Notifies about benign misbehaviour. /// Notifies about benign misbehaviour.
fn report_benign(&self, _validator: &Address) {} fn report_benign(&self, _validator: &Address, _block: BlockNumber) {}
/// Allows blockchain state access. /// Allows blockchain state access.
fn register_contract(&self, _client: Weak<Client>) {} fn register_contract(&self, _client: Weak<Client>) {}
} }

View File

@ -19,7 +19,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::Weak; use std::sync::Weak;
use engines::{Call, EpochChange}; use engines::{Call, EpochChange};
use util::{H256, Address, RwLock}; use util::{Bytes, H256, Address, RwLock};
use ids::BlockId; use ids::BlockId;
use header::{BlockNumber, Header}; use header::{BlockNumber, Header};
use client::{Client, BlockChainClient}; use client::{Client, BlockChainClient};
@ -110,16 +110,12 @@ impl ValidatorSet for Multi {
.map_or_else(usize::max_value, |set| set.count_with_caller(bh, caller)) .map_or_else(usize::max_value, |set| set.count_with_caller(bh, caller))
} }
fn report_malicious(&self, validator: &Address) { fn report_malicious(&self, validator: &Address, block: BlockNumber, proof: Bytes) {
for set in self.sets.values() { self.correct_set_by_number(block).1.report_malicious(validator, block, proof);
set.report_malicious(validator);
}
} }
fn report_benign(&self, validator: &Address) { fn report_benign(&self, validator: &Address, block: BlockNumber) {
for set in self.sets.values() { self.correct_set_by_number(block).1.report_benign(validator, block);
set.report_benign(validator);
}
} }
fn register_contract(&self, client: Weak<Client>) { fn register_contract(&self, client: Weak<Client>) {

View File

@ -18,7 +18,7 @@
use std::fmt::Debug; use std::fmt::Debug;
use util::*; use util::*;
use rlp::Encodable; use rlp::{Encodable, RlpStream};
pub trait Message: Clone + PartialEq + Eq + Hash + Encodable + Debug { pub trait Message: Clone + PartialEq + Eq + Hash + Encodable + Debug {
type Round: Clone + PartialEq + Eq + Hash + Default + Debug + Ord; type Round: Clone + PartialEq + Eq + Hash + Default + Debug + Ord;
@ -40,25 +40,44 @@ pub struct VoteCollector<M: Message> {
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct StepCollector<M: Message> { struct StepCollector<M: Message> {
voted: HashSet<Address>, voted: HashMap<Address, M>,
pub block_votes: HashMap<Option<H256>, HashMap<H520, Address>>, pub block_votes: HashMap<Option<H256>, HashMap<H520, Address>>,
messages: HashSet<M>, 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> { impl <M: Message> StepCollector<M> {
/// Returns Some(&Address) when validator is double voting. /// 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. // Do nothing when message was seen.
if self.messages.insert(message.clone()) { 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 self
.block_votes .block_votes
.entry(message.block_hash()) .entry(message.block_hash())
.or_insert_with(HashMap::new) .or_insert_with(HashMap::new)
.insert(message.signature(), address.clone()); .insert(message.signature(), address.clone());
} else {
// Bad validator sent a different message.
return Some(address);
} }
} }
None None
@ -101,7 +120,7 @@ impl <M: Message + Default> Default for VoteCollector<M> {
impl <M: Message + Default + Encodable + Debug> VoteCollector<M> { impl <M: Message + Default + Encodable + Debug> VoteCollector<M> {
/// Insert vote if it is newer than the oldest one. /// 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 self
.votes .votes
.write() .write()
@ -220,11 +239,11 @@ mod tests {
} }
fn random_vote(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>) -> bool { 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> { 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) collector.vote(TestMessage { signature: signature, step: step, block_hash: block_hash }, address).is_none()
} }
#[test] #[test]
@ -319,9 +338,9 @@ mod tests {
let collector = VoteCollector::default(); let collector = VoteCollector::default();
let round = 3; let round = 3;
// Vote is inserted fine. // 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. // 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); assert_eq!(collector.count_round_votes(&round), 1);
} }
} }