wip: fix case where nonces message should not be shown

This commit is contained in:
Pascal
2020-07-10 02:08:53 -07:00
parent 4150d81772
commit 3f2adea06d
4 changed files with 92 additions and 52 deletions

View File

@@ -154,6 +154,7 @@ pub enum MemPoolRejection {
FailedToValidate(Error),
FeeTooLow(u64, u64),
BadNonces(TransactionNonceMismatch),
IgnoreBadNonces(TransactionNonceMismatch),
NotEnoughFunds(u128, u128),
NoSuchContract,
NoSuchPublicFunction,
@@ -195,6 +196,14 @@ impl MemPoolRejection {
"actual": actual,
"principal": principal.to_string(),
"is_origin": is_origin}))),
IgnoreBadNonces(TransactionNonceMismatch {
expected, actual, principal, is_origin, .. }) =>
("IgnoreBadNonces",
Some(json!({
"expected": expected,
"actual": actual,
"principal": principal.to_string(),
"is_origin": is_origin}))),
NotEnoughFunds(expected, actual) =>
("NotEnoughFunds",
Some(json!({
@@ -2641,7 +2650,8 @@ impl StacksChainState {
for microblock in microblocks.iter() {
debug!("Process microblock {}", &microblock.block_hash());
for tx in microblock.txs.iter() {
let (tx_fee, tx_receipt) = StacksChainState::process_transaction(clarity_tx, tx)
// TODO(psq): not quiet in this case???
let (tx_fee, tx_receipt) = StacksChainState::process_transaction(clarity_tx, tx, true)
.map_err(|e| (e, microblock.block_hash()))?;
fees = fees.checked_add(tx_fee as u128).expect("Fee overflow");
@@ -2659,7 +2669,8 @@ impl StacksChainState {
let mut burns = 0u128;
let mut receipts = vec![];
for tx in block.txs.iter() {
let (tx_fee, tx_receipt) = StacksChainState::process_transaction(clarity_tx, tx)?;
// TODO(psq): not quiet in this case
let (tx_fee, tx_receipt) = StacksChainState::process_transaction(clarity_tx, tx, true)?;
fees = fees.checked_add(tx_fee as u128).expect("Fee overflow");
burns = burns.checked_add(tx_receipt.stx_burned as u128).expect("Burns overflow");
receipts.push(tx_receipt);
@@ -3296,7 +3307,7 @@ impl StacksChainState {
}
// 4: the account nonces must be correct
let (origin, payer) = match StacksChainState::check_transaction_nonces(clarity_connection, &tx) {
let (origin, payer) = match StacksChainState::check_transaction_nonces(clarity_connection, &tx, true) {
Ok(x) => x,
Err((mut e, (origin, payer))) => {
// let's see if the tx has matching nonce in the mempool

View File

@@ -186,7 +186,8 @@ pub struct TransactionNonceMismatch {
pub actual: u64,
pub txid: Txid,
pub principal: PrincipalData,
pub is_origin: bool
pub is_origin: bool,
pub ignore: bool,
}
impl std::fmt::Display for TransactionNonceMismatch {
@@ -197,15 +198,23 @@ impl std::fmt::Display for TransactionNonceMismatch {
}
}
impl <T> From<(TransactionNonceMismatch, T)> for Error {
fn from(e: (TransactionNonceMismatch, T)) -> Error {
Error::InvalidStacksTransaction(e.0.to_string())
impl From<TransactionNonceMismatch, T> for Error {
fn from(e: TransactionNonceMismatch, T) -> Error {
if e.ignore {
Error::IgnoreStacksTransaction(e.0.to_string())
} else {
Error::InvalidStacksTransaction(e.0.to_string())
}
}
}
impl From<TransactionNonceMismatch> for MemPoolRejection {
fn from(e: TransactionNonceMismatch) -> MemPoolRejection {
MemPoolRejection::BadNonces(e)
if e.ignore {
MemPoolRejection::IgnoreBadNonces(e)
} else {
MemPoolRejection::BadNonces(e)
}
}
}
@@ -227,8 +236,8 @@ impl StacksChainState {
/// Check the account nonces for the supplied stacks transaction,
/// returning the origin and payer accounts if valid.
pub fn check_transaction_nonces<T: ClarityConnection>(clarity_tx: &mut T, tx: &StacksTransaction) -> Result<(StacksAccount, StacksAccount),
(TransactionNonceMismatch, (StacksAccount, StacksAccount))> {
pub fn check_transaction_nonces<T: ClarityConnection>(clarity_tx: &mut T, tx: &StacksTransaction, warn_on_bad_nonces: bool) -> Result<(StacksAccount, StacksAccount),
(TransactionNonceMismatch, (StacksAccount, StacksAccount)) {
// who's sending it?
let origin = tx.get_origin();
let origin_account = StacksChainState::get_account(clarity_tx, &tx.origin_address().into());
@@ -244,8 +253,11 @@ impl StacksChainState {
actual: payer.nonce(),
txid: tx.txid(),
principal: payer_account.principal.clone(),
is_origin: false };
warn!("{}", &e);
is_origin: false,
ignore: !warn_on_bad_nonces };
if warn_on_bad_nonces {
warn!("{}", &e);
}
return Err((e, (origin_account, payer_account)))
}
@@ -260,8 +272,11 @@ impl StacksChainState {
actual: origin.nonce(),
txid: tx.txid(),
principal: origin_account.principal.clone(),
is_origin: true };
warn!("{}", &e);
is_origin: true,
ignore: !warn_on_bad_nonces };
if warn_on_bad_nonces {
warn!("{}", &e);
}
return Err((e, (origin_account, payer_account)))
}
@@ -717,13 +732,13 @@ impl StacksChainState {
}
/// Process a transaction. Return the fee and the transaction receipt
pub fn process_transaction(clarity_block: &mut ClarityTx, tx: &StacksTransaction) -> Result<(u64, StacksTransactionReceipt), Error> {
pub fn process_transaction(clarity_block: &mut ClarityTx, tx: &StacksTransaction, warn_on_bad_nonces: bool) -> Result<(u64, StacksTransactionReceipt), Error> {
debug!("Process transaction {} ({})", tx.txid(), tx.payload.name());
StacksChainState::process_transaction_precheck(&clarity_block.config, tx)?;
let mut transaction = clarity_block.connection().start_transaction_processing();
let (origin_account, payer_account) = StacksChainState::check_transaction_nonces(&mut transaction, tx)?;
let (origin_account, payer_account) = StacksChainState::check_transaction_nonces(&mut transaction, tx, warn_on_bad_nonces)?;
let tx_receipt = StacksChainState::process_transaction_payload(&mut transaction, tx, &origin_account)?;
@@ -800,7 +815,7 @@ pub mod test {
conn.connection().as_transaction(
|tx| StacksChainState::account_credit(tx, &addr.to_account_principal(), 223));
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
let account_after = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
assert_eq!(account_after.nonce, 1);
@@ -837,7 +852,7 @@ pub mod test {
assert_eq!(recv_account.stx_balance, 0);
assert_eq!(recv_account.nonce, 0);
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
let account_after = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
assert_eq!(account_after.nonce, 2);
@@ -950,7 +965,7 @@ pub mod test {
assert_eq!(account.stx_balance, 123);
assert_eq!(account.nonce, 0);
let res = StacksChainState::process_transaction(&mut conn, &signed_tx);
let res = StacksChainState::process_transaction(&mut conn, &signed_tx, true);
assert!(res.is_err());
match res {
@@ -1017,7 +1032,7 @@ pub mod test {
conn.connection().as_transaction(
|tx| StacksChainState::account_credit(tx, &addr.to_account_principal(), 123));
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
let account_after = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
assert_eq!(account_after.nonce, 1);
@@ -1071,7 +1086,7 @@ pub mod test {
let account = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
assert_eq!(account.nonce, 0);
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
let account = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
assert_eq!(account.nonce, 1);
@@ -1149,7 +1164,7 @@ pub mod test {
let account = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
assert_eq!(account.nonce, next_nonce);
let res = StacksChainState::process_transaction(&mut conn, &signed_tx);
let res = StacksChainState::process_transaction(&mut conn, &signed_tx, true);
if expected_behavior[i] {
assert!(res.is_ok());
@@ -1236,7 +1251,7 @@ pub mod test {
assert_eq!(account.nonce, i as u64);
// runtime error should be handled
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
// account nonce should increment
let account = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
@@ -1296,7 +1311,7 @@ pub mod test {
let _account_sponsor = StacksChainState::get_account(&mut conn, &addr_sponsor.to_account_principal());
assert_eq!(account.nonce, 0);
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
let account = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
assert_eq!(account.nonce, 1);
@@ -1372,12 +1387,12 @@ pub mod test {
let var_before_res = StacksChainState::get_data_var(&mut conn, &contract_id, "bar").unwrap();
assert!(var_before_res.is_none());
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
let var_before_set_res = StacksChainState::get_data_var(&mut conn, &contract_id, "bar").unwrap();
assert_eq!(var_before_set_res, Some(Value::Int(0)));
let (fee_2, _) = StacksChainState::process_transaction(&mut conn, &signed_tx_2).unwrap();
let (fee_2, _) = StacksChainState::process_transaction(&mut conn, &signed_tx_2, true).unwrap();
let account = StacksChainState::get_account(&mut conn, &addr.to_account_principal());
assert_eq!(account.nonce, 1);
@@ -1428,7 +1443,7 @@ pub mod test {
let mut conn = chainstate.block_begin(&FIRST_BURNCHAIN_BLOCK_HASH, &FIRST_STACKS_BLOCK_HASH, &BurnchainHeaderHash([1u8; 32]), &BlockHeaderHash([1u8; 32]));
let contract_id = QualifiedContractIdentifier::new(StandardPrincipalData::from(addr.clone()), ContractName::from("hello-world"));
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
// contract-calls that don't commit
let contract_calls = vec![
@@ -1461,7 +1476,7 @@ pub mod test {
let account_2 = StacksChainState::get_account(&mut conn, &addr_2.to_account_principal());
assert_eq!(account_2.nonce, next_nonce);
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx_2).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx_2, true).unwrap();
// nonce should have incremented
next_nonce += 1;
@@ -1510,7 +1525,7 @@ pub mod test {
let signed_tx = signer.get_tx().unwrap();
let mut conn = chainstate.block_begin(&FIRST_BURNCHAIN_BLOCK_HASH, &FIRST_STACKS_BLOCK_HASH, &BurnchainHeaderHash([1u8; 32]), &BlockHeaderHash([1u8; 32]));
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
// invalid contract-calls
let contract_calls = vec![
@@ -1543,7 +1558,7 @@ pub mod test {
assert_eq!(account_2.nonce, next_nonce);
// transaction is invalid, and won't be mined
let res = StacksChainState::process_transaction(&mut conn, &signed_tx_2);
let res = StacksChainState::process_transaction(&mut conn, &signed_tx_2, true);
assert!(res.is_err());
// nonce should NOT have incremented
@@ -1629,7 +1644,7 @@ pub mod test {
let var_before_res = StacksChainState::get_data_var(&mut conn, &contract_id, "bar").unwrap();
assert!(var_before_res.is_none());
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx).unwrap();
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_tx, true).unwrap();
let account_publisher = StacksChainState::get_account(&mut conn, &addr_publisher.to_account_principal());
assert_eq!(account_publisher.nonce, 1);
@@ -1637,7 +1652,7 @@ pub mod test {
let var_before_set_res = StacksChainState::get_data_var(&mut conn, &contract_id, "bar").unwrap();
assert_eq!(var_before_set_res, Some(Value::Int(0)));
let (fee_2, _) = StacksChainState::process_transaction(&mut conn, &signed_tx_2).unwrap();
let (fee_2, _) = StacksChainState::process_transaction(&mut conn, &signed_tx_2, true).unwrap();
let account_origin = StacksChainState::get_account(&mut conn, &addr_origin.to_account_principal());
assert_eq!(account_origin.nonce, 1);
@@ -1991,7 +2006,7 @@ pub mod test {
let _ = StacksChainState::get_account_ft(&mut conn, &contract_id, "stackaroos", &recv_principal).unwrap_err();
// publish contract
let _ = StacksChainState::process_transaction(&mut conn, &signed_contract_tx).unwrap();
let _ = StacksChainState::process_transaction(&mut conn, &signed_contract_tx, true).unwrap();
// no initial stackaroos balance
let account_stackaroos_balance = StacksChainState::get_account_ft(&mut conn, &contract_id, "stackaroos", &recv_principal).unwrap();
@@ -2004,7 +2019,7 @@ pub mod test {
let mut expected_next_name : u64 = 0;
for tx_pass in post_conditions_pass.iter() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass, true).unwrap();
expected_stackaroos_balance += 100;
expected_nonce += 1;
@@ -2016,7 +2031,7 @@ pub mod test {
}
for tx_pass in post_conditions_pass_payback.iter() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass, true).unwrap();
expected_stackaroos_balance -= 100;
expected_payback_stackaroos_balance += 100;
expected_recv_nonce += 1;
@@ -2035,7 +2050,7 @@ pub mod test {
}
for (_i, tx_pass) in post_conditions_pass_nft.iter().enumerate() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass, true).unwrap();
expected_nonce += 1;
let expected_value = Value::buff_from(expected_next_name.to_be_bytes().to_vec()).unwrap();
@@ -2049,7 +2064,7 @@ pub mod test {
}
for tx_fail in post_conditions_fail.iter() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail, true).unwrap();
expected_nonce += 1;
// no change in balance
@@ -2065,7 +2080,7 @@ pub mod test {
}
for tx_fail in post_conditions_fail_payback.iter() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail, true).unwrap();
expected_recv_nonce += 1;
// no change in balance
@@ -2085,7 +2100,7 @@ pub mod test {
}
for (_i, tx_fail) in post_conditions_fail_nft.iter().enumerate() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail, true).unwrap();
expected_nonce += 1;
// nft shouldn't exist -- the nft-mint! should have been rolled back
@@ -2393,7 +2408,7 @@ pub mod test {
let _ = StacksChainState::get_account_ft(&mut conn, &contract_id, "stackaroos", &recv_principal).unwrap_err();
// publish contract
let _ = StacksChainState::process_transaction(&mut conn, &signed_contract_tx).unwrap();
let _ = StacksChainState::process_transaction(&mut conn, &signed_contract_tx, true).unwrap();
// no initial stackaroos balance
let account_stackaroos_balance = StacksChainState::get_account_ft(&mut conn, &contract_id, "stackaroos", &recv_principal).unwrap();
@@ -2405,7 +2420,7 @@ pub mod test {
let mut expected_payback_stackaroos_balance = 0;
for (_i, tx_pass) in post_conditions_pass.iter().enumerate() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass, true).unwrap();
expected_stackaroos_balance += 100;
expected_nonce += 1;
@@ -2428,7 +2443,7 @@ pub mod test {
}
for (_i, tx_pass) in post_conditions_pass_payback.iter().enumerate() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_pass, true).unwrap();
expected_stackaroos_balance -= 100;
expected_payback_stackaroos_balance += 100;
expected_recv_nonce += 1;
@@ -2460,7 +2475,7 @@ pub mod test {
}
for (_i, tx_fail) in post_conditions_fail.iter().enumerate() {
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail, true).unwrap();
expected_nonce += 1;
// no change in balance
@@ -2486,7 +2501,7 @@ pub mod test {
for (_i, tx_fail) in post_conditions_fail_payback.iter().enumerate() {
eprintln!("tx fail {:?}", &tx_fail);
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail).unwrap();
let (_fee, _) = StacksChainState::process_transaction(&mut conn, &tx_fail, true).unwrap();
expected_recv_nonce += 1;
// no change in balance
@@ -3280,8 +3295,8 @@ pub mod test {
let signed_contract_call_tx = signer.get_tx().unwrap();
let mut conn = chainstate.block_begin(&FIRST_BURNCHAIN_BLOCK_HASH, &FIRST_STACKS_BLOCK_HASH, &BurnchainHeaderHash([1u8; 32]), &BlockHeaderHash([1u8; 32]));
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_contract_tx).unwrap();
let err = StacksChainState::process_transaction(&mut conn, &signed_contract_call_tx).unwrap_err();
let (fee, _) = StacksChainState::process_transaction(&mut conn, &signed_contract_tx, true).unwrap();
let err = StacksChainState::process_transaction(&mut conn, &signed_contract_call_tx, true).unwrap_err();
conn.commit_block();
eprintln!("{:?}", &err);

View File

@@ -31,6 +31,7 @@ use chainstate::stacks::db::{
use chainstate::stacks::index::TrieHash;
use chainstate::burn::BlockHeaderHash;
use chainstate::stacks::events::StacksTransactionReceipt;
// use chainstate::stacks::db::transactions::TransactionNonceMismatch;
use net::StacksMessageCodec;
use net::Error as net_error;
@@ -149,7 +150,7 @@ impl <'a> StacksMicroblockBuilder <'a> {
if bytes_so_far + mempool_tx.metadata.len >= MAX_EPOCH_SIZE.into() {
return Err(Error::BlockTooBigError);
}
match StacksChainState::process_transaction(clarity_tx, &mempool_tx.tx) {
match StacksChainState::process_transaction(clarity_tx, &mempool_tx.tx, true) {
Ok(_) => {
return Ok(Some((mempool_tx.tx, mempool_tx.metadata.len)))
},
@@ -374,7 +375,8 @@ impl StacksBlockBuilder {
return Err(Error::InvalidStacksTransaction("Invalid transaction anchor mode for anchored data".to_string()));
}
let (fee, _receipt) = StacksChainState::process_transaction(clarity_tx, tx)
// TODO(psq): quiet in this case
let (fee, _receipt) = StacksChainState::process_transaction(clarity_tx, tx, false)
.map_err(|e| {
match e {
Error::CostOverflowError(cost_before, cost_after, total_budget) => {
@@ -396,7 +398,8 @@ impl StacksBlockBuilder {
return Err(Error::InvalidStacksTransaction("Invalid transaction anchor mode for streamed data".to_string()));
}
let (fee, _receipt) = StacksChainState::process_transaction(clarity_tx, tx)
// TODO(psq): quiet in this case
let (fee, _receipt) = StacksChainState::process_transaction(clarity_tx, tx, false)
.map_err(|e| {
match e {
Error::CostOverflowError(cost_before, cost_after, total_budget) => {
@@ -431,7 +434,8 @@ impl StacksBlockBuilder {
if !self.anchored_done {
// save
match StacksChainState::process_transaction(clarity_tx, tx) {
// TODO(psq): quiet in this case, does it matter???
match StacksChainState::process_transaction(clarity_tx, tx, false) {
Ok((fee, receipt)) => {
self.total_anchored_fees += fee;
},
@@ -443,7 +447,8 @@ impl StacksBlockBuilder {
self.txs.push(tx.clone());
}
else {
match StacksChainState::process_transaction(clarity_tx, tx) {
// TODO(psq): quiet in this case, does it matter
match StacksChainState::process_transaction(clarity_tx, tx, false) {
Ok((fee, receipt)) => {
self.total_streamed_fees += fee;
},
@@ -710,13 +715,19 @@ impl StacksBlockBuilder {
considered.insert(txinfo.tx.txid());
match builder.try_mine_tx_with_len(&mut epoch_tx, &txinfo.tx, txinfo.metadata.len) {
let err = builder.try_mine_tx_with_len(&mut epoch_tx, &txinfo.tx, txinfo.metadata.len);
match err {
Ok(_) => {},
Err(Error::BlockTooBigError) => {
// done mining -- our execution budget is exceeded.
// Make the block from the transactions we did manage to get
debug!("Block budget exceeded on tx {}", &txinfo.tx.txid());
},
Err(Error::IgnoreStacksTransaction(_)) => {
// if the nonce is incorrect, this tx was mined in a prior block
// for this chain tip, ignoring
continue;
},
Err(e) => {
warn!("Failed to apply tx {}: {:?}", &txinfo.tx.txid(), &e);
continue;

View File

@@ -133,6 +133,7 @@ impl AddressHashMode {
#[derive(Debug)]
pub enum Error {
InvalidFee,
IgnoreStacksTransaction(String),
InvalidStacksBlock(String),
InvalidStacksMicroblock(String, BlockHeaderHash),
InvalidStacksTransaction(String),
@@ -158,6 +159,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::InvalidFee => write!(f, "Invalid fee"),
Error::IgnoreStacksTransaction(ref s) => fmt::Display::fmt(s, f),
Error::InvalidStacksBlock(ref s) => fmt::Display::fmt(s, f),
Error::InvalidStacksMicroblock(ref s, _) => fmt::Display::fmt(s, f),
Error::InvalidStacksTransaction(ref s) => fmt::Display::fmt(s, f),
@@ -185,6 +187,7 @@ impl error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
Error::InvalidFee => None,
Error::IgnoreStacksTransaction(ref _s) => None,
Error::InvalidStacksBlock(ref _s) => None,
Error::InvalidStacksMicroblock(ref _s, ref _h) => None,
Error::InvalidStacksTransaction(ref _s) => None,