Skip to content

Block malicous users #1434

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions core/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use std::sync::{Arc, Weak};
use std::time::Instant;

use cio::IoChannel;
use ckey::{Address, PlatformAddress, Public};
use ckey::{Address, NetworkId, PlatformAddress, Public};
use cmerkle::Result as TrieResult;
use cnetwork::NodeId;
use cstate::{
Expand Down Expand Up @@ -892,7 +892,31 @@ impl BlockProducer for Client {
}
}

impl MiningBlockChainClient for Client {}
impl MiningBlockChainClient for Client {
fn get_malicious_users(&self) -> Vec<Address> {
self.importer.miner.get_malicious_users()
}

fn release_malicious_users(&self, prisoner_vec: Vec<Address>) {
self.importer.miner.release_malicious_users(prisoner_vec)
}

fn imprison_malicious_users(&self, prisoner_vec: Vec<Address>) {
self.importer.miner.imprison_malicious_users(prisoner_vec)
}

fn get_immune_users(&self) -> Vec<Address> {
self.importer.miner.get_immune_users()
}

fn register_immune_users(&self, immune_user_vec: Vec<Address>) {
self.importer.miner.register_immune_users(immune_user_vec)
}

fn get_network_id(&self) -> NetworkId {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Network id can be retrieved with EngineInfo::common_params(Latest)?.network_id()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant that get_network_id() is unnecessary.

self.common_params(BlockId::Latest).unwrap().network_id()
}
}

