Allow balances to be negative

* Will allow owners to loan token to others.
* Will allow for parallel verification of balances without spilling
  over 64 bits.

Fixes #43
This commit is contained in:
Greg Fitzgerald 2018-03-05 17:29:32 -07:00
parent 5dca3c41f2
commit 720c54a5bb
6 changed files with 27 additions and 27 deletions

View File

@ -21,8 +21,8 @@ pub enum AccountingError {
pub type Result<T> = result::Result<T, AccountingError>;
pub struct Accountant {
pub historian: Historian<u64>,
pub balances: HashMap<PublicKey, u64>,
pub historian: Historian<i64>,
pub balances: HashMap<PublicKey, i64>,
pub first_id: Sha256Hash,
pub last_id: Sha256Hash,
}
@ -30,7 +30,7 @@ pub struct Accountant {
impl Accountant {
pub fn new_from_entries<I>(entries: I, ms_per_tick: Option<u64>) -> Self
where
I: IntoIterator<Item = Entry<u64>>,
I: IntoIterator<Item = Entry<i64>>,
{
let mut entries = entries.into_iter();
@ -39,7 +39,7 @@ impl Accountant {
let entry0 = entries.next().unwrap();
let start_hash = entry0.id;
let hist = Historian::<u64>::new(&start_hash, ms_per_tick);
let hist = Historian::<i64>::new(&start_hash, ms_per_tick);
let mut acc = Accountant {
historian: hist,
balances: HashMap::new(),
@ -74,7 +74,7 @@ impl Accountant {
allow_deposits && from == to
}
pub fn process_event(self: &mut Self, event: Event<u64>) -> Result<()> {
pub fn process_event(self: &mut Self, event: Event<i64>) -> Result<()> {
if !verify_event(&event) {
return Err(AccountingError::InvalidEvent);
}
@ -95,7 +95,7 @@ impl Accountant {
fn process_verified_event(
self: &mut Self,
event: &Event<u64>,
event: &Event<i64>,
allow_deposits: bool,
) -> Result<()> {
if !reserve_signature(&mut self.historian.signatures, event) {
@ -122,7 +122,7 @@ impl Accountant {
pub fn transfer(
self: &mut Self,
n: u64,
n: i64,
keypair: &Ed25519KeyPair,
to: PublicKey,
) -> Result<Signature> {
@ -139,7 +139,7 @@ impl Accountant {
self.process_event(event).map(|_| sig)
}
pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option<u64> {
pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option<i64> {
self.balances.get(pubkey).map(|x| *x)
}
}

View File

@ -14,7 +14,7 @@ pub enum Request {
Transfer {
from: PublicKey,
to: PublicKey,
val: u64,
val: i64,
last_id: Sha256Hash,
sig: Signature,
},
@ -31,8 +31,8 @@ pub enum Request {
#[derive(Serialize, Deserialize, Debug)]
pub enum Response {
Balance { key: PublicKey, val: Option<u64> },
Entries { entries: Vec<Entry<u64>> },
Balance { key: PublicKey, val: Option<i64> },
Entries { entries: Vec<Entry<i64>> },
Id { id: Sha256Hash, is_last: bool },
}

View File

@ -29,7 +29,7 @@ impl AccountantStub {
&self,
from: PublicKey,
to: PublicKey,
val: u64,
val: i64,
last_id: Sha256Hash,
sig: Signature,
) -> io::Result<usize> {
@ -46,7 +46,7 @@ impl AccountantStub {
pub fn transfer(
&self,
n: u64,
n: i64,
keypair: &Ed25519KeyPair,
to: PublicKey,
last_id: &Sha256Hash,
@ -57,7 +57,7 @@ impl AccountantStub {
.map(|_| sig)
}
pub fn get_balance(&self, pubkey: &PublicKey) -> io::Result<Option<u64>> {
pub fn get_balance(&self, pubkey: &PublicKey) -> io::Result<Option<i64>> {
let req = Request::GetBalance { key: *pubkey };
let data = serialize(&req).expect("serialize GetBalance");
self.socket.send_to(&data, &self.addr)?;

View File

@ -5,13 +5,13 @@ extern crate serde_json;
extern crate silk;
use silk::genesis::Genesis;
use silk::log::verify_slice_u64;
use silk::log::verify_slice_i64;
use std::io::stdin;
fn main() {
let gen: Genesis = serde_json::from_reader(stdin()).unwrap();
let entries = gen.create_entries();
verify_slice_u64(&entries, &entries[0].id);
verify_slice_i64(&entries, &entries[0].id);
for x in entries {
println!("{}", serde_json::to_string(&x).unwrap());
}

View File

@ -9,11 +9,11 @@ use untrusted::Input;
#[derive(Serialize, Deserialize, Debug)]
pub struct Creator {
pub pubkey: PublicKey,
pub tokens: u64,
pub tokens: i64,
}
impl Creator {
pub fn new(tokens: u64) -> Self {
pub fn new(tokens: i64) -> Self {
Creator {
pubkey: get_pubkey(&generate_keypair()),
tokens,
@ -24,12 +24,12 @@ impl Creator {
#[derive(Serialize, Deserialize, Debug)]
pub struct Genesis {
pub pkcs8: Vec<u8>,
pub tokens: u64,
pub tokens: i64,
pub creators: Vec<Creator>,
}
impl Genesis {
pub fn new(tokens: u64, creators: Vec<Creator>) -> Self {
pub fn new(tokens: i64, creators: Vec<Creator>) -> Self {
let rnd = SystemRandom::new();
let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rnd).unwrap().to_vec();
println!("{:?}", pkcs8);
@ -52,7 +52,7 @@ impl Genesis {
get_pubkey(&self.get_keypair())
}
pub fn create_transaction(&self, data: u64, to: &PublicKey) -> Event<u64> {
pub fn create_transaction(&self, data: i64, to: &PublicKey) -> Event<i64> {
let last_id = self.get_seed();
let from = self.get_pubkey();
let sig = sign_transaction_data(&data, &self.get_keypair(), to, &last_id);
@ -65,7 +65,7 @@ impl Genesis {
}
}
pub fn create_events(&self) -> Vec<Event<u64>> {
pub fn create_events(&self) -> Vec<Event<i64>> {
let pubkey = self.get_pubkey();
let event0 = Event::Tick;
let event1 = self.create_transaction(self.tokens, &pubkey);
@ -79,7 +79,7 @@ impl Genesis {
events
}
pub fn create_entries(&self) -> Vec<Entry<u64>> {
pub fn create_entries(&self) -> Vec<Entry<i64>> {
create_entries(&self.get_seed(), self.create_events())
}
}
@ -87,7 +87,7 @@ impl Genesis {
#[cfg(test)]
mod tests {
use super::*;
use log::verify_slice_u64;
use log::verify_slice_i64;
#[test]
fn test_create_events() {
@ -114,12 +114,12 @@ mod tests {
#[test]
fn test_verify_entries() {
let entries = Genesis::new(100, vec![]).create_entries();
assert!(verify_slice_u64(&entries, &entries[0].id));
assert!(verify_slice_i64(&entries, &entries[0].id));
}
#[test]
fn test_verify_entries_with_transactions() {
let entries = Genesis::new(100, vec![Creator::new(42)]).create_entries();
assert!(verify_slice_u64(&entries, &entries[0].id));
assert!(verify_slice_i64(&entries, &entries[0].id));
}
}

View File

@ -130,7 +130,7 @@ pub fn verify_slice(events: &[Entry<Sha256Hash>], start_hash: &Sha256Hash) -> bo
}
/// Verifies the hashes and counts of a slice of events are all consistent.
pub fn verify_slice_u64(events: &[Entry<u64>], start_hash: &Sha256Hash) -> bool {
pub fn verify_slice_i64(events: &[Entry<i64>], start_hash: &Sha256Hash) -> bool {
let genesis = [Entry::new_tick(Default::default(), start_hash)];
let event_pairs = genesis.par_iter().chain(events).zip(events);
event_pairs.all(|(x0, x1)| verify_entry(&x1, &x0.id))