Move reserve_signatures into accountant
Reasons Transaction signatures need to be unique: 1. guard against duplicates 2. accountant uses them as IDs to link Witness signatures to transactions via the `pending` hash map
This commit is contained in:
parent
46e8c09bd8
commit
3abe305a21
|
@ -39,6 +39,7 @@ pub struct Accountant {
|
||||||
historian: Historian,
|
historian: Historian,
|
||||||
balances: HashMap<PublicKey, i64>,
|
balances: HashMap<PublicKey, i64>,
|
||||||
pending: HashMap<Signature, Plan>,
|
pending: HashMap<Signature, Plan>,
|
||||||
|
signatures: HashSet<Signature>,
|
||||||
time_sources: HashSet<PublicKey>,
|
time_sources: HashSet<PublicKey>,
|
||||||
last_time: DateTime<Utc>,
|
last_time: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
@ -61,6 +62,7 @@ impl Accountant {
|
||||||
historian: hist,
|
historian: hist,
|
||||||
balances: HashMap::new(),
|
balances: HashMap::new(),
|
||||||
pending: HashMap::new(),
|
pending: HashMap::new(),
|
||||||
|
signatures: HashSet::new(),
|
||||||
time_sources: HashSet::new(),
|
time_sources: HashSet::new(),
|
||||||
last_time: Utc.timestamp(0, 0),
|
last_time: Utc.timestamp(0, 0),
|
||||||
};
|
};
|
||||||
|
@ -124,13 +126,21 @@ impl Accountant {
|
||||||
self.log_verified_transaction(tr)
|
self.log_verified_transaction(tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reserve_signature(&mut self, sig: &Signature) -> bool {
|
||||||
|
if self.signatures.contains(sig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.signatures.insert(*sig);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
/// Process a Transaction that has already been verified.
|
/// Process a Transaction that has already been verified.
|
||||||
fn process_verified_transaction(
|
fn process_verified_transaction(
|
||||||
self: &mut Self,
|
self: &mut Self,
|
||||||
tr: &Transaction,
|
tr: &Transaction,
|
||||||
allow_deposits: bool,
|
allow_deposits: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if !self.historian.reserve_signature(&tr.sig) {
|
if !self.reserve_signature(&tr.sig) {
|
||||||
return Err(AccountingError::InvalidTransferSignature);
|
return Err(AccountingError::InvalidTransferSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,4 +410,13 @@ mod tests {
|
||||||
acc.process_verified_sig(alice.pubkey(), sig).unwrap(); // <-- Attack! Attempt to cancel completed transaction.
|
acc.process_verified_sig(alice.pubkey(), sig).unwrap(); // <-- Attack! Attempt to cancel completed transaction.
|
||||||
assert_ne!(acc.get_balance(&alice.pubkey()), Some(2));
|
assert_ne!(acc.get_balance(&alice.pubkey()), Some(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_duplicate_event_signature() {
|
||||||
|
let alice = Mint::new(1);
|
||||||
|
let mut acc = Accountant::new(&alice, None);
|
||||||
|
let sig = Signature::default();
|
||||||
|
assert!(acc.reserve_signature(&sig));
|
||||||
|
assert!(!acc.reserve_signature(&sig));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use recorder::{ExitReason, Recorder, Signal};
|
use recorder::{ExitReason, Recorder, Signal};
|
||||||
use signature::Signature;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||||
use std::thread::{spawn, JoinHandle};
|
use std::thread::{spawn, JoinHandle};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -14,7 +12,6 @@ pub struct Historian {
|
||||||
pub sender: SyncSender<Signal>,
|
pub sender: SyncSender<Signal>,
|
||||||
pub receiver: Receiver<Entry>,
|
pub receiver: Receiver<Entry>,
|
||||||
pub thread_hdl: JoinHandle<ExitReason>,
|
pub thread_hdl: JoinHandle<ExitReason>,
|
||||||
pub signatures: HashSet<Signature>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Historian {
|
impl Historian {
|
||||||
|
@ -23,23 +20,13 @@ impl Historian {
|
||||||
let (entry_sender, receiver) = sync_channel(1000);
|
let (entry_sender, receiver) = sync_channel(1000);
|
||||||
let thread_hdl =
|
let thread_hdl =
|
||||||
Historian::create_recorder(*start_hash, ms_per_tick, event_receiver, entry_sender);
|
Historian::create_recorder(*start_hash, ms_per_tick, event_receiver, entry_sender);
|
||||||
let signatures = HashSet::new();
|
|
||||||
Historian {
|
Historian {
|
||||||
sender,
|
sender,
|
||||||
receiver,
|
receiver,
|
||||||
thread_hdl,
|
thread_hdl,
|
||||||
signatures,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reserve_signature(&mut self, sig: &Signature) -> bool {
|
|
||||||
if self.signatures.contains(sig) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.signatures.insert(*sig);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A background thread that will continue tagging received Event messages and
|
/// A background thread that will continue tagging received Event messages and
|
||||||
/// sending back Entry messages until either the receiver or sender channel is closed.
|
/// sending back Entry messages until either the receiver or sender channel is closed.
|
||||||
fn create_recorder(
|
fn create_recorder(
|
||||||
|
@ -110,15 +97,6 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duplicate_event_signature() {
|
|
||||||
let zero = Hash::default();
|
|
||||||
let mut hist = Historian::new(&zero, None);
|
|
||||||
let sig = Signature::default();
|
|
||||||
assert!(hist.reserve_signature(&sig));
|
|
||||||
assert!(!hist.reserve_signature(&sig));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ticking_historian() {
|
fn test_ticking_historian() {
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
|
|
Loading…
Reference in New Issue