impl ChainTimeInfo for Client {
fn transaction_block_age(&self, tracker: &H256, parent_block_number: BlockNumber) -> Option<u64> {
Expand Down
22 changes: 20 additions & 2 deletions core/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub use self::test_client::TestBlockChainClient;
use std::ops::Range;
use std::sync::Arc;

use ckey::{Address, PlatformAddress, Public};
use ckey::{Address, NetworkId, PlatformAddress, Public};
use cmerkle::Result as TrieResult;
use cnetwork::NodeId;
use cstate::{AssetScheme, FindActionHandler, OwnedAsset, StateResult, Text, TopLevelState, TopStateView};
Expand Down Expand Up @@ -271,7 +271,25 @@ pub trait BlockProducer {
}

/// Extended client interface used for mining
pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + FindActionHandler {}
pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + FindActionHandler {
/// Returns malicious users who sent failing transactions.
fn get_malicious_users(&self) -> Vec<Address>;

/// Release designated users from the malicious user list.
fn release_malicious_users(&self, prisoner_vec: Vec<Address>);

/// Append designated users to the malicious user list.
fn imprison_malicious_users(&self, prisoner_vec: Vec<Address>);

/// Returns users immune from getting banned.
fn get_immune_users(&self) -> Vec<Address>;

/// Append designated users to the immune user list.
fn register_immune_users(&self, immune_user_vec: Vec<Address>);

/// Returns network id.
fn get_network_id(&self) -> NetworkId;
}

/// Provides methods to access database.
pub trait DatabaseClient {
Expand Down
26 changes: 25 additions & 1 deletion core/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,31 @@ impl BlockProducer for TestBlockChainClient {
}
}

impl MiningBlockChainClient for TestBlockChainClient {}
impl MiningBlockChainClient for TestBlockChainClient {
fn get_malicious_users(&self) -> Vec<Address> {
self.miner.get_malicious_users()
}

fn release_malicious_users(&self, prisoner_vec: Vec<Address>) {
self.miner.release_malicious_users(prisoner_vec)
}

fn imprison_malicious_users(&self, prisoner_vec: Vec<Address>) {
self.miner.imprison_malicious_users(prisoner_vec)
}

fn get_immune_users(&self) -> Vec<Address> {
self.miner.get_immune_users()
}

fn register_immune_users(&self, immune_user_vec: Vec<Address>) {
self.miner.register_immune_users(immune_user_vec)
}

fn get_network_id(&self) -> NetworkId {
NetworkId::default()
}
}

impl AccountData for TestBlockChainClient {
fn seq(&self, address: &Address, id: BlockId) -> Option<u64> {
Expand Down
5 changes: 5 additions & 0 deletions core/src/miner/mem_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,11 @@ impl MemPool {
self.current.queue.iter().any(|tx| tx.origin.is_local())
}

/// Returns Some(true) if the given transaction is local and None for not found.
pub fn is_local_transaction(&self, tx_hash: H256) -> Option<bool> {
self.by_hash.get(&tx_hash).and_then(|found_item| Some(found_item.origin.is_local()))
}

/// Checks the given timelock with the current time/timestamp.
fn should_wait_timelock(timelock: &TxTimelock, best_block_number: BlockNumber, best_block_timestamp: u64) -> bool {
if let Some(block_number) = timelock.block {
Expand Down
137 changes: 108 additions & 29 deletions core/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@

use std::collections::HashSet;
use std::iter::once;
use std::iter::FromIterator;
use std::ops::Range;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};

use ckey::{public_to_address, Address, Password, PlatformAddress, Public};
use cstate::{FindActionHandler, TopLevelState};
use ctypes::errors::HistoryError;
use ctypes::errors::{HistoryError, RuntimeError};
use ctypes::transaction::{Action, IncompleteTransaction, Timelock};
use ctypes::{BlockNumber, Header};
use cvm::ChainTimeInfo;
Expand Down Expand Up @@ -127,6 +128,8 @@ pub struct Miner {

accounts: Option<Arc<AccountProvider>>,
notifiers: RwLock<Vec<Box<dyn NotifyWork>>>,
malicious_users: RwLock<HashSet<Address>>,
immune_users: RwLock<HashSet<Address>>,
}

impl Miner {
Expand Down Expand Up @@ -184,6 +187,8 @@ impl Miner {
sealing_enabled: AtomicBool::new(true),
accounts,
notifiers: RwLock::new(notifiers),
malicious_users: RwLock::new(HashSet::new()),
immune_users: RwLock::new(HashSet::new()),
}
}

Expand Down Expand Up @@ -269,48 +274,71 @@ impl Miner {
.into_iter()
.map(|tx| {
let hash = tx.hash();
// FIXME: Refactoring is needed. recover_public is calling in verify_transaction_unordered.
let signer_public = tx.recover_public()?;
let signer_address = public_to_address(&signer_public);
if default_origin.is_local() {
self.immune_users.write().insert(signer_address);
}

let origin = self
.accounts
.as_ref()
.and_then(|accounts| match accounts.has_public(&signer_public) {
Ok(true) => Some(TxOrigin::Local),
Ok(false) => None,
Err(_) => None,
})
.unwrap_or(default_origin);

if self.malicious_users.read().contains(&signer_address) {
// FIXME: just to skip, think about another way.
return Ok(())
}
if client.transaction_block(&TransactionId::Hash(hash)).is_some() {
cdebug!(MINER, "Rejected transaction {:?}: already in the blockchain", hash);
return Err(HistoryError::TransactionAlreadyImported.into())
}
if !self.is_allowed_transaction(&tx.action) {
cdebug!(MINER, "Rejected transaction {:?}: {:?} is not allowed transaction", hash, tx.action);
}
match tx
let immune_users = self.immune_users.read();
let tx = tx
.verify_basic()
.map_err(From::from)
.and_then(|_| {
let common_params = client.common_params(best_header.hash().into()).unwrap();
self.engine.verify_transaction_with_params(&tx, &common_params)
})
.and_then(|_| CodeChainMachine::verify_transaction_seal(tx, &fake_header))
{
Err(e) => {
.map_err(|e| {
match e {
Error::Syntax(_) if !origin.is_local() && !immune_users.contains(&signer_address) => {
self.malicious_users.write().insert(signer_address);
}
_ => {}
}
cdebug!(MINER, "Rejected transaction {:?} with invalid signature: {:?}", hash, e);
Err(e)
e
})?;

// This check goes here because verify_transaction takes SignedTransaction parameter
self.engine.machine().verify_transaction(&tx, &fake_header, client, false).map_err(|e| {
match e {
Error::Syntax(_) if !origin.is_local() && !immune_users.contains(&signer_address) => {
self.malicious_users.write().insert(signer_address);
}
_ => {}
}
Ok(tx) => {
// This check goes here because verify_transaction takes SignedTransaction parameter
self.engine.machine().verify_transaction(&tx, &fake_header, client, false)?;

let origin = self
.accounts
.as_ref()
.and_then(|accounts| match accounts.has_public(&tx.signer_public()) {
Ok(true) => Some(TxOrigin::Local),
Ok(false) => None,
Err(_) => None,
})
.unwrap_or(default_origin);
e
})?;

let timelock = self.calculate_timelock(&tx, client)?;
let tx_hash = tx.hash();
let timelock = self.calculate_timelock(&tx, client)?;
let tx_hash = tx.hash();

to_insert.push(MemPoolInput::new(tx, origin, timelock));
tx_hashes.push(tx_hash);
Ok(())
}
}
to_insert.push(MemPoolInput::new(tx, origin, timelock));
tx_hashes.push(tx_hash);
Ok(())
})
.collect();

Expand Down Expand Up @@ -499,15 +527,22 @@ impl Miner {

let mut tx_count: usize = 0;
let tx_total = transactions.len();
let mut invald_tx_users = HashSet::new();
let mut invalid_tx_users = HashSet::new();

let immune_users = self.immune_users.read();
for tx in transactions {
let signer_public = tx.signer_public();
if invald_tx_users.contains(&signer_public) {
let signer_address = public_to_address(&signer_public);
if self.malicious_users.read().contains(&signer_address) {
invalid_transactions.push(tx.hash());
continue
}
if invalid_tx_users.contains(&signer_public) {
// The previous transaction has failed
continue
}
if !self.is_allowed_transaction(&tx.action) {
invald_tx_users.insert(signer_public);
invalid_tx_users.insert(signer_public);
invalid_transactions.push(tx.hash());
continue
}
Expand All @@ -524,7 +559,22 @@ impl Miner {
// already have transaction - ignore
Err(Error::History(HistoryError::TransactionAlreadyImported)) => {}
Err(e) => {
invald_tx_users.insert(signer_public);
match e {
Error::Runtime(RuntimeError::AssetSupplyOverflow)
| Error::Runtime(RuntimeError::InvalidScript) => {
if !self
.mem_pool
.read()
.is_local_transaction(hash)
.expect("The tx is clearly fetched from the mempool")
&& !immune_users.contains(&signer_address)
{
self.malicious_users.write().insert(signer_address);
}
}
_ => {}
}
invalid_tx_users.insert(signer_public);
invalid_transactions.push(hash);
cinfo!(
MINER,
Expand Down Expand Up @@ -1074,6 +1124,35 @@ impl MinerService for Miner {
cdebug!(MINER, "Stop sealing");
self.sealing_enabled.store(false, Ordering::Relaxed);
}

fn get_malicious_users(&self) -> Vec<Address> {
Vec::from_iter(self.malicious_users.read().iter().map(Clone::clone))
}

fn release_malicious_users(&self, prisoner_vec: Vec<Address>) {
let mut malicious_users = self.malicious_users.write();
for address in prisoner_vec {
malicious_users.remove(&address);
}
}

fn imprison_malicious_users(&self, prisoner_vec: Vec<Address>) {
let mut malicious_users = self.malicious_users.write();
for address in prisoner_vec {
malicious_users.insert(address);
}
}

fn get_immune_users(&self) -> Vec<Address> {
Vec::from_iter(self.immune_users.read().iter().map(Clone::clone))
}

fn register_immune_users(&self, immune_user_vec: Vec<Address>) {
let mut immune_users = self.immune_users.write();
for address in immune_user_vec {
immune_users.insert(address);
}
}
}

fn get_next_seq(transactions: impl IntoIterator<Item = SignedTransaction>, addresses: &[Address]) -> Option<u64> {
Expand Down
15 changes: 15 additions & 0 deletions core/src/miner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@ pub trait MinerService: Send + Sync {

/// Stop sealing.
fn stop_sealing(&self);

/// Get malicious users
fn get_malicious_users(&self) -> Vec<Address>;

/// Release target malicious users from malicious user set.
fn release_malicious_users(&self, prisoner_vec: Vec<Address>);

/// Imprison target malicious users to malicious user set.
fn imprison_malicious_users(&self, prisoner_vec: Vec<Address>);

/// Get ban-immune users.
fn get_immune_users(&self) -> Vec<Address>;

/// Register users to ban-immune users.
fn register_immune_users(&self, immune_user_vec: Vec<Address>);
}

/// Mining status
Expand Down
Loading