use self::core::consensus;
use self::core::core::block;
use self::core::core::committed;
use self::core::core::hash::Hash;
use self::core::core::transaction::{self, Transaction};
use self::core::core::{BlockHeader, BlockSums, Inputs, OutputIdentifier};
use self::core::global::DEFAULT_ACCEPT_FEE_BASE;
use chrono::prelude::*;
use failure::Fail;
use aigc_core as core;
use aigc_keychain as keychain;
const DANDELION_EPOCH_SECS: u16 = 600;
const DANDELION_EMBARGO_SECS: u16 = 180;
const DANDELION_AGGREGATION_SECS: u16 = 30;
const DANDELION_STEM_PROBABILITY: u8 = 90;
const DANDELION_ALWAYS_STEM_OUR_TXS: bool = true;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DandelionConfig {
#[serde(default = "default_dandelion_epoch_secs")]
pub epoch_secs: u16,
#[serde(default = "default_dandelion_embargo_secs")]
pub embargo_secs: u16,
#[serde(default = "default_dandelion_aggregation_secs")]
pub aggregation_secs: u16,
#[serde(default = "default_dandelion_stem_probability")]
pub stem_probability: u8,
#[serde(default = "default_dandelion_always_stem_our_txs")]
pub always_stem_our_txs: bool,
}
impl Default for DandelionConfig {
fn default() -> DandelionConfig {
DandelionConfig {
epoch_secs: default_dandelion_epoch_secs(),
embargo_secs: default_dandelion_embargo_secs(),
aggregation_secs: default_dandelion_aggregation_secs(),
stem_probability: default_dandelion_stem_probability(),
always_stem_our_txs: default_dandelion_always_stem_our_txs(),
}
}
}
fn default_dandelion_epoch_secs() -> u16 {
DANDELION_EPOCH_SECS
}
fn default_dandelion_embargo_secs() -> u16 {
DANDELION_EMBARGO_SECS
}
fn default_dandelion_aggregation_secs() -> u16 {
DANDELION_AGGREGATION_SECS
}
fn default_dandelion_stem_probability() -> u8 {
DANDELION_STEM_PROBABILITY
}
fn default_dandelion_always_stem_our_txs() -> bool {
DANDELION_ALWAYS_STEM_OUR_TXS
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct PoolConfig {
#[serde(default = "default_accept_fee_base")]
pub accept_fee_base: u64,
#[serde(default = "default_reorg_cache_period")]
pub reorg_cache_period: u32,
#[serde(default = "default_max_pool_size")]
pub max_pool_size: usize,
#[serde(default = "default_max_stempool_size")]
pub max_stempool_size: usize,
#[serde(default = "default_mineable_max_weight")]
pub mineable_max_weight: u64,
}
impl Default for PoolConfig {
fn default() -> PoolConfig {
PoolConfig {
accept_fee_base: default_accept_fee_base(),
reorg_cache_period: default_reorg_cache_period(),
max_pool_size: default_max_pool_size(),
max_stempool_size: default_max_stempool_size(),
mineable_max_weight: default_mineable_max_weight(),
}
}
}
pub fn default_accept_fee_base() -> u64 {
DEFAULT_ACCEPT_FEE_BASE
}
fn default_reorg_cache_period() -> u32 {
30
}
fn default_max_pool_size() -> usize {
50_000
}
fn default_max_stempool_size() -> usize {
50_000
}
fn default_mineable_max_weight() -> u64 {
consensus::MAX_BLOCK_WEIGHT
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PoolEntry {
pub src: TxSource,
pub tx_at: DateTime<Utc>,
pub tx: Transaction,
}
impl PoolEntry {
pub fn new(tx: Transaction, src: TxSource) -> PoolEntry {
PoolEntry {
src,
tx_at: Utc::now(),
tx,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum TxSource {
PushApi,
Broadcast,
Fluff,
EmbargoExpired,
Deaggregate,
}
impl TxSource {
pub fn is_pushed(&self) -> bool {
match self {
TxSource::PushApi => true,
_ => false,
}
}
}
#[derive(Debug, Fail, PartialEq)]
pub enum PoolError {
#[fail(display = "Invalid Tx {}", _0)]
InvalidTx(transaction::Error),
#[fail(display = "Invalid Block {}", _0)]
InvalidBlock(block::Error),
#[fail(display = "Keychain error {}", _0)]
Keychain(keychain::Error),
#[fail(display = "Committed error {}", _0)]
Committed(committed::Error),
#[fail(display = "Immature transaction")]
ImmatureTransaction,
#[fail(display = "Immature coinbase")]
ImmatureCoinbase,
#[fail(display = "Dandelion error")]
DandelionError,
#[fail(display = "Over capacity")]
OverCapacity,
#[fail(display = "Low fee transaction {}", _0)]
LowFeeTransaction(u64),
#[fail(display = "Duplicate commitment")]
DuplicateCommitment,
#[fail(display = "Duplicate tx")]
DuplicateTx,
#[fail(display = "NRD kernel pre-HF3")]
NRDKernelPreHF3,
#[fail(display = "NRD kernel not enabled")]
NRDKernelNotEnabled,
#[fail(display = "NRD kernel relative height")]
NRDKernelRelativeHeight,
#[fail(display = "General pool error {}", _0)]
Other(String),
}
impl From<transaction::Error> for PoolError {
fn from(e: transaction::Error) -> PoolError {
match e {
transaction::Error::InvalidNRDRelativeHeight => PoolError::NRDKernelRelativeHeight,
e @ _ => PoolError::InvalidTx(e),
}
}
}
impl From<block::Error> for PoolError {
fn from(e: block::Error) -> PoolError {
PoolError::InvalidBlock(e)
}
}
impl From<keychain::Error> for PoolError {
fn from(e: keychain::Error) -> PoolError {
PoolError::Keychain(e)
}
}
impl From<committed::Error> for PoolError {
fn from(e: committed::Error) -> PoolError {
PoolError::Committed(e)
}
}
pub trait BlockChain: Sync + Send {
fn verify_coinbase_maturity(&self, inputs: &Inputs) -> Result<(), PoolError>;
fn verify_tx_lock_height(&self, tx: &transaction::Transaction) -> Result<(), PoolError>;
fn validate_tx(&self, tx: &Transaction) -> Result<(), PoolError>;
fn validate_inputs(&self, inputs: &Inputs) -> Result<Vec<OutputIdentifier>, PoolError>;
fn chain_head(&self) -> Result<BlockHeader, PoolError>;
fn get_block_header(&self, hash: &Hash) -> Result<BlockHeader, PoolError>;
fn get_block_sums(&self, hash: &Hash) -> Result<BlockSums, PoolError>;
}
pub trait PoolAdapter: Send + Sync {
fn tx_accepted(&self, entry: &PoolEntry);
fn stem_tx_accepted(&self, entry: &PoolEntry) -> Result<(), PoolError>;
}
#[allow(dead_code)]
pub struct NoopPoolAdapter {}
impl PoolAdapter for NoopPoolAdapter {
fn tx_accepted(&self, _entry: &PoolEntry) {}
fn stem_tx_accepted(&self, _entry: &PoolEntry) -> Result<(), PoolError> {
Ok(())
}
}