Skip to content
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
2 changes: 1 addition & 1 deletion core/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

mod bit_set;
mod null_engine;
mod signer;
pub(crate) mod signer;
mod simple_poa;
mod solo;
pub mod stake;
Expand Down
6 changes: 6 additions & 0 deletions core/src/consensus/stake/action_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,9 @@ impl Candidates {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.len() == 0
}

#[cfg(test)]
pub fn get_index(&self, account: &Address) -> Option<usize> {
Expand Down Expand Up @@ -715,6 +718,9 @@ impl Jail {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.len() == 0
}

pub fn add(&mut self, candidate: Candidate, custody_until: u64, released_at: u64) {
assert!(custody_until <= released_at);
Expand Down
5 changes: 4 additions & 1 deletion core/src/consensus/stake/distribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use std::collections::hash_map;
use std::collections::HashMap;
use std::convert::TryFrom;

pub fn fee_distribute(total_min_fee: u64, stakes: &HashMap<Address, u64>) -> FeeDistributeIter<'_> {
pub fn fee_distribute<S: ::std::hash::BuildHasher>(
total_min_fee: u64,
stakes: &HashMap<Address, u64, S>,
) -> FeeDistributeIter<'_> {
FeeDistributeIter {
total_stakes: stakes.values().sum(),
total_min_fee,
Expand Down
12 changes: 9 additions & 3 deletions core/src/consensus/stake/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ use parking_lot::RwLock;
use primitives::{Bytes, H256};
use rlp::{Decodable, Rlp};
use std::collections::btree_map::BTreeMap;
use std::collections::hash_map::RandomState;
use std::collections::HashMap;
use std::sync::{Arc, Weak};

pub use self::action_data::{Banned, CurrentValidators, NextValidators, PreviousValidators, Validator};
use self::action_data::{Candidates, Delegation, IntermediateRewards, Jail, ReleaseResult, StakeAccount, Stakeholders};
pub use self::action_data::{
Banned, Candidates, CurrentValidators, Jail, NextValidators, PreviousValidators, Validator,
};
use self::action_data::{Delegation, IntermediateRewards, ReleaseResult, StakeAccount, Stakeholders};
pub use self::actions::Action;
pub use self::distribute::fee_distribute;
use super::ValidatorSet;
Expand Down Expand Up @@ -330,7 +333,10 @@ pub fn drain_current_rewards(state: &mut TopLevelState) -> StateResult<BTreeMap<
Ok(drained)
}

pub fn update_calculated_rewards(state: &mut TopLevelState, values: HashMap<Address, u64>) -> StateResult<()> {
pub fn update_calculated_rewards(
state: &mut TopLevelState,
values: HashMap<Address, u64, RandomState>,
) -> StateResult<()> {
let mut rewards = IntermediateRewards::load_from_state(state)?;
rewards.update_calculated(values.into_iter().collect());
rewards.save_to_state(state)
Expand Down
2 changes: 1 addition & 1 deletion core/src/consensus/tendermint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use self::chain_notify::TendermintChainNotify;
pub use self::message::{ConsensusMessage, VoteOn, VoteStep};
pub use self::params::{TendermintParams, TimeGapParams, TimeoutParams};
pub use self::types::{Height, Step, View};
use super::{stake, ValidatorSet};
pub use super::{stake, ValidatorSet};
use crate::client::ConsensusClient;
use crate::codechain_machine::CodeChainMachine;
use crate::snapshot_notify::NotifySender as SnapshotNotifySender;
Expand Down
5 changes: 5 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ extern crate codechain_types as ctypes;
extern crate codechain_vm as cvm;
#[cfg(test)]
extern crate rand_xorshift;
extern crate rlp;
#[macro_use]
extern crate rlp_derive;
#[macro_use]
Expand Down Expand Up @@ -63,16 +64,20 @@ mod tests;
pub use crate::account_provider::{AccountProvider, Error as AccountProviderError};
pub use crate::block::Block;
pub use crate::client::snapshot_notify;
pub use crate::client::ConsensusClient;
pub use crate::client::{
AccountData, AssetClient, BlockChainClient, BlockChainTrait, ChainNotify, Client, ClientConfig, DatabaseClient,
EngineClient, EngineInfo, ExecuteClient, ImportBlock, MiningBlockChainClient, Shard, SnapshotClient, StateInfo,
TermInfo, TestBlockChainClient,
};
pub use crate::consensus::signer::EngineSigner;
pub use crate::consensus::stake;
pub use crate::consensus::{EngineType, TimeGapParams};
pub use crate::db::{COL_PEER, COL_STATE, NUM_COLUMNS};
pub use crate::error::{BlockImportError, Error, ImportError};
pub use crate::miner::{MemPoolFees, Miner, MinerOptions, MinerService};
pub use crate::peer_db::PeerDb;
pub use crate::rlp::Encodable;
pub use crate::scheme::Scheme;
pub use crate::service::ClientService;
pub use crate::transaction::{
Expand Down
4 changes: 4 additions & 0 deletions core/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,10 @@ impl MinerService for Miner {
}
}

fn get_author_address(&self) -> Address {
self.params.read().author
}

fn set_extra_data(&self, extra_data: Bytes) {
self.params.write().extra_data = extra_data;
}
Expand Down
3 changes: 3 additions & 0 deletions core/src/miner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ pub trait MinerService: Send + Sync {
/// Set the author that we will seal blocks as.
fn set_author(&self, author: Address) -> Result<(), AccountProviderError>;

///Get the address that sealed the block.
fn get_author_address(&self) -> Address;

/// Set the extra_data that we will seal blocks with.
fn set_extra_data(&self, extra_data: Bytes);

Expand Down
196 changes: 196 additions & 0 deletions foundry/auto_self_nominate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Copyright 2020 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::config::load_config;
use ccore::stake::Action::SelfNominate;
use ccore::stake::{Banned, Candidates, Jail, CUSTOM_ACTION_HANDLER_ID};
use ccore::{
AccountProvider, AccountProviderError, BlockId, ConsensusClient, Encodable, SignedTransaction,
UnverifiedTransaction,
};
use ckey::PlatformAddress;
use ckey::{Address, Public, Signature};
use ckeystore::DecryptedAccount;
use clap::ArgMatches;
use codechain_types::transaction::{Action, Transaction};
use primitives::{Bytes, H256};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

const NEED_NOMINATION_UNDER_TERM_LEFT: u64 = 1;
#[derive(Clone)]
struct SelfSigner {
account_provider: Arc<AccountProvider>,
signer: Option<(Address, Public)>,
decrypted_account: Option<DecryptedAccount>,
}
impl SelfSigner {
pub fn new(ap: Arc<AccountProvider>, address: Address) -> Self {
let public = {
let account = ap.get_unlocked_account(&address).expect("The address must be registered in AccountProvider");
account.public().expect("Cannot get public from account")
};
Self {
account_provider: ap,
signer: Some((address, public)),
decrypted_account: None,
}
}

pub fn sign_ecdsa(&self, hash: H256) -> Result<Signature, AccountProviderError> {
let address = self.signer.map(|(address, _public)| address).unwrap_or_else(Default::default);
let result = match &self.decrypted_account {
Some(account) => account.sign(&hash)?,
None => {
let account = self.account_provider.get_unlocked_account(&address)?;
account.sign(&hash)?
}
};
Ok(result)
}

pub fn address(&self) -> Option<&Address> {
self.signer.as_ref().map(|(address, _)| address)
}
}

pub struct AutoSelfNomination {
client: Arc<dyn ConsensusClient>,
signer: SelfSigner,
}

impl AutoSelfNomination {
pub fn new(client: Arc<dyn ConsensusClient>, ap: Arc<AccountProvider>, address: Address) -> Arc<Self> {
Arc::new(Self {
client,
signer: SelfSigner::new(ap, address),
})
}

pub fn send_self_nominate_transaction(&self, matches: &ArgMatches) {
let config = load_config(matches).unwrap();
let account_address = config.mining.engine_signer.unwrap();
let defualt_metadata = config.mining.self_nomination_metadata.unwrap();
let target_deposite = config.mining.self_target_deposit.unwrap();
let interval = config.mining.self_nomination_interval.unwrap();
let self_client = self.client.clone();
let self_signer = self.signer.clone();
thread::Builder::new()
.name("Auto Self Nomination".to_string())
.spawn(move || loop {
AutoSelfNomination::send(
&self_client,
&self_signer,
&account_address,
&defualt_metadata,
target_deposite,
);
thread::sleep(Duration::from_millis(interval));
})
.unwrap();
}

fn send(
client: &Arc<dyn ConsensusClient>,
signer: &SelfSigner,
account_address: &PlatformAddress,
metadata: &str,
targetdep: u64,
) {
let metabytes = metadata.rlp_bytes();
let mut dep = targetdep;
let address = account_address.address();
let block_id = BlockId::Latest;
let state = client.state_at(block_id).unwrap();
let current_term = client.current_term_id(block_id).unwrap();
let banned = Banned::load_from_state(&state).unwrap();
if banned.is_banned(address) {
cwarn!(ENGINE, "Account is banned");
return
}
let jailed = Jail::load_from_state(&state).unwrap();
if jailed.get_prisoner(&address).is_some() {
let prisoner = jailed.get_prisoner(&address).unwrap();

if prisoner.custody_until <= (current_term) {
cwarn!(ENGINE, "Account is still in custody");
return
}
}
let candidate = Candidates::load_from_state(&state).unwrap();
if candidate.get_candidate(&address).is_some() {
let candidate_need_nomination = candidate.get_candidate(&address).unwrap();
if candidate_need_nomination.nomination_ends_at <= current_term + NEED_NOMINATION_UNDER_TERM_LEFT {
cdebug!(ENGINE, "No need self nominate");
return
}
if candidate_need_nomination.deposit.lt(&targetdep) {
dep = targetdep.min(targetdep);
} else {
dep = 0 as u64;
}
}

AutoSelfNomination::self_nomination_transaction(&client, &signer, dep, metabytes);
}

fn self_nomination_transaction(
client: &Arc<dyn ConsensusClient>,
signer: &SelfSigner,
deposit: u64,
metadata: Bytes,
) {
let network_id = client.network_id();
let seq = match signer.address() {
Some(address) => client.latest_seq(address),
None => {
cwarn!(ENGINE, "Signer was not assigned");
return
}
};
let selfnominate = SelfNominate {
deposit,
metadata,
};
let tx = Transaction {
seq,
fee: 0,
network_id,
action: Action::Custom {
handler_id: CUSTOM_ACTION_HANDLER_ID,
bytes: selfnominate.rlp_bytes(),
},
};

let signature = match signer.sign_ecdsa(*tx.hash()) {
Ok(signature) => signature,
Err(e) => {
cerror!(ENGINE, "Could not sign the message:{}", e);
return
}
};
let unverified = UnverifiedTransaction::new(tx, signature);
let signed = SignedTransaction::try_new(unverified).expect("secret is valid so it's recoverable");

match client.queue_own_transaction(signed) {
Ok(_) => {}
Err(e) => {
cerror!(ENGINE, "Failed to queue self nominate transaction: {}", e);
}
}
}
}
29 changes: 29 additions & 0 deletions foundry/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ pub struct Mining {
pub engine_signer: Option<PlatformAddress>,
pub mem_pool_size: Option<usize>,
pub mem_pool_mem_limit: Option<usize>,
pub self_nomination_metadata: Option<String>,
pub self_target_deposit: Option<u64>,
pub self_nomination_enable: bool,
pub self_nomination_interval: Option<u64>,
pub mem_pool_fee_bump_shift: Option<usize>,
pub allow_create_shard: Option<bool>,
pub force_sealing: Option<bool>,
Expand Down Expand Up @@ -387,6 +391,15 @@ impl Mining {
if other.engine_signer.is_some() {
self.engine_signer = other.engine_signer;
}
if other.self_nomination_metadata.is_some() {
self.self_nomination_metadata = other.self_nomination_metadata.clone();
}
if other.self_target_deposit.is_some() {
self.self_target_deposit = other.self_target_deposit;
}
if other.self_nomination_interval.is_some() {
self.self_nomination_interval = other.self_nomination_interval;
}
if other.mem_pool_size.is_some() {
self.mem_pool_size = other.mem_pool_size;
}
Expand Down Expand Up @@ -456,6 +469,22 @@ impl Mining {
if let Some(engine_signer) = matches.value_of("engine-signer") {
self.engine_signer = Some(engine_signer.parse().map_err(|_| "Invalid address format")?);
}
if let Some(self_nomination_metadata) = matches.value_of("self-nomination-metadata") {
self.self_nomination_metadata =
Some(self_nomination_metadata.parse().map_err(|_| "Invalid self nomination metadata format")?);
}
if let Some(self_nomination_target_deposit) = matches.value_of("self-nomination-target-deposit") {
self.self_target_deposit = Some(
self_nomination_target_deposit.parse().map_err(|_| "Invalid self nomination target deposit format")?,
);
}
if let Some(self_nomination_interval) = matches.value_of("self-nomination-interval") {
self.self_nomination_interval =
Some(self_nomination_interval.parse().map_err(|_| "Invalid self nomination interval format")?);
}
if matches.is_present("enable-auto-self-nomination") {
self.self_nomination_enable = true;
}
if matches.is_present("no-miner") {
self.author = None;
self.engine_signer = None;
Expand Down
1 change: 1 addition & 0 deletions foundry/config/presets/config.dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ reseal_on_txs = "all"
reseal_min_period = 0
reseal_max_period = 120000
no_reseal_timer = false
self_nomination_enable = false
allowed_past_gap = 30000
allowed_future_gap = 5000

Expand Down
Loading