Skip to content
This repository has been archived by the owner on Jun 25, 2021. It is now read-only.

Commit

Permalink
Merge 4d839a6 into 80f2a17
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuef committed Mar 22, 2021
2 parents 80f2a17 + 4d839a6 commit 906eda4
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 66 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ version = "0.5.0"

[dependencies]
bincode = "1.2.1"
sn_data_types = "~0.16.0"
sn_data_types = "~0.17.0"
thiserror = "1.0.23"
crdts = "4.3.0"
threshold_crypto = "~0.4.0"
Expand Down
79 changes: 51 additions & 28 deletions src/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use itertools::Itertools;
use log::debug;
use sn_data_types::{
ActorHistory, Credit, CreditAgreementProof, CreditId, Debit, DebitId, OwnerType, PublicKey,
SignatureShare, SignedCredit, SignedDebit, Signing, Token, TransferAgreementProof, WalletInfo,
SectionElders, SignatureShare, SignedCredit, SignedDebit, Signing, Token,
TransferAgreementProof, WalletHistory,
};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt;
Expand All @@ -43,7 +44,7 @@ pub struct Actor<V: ReplicaValidator, S: Signing> {
/// After quorum is reached and proof produced, the set is cleared.
accumulating_validations: HashMap<DebitId, HashMap<usize, TransferValidated>>,
/// The PK Set of the Replicas
replicas: PublicKeySet,
replicas: SectionElders,
/// The passed in replica_validator, contains the logic from upper layers
/// for determining if a remote group of Replicas, represented by a PublicKey, is indeed valid.
replica_validator: V,
Expand All @@ -60,7 +61,7 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
/// If upper layer trusts them, the validator might do nothing but return "true".
/// If it wants to execute some logic for verifying that the remote replicas are in fact part of the system,
/// before accepting credits, it then implements that in the replica_validator.
pub fn new(signing: S, replicas: PublicKeySet, replica_validator: V) -> Actor<V, S> {
pub fn new(signing: S, replicas: SectionElders, replica_validator: V) -> Actor<V, S> {
let id = signing.id();
let wallet = Wallet::new(id.clone());
Actor {
Expand All @@ -76,19 +77,25 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
}

///
pub fn from_info(signing: S, info: WalletInfo, replica_validator: V) -> Result<Actor<V, S>> {
pub fn from_info(signing: S, info: WalletHistory, replica_validator: V) -> Result<Actor<V, S>> {
let mut actor = Self::new(signing, info.replicas, replica_validator);
if let Some(e) = actor.from_history(info.history)? {
actor.apply(ActorEvent::TransfersSynched(e))?;
match actor.from_history(info.history) {
Ok(Some(event)) => actor.apply(ActorEvent::TransfersSynched(event))?,
Ok(None) => {}
Err(Error::NoActorHistory) => {
// do nothing
}
Err(error) => return Err(error),
}

Ok(actor)
}

/// Temp, for test purposes
pub fn from_snapshot(
wallet: Wallet,
signing: S,
replicas: PublicKeySet,
replicas: SectionElders,
replica_validator: V,
) -> Actor<V, S> {
let id = wallet.id().clone();
Expand Down Expand Up @@ -125,11 +132,11 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {

///
pub fn replicas_public_key(&self) -> PublicKey {
PublicKey::Bls(self.replicas.public_key())
PublicKey::Bls(self.replicas.key_set.public_key())
}

///
pub fn replicas_key_set(&self) -> PublicKeySet {
pub fn replicas(&self) -> SectionElders {
self.replicas.clone()
}

Expand Down Expand Up @@ -199,6 +206,7 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
pub fn receive(&self, validation: TransferValidated) -> Outcome<TransferValidationReceived> {
// Always verify signature first! (as to not leak any information).
if self.verify(&validation).is_err() {
debug!("Invalid signature in transfer/actor receive step.");
return Err(Error::InvalidSignature);
}
debug!("Actor: Verified validation.");
Expand Down Expand Up @@ -230,6 +238,8 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
return Err(Error::NoSetForDebitId(validation.id()));
}

debug!("Actor receive stepped passed all checks");

// TODO: Cover scenario where replica keys might have changed during an ongoing transfer.
let map = self
.accumulating_validations
Expand All @@ -241,8 +251,8 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
// If the previous count of accumulated + current validation coming in here,
// is greater than the threshold, then we have reached the quorum needed
// to build the proof. (Quorum = threshold + 1)
let majority =
map.len() + 1 > self.replicas.threshold() && self.replicas == validation.replicas;
let majority = map.len() + 1 > self.replicas.key_set.threshold()
&& self.replicas.key_set == validation.replicas;
if majority {
let debit_bytes = match bincode::serialize(&signed_debit) {
Err(_) => return Err(Error::Serialisation("Serialization Error".to_string())),
Expand Down Expand Up @@ -271,16 +281,26 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
// Combine shares to produce the main signature.
let debit_sig = self
.replicas
.key_set
.combine_signatures(&debit_sig_shares)
.map_err(|_| Error::CannotAggregate)?;
// Combine shares to produce the main signature.
let credit_sig = self
.replicas
.key_set
.combine_signatures(&credit_sig_shares)
.map_err(|_| Error::CannotAggregate)?;

let valid_debit = self.replicas.public_key().verify(&debit_sig, debit_bytes);
let valid_credit = self.replicas.public_key().verify(&credit_sig, credit_bytes);
let valid_debit = self
.replicas
.key_set
.public_key()
.verify(&debit_sig, debit_bytes);
let valid_credit = self
.replicas
.key_set
.public_key()
.verify(&credit_sig, credit_bytes);

// Validate the combined signatures. If the shares were valid, this can't fail.
if valid_debit && valid_credit {
Expand All @@ -289,7 +309,7 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
debit_sig: sn_data_types::Signature::Bls(debit_sig),
signed_credit: signed_credit.clone(),
credit_sig: sn_data_types::Signature::Bls(credit_sig),
debiting_replicas_keys: self.replicas.clone(),
debiting_replicas_keys: self.replicas.key_set.clone(),
});
} // else, we have some corrupt data. (todo: Do we need to act on that fact?)
}
Expand Down Expand Up @@ -362,7 +382,7 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
if !credits.is_empty() || !debits.is_empty() {
Outcome::success(TransfersSynched(ActorHistory { credits, debits }))
} else {
Err(Error::NothingToSync) // TODO: the error is actually that credits and/or debits failed validation..
Err(Error::NoActorHistory) // TODO: the error is actually that credits and/or debits failed validation..
}
}

Expand Down Expand Up @@ -423,18 +443,14 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
/// There is no validation of an event, it is assumed to have
/// been properly validated before raised, and thus anything that breaks is a bug.
pub fn apply(&mut self, event: ActorEvent) -> Result<()> {
debug!("Applying event {:?}", event);
debug!("Transfer Actor {}: applying event {:?}", self.id(), event);
match event {
ActorEvent::TransferInitiated(e) => {
self.next_expected_debit = e.id().counter + 1;
let _ = self.accumulating_validations.insert(e.id(), HashMap::new());
Ok(())
}
ActorEvent::TransferValidationReceived(e) => {
if e.proof.is_some() {
// if we have a proof, then we have a valid set of replicas (potentially new) to update with
self.replicas = e.validation.replicas.clone();
}
match self.accumulating_validations.get_mut(&e.validation.id()) {
Some(map) => {
let _ = map.insert(e.validation.replica_debit_sig.index, e.validation);
Expand Down Expand Up @@ -548,15 +564,15 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
let valid_debit = match bincode::serialize(&proof.signed_debit) {
Err(_) => return Err(Error::Serialisation("Could not serialise debit".into())),
Ok(data) => {
let public_key = sn_data_types::PublicKey::Bls(self.replicas.public_key());
let public_key = sn_data_types::PublicKey::Bls(self.replicas.key_set.public_key());
public_key.verify(&proof.debit_sig, &data).is_ok()
}
};

let valid_credit = match bincode::serialize(&proof.signed_credit) {
Err(_) => return Err(Error::Serialisation("Could not serialise credit".into())),
Ok(data) => {
let public_key = sn_data_types::PublicKey::Bls(self.replicas.public_key());
let public_key = sn_data_types::PublicKey::Bls(self.replicas.key_set.public_key());
public_key.verify(&proof.credit_sig, &data).is_ok()
}
};
Expand Down Expand Up @@ -598,7 +614,7 @@ impl<V: ReplicaValidator, S: Signing> Actor<V, S> {
signed_debit: &SignedDebit,
signed_credit: &SignedCredit,
) -> Result<()> {
debug!("Actor: Verifying is our transfer!");
debug!("Actor: Verifying is this our transfer?!");
let valid_debit = self
.signing
.verify(&signed_debit.actor_signature, &signed_debit.debit);
Expand Down Expand Up @@ -630,7 +646,7 @@ impl<V: ReplicaValidator + fmt::Debug, S: Signing + fmt::Debug> fmt::Debug for A
self.wallet,
self.next_expected_debit,
self.accumulating_validations,
self.replicas.public_key(),
self.replicas.key_set.public_key(),
self.replica_validator
)
}
Expand All @@ -645,11 +661,12 @@ mod test {
use crdts::Dot;
use serde::Serialize;
use sn_data_types::{
Credit, Debit, Keypair, PublicKey, Signature, SignatureShare, Token,
Credit, Debit, Keypair, PublicKey, SectionElders, Signature, SignatureShare, Token,
TransferAgreementProof, TransferValidated,
};
use std::collections::BTreeMap;
use threshold_crypto::{SecretKey, SecretKeySet};
use xor_name::Prefix;
struct Validator {}

impl ReplicaValidator for Validator {
Expand Down Expand Up @@ -748,7 +765,7 @@ mod test {
for i in 0..7 {
let transfer_validation = actor
.receive(validations[i].clone())?
.ok_or(Error::UnexpectedOutcome)?;
.ok_or(Error::ReceiveValidationFailed)?;

if i < 1
// threshold is 1
Expand All @@ -768,7 +785,7 @@ mod test {
fn get_debit(actor: &Actor<Validator, Keypair>) -> Result<TransferInitiated> {
let event = actor
.transfer(Token::from_nano(10), get_random_pk(), "asdf".to_string())?
.ok_or(Error::UnexpectedOutcome)?;
.ok_or(Error::TransferCreationFailed)?;
Ok(event)
}

Expand Down Expand Up @@ -895,7 +912,13 @@ mod test {
let mut wallet = Wallet::new(OwnerType::Single(credit.recipient()));
wallet.apply_credit(credit)?;

let actor = Actor::from_snapshot(wallet, keypair, replicas_id, replica_validator);
let replicas = SectionElders {
prefix: Prefix::default(),
names: Default::default(),
key_set: replicas_id,
};

let actor = Actor::from_snapshot(wallet, keypair, replicas, replica_validator);
Ok((actor, bls_secret_key))
}

Expand Down
53 changes: 42 additions & 11 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@ pub enum Error {
#[error("Transfer not expected for this actor {0:?}")]
NoSetForTransferId(Dot<PublicKey>),
/// Proposed operation is not the next in sequence. The debit op should be current actor count + 1
#[error("Operation out of order: debit's counter is '{0}', current actor counter is '{1}'")]
#[error(
"Operation out of order: debit's counter is '{0}', actor next expected op count is '{1}'"
)]
OperationOutOfOrder(u64, u64),
/// This account has not seen any debits yet. Sent debit should be 0 but was not.
#[error("Operation out of order debit counter should be 0")]
ShouldBeInitialOperation,
/// No credits or debits were found to sync
#[error("No credits or debits found to sync to actor")]
NothingToSync,
#[error("There was no valid history found for provided actor.")]
NoActorHistory,
/// 0-value transfers are invalid
#[error("Transfer amount must be greater than zero")]
ZeroValueTransfer,
Expand All @@ -67,25 +69,54 @@ pub enum Error {
/// Debit is not from this wallet
#[error("Debit is not from wallet {0}. Debit: {1:?}")]
DebitDoesNotBelong(PublicKey, Debit),
/// Credit is not from this wallet
#[error("Credit is not from wallet {0}. Credit: {1:?}")]
/// Credit is not to this wallet
#[error("Credit is not to wallet {0}. Credit: {1:?}")]
CreditDoesNotBelong(PublicKey, Credit),
/// Subtracting this transfer would cause an overlow
#[error("Overflow when subtracting {0} from balance of: {1}")]
SubtractionOverflow(Token, Token),
/// Adding this transfer would cause an overflow
#[error("Overflow when adding balance {0} and credit of: {1}")]
AdditionOverflow(Token, Token),
/// Unexpected outcome
// TODO: clarify this...
#[error("Unexpected outcome")]
UnexpectedOutcome,
/// Receive validation failed..
#[error("Receive validation failed")]
ReceiveValidationFailed,
/// TransferCreationFailed..
#[error("TransferCreationFailed")]
TransferCreationFailed,
/// SenderValidationFailed..
#[error("SenderValidationFailed")]
SenderValidationFailed,
/// RegisterProofFailed..
#[error("RegisterProofFailed")]
RegisterProofFailed,
/// InvalidCreditOrDebit..
#[error("InvalidCreditOrDebit")]
InvalidCreditOrDebit,
/// CouldNotGetWalletForReplica..
#[error("CouldNotGetWalletForReplica")]
CouldNotGetWalletForReplica,
/// CouldNotFindGroup..
#[error("CouldNotFindGroup")]
CouldNotFindGroup,
/// ReceivePropagationFailed..
#[error("ReceivePropagationFailed")]
ReceivePropagationFailed,
/// SyncFailed..
#[error("SyncFailed")]
SyncFailed,
/// ValidationFailed..
#[error("ValidationFailed")]
ValidationFailed,
/// GetGenesisFailed..
#[error("GenesisFailed")]
GenesisFailed,
/// Unknown error
#[error("Unknown error: {0}")]
Unknown(String),
/// Wallet not found
#[error("Wallet not found locally. The following debit was the cause: {0:?}")]
WalletNotFound(Debit),
#[error("{0} Wallet not found locally.")]
WalletNotFound(PublicKey),
/// Signature shares are insufficient for BLS aggregation
#[error("Could not aggregate with given signature shares")]
CannotAggregate,
Expand Down

0 comments on commit 906eda4

Please sign in to comment.