Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ impl<Extra: Clone> AccountState<Extra> {
/// the counter is incremented. A matching counter
/// needs to be used in the spending phase to make
/// sure we have non-replayability of a transaction.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpendingCounter(pub(crate) u32);

impl SpendingCounter {
Expand Down
74 changes: 55 additions & 19 deletions chain-impl-mockchain/src/ledger/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use super::governance::{Governance, ParametersGovernanceAction, TreasuryGovernan
use super::leaderlog::LeadersParticipationRecord;
use super::pots::Pots;
use super::reward_info::{EpochRewardsInfo, RewardsInfoParameters};
use crate::chaineval::HeaderContentEvalContext;
use crate::chaintypes::{ChainLength, ConsensusType, HeaderId};
use crate::config::{self, ConfigParam};
use crate::date::{BlockDate, Epoch};
Expand All @@ -22,6 +21,7 @@ use crate::treasury::Treasury;
use crate::value::*;
use crate::vote::{CommitteeId, VotePlanLedger, VotePlanLedgerError, VotePlanStatus};
use crate::{account, certificate, legacy, multisig, setting, stake, update, utxo};
use crate::{account::SpendingCounter, chaineval::HeaderContentEvalContext};
use crate::{
certificate::{PoolId, VoteAction, VotePlan},
chaineval::ConsensusEvalContext,
Expand Down Expand Up @@ -307,6 +307,12 @@ pub enum Error {
VotePlan(#[from] VotePlanLedgerError),
#[error("Scripts addresses are not yet supported by the system")]
ScriptsAddressNotAllowedYet,
#[error("Invalid spending counter for account {account}: expected {} but got {} instead", expected.0, got.0)]
InvalidSpendingCounter {
expected: SpendingCounter,
got: SpendingCounter,
account: UnspecifiedAccountIdentifier,
},
}

impl LedgerParameters {
Expand Down Expand Up @@ -1025,7 +1031,7 @@ impl Ledger {
InputEnum::UtxoInput(_) => {
return Err(Error::VoteCastInvalidTransaction);
}
InputEnum::AccountInput(account_id, _value) => {
InputEnum::AccountInput(account_id, _spending_counter, _value) => {
committee.insert(account_id.as_ref().try_into().unwrap());
}
}
Expand All @@ -1048,17 +1054,17 @@ impl Ledger {
) -> Result<(Self, Value), Error> {
let sign_data_hash = tx.transaction_sign_data_hash();

let (account_id, value, witness) = {
let (account_id, spending_counter, value, witness) = {
check::valid_vote_cast(tx)?;

let input = tx.inputs().iter().next().unwrap();
match input.to_enum() {
InputEnum::UtxoInput(_) => {
return Err(Error::VoteCastInvalidTransaction);
}
InputEnum::AccountInput(account_id, value) => {
InputEnum::AccountInput(account_id, spending_counter, value) => {
let witness = tx.witnesses().iter().next().unwrap();
(account_id, value, witness)
(account_id, spending_counter, value, witness)
}
}
};
Expand All @@ -1079,6 +1085,7 @@ impl Ledger {
&sign_data_hash,
&account_id,
witness,
spending_counter,
value,
)?;
}
Expand All @@ -1089,6 +1096,7 @@ impl Ledger {
&sign_data_hash,
&account_id,
witness,
spending_counter,
value,
)?;
}
Expand Down Expand Up @@ -1273,17 +1281,17 @@ impl Ledger {
) -> Result<(Self, Value), Error> {
let sign_data_hash = tx.transaction_sign_data_hash();

let (account_id, value, witness) = {
let (account_id, spending_counter, value, witness) = {
check::valid_stake_owner_delegation_transaction(tx)?;

let input = tx.inputs().iter().next().unwrap();
match input.to_enum() {
InputEnum::UtxoInput(_) => {
return Err(Error::OwnerStakeDelegationInvalidTransaction);
}
InputEnum::AccountInput(account_id, value) => {
InputEnum::AccountInput(account_id, spending_counter, value) => {
let witness = tx.witnesses().iter().next().unwrap();
(account_id, value, witness)
(account_id, spending_counter, value, witness)
}
}
};
Expand All @@ -1304,6 +1312,7 @@ impl Ledger {
&sign_data_hash,
&account_id,
witness,
spending_counter,
value,
)?;
self.accounts = single.set_delegation(
Expand All @@ -1318,6 +1327,7 @@ impl Ledger {
&sign_data_hash,
&account_id,
witness,
spending_counter,
value,
)?;
self.multisig = multi.set_delegation(
Expand Down Expand Up @@ -1434,7 +1444,7 @@ impl Ledger {
InputEnum::UtxoInput(utxo) => {
self = self.apply_input_to_utxo(&sign_data_hash, &utxo, &witness)?
}
InputEnum::AccountInput(account_id, value) => {
InputEnum::AccountInput(account_id, spending_counter, value) => {
match match_identifier_witness(&account_id, &witness)? {
MatchingIdentifierWitness::Single(account_id, witness) => {
self.accounts = input_single_account_verify(
Expand All @@ -1443,6 +1453,7 @@ impl Ledger {
&sign_data_hash,
&account_id,
witness,
spending_counter,
value,
)?
}
Expand All @@ -1453,6 +1464,7 @@ impl Ledger {
&sign_data_hash,
&account_id,
witness,
spending_counter,
value,
)?
}
Expand Down Expand Up @@ -1702,38 +1714,57 @@ fn match_identifier_witness<'a>(
}

fn input_single_account_verify<'a>(
mut ledger: account::Ledger,
ledger: account::Ledger,
block0_hash: &HeaderId,
sign_data_hash: &TransactionSignDataHash,
account: &account::Identifier,
witness: &'a account::Witness,
spending_counter: SpendingCounter,
value: Value,
) -> Result<account::Ledger, Error> {
// .remove_value() check if there's enough value and if not, returns a Err.
let (new_ledger, spending_counter) = ledger.remove_value(&account, value)?;
ledger = new_ledger;
let (new_ledger, spending_counter_ledger) = ledger.remove_value(&account, value)?;

if spending_counter != spending_counter_ledger {
return Err(Error::InvalidSpendingCounter {
expected: spending_counter_ledger,
got: spending_counter,
account: UnspecifiedAccountIdentifier::from_single_account(account.clone()),
});
}

let tidsc = WitnessAccountData::new(block0_hash, sign_data_hash, spending_counter);
let tidsc = WitnessAccountData::new(block0_hash, sign_data_hash);
let verified = witness.verify(account.as_ref(), &tidsc);
if verified == chain_crypto::Verification::Failed {
return Err(Error::AccountInvalidSignature {
account: account.clone(),
witness: Witness::Account(witness.clone()),
});
};
Ok(ledger)

Ok(new_ledger)
}

fn input_multi_account_verify<'a>(
mut ledger: multisig::Ledger,
ledger: multisig::Ledger,
block0_hash: &HeaderId,
sign_data_hash: &TransactionSignDataHash,
account: &multisig::Identifier,
witness: &'a multisig::Witness,
spending_counter: SpendingCounter,
value: Value,
) -> Result<multisig::Ledger, Error> {
// .remove_value() check if there's enough value and if not, returns a Err.
let (new_ledger, declaration, spending_counter) = ledger.remove_value(&account, value)?;
let (new_ledger, declaration, spending_counter_ledger) =
ledger.remove_value(&account, value)?;

if spending_counter != spending_counter_ledger {
return Err(Error::InvalidSpendingCounter {
expected: spending_counter_ledger,
got: spending_counter,
account: UnspecifiedAccountIdentifier::from_multi_account(account.clone()),
});
}

let data_to_verify = WitnessMultisigData::new(&block0_hash, sign_data_hash, spending_counter);
if !witness.verify(declaration, &data_to_verify) {
Expand All @@ -1742,8 +1773,8 @@ fn input_multi_account_verify<'a>(
witness: Witness::Multisig(witness.clone()),
});
}
ledger = new_ledger;
Ok(ledger)

Ok(new_ledger)
}

#[cfg(test)]
Expand Down Expand Up @@ -1923,6 +1954,7 @@ mod tests {
block0_hash: HeaderId,
sign_data_hash: TransactionSignDataHash,
witness: account::Witness,
spending_counter: SpendingCounter,
) -> TestResult {
let mut account_ledger = account::Ledger::new();
account_ledger = account_ledger
Expand All @@ -1934,6 +1966,7 @@ mod tests {
&sign_data_hash,
&id,
&witness,
spending_counter,
value_to_sub,
);

Expand Down Expand Up @@ -1962,6 +1995,7 @@ mod tests {
&sign_data_hash,
&id,
&to_account_witness(&signed_tx.witnesses().iter().next().unwrap()),
account.spending_counter.unwrap(),
value_to_sub,
);
assert!(result.is_ok())
Expand Down Expand Up @@ -1998,6 +2032,7 @@ mod tests {
&sign_data_hash,
&id,
&to_account_witness(&signed_tx.witnesses().iter().next().unwrap()),
account.spending_counter.unwrap(),
value_to_sub,
);
assert!(result.is_err())
Expand Down Expand Up @@ -2033,6 +2068,7 @@ mod tests {
&sign_data_hash,
&id,
&to_account_witness(&signed_tx.witnesses().iter().next().unwrap()),
account.spending_counter.unwrap(),
value_to_sub,
);
assert!(result.is_err())
Expand Down Expand Up @@ -2062,6 +2098,7 @@ mod tests {
&sign_data_hash,
&non_existing_account.public_key().into(),
&to_account_witness(&signed_tx.witnesses().iter().next().unwrap()),
account.spending_counter.unwrap(),
value_to_sub,
);
assert!(result.is_err())
Expand Down Expand Up @@ -2729,7 +2766,6 @@ mod tests {
let witness = Witness::new_account(
&test_ledger.block0_hash,
&tx_builder.get_auth_data_for_witness().hash(),
SpendingCounter::zero(),
|d| faucet.private_key().sign(d),
);

Expand Down
2 changes: 1 addition & 1 deletion chain-impl-mockchain/src/ledger/tests/transaction_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn duplicated_account_transaction() {
Err(err) => panic!("first transaction should be succesful but {}", err),
Ok(_) => {
assert_err_match!(
ledger::Error::AccountInvalidSignature { .. },
ledger::Error::InvalidSpendingCounter { .. },
test_ledger.apply_transaction(fragment2)
);
}
Expand Down
9 changes: 3 additions & 6 deletions chain-impl-mockchain/src/testing/builders/witness_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,9 @@ pub fn make_witness(
transaction_hash: &TransactionSignDataHash,
) -> Witness {
match addres_data.address.kind() {
Kind::Account(_) => Witness::new_account(
block0,
transaction_hash,
addres_data.spending_counter.unwrap(),
|d| addres_data.private_key().sign(d),
),
Kind::Account(_) => Witness::new_account(block0, transaction_hash, |d| {
addres_data.private_key().sign(d)
}),
_ => Witness::new_utxo(block0, transaction_hash, |d| {
addres_data.private_key().sign(d)
}),
Expand Down
6 changes: 5 additions & 1 deletion chain-impl-mockchain/src/testing/data/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ impl AddressData {

pub fn make_input(&self, value: Value, utxo: Option<Entry<Address>>) -> Input {
match self.address.kind() {
Kind::Account { .. } => Input::from_account_public_key(self.public_key(), value),
Kind::Account { .. } => Input::from_account_public_key(
self.public_key(),
self.spending_counter.unwrap(),
value,
),
Kind::Single { .. } | Kind::Group { .. } => {
Input::from_utxo_entry(utxo.unwrap_or_else(|| {
panic!(
Expand Down
Loading