Minimal Transaction Pool (#1067)
* verify a tx like we verify a block (experimental) * first minimal_pool test up and running but not testing what we need to * rework tx_pool validation to use txhashset extension * minimal tx pool wired up but rough * works locally (rough statew though) delete "legacy" pool and graph code * rework the new pool into TransactionPool and Pool impls * rework pool to store pool entries with associated timer and source etc. * all_transactions * extra_txs so we can validate stempool against existing txpool * rework reconcile_block * txhashset apply_raw_tx can now rewind to a checkpoint (prev raw tx) * wip - txhashset tx tests * more flexible rewind on MMRs * add tests to cover apply_raw_txs on txhashset extension * add_to_stempool and add_to_txpool * deaggregate multi kernel tx when adding to txpoool * handle freshness in stempool handle propagation of stempool txs via dandelion monitor * patience timer and fluff if we cannot propagate to next relay * aggregate and fluff stempool is we have no relay * refactor coinbase maturity * rewrote basic tx pool tests to use a real txhashset via chain adapter * rework dandelion monitor to reflect recent discussion works locally but needs a cleanup * refactor dandelion_monitor - split out phases * more pool test coverage * remove old test code from pool (still wip) * block_building and block_reconciliation tests * tracked down chain test failure... * fix test_coinbase_maturity * dandelion_monitor now runs... * refactor dandelion config, shared across p2p and pool components * fix pool tests with new config * fix p2p tests * rework tx pool to deal with duplicate commitments (testnet2 limitation) * cleanup and address some PR feedback * add big comment about pre_tx...
This commit is contained in:
@@ -15,28 +15,28 @@
|
||||
//! Adapters connecting new block, new transaction, and accepted transaction
|
||||
//! events to consumers of those events.
|
||||
|
||||
use rand;
|
||||
use rand::Rng;
|
||||
use std::fs::File;
|
||||
use std::net::SocketAddr;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, RwLock, Weak};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, RwLock, Weak};
|
||||
use std::thread;
|
||||
use std::time::Instant;
|
||||
use rand;
|
||||
use rand::Rng;
|
||||
|
||||
use chain::{self, ChainAdapter, Options, Tip};
|
||||
use common::types::{ChainValidationMode, ServerConfig};
|
||||
use core::core;
|
||||
use core::core::block::BlockHeader;
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::transaction::{Input, OutputIdentifier};
|
||||
use core::core::transaction::Transaction;
|
||||
use p2p;
|
||||
use pool;
|
||||
use util::OneTime;
|
||||
use store;
|
||||
use common::types::{ChainValidationMode, ServerConfig};
|
||||
use util::LOGGER;
|
||||
use util::OneTime;
|
||||
|
||||
// All adapters use `Weak` references instead of `Arc` to avoid cycles that
|
||||
// can never be destroyed. These 2 functions are simple helpers to reduce the
|
||||
@@ -75,35 +75,23 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
debug_name: "p2p".to_string(),
|
||||
identifier: "?.?.?.?".to_string(),
|
||||
};
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received tx {} from {}, going to process.",
|
||||
"Received tx {} from {:?}, going to process.",
|
||||
tx.hash(),
|
||||
source.identifier,
|
||||
source,
|
||||
);
|
||||
|
||||
let h = tx.hash();
|
||||
|
||||
if !stem && tx.kernels.len() != 1 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received regular multi-kernel transaction will attempt to deaggregate"
|
||||
);
|
||||
if let Err(e) = self.tx_pool
|
||||
.write()
|
||||
.unwrap()
|
||||
.deaggregate_and_add_to_memory_pool(source, tx, stem)
|
||||
{
|
||||
debug!(LOGGER, "Transaction {} rejected: {:?}", h, e);
|
||||
}
|
||||
} else {
|
||||
if let Err(e) = self.tx_pool
|
||||
.write()
|
||||
.unwrap()
|
||||
.add_to_memory_pool(source, tx, stem)
|
||||
{
|
||||
debug!(LOGGER, "Transaction {} rejected: {:?}", h, e);
|
||||
}
|
||||
let res = {
|
||||
let mut tx_pool = self.tx_pool.write().unwrap();
|
||||
tx_pool.add_to_pool(source, tx, stem)
|
||||
};
|
||||
|
||||
if let Err(e) = res {
|
||||
debug!(LOGGER, "Transaction {} rejected: {:?}", h, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,8 +623,8 @@ impl ChainToPoolAndNetAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize a ChainToPoolAndNetAdapter instance with hanlde to a Peers object.
|
||||
/// Should only be called once.
|
||||
/// Initialize a ChainToPoolAndNetAdapter instance with hanlde to a Peers
|
||||
/// object. Should only be called once.
|
||||
pub fn init(&self, peers: Weak<p2p::Peers>) {
|
||||
self.peers.init(peers);
|
||||
}
|
||||
@@ -649,8 +637,11 @@ pub struct PoolToNetAdapter {
|
||||
}
|
||||
|
||||
impl pool::PoolAdapter for PoolToNetAdapter {
|
||||
fn stem_tx_accepted(&self, tx: &core::Transaction) {
|
||||
wo(&self.peers).broadcast_stem_transaction(tx);
|
||||
fn stem_tx_accepted(&self, tx: &core::Transaction) -> Result<(), pool::PoolError> {
|
||||
wo(&self.peers)
|
||||
.broadcast_stem_transaction(tx)
|
||||
.map_err(|_| pool::PoolError::DandelionError)?;
|
||||
Ok(())
|
||||
}
|
||||
fn tx_accepted(&self, tx: &core::Transaction) {
|
||||
wo(&self.peers).broadcast_transaction(tx);
|
||||
@@ -694,26 +685,25 @@ impl PoolToChainAdapter {
|
||||
}
|
||||
|
||||
impl pool::BlockChain for PoolToChainAdapter {
|
||||
fn is_unspent(&self, output_ref: &OutputIdentifier) -> Result<Hash, pool::PoolError> {
|
||||
wo(&self.chain).is_unspent(output_ref).map_err(|e| match e {
|
||||
chain::types::Error::OutputNotFound => pool::PoolError::OutputNotFound,
|
||||
chain::types::Error::OutputSpent => pool::PoolError::OutputSpent,
|
||||
_ => pool::PoolError::GenericPoolError,
|
||||
fn validate_raw_txs(
|
||||
&self,
|
||||
txs: Vec<Transaction>,
|
||||
pre_tx: Option<Transaction>,
|
||||
) -> Result<(Vec<Transaction>), pool::PoolError> {
|
||||
wo(&self.chain).validate_raw_txs(txs, pre_tx).map_err(|_| {
|
||||
pool::PoolError::Other("Chain adapter failed to validate_raw_txs.".to_string())
|
||||
})
|
||||
}
|
||||
|
||||
fn is_matured(&self, input: &Input, height: u64) -> Result<(), pool::PoolError> {
|
||||
fn verify_coinbase_maturity(&self, tx: &Transaction) -> Result<(), pool::PoolError> {
|
||||
wo(&self.chain)
|
||||
.is_matured(input, height)
|
||||
.map_err(|e| match e {
|
||||
chain::types::Error::OutputNotFound => pool::PoolError::OutputNotFound,
|
||||
_ => pool::PoolError::GenericPoolError,
|
||||
})
|
||||
.verify_coinbase_maturity(tx)
|
||||
.map_err(|_| pool::PoolError::ImmatureCoinbase)
|
||||
}
|
||||
|
||||
fn head_header(&self) -> Result<BlockHeader, pool::PoolError> {
|
||||
fn verify_tx_lock_height(&self, tx: &Transaction) -> Result<(), pool::PoolError> {
|
||||
wo(&self.chain)
|
||||
.head_header()
|
||||
.map_err(|_| pool::PoolError::GenericPoolError)
|
||||
.verify_tx_lock_height(tx)
|
||||
.map_err(|_| pool::PoolError::ImmatureTransaction)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,24 @@ use std::convert::From;
|
||||
use api;
|
||||
use chain;
|
||||
use core::core;
|
||||
use core::global::ChainTypes;
|
||||
use core::pow;
|
||||
use p2p;
|
||||
use pool;
|
||||
use store;
|
||||
use wallet;
|
||||
use core::global::ChainTypes;
|
||||
use core::pow;
|
||||
|
||||
/// Dandelion relay timer
|
||||
const DANDELION_RELAY_SECS: u64 = 600;
|
||||
|
||||
/// Dandelion emabargo timer
|
||||
const DANDELION_EMBARGO_SECS: u64 = 180;
|
||||
|
||||
/// Dandelion patience timer
|
||||
const DANDELION_PATIENCE_SECS: u64 = 10;
|
||||
|
||||
/// Dandelion stem probability (stem 90% of the time, fluff 10%).
|
||||
const DANDELION_STEM_PROBABILITY: usize = 90;
|
||||
|
||||
/// Error type wrapping underlying module errors.
|
||||
#[derive(Debug)]
|
||||
@@ -123,6 +135,54 @@ impl Default for Seeding {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_dandelion_stem_probability() -> usize {
|
||||
DANDELION_STEM_PROBABILITY
|
||||
}
|
||||
|
||||
fn default_dandelion_relay_secs() -> u64 {
|
||||
DANDELION_RELAY_SECS
|
||||
}
|
||||
|
||||
fn default_dandelion_embargo_secs() -> u64 {
|
||||
DANDELION_EMBARGO_SECS
|
||||
}
|
||||
|
||||
fn default_dandelion_patience_secs() -> u64 {
|
||||
DANDELION_PATIENCE_SECS
|
||||
}
|
||||
|
||||
/// Dandelion config.
|
||||
/// Note: Used by both p2p and pool components.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DandelionConfig {
|
||||
/// Choose new Dandelion relay peer every n secs.
|
||||
#[serde = "default_dandelion_relay_secs"]
|
||||
pub relay_secs: u64,
|
||||
/// Dandelion embargo, fluff and broadcast tx if not seen on network before
|
||||
/// embargo expires.
|
||||
#[serde = "default_dandelion_embargo_secs"]
|
||||
pub embargo_secs: u64,
|
||||
/// Dandelion patience timer, fluff/stem processing runs every n secs.
|
||||
/// Tx aggregation happens on stem txs received within this window.
|
||||
#[serde = "default_dandelion_patience_secs"]
|
||||
pub patience_secs: u64,
|
||||
/// Dandelion stem probability.
|
||||
#[serde = "default_dandelion_stem_probability"]
|
||||
pub stem_probability: usize,
|
||||
}
|
||||
|
||||
/// Default address for peer-to-peer connections.
|
||||
impl Default for DandelionConfig {
|
||||
fn default() -> DandelionConfig {
|
||||
DandelionConfig {
|
||||
relay_secs: default_dandelion_relay_secs(),
|
||||
embargo_secs: default_dandelion_embargo_secs(),
|
||||
patience_secs: default_dandelion_patience_secs(),
|
||||
stem_probability: default_dandelion_stem_probability(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Full server configuration, aggregating configurations required for the
|
||||
/// different components.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -167,6 +227,10 @@ pub struct ServerConfig {
|
||||
#[serde(default)]
|
||||
pub pool_config: pool::PoolConfig,
|
||||
|
||||
/// Dandelion configuration
|
||||
#[serde(default)]
|
||||
pub dandelion_config: DandelionConfig,
|
||||
|
||||
/// Whether to skip the sync timeout on startup
|
||||
/// (To assist testing on solo chains)
|
||||
pub skip_sync_wait: Option<bool>,
|
||||
@@ -185,6 +249,28 @@ pub struct ServerConfig {
|
||||
pub test_miner_wallet_url: Option<String>,
|
||||
}
|
||||
|
||||
impl ServerConfig {
|
||||
/// Adapter for configuring Dandelion on the pool component.
|
||||
pub fn pool_dandelion_config(&self) -> pool::DandelionConfig {
|
||||
pool::DandelionConfig {
|
||||
relay_secs: self.dandelion_config.relay_secs,
|
||||
embargo_secs: self.dandelion_config.embargo_secs,
|
||||
patience_secs: self.dandelion_config.patience_secs,
|
||||
stem_probability: self.dandelion_config.stem_probability,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adapter for configuring Dandelion on the p2p component.
|
||||
pub fn p2p_dandelion_config(&self) -> p2p::DandelionConfig {
|
||||
p2p::DandelionConfig {
|
||||
relay_secs: self.dandelion_config.relay_secs,
|
||||
embargo_secs: self.dandelion_config.embargo_secs,
|
||||
patience_secs: self.dandelion_config.patience_secs,
|
||||
stem_probability: self.dandelion_config.stem_probability,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ServerConfig {
|
||||
fn default() -> ServerConfig {
|
||||
ServerConfig {
|
||||
@@ -194,6 +280,7 @@ impl Default for ServerConfig {
|
||||
seeding_type: Seeding::default(),
|
||||
seeds: None,
|
||||
p2p_config: p2p::P2PConfig::default(),
|
||||
dandelion_config: DandelionConfig::default(),
|
||||
stratum_mining_config: Some(StratumServerConfig::default()),
|
||||
chain_type: ChainTypes::default(),
|
||||
archive_mode: None,
|
||||
|
||||
@@ -12,17 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use rand;
|
||||
use rand::Rng;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use time::now_utc;
|
||||
use util::LOGGER;
|
||||
|
||||
use pool::BlockChain;
|
||||
use pool::PoolConfig;
|
||||
use pool::TransactionPool;
|
||||
use pool::TxSource;
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::transaction;
|
||||
use p2p::DandelionConfig;
|
||||
use pool::{BlockChain, PoolEntryState, PoolError, TransactionPool, TxSource};
|
||||
use util::LOGGER;
|
||||
|
||||
/// A process to monitor transactions in the stempool.
|
||||
/// With Dandelion, transaction can be broadcasted in stem or fluff phase.
|
||||
@@ -33,53 +35,218 @@ use pool::TxSource;
|
||||
/// the transaction will be sent in fluff phase (to multiple peers) instead of
|
||||
/// sending only to the peer relay.
|
||||
pub fn monitor_transactions<T>(
|
||||
config: PoolConfig,
|
||||
dandelion_config: DandelionConfig,
|
||||
tx_pool: Arc<RwLock<TransactionPool<T>>>,
|
||||
stop: Arc<AtomicBool>,
|
||||
) where
|
||||
T: BlockChain + Send + Sync + 'static,
|
||||
{
|
||||
debug!(LOGGER, "Started Dandelion transaction monitor");
|
||||
debug!(LOGGER, "Started Dandelion transaction monitor.");
|
||||
|
||||
let _ = thread::Builder::new()
|
||||
.name("dandelion".to_string())
|
||||
.spawn(move || {
|
||||
loop {
|
||||
let tx_pool = tx_pool.clone();
|
||||
let stem_transactions = tx_pool.read().unwrap().stem_transactions.clone();
|
||||
let time_stem_transactions = tx_pool.read().unwrap().time_stem_transactions.clone();
|
||||
|
||||
for tx_hash in stem_transactions.keys() {
|
||||
let time_transaction = time_stem_transactions.get(tx_hash).unwrap();
|
||||
let interval = now_utc().to_timespec().sec - time_transaction;
|
||||
|
||||
if interval >= config.dandelion_embargo {
|
||||
let source = TxSource {
|
||||
debug_name: "dandelion-monitor".to_string(),
|
||||
identifier: "?.?.?.?".to_string(),
|
||||
};
|
||||
let stem_transaction = stem_transactions.get(tx_hash).unwrap();
|
||||
let res = tx_pool.write().unwrap().add_to_memory_pool(
|
||||
source,
|
||||
stem_transaction.clone(),
|
||||
false,
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(()) => {
|
||||
info!(LOGGER, "Fluffing transaction after embargo timer expired.")
|
||||
}
|
||||
Err(e) => debug!(LOGGER, "error - {:?}", e),
|
||||
};
|
||||
// Remove from tx pool
|
||||
tx_pool.write().unwrap().remove_from_stempool(tx_hash);
|
||||
}
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
|
||||
if stop.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
|
||||
// This is the patience timer, we loop every n secs.
|
||||
let patience_secs = dandelion_config.patience_secs;
|
||||
thread::sleep(Duration::from_secs(patience_secs));
|
||||
|
||||
let tx_pool = tx_pool.clone();
|
||||
|
||||
// Step 1: find all "ToStem" entries in stempool from last run.
|
||||
// Aggregate them up to give a single (valid) aggregated tx and propagate it
|
||||
// to the next Dandelion relay along the stem.
|
||||
if process_stem_phase(tx_pool.clone()).is_err() {
|
||||
error!(LOGGER, "dand_mon: Problem with stem phase.");
|
||||
}
|
||||
|
||||
// Step 2: find all "ToFluff" entries in stempool from last run.
|
||||
// Aggregate them up to give a single (valid) aggregated tx and (re)add it
|
||||
// to our pool with stem=false (which will then broadcast it).
|
||||
if process_fluff_phase(tx_pool.clone()).is_err() {
|
||||
error!(LOGGER, "dand_mon: Problem with fluff phase.");
|
||||
}
|
||||
|
||||
// Step 3: now find all "Fresh" entries in stempool since last run.
|
||||
// Coin flip for each (90/10) and label them as either "ToStem" or "ToFluff".
|
||||
// We will process these in the next run (waiting patience secs).
|
||||
if process_fresh_entries(dandelion_config.clone(), tx_pool.clone()).is_err() {
|
||||
error!(LOGGER, "dand_mon: Problem processing fresh pool entries.");
|
||||
}
|
||||
|
||||
// Step 4: now find all expired entries based on embargo timer.
|
||||
if process_expired_entries(dandelion_config.clone(), tx_pool.clone()).is_err() {
|
||||
error!(LOGGER, "dand_mon: Problem processing fresh pool entries.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn process_stem_phase<T>(tx_pool: Arc<RwLock<TransactionPool<T>>>) -> Result<(), PoolError>
|
||||
where
|
||||
T: BlockChain + Send + Sync + 'static,
|
||||
{
|
||||
let mut tx_pool = tx_pool.write().unwrap();
|
||||
|
||||
let txpool_tx = tx_pool.txpool.aggregate_transaction()?;
|
||||
let stem_txs = tx_pool.stempool.select_valid_transactions(
|
||||
PoolEntryState::ToStem,
|
||||
PoolEntryState::Stemmed,
|
||||
txpool_tx,
|
||||
)?;
|
||||
|
||||
if stem_txs.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Found {} txs for stemming.",
|
||||
stem_txs.len()
|
||||
);
|
||||
|
||||
let agg_tx = transaction::aggregate(stem_txs)?;
|
||||
|
||||
let res = tx_pool.adapter.stem_tx_accepted(&agg_tx);
|
||||
if res.is_err() {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Unable to propagate stem tx. No relay, fluffing instead."
|
||||
);
|
||||
|
||||
let src = TxSource {
|
||||
debug_name: "no_relay".to_string(),
|
||||
identifier: "?.?.?.?".to_string(),
|
||||
};
|
||||
|
||||
tx_pool.add_to_pool(src, agg_tx, false)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_fluff_phase<T>(tx_pool: Arc<RwLock<TransactionPool<T>>>) -> Result<(), PoolError>
|
||||
where
|
||||
T: BlockChain + Send + Sync + 'static,
|
||||
{
|
||||
let mut tx_pool = tx_pool.write().unwrap();
|
||||
|
||||
let txpool_tx = tx_pool.txpool.aggregate_transaction()?;
|
||||
let stem_txs = tx_pool.stempool.select_valid_transactions(
|
||||
PoolEntryState::ToFluff,
|
||||
PoolEntryState::Fluffed,
|
||||
txpool_tx,
|
||||
)?;
|
||||
|
||||
if stem_txs.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Found {} txs for fluffing.",
|
||||
stem_txs.len()
|
||||
);
|
||||
|
||||
let agg_tx = transaction::aggregate(stem_txs)?;
|
||||
|
||||
let src = TxSource {
|
||||
debug_name: "fluff".to_string(),
|
||||
identifier: "?.?.?.?".to_string(),
|
||||
};
|
||||
|
||||
tx_pool.add_to_pool(src, agg_tx, false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_fresh_entries<T>(
|
||||
dandelion_config: DandelionConfig,
|
||||
tx_pool: Arc<RwLock<TransactionPool<T>>>,
|
||||
) -> Result<(), PoolError>
|
||||
where
|
||||
T: BlockChain + Send + Sync + 'static,
|
||||
{
|
||||
let mut tx_pool = tx_pool.write().unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let fresh_entries = &mut tx_pool
|
||||
.stempool
|
||||
.entries
|
||||
.iter_mut()
|
||||
.filter(|x| x.state == PoolEntryState::Fresh)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if fresh_entries.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Found {} fresh entries in stempool.",
|
||||
fresh_entries.len()
|
||||
);
|
||||
|
||||
for x in &mut fresh_entries.iter_mut() {
|
||||
let random = rng.gen_range(0, 101);
|
||||
if random <= dandelion_config.stem_probability {
|
||||
x.state = PoolEntryState::ToStem;
|
||||
} else {
|
||||
x.state = PoolEntryState::ToFluff;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_expired_entries<T>(
|
||||
dandelion_config: DandelionConfig,
|
||||
tx_pool: Arc<RwLock<TransactionPool<T>>>,
|
||||
) -> Result<(), PoolError>
|
||||
where
|
||||
T: BlockChain + Send + Sync + 'static,
|
||||
{
|
||||
let now = now_utc().to_timespec().sec;
|
||||
let embargo_sec = dandelion_config.embargo_secs + rand::thread_rng().gen_range(0, 31);
|
||||
let cutoff = now - embargo_sec as i64;
|
||||
|
||||
let mut expired_entries = vec![];
|
||||
{
|
||||
let tx_pool = tx_pool.read().unwrap();
|
||||
for entry in tx_pool
|
||||
.stempool
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|x| x.tx_at.sec < cutoff)
|
||||
{
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Embargo timer expired for {:?}",
|
||||
entry.tx.hash()
|
||||
);
|
||||
expired_entries.push(entry.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if expired_entries.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Found {} expired txs.",
|
||||
expired_entries.len()
|
||||
);
|
||||
|
||||
{
|
||||
let mut tx_pool = tx_pool.write().unwrap();
|
||||
for entry in expired_entries {
|
||||
let src = TxSource {
|
||||
debug_name: "embargo_expired".to_string(),
|
||||
identifier: "?.?.?.?".to_string(),
|
||||
};
|
||||
match tx_pool.add_to_pool(src, entry.tx, false) {
|
||||
Ok(_) => debug!(
|
||||
LOGGER,
|
||||
"dand_mon: embargo expired, fluffed tx successfully."
|
||||
),
|
||||
Err(e) => debug!(LOGGER, "dand_mon: Failed to fluff expired tx - {:?}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ use std::io::Read;
|
||||
use std::net::SocketAddr;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::str;
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use time::{self, now_utc};
|
||||
|
||||
use hyper;
|
||||
@@ -73,7 +73,7 @@ pub fn connect_and_monitor(
|
||||
tx.clone(),
|
||||
);
|
||||
|
||||
update_dandelion_relay(peers.clone(), p2p_server.config.clone());
|
||||
update_dandelion_relay(peers.clone(), p2p_server.dandelion_config.clone());
|
||||
|
||||
prev = current_time;
|
||||
}
|
||||
@@ -159,7 +159,7 @@ fn monitor_peers(
|
||||
}
|
||||
}
|
||||
|
||||
fn update_dandelion_relay(peers: Arc<p2p::Peers>, config: p2p::P2PConfig) {
|
||||
fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: p2p::DandelionConfig) {
|
||||
// Dandelion Relay Updater
|
||||
let dandelion_relay = peers.get_dandelion_relay();
|
||||
if dandelion_relay.is_empty() {
|
||||
@@ -168,7 +168,7 @@ fn update_dandelion_relay(peers: Arc<p2p::Peers>, config: p2p::P2PConfig) {
|
||||
} else {
|
||||
for last_added in dandelion_relay.keys() {
|
||||
let dandelion_interval = now_utc().to_timespec().sec - last_added;
|
||||
if dandelion_interval >= config.dandelion_relay_time() {
|
||||
if dandelion_interval >= dandelion_config.relay_secs as i64 {
|
||||
debug!(LOGGER, "monitor_peers: updating expired dandelion relay");
|
||||
peers.update_dandelion_relay();
|
||||
}
|
||||
|
||||
+16
-16
@@ -17,27 +17,27 @@
|
||||
//! as a facade.
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
||||
use common::adapters::*;
|
||||
use api;
|
||||
use chain;
|
||||
use core::{consensus, genesis, global, pow};
|
||||
use core::core::target::Difficulty;
|
||||
use common::adapters::*;
|
||||
use common::stats::*;
|
||||
use common::types::*;
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::target::Difficulty;
|
||||
use core::{consensus, genesis, global, pow};
|
||||
use grin::dandelion_monitor;
|
||||
use mining::stratumserver;
|
||||
use p2p;
|
||||
use pool;
|
||||
use grin::seed;
|
||||
use grin::sync;
|
||||
use common::types::*;
|
||||
use common::stats::*;
|
||||
use util::LOGGER;
|
||||
use mining::stratumserver;
|
||||
use mining::test_miner::Miner;
|
||||
use p2p;
|
||||
use pool;
|
||||
use util::LOGGER;
|
||||
|
||||
/// Grin server holding internal structures.
|
||||
pub struct Server {
|
||||
@@ -157,11 +157,11 @@ impl Server {
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let p2p_config = config.p2p_config.clone();
|
||||
let p2p_server = Arc::new(p2p::Server::new(
|
||||
config.db_root.clone(),
|
||||
config.capabilities,
|
||||
p2p_config,
|
||||
config.p2p_config.clone(),
|
||||
config.p2p_dandelion_config(),
|
||||
net_adapter.clone(),
|
||||
genesis.hash(),
|
||||
stop.clone(),
|
||||
@@ -232,7 +232,7 @@ impl Server {
|
||||
"Starting dandelion monitor: {}", &config.api_http_addr
|
||||
);
|
||||
dandelion_monitor::monitor_transactions(
|
||||
config.pool_config.clone(),
|
||||
config.p2p_dandelion_config(),
|
||||
tx_pool.clone(),
|
||||
stop.clone(),
|
||||
);
|
||||
@@ -288,9 +288,9 @@ impl Server {
|
||||
});
|
||||
}
|
||||
|
||||
/// Start mining for blocks internally on a separate thread. Relies on internal miner,
|
||||
/// and should only be used for automated testing. Burns reward if wallet_listener_url
|
||||
/// is 'None'
|
||||
/// Start mining for blocks internally on a separate thread. Relies on
|
||||
/// internal miner, and should only be used for automated testing. Burns
|
||||
/// reward if wallet_listener_url is 'None'
|
||||
pub fn start_test_miner(&self, wallet_listener_url: Option<String>) {
|
||||
let currently_syncing = self.currently_syncing.clone();
|
||||
let config_wallet_url = match wallet_listener_url.clone() {
|
||||
|
||||
@@ -28,7 +28,6 @@ use common::adapters::PoolToChainAdapter;
|
||||
use common::types::Error;
|
||||
use core::consensus;
|
||||
use core::core;
|
||||
use core::core::Transaction;
|
||||
use core::core::hash::Hashed;
|
||||
use core::ser;
|
||||
use core::ser::AsFixedBytes;
|
||||
@@ -163,8 +162,6 @@ fn build_block(
|
||||
.unwrap()
|
||||
.prepare_mineable_transactions(max_tx);
|
||||
|
||||
let txs: Vec<&Transaction> = txs.iter().collect();
|
||||
|
||||
// build the coinbase and the block itself
|
||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||
let height = head.height + 1;
|
||||
|
||||
Reference in New Issue
Block a user