diff --git a/chain-impl-mockchain/src/account.rs b/chain-impl-mockchain/src/account.rs index 0d3e99727..7532a4f1d 100644 --- a/chain-impl-mockchain/src/account.rs +++ b/chain-impl-mockchain/src/account.rs @@ -27,3 +27,9 @@ pub type Secret = key::AccountSecretKey; /// The public ledger of all accounts associated with their current state pub type Ledger = account::Ledger; + +impl std::fmt::Display for Identifier { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.0.fmt(f) + } +} diff --git a/chain-impl-mockchain/src/accounting/account.rs b/chain-impl-mockchain/src/accounting/account.rs index 60876a121..b9715743a 100644 --- a/chain-impl-mockchain/src/accounting/account.rs +++ b/chain-impl-mockchain/src/accounting/account.rs @@ -7,38 +7,16 @@ use crate::value::*; use imhamt::{Hamt, InsertError, UpdateError}; use std::collections::hash_map::DefaultHasher; -use std::fmt::{self, Display, Formatter}; use std::hash::Hash; -/// Possible errors during an account operation -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum LedgerError { - NonExistent, - AlreadyExists, - NeedTotalWithdrawal, - NonZero, - ValueError(ValueError), -} - -impl Display for LedgerError { - fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { - match self { - LedgerError::NonExistent => "Account does not exist", - LedgerError::AlreadyExists => "Account already exists", - LedgerError::NeedTotalWithdrawal => { - "Operation counter reached its maximum and next operation must be full withdrawal" - } - LedgerError::NonZero => "Removed account is not empty", - LedgerError::ValueError(_) => "Value calculation failed", - } - .fmt(formatter) - } -} - -impl From for LedgerError { - fn from(e: ValueError) -> Self { - LedgerError::ValueError(e) - } +custom_error! { + #[derive(Clone, PartialEq, Eq)] + pub LedgerError + NonExistent = "Account does not exist", + AlreadyExists = "Account already exists", + NeedTotalWithdrawal = "Operation counter reached its maximum and next operation must be full withdrawal", + NonZero = "Removed account is not empty", + ValueError{ source: ValueError } = "Value calculation failed", } impl From> for LedgerError { diff --git a/chain-impl-mockchain/src/leadership/genesis/mod.rs b/chain-impl-mockchain/src/leadership/genesis/mod.rs index 1a45b121c..9a80c5723 100644 --- a/chain-impl-mockchain/src/leadership/genesis/mod.rs +++ b/chain-impl-mockchain/src/leadership/genesis/mod.rs @@ -31,6 +31,11 @@ pub struct GenesisLeaderSelection { active_slots_coeff: ActiveSlotsCoeff, } +custom_error! {GenesisError + InvalidEpoch { expected: Epoch, actual: Epoch } = "Wrong epoch, expected epoch {expected} but received block at epoch {actual}", + TotalStakeIsZero = "Total stake is null", +} + impl GenesisLeaderSelection { pub fn new(epoch: Epoch, ledger: &Ledger) -> Self { GenesisLeaderSelection { @@ -49,8 +54,13 @@ impl GenesisLeaderSelection { date: BlockDate, ) -> Result, Error> { if date.epoch != self.epoch { - // TODO: add more error details: invalid Date - return Err(Error::new(ErrorKind::Failure)); + return Err(Error::new_( + ErrorKind::Failure, + GenesisError::InvalidEpoch { + actual: date.epoch, + expected: self.epoch, + }, + )); } let stake_snapshot = &self.distribution; @@ -62,8 +72,10 @@ impl GenesisLeaderSelection { let total_stake: Value = stake_snapshot.total_stake(); if total_stake == Value::zero() { - // TODO: give more info about the error here... - return Err(Error::new(ErrorKind::Failure)); + return Err(Error::new_( + ErrorKind::Failure, + GenesisError::TotalStakeIsZero, + )); } let percent_stake = PercentStake { @@ -83,8 +95,13 @@ impl GenesisLeaderSelection { pub(crate) fn verify(&self, block_header: &Header) -> Verification { if block_header.block_date().epoch != self.epoch { - // TODO: add more error details: invalid Date - return Verification::Failure(Error::new(ErrorKind::Failure)); + return Verification::Failure(Error::new_( + ErrorKind::Failure, + GenesisError::InvalidEpoch { + expected: self.epoch, + actual: block_header.block_date().epoch, + }, + )); } let stake_snapshot = &self.distribution; diff --git a/chain-impl-mockchain/src/leadership/mod.rs b/chain-impl-mockchain/src/leadership/mod.rs index 453a35863..92f914e27 100644 --- a/chain-impl-mockchain/src/leadership/mod.rs +++ b/chain-impl-mockchain/src/leadership/mod.rs @@ -93,6 +93,9 @@ impl LeadershipConsensus { LeadershipConsensus::Bft(_) if block_version == BlockVersion::Ed25519Signed => { Verification::Success } + LeadershipConsensus::GenesisPraos(_) if block_version == BlockVersion::KesVrfproof => { + Verification::Success + } _ => Verification::Failure(Error::new(ErrorKind::IncompatibleBlockVersion)), } } @@ -232,10 +235,13 @@ impl Error { } } - pub fn new_(kind: ErrorKind, cause: Box) -> Self { + pub fn new_(kind: ErrorKind, cause: E) -> Self + where + E: std::error::Error + 'static, + { Error { kind: kind, - cause: Some(cause), + cause: Some(Box::new(cause)), } } } diff --git a/chain-impl-mockchain/src/ledger.rs b/chain-impl-mockchain/src/ledger.rs index 027001be7..83de94e5f 100644 --- a/chain-impl-mockchain/src/ledger.rs +++ b/chain-impl-mockchain/src/ledger.rs @@ -55,112 +55,69 @@ pub struct Ledger { pub(crate) chain_length: ChainLength, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Block0Error { - OnlyMessageReceived, - TransactionHasInput, - TransactionHasOutput, - TransactionHasWitnesses, - InitialMessageMissing, - InitialMessageMany, - InitialMessageDuplicateBlock0Date, - InitialMessageDuplicateDiscrimination, - InitialMessageDuplicateConsensusVersion, - InitialMessageDuplicateSlotDuration, - InitialMessageDuplicateEpochStabilityDepth, - InitialMessageDuplicatePraosActiveSlotsCoeff, - InitialMessageNoDate, - InitialMessageNoSlotDuration, - InitialMessageNoSlotsPerEpoch, - InitialMessageNoDiscrimination, - InitialMessageNoConsensusVersion, - InitialMessageNoConsensusLeaderId, - InitialMessageNoPraosActiveSlotsCoeff, - InitialMessageNoKesUpdateSpeed, - UtxoTotalValueTooBig, - HasUpdateProposal, - HasUpdateVote, +custom_error! { + #[derive(Clone, PartialEq, Eq)] + pub Block0Error + OnlyMessageReceived = "Old UTxOs and Initial Message are not valid in a normal block", + TransactionHasInput = "Transaction should not have inputs in a block0", + TransactionHasOutput = "Transaction should not have outputs in a block0", + TransactionHasWitnesses = "Transaction should not have witnesses in a block0", + InitialMessageMissing = "The initial message is missing.", + InitialMessageMany = "Only one initial message is required", + InitialMessageDuplicateBlock0Date = "Block0 Date is duplicated in the initial message", + InitialMessageDuplicateDiscrimination = "Address discrimination setting is duplicated in the initial fragment", + InitialMessageDuplicateConsensusVersion = "Consensus version is duplicated in the initial fragment", + InitialMessageDuplicateSlotDuration = "Slot Duration is duplicated in the initial fragment", + InitialMessageDuplicateEpochStabilityDepth = "Epoch stability depth is duplicated in the initial fragment", + InitialMessageDuplicatePraosActiveSlotsCoeff = "Praos active slot coefficient setting is duplicated in the initial fragment", + InitialMessageNoDate = "Missing block0 date in the initial fragment", + InitialMessageNoSlotDuration = "Missing slot duration in the initial fragment", + InitialMessageNoSlotsPerEpoch = "Missing slots per epoch in the initial fragment", + InitialMessageNoDiscrimination = "Missing address discrimination in the initial fragment", + InitialMessageNoConsensusVersion = "Missing consensus version in the initial fragment", + InitialMessageNoConsensusLeaderId = "Missing consensus leader id list in the initial fragment", + InitialMessageNoPraosActiveSlotsCoeff = "Missing praos active slot coefficient in the initial fragment", + InitialMessageNoKesUpdateSpeed = "Missing KES Update speed in the initial fragment", + UtxoTotalValueTooBig = "Total initial value is too big", + HasUpdateProposal = "Update proposal fragments are not valid in the block0", + HasUpdateVote = "Update vote fragments are not valid in the block0", } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Error { - Config(config::Error), - NotEnoughSignatures(usize, usize), - UtxoValueNotMatching(Value, Value), - UtxoError(utxo::Error), - UtxoInvalidSignature(UtxoPointer, Output
, Witness), - OldUtxoInvalidSignature(UtxoPointer, Output, Witness), - OldUtxoInvalidPublicKey(UtxoPointer, Output, Witness), - AccountInvalidSignature(account::Identifier, Witness), - MultisigInvalidSignature(multisig::Identifier, Witness), - TransactionHasNoInput, - FeeCalculationError(ValueError), - PraosActiveSlotsCoeffInvalid(ActiveSlotsCoeffError), - UtxoInputsTotal(ValueError), - UtxoOutputsTotal(ValueError), - Block0(Block0Error), - Account(account::LedgerError), - Multisig(multisig::LedgerError), - NotBalanced(Value, Value), - ZeroOutput(Output
), - Delegation(DelegationError), - AccountIdentifierInvalid, - InvalidDiscrimination, - ExpectingAccountWitness, - ExpectingUtxoWitness, - ExpectingInitialMessage, - CertificateInvalidSignature, - Update(update::Error), - WrongChainLength { - actual: ChainLength, - expected: ChainLength, - }, - NonMonotonicDate { - block_date: BlockDate, - chain_date: BlockDate, - }, -} - -impl From for Error { - fn from(e: utxo::Error) -> Self { - Error::UtxoError(e) - } -} - -impl From for Error { - fn from(e: Block0Error) -> Self { - Error::Block0(e) - } -} - -impl From for Error { - fn from(e: account::LedgerError) -> Self { - Error::Account(e) - } -} - -impl From for Error { - fn from(e: multisig::LedgerError) -> Self { - Error::Multisig(e) - } -} - -impl From for Error { - fn from(e: DelegationError) -> Self { - Error::Delegation(e) - } -} - -impl From for Error { - fn from(e: config::Error) -> Self { - Error::Config(e) - } -} - -impl From for Error { - fn from(e: update::Error) -> Self { - Error::Update(e) - } +pub type OutputOldAddress = Output; +pub type OutputAddress = Output
; + +custom_error! { + #[derive(Clone, PartialEq, Eq)] + pub Error + Config { source: config::Error } = "Invalid settings", + NotEnoughSignatures { actual: usize, expected: usize } = "Not enough signatures, expected {expected} signatures but received {actual}", + UtxoValueNotMatching { expected: Value, value: Value } = "The UTxO value ({expected}) in the transaction does not match the actually state value: {value}", + UtxoError { source: utxo::Error } = "Invalid UTxO", + UtxoInvalidSignature { utxo: UtxoPointer, output: OutputAddress, witness: Witness } = "Transaction with invalid signature", + OldUtxoInvalidSignature { utxo: UtxoPointer, output: OutputOldAddress, witness: Witness } = "Old Transaction with invalid signature", + OldUtxoInvalidPublicKey { utxo: UtxoPointer, output: OutputOldAddress, witness: Witness } = "Old Transaction with invalid public key", + AccountInvalidSignature { account: account::Identifier, witness: Witness } = "Account with invalid signature", + MultisigInvalidSignature { multisig: multisig::Identifier, witness: Witness } = "Multisig with invalid signature", + TransactionHasNoInput = "Transaction has no inputs", + FeeCalculationError { error: ValueError } = "Error while computing the fees: {error}", + PraosActiveSlotsCoeffInvalid { error: ActiveSlotsCoeffError } = "Praos active slot coefficient invalid: {error}", + UtxoInputsTotal { error: ValueError } = "Error while computing the transaction's total input: {error}", + UtxoOutputsTotal { error: ValueError } = "Error while computing the transaction's total output: {error}", + Block0 { source: Block0Error } = "Invalid Block0", + Account { source: account::LedgerError } = "Error or Invalid account", + Multisig { source: multisig::LedgerError } = "Error or Invalid multisig", + NotBalanced { inputs: Value, outputs: Value } = "Inputs, outputs and fees are not balanced, transaction with {inputs} input and {outputs} output", + ZeroOutput { output: Output
} = "Empty output", + Delegation { source: DelegationError } = "Error or Invalid delegation ", + AccountIdentifierInvalid = "Invalid account identifier", + InvalidDiscrimination = "Invalid discrimination", + ExpectingAccountWitness = "Expected an account witness", + ExpectingUtxoWitness = "Expected a UTxO witness", + ExpectingInitialMessage = "Expected an Initial Fragment", + CertificateInvalidSignature = "Invalid certificate's signature", + Update { source: update::Error } = "Error or Invalid update", + WrongChainLength { actual: ChainLength, expected: ChainLength } = "Wrong chain length, expected {expected} but received {actual}", + NonMonotonicDate { block_date: BlockDate, chain_date: BlockDate } = "Non Monotonic date, chain date is at {chain_date} but the block is at {block_date}", } impl Ledger { @@ -188,7 +145,9 @@ impl Ledger { let init_ents = match content_iter.next() { Some(Message::Initial(ref init_ents)) => Ok(init_ents), Some(_) => Err(Error::ExpectingInitialMessage), - None => Err(Error::Block0(Block0Error::InitialMessageMissing)), + None => Err(Error::Block0 { + source: Block0Error::InitialMessageMissing, + }), }?; let mut regular_ents = crate::message::ConfigParams::new(); @@ -220,16 +179,21 @@ impl Ledger { } // here we make sure those specific parameters are present, otherwise we returns a given error - let block0_start_time = - block0_start_time.ok_or(Error::Block0(Block0Error::InitialMessageNoDate))?; - let discrimination = - discrimination.ok_or(Error::Block0(Block0Error::InitialMessageNoDiscrimination))?; - let slot_duration = - slot_duration.ok_or(Error::Block0(Block0Error::InitialMessageNoSlotDuration))?; - let slots_per_epoch = - slots_per_epoch.ok_or(Error::Block0(Block0Error::InitialMessageNoSlotsPerEpoch))?; - let kes_update_speed = - kes_update_speed.ok_or(Error::Block0(Block0Error::InitialMessageNoKesUpdateSpeed))?; + let block0_start_time = block0_start_time.ok_or(Error::Block0 { + source: Block0Error::InitialMessageNoDate, + })?; + let discrimination = discrimination.ok_or(Error::Block0 { + source: Block0Error::InitialMessageNoDiscrimination, + })?; + let slot_duration = slot_duration.ok_or(Error::Block0 { + source: Block0Error::InitialMessageNoSlotDuration, + })?; + let slots_per_epoch = slots_per_epoch.ok_or(Error::Block0 { + source: Block0Error::InitialMessageNoSlotsPerEpoch, + })?; + let kes_update_speed = kes_update_speed.ok_or(Error::Block0 { + source: Block0Error::InitialMessageNoKesUpdateSpeed, + })?; let static_params = LedgerStaticParameters { block0_initial_hash, @@ -248,9 +212,9 @@ impl Ledger { let settings = setting::Settings::new(era).apply(®ular_ents)?; if settings.bft_leaders.is_empty() { - return Err(Error::Block0( - Block0Error::InitialMessageNoConsensusLeaderId, - )); + return Err(Error::Block0 { + source: Block0Error::InitialMessageNoConsensusLeaderId, + }); } let mut ledger = Ledger::empty(settings, static_params); @@ -260,17 +224,23 @@ impl Ledger { for content in content_iter { match content { Message::Initial(_) => { - return Err(Error::Block0(Block0Error::InitialMessageMany)); + return Err(Error::Block0 { + source: Block0Error::InitialMessageMany, + }); } Message::OldUtxoDeclaration(old) => { ledger.oldutxos = apply_old_declaration(ledger.oldutxos, old)?; } Message::Transaction(authenticated_tx) => { if authenticated_tx.transaction.inputs.len() != 0 { - return Err(Error::Block0(Block0Error::TransactionHasInput)); + return Err(Error::Block0 { + source: Block0Error::TransactionHasInput, + }); } if authenticated_tx.witnesses.len() != 0 { - return Err(Error::Block0(Block0Error::TransactionHasWitnesses)); + return Err(Error::Block0 { + source: Block0Error::TransactionHasWitnesses, + }); } let transaction_id = authenticated_tx.transaction.hash(); let (new_utxos, new_accounts, new_multisig) = @@ -288,20 +258,30 @@ impl Ledger { ledger.multisig = new_multisig; } Message::UpdateProposal(_) => { - return Err(Error::Block0(Block0Error::HasUpdateProposal)); + return Err(Error::Block0 { + source: Block0Error::HasUpdateProposal, + }); } Message::UpdateVote(_) => { - return Err(Error::Block0(Block0Error::HasUpdateVote)); + return Err(Error::Block0 { + source: Block0Error::HasUpdateVote, + }); } Message::Certificate(authenticated_cert_tx) => { if authenticated_cert_tx.transaction.inputs.len() != 0 { - return Err(Error::Block0(Block0Error::TransactionHasInput)); + return Err(Error::Block0 { + source: Block0Error::TransactionHasInput, + }); } if authenticated_cert_tx.witnesses.len() != 0 { - return Err(Error::Block0(Block0Error::TransactionHasWitnesses)); + return Err(Error::Block0 { + source: Block0Error::TransactionHasWitnesses, + }); } if authenticated_cert_tx.transaction.outputs.len() != 0 { - return Err(Error::Block0(Block0Error::TransactionHasOutput)); + return Err(Error::Block0 { + source: Block0Error::TransactionHasOutput, + }); } let (new_delegation, action) = ledger .delegation @@ -378,9 +358,15 @@ impl Ledger { let mut new_ledger = self.clone(); match content { - Message::Initial(_) => return Err(Error::Block0(Block0Error::OnlyMessageReceived)), + Message::Initial(_) => { + return Err(Error::Block0 { + source: Block0Error::OnlyMessageReceived, + }) + } Message::OldUtxoDeclaration(_) => { - return Err(Error::Block0(Block0Error::OnlyMessageReceived)); + return Err(Error::Block0 { + source: Block0Error::OnlyMessageReceived, + }); } Message::Transaction(authenticated_tx) => { let (new_ledger_, _fee) = @@ -421,7 +407,9 @@ impl Ledger { .fees .calculate(&signed_tx.transaction) .map(Ok) - .unwrap_or(Err(Error::FeeCalculationError(ValueError::Overflow)))?; + .unwrap_or(Err(Error::FeeCalculationError { + error: ValueError::Overflow, + }))?; self = internal_apply_transaction( self, dyn_params, @@ -529,20 +517,19 @@ impl Ledger { fn validate_utxo_total_value(&self) -> Result<(), Error> { let old_utxo_values = self.oldutxos.iter().map(|entry| entry.output.value); let new_utxo_values = self.utxos.iter().map(|entry| entry.output.value); - let account_value = self - .accounts - .get_total_value() - .map_err(|_| Error::Block0(Block0Error::UtxoTotalValueTooBig))?; - let multisig_value = self - .multisig - .get_total_value() - .map_err(|_| Error::Block0(Block0Error::UtxoTotalValueTooBig))?; + let account_value = self.accounts.get_total_value().map_err(|_| Error::Block0 { + source: Block0Error::UtxoTotalValueTooBig, + })?; + let multisig_value = self.multisig.get_total_value().map_err(|_| Error::Block0 { + source: Block0Error::UtxoTotalValueTooBig, + })?; let all_utxo_values = old_utxo_values .chain(new_utxo_values) .chain(Some(account_value)) .chain(Some(multisig_value)); - Value::sum(all_utxo_values) - .map_err(|_| Error::Block0(Block0Error::UtxoTotalValueTooBig))?; + Value::sum(all_utxo_values).map_err(|_| Error::Block0 { + source: Block0Error::UtxoTotalValueTooBig, + })?; Ok(()) } } @@ -586,7 +573,10 @@ fn internal_apply_transaction( // 1. verify that number of signatures matches number of // transactions if inputs.len() != witnesses.len() { - return Err(Error::NotEnoughSignatures(inputs.len(), witnesses.len())); + return Err(Error::NotEnoughSignatures { + expected: inputs.len(), + actual: witnesses.len(), + }); } // 2. validate inputs of transaction by gathering what we know of it, @@ -613,12 +603,15 @@ fn internal_apply_transaction( } // 3. verify that transaction sum is zero. - let total_input = - Value::sum(inputs.iter().map(|i| i.value)).map_err(|e| Error::UtxoInputsTotal(e))?; + let total_input = Value::sum(inputs.iter().map(|i| i.value)) + .map_err(|e| Error::UtxoInputsTotal { error: e })?; let total_output = Value::sum(inputs.iter().map(|i| i.value).chain(std::iter::once(fee))) - .map_err(|e| Error::UtxoOutputsTotal(e))?; + .map_err(|e| Error::UtxoOutputsTotal { error: e })?; if total_input != total_output { - return Err(Error::NotBalanced(total_input, total_output)); + return Err(Error::NotBalanced { + inputs: total_input, + outputs: total_output, + }); } // 4. add the new outputs @@ -651,7 +644,9 @@ fn internal_apply_transaction_output( for (index, output) in outputs.iter().enumerate() { // Reject zero-valued outputs. if output.value == Value::zero() { - return Err(Error::ZeroOutput(output.clone())); + return Err(Error::ZeroOutput { + output: output.clone(), + }); } if output.address.discrimination() != static_params.discrimination { @@ -701,29 +696,29 @@ fn input_utxo_verify( ledger.oldutxos = old_utxos; if utxo.value != associated_output.value { - return Err(Error::UtxoValueNotMatching( - utxo.value, - associated_output.value, - )); + return Err(Error::UtxoValueNotMatching { + expected: utxo.value, + value: associated_output.value, + }); }; if legacy::oldaddress_from_xpub(&associated_output.address, xpub) { - return Err(Error::OldUtxoInvalidPublicKey( - utxo.clone(), - associated_output.clone(), - witness.clone(), - )); + return Err(Error::OldUtxoInvalidPublicKey { + utxo: utxo.clone(), + output: associated_output.clone(), + witness: witness.clone(), + }); }; let data_to_verify = WitnessUtxoData::new(&ledger.static_params.block0_initial_hash, &transaction_id); let verified = signature.verify(&xpub, &data_to_verify); if verified == chain_crypto::Verification::Failed { - return Err(Error::OldUtxoInvalidSignature( - utxo.clone(), - associated_output.clone(), - witness.clone(), - )); + return Err(Error::OldUtxoInvalidSignature { + utxo: utxo.clone(), + output: associated_output.clone(), + witness: witness.clone(), + }); }; Ok(ledger) @@ -734,10 +729,10 @@ fn input_utxo_verify( .remove(&utxo.transaction_id, utxo.output_index)?; ledger.utxos = new_utxos; if utxo.value != associated_output.value { - return Err(Error::UtxoValueNotMatching( - utxo.value, - associated_output.value, - )); + return Err(Error::UtxoValueNotMatching { + expected: utxo.value, + value: associated_output.value, + }); } let data_to_verify = @@ -747,11 +742,11 @@ fn input_utxo_verify( &data_to_verify, ); if verified == chain_crypto::Verification::Failed { - return Err(Error::UtxoInvalidSignature( - utxo.clone(), - associated_output.clone(), - witness.clone(), - )); + return Err(Error::UtxoInvalidSignature { + utxo: utxo.clone(), + output: associated_output.clone(), + witness: witness.clone(), + }); }; Ok(ledger) } @@ -784,10 +779,10 @@ fn input_account_verify( let tidsc = WitnessAccountData::new(block0_hash, transaction_id, &spending_counter); let verified = sig.verify(&account.clone().into(), &tidsc); if verified == chain_crypto::Verification::Failed { - return Err(Error::AccountInvalidSignature( - account.clone(), - witness.clone(), - )); + return Err(Error::AccountInvalidSignature { + account: account.clone(), + witness: witness.clone(), + }); }; Ok((ledger, mledger)) } @@ -801,7 +796,10 @@ fn input_account_verify( let data_to_verify = WitnessMultisigData::new(&block0_hash, &transaction_id, &spending_counter); if msignature.verify(declaration, &data_to_verify) != true { - return Err(Error::MultisigInvalidSignature(account, witness.clone())); + return Err(Error::MultisigInvalidSignature { + multisig: account, + witness: witness.clone(), + }); } mledger = new_ledger; @@ -810,13 +808,6 @@ fn input_account_verify( } } -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} -impl std::error::Error for Error {} - #[cfg(test)] pub mod test { use super::*; @@ -956,7 +947,13 @@ pub mod test { let dyn_params = ledger.get_ledger_parameters(); let r = ledger.apply_transaction(&signed_tx, &dyn_params); - assert_err!(Error::NotEnoughSignatures(1, 0), r) + assert_err!( + Error::NotEnoughSignatures { + expcted: 1, + actual: 0 + }, + r + ) } #[test] diff --git a/chain-impl-mockchain/src/multisig/declaration.rs b/chain-impl-mockchain/src/multisig/declaration.rs index ccdaa3ef2..c28289fbb 100644 --- a/chain-impl-mockchain/src/multisig/declaration.rs +++ b/chain-impl-mockchain/src/multisig/declaration.rs @@ -20,12 +20,19 @@ impl From<[u8; 32]> for Identifier { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum DeclarationError { - ThresholdInvalid, - HasNotEnoughOwners, - HasTooManyOwners, - SubNotImplemented, +custom_error! { + #[derive(Clone, PartialEq, Eq)] + pub DeclarationError + ThresholdInvalid = "Invalid threshold", + HasNotEnoughOwners = "Not enough owners", + HasTooManyOwners = "Too many owners", + SubNotImplemented = "Sub not implemented", +} + +impl std::fmt::Display for Identifier { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.0.fmt(f) + } } /// Declaration of a multisig account parameters which is: diff --git a/chain-impl-mockchain/src/multisig/ledger.rs b/chain-impl-mockchain/src/multisig/ledger.rs index b35f1751c..4b7d8a03b 100644 --- a/chain-impl-mockchain/src/multisig/ledger.rs +++ b/chain-impl-mockchain/src/multisig/ledger.rs @@ -13,21 +13,16 @@ pub struct Ledger { declarations: Hamt, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum LedgerError { - ParticipantOutOfBound, - AlreadyExist, - DoesntExist, - DeclarationError(DeclarationError), - AccountError(account::LedgerError), - IdentifierMismatch, - ThresholdNotMet, -} - -impl From for LedgerError { - fn from(a: account::LedgerError) -> Self { - LedgerError::AccountError(a) - } +custom_error! { + #[derive(Clone, PartialEq, Eq)] + pub LedgerError + ParticipantOutOfBound = "Too many participant in the multisig account", + AlreadyExist = "Multisig account already exists", + DoesntExist = "Multisig account does not exist", + DeclarationError { source: DeclarationError } = "Multisig declaration error or invalid", + AccountError { source: account::LedgerError } = "Multisig account error or invalid", + IdentifierMismatch = "Multisig identifier mismatched", + ThresholdNotMet = "Multisig account's threshold not met", } impl From for LedgerError { @@ -36,12 +31,6 @@ impl From for LedgerError { } } -impl From for LedgerError { - fn from(e: DeclarationError) -> Self { - LedgerError::DeclarationError(e) - } -} - impl From for LedgerError { fn from(_: RemoveError) -> Self { LedgerError::DoesntExist diff --git a/chain-impl-mockchain/src/transaction/transfer.rs b/chain-impl-mockchain/src/transaction/transfer.rs index 5a743ac68..3d268089a 100644 --- a/chain-impl-mockchain/src/transaction/transfer.rs +++ b/chain-impl-mockchain/src/transaction/transfer.rs @@ -177,3 +177,19 @@ impl Readable for Output
{ Ok(Output { address, value }) } } + +impl std::fmt::Display for Output { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "{}.{}", + chain_addr::AddressReadable::from_address(&self.address).to_string(), + self.value + ) + } +} +impl std::fmt::Display for Output { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}.{}", self.address, self.value) + } +} diff --git a/chain-impl-mockchain/src/transaction/utxo.rs b/chain-impl-mockchain/src/transaction/utxo.rs index d13841f9c..bd96b1e90 100644 --- a/chain-impl-mockchain/src/transaction/utxo.rs +++ b/chain-impl-mockchain/src/transaction/utxo.rs @@ -30,3 +30,13 @@ impl UtxoPointer { } } } + +impl std::fmt::Display for UtxoPointer { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "{}@{}.{}", + self.transaction_id, self.output_index, self.value + ) + } +} diff --git a/chain-impl-mockchain/src/transaction/witness.rs b/chain-impl-mockchain/src/transaction/witness.rs index 22762db9e..5fbb12980 100644 --- a/chain-impl-mockchain/src/transaction/witness.rs +++ b/chain-impl-mockchain/src/transaction/witness.rs @@ -41,6 +41,17 @@ impl PartialEq for Witness { } impl Eq for Witness {} +impl std::fmt::Display for Witness { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Witness::Utxo(_) => write!(f, "UTxO Witness"), + Witness::Account(_) => write!(f, "Account Witness"), + Witness::OldUtxo(_, _) => write!(f, "Old UTxO Witness"), + Witness::Multisig(_) => write!(f, "Multisig Witness"), + } + } +} + pub struct WitnessUtxoData(Vec); impl WitnessUtxoData { diff --git a/chain-impl-mockchain/src/utxo.rs b/chain-impl-mockchain/src/utxo.rs index db00499ec..41b5fc723 100644 --- a/chain-impl-mockchain/src/utxo.rs +++ b/chain-impl-mockchain/src/utxo.rs @@ -11,17 +11,12 @@ use std::collections::BTreeMap; use imhamt::{Hamt, HamtIter, InsertError, RemoveError, ReplaceError, UpdateError}; -#[derive(Debug, Clone, PartialEq, Eq)] -/// UTXO Ledger Error -pub enum Error { - /// The transaction ID already exists - AlreadyExists, - /// The transaction ID was not found - TransactionNotFound, - /// UTXO Index not found in a specific transaction, - /// for example if the index never existed (out of bounds) or - /// that the specific UTXO was already spent - IndexNotFound, +custom_error! { + #[derive(Clone, PartialEq, Eq)] + pub Error + AlreadyExists = "Transaction ID Already exits", + TransactionNotFound = "Transaction is not found", + IndexNotFound = "Index not found", } impl From for Error { diff --git a/chain-impl-mockchain/src/value.rs b/chain-impl-mockchain/src/value.rs index 906c4f521..ef701f821 100644 --- a/chain-impl-mockchain/src/value.rs +++ b/chain-impl-mockchain/src/value.rs @@ -88,3 +88,9 @@ impl property::Serialize for Value { codec.put_u64(self.0) } } + +impl std::fmt::Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) + } +}