Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 12eba4b

Browse files
authored
Merge pull request #26 from garious/add-accountant
Add testnode and client-demo
2 parents f3dd479 + 4610de8 commit 12eba4b

9 files changed

+403
-105
lines changed

Cargo.toml

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "silk"
33
description = "A silky smooth implementation of the Loom architecture"
4-
version = "0.2.3"
4+
version = "0.3.0"
55
documentation = "https://docs.rs/silk"
66
homepage = "http://loomprotocol.com/"
77
repository = "https://github.com/loomprotocol/silk"
@@ -15,6 +15,14 @@ license = "Apache-2.0"
1515
name = "silk-demo"
1616
path = "src/bin/demo.rs"
1717

18+
[[bin]]
19+
name = "silk-client-demo"
20+
path = "src/bin/client-demo.rs"
21+
22+
[[bin]]
23+
name = "silk-testnode"
24+
path = "src/bin/testnode.rs"
25+
1826
[badges]
1927
codecov = { repository = "loomprotocol/silk", branch = "master", service = "github" }
2028

src/accountant.rs

+62-26
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! event log to record transactions. Its users can deposit funds and
33
//! transfer funds to other users.
44
5-
use log::{verify_entry, Event, PublicKey, Sha256Hash};
5+
use log::{Event, PublicKey, Sha256Hash, Signature};
66
use historian::Historian;
77
use ring::signature::Ed25519KeyPair;
88
use std::sync::mpsc::{RecvError, SendError};
@@ -24,8 +24,8 @@ impl Accountant {
2424
}
2525
}
2626

27-
pub fn process_event(self: &mut Self, event: Event<u64>) {
28-
match event {
27+
pub fn process_event(self: &mut Self, event: &Event<u64>) {
28+
match *event {
2929
Event::Claim { key, data, .. } => {
3030
if self.balances.contains_key(&key) {
3131
if let Some(x) = self.balances.get_mut(&key) {
@@ -52,39 +52,76 @@ impl Accountant {
5252
}
5353

5454
pub fn sync(self: &mut Self) {
55+
let mut entries = vec![];
5556
while let Ok(entry) = self.historian.receiver.try_recv() {
56-
assert!(verify_entry(&entry, &self.end_hash));
57-
self.end_hash = entry.end_hash;
58-
59-
self.process_event(entry.event);
57+
entries.push(entry);
58+
}
59+
// TODO: Does this cause the historian's channel to get blocked?
60+
//use log::verify_slice_u64;
61+
//println!("accountant: verifying {} entries...", entries.len());
62+
//assert!(verify_slice_u64(&entries, &self.end_hash));
63+
//println!("accountant: Done verifying {} entries.", entries.len());
64+
if let Some(last_entry) = entries.last() {
65+
self.end_hash = last_entry.end_hash;
6066
}
67+
for e in &entries {
68+
self.process_event(&e.event);
69+
}
70+
}
71+
72+
pub fn deposit_signed(
73+
self: &Self,
74+
key: PublicKey,
75+
data: u64,
76+
sig: Signature,
77+
) -> Result<(), SendError<Event<u64>>> {
78+
let event = Event::Claim { key, data, sig };
79+
self.historian.sender.send(event)
6180
}
6281

6382
pub fn deposit(
6483
self: &Self,
6584
n: u64,
6685
keypair: &Ed25519KeyPair,
6786
) -> Result<(), SendError<Event<u64>>> {
68-
use log::sign_hash;
69-
let event = sign_hash(n, &keypair);
87+
use log::{get_pubkey, sign_serialized};
88+
let key = get_pubkey(keypair);
89+
let sig = sign_serialized(&n, keypair);
90+
self.deposit_signed(key, n, sig)
91+
}
92+
93+
pub fn transfer_signed(
94+
self: &mut Self,
95+
from: PublicKey,
96+
to: PublicKey,
97+
data: u64,
98+
sig: Signature,
99+
) -> Result<(), SendError<Event<u64>>> {
100+
if self.get_balance(&from).unwrap() < data {
101+
// TODO: Replace the SendError result with a custom one.
102+
println!("Error: Insufficient funds");
103+
return Ok(());
104+
}
105+
let event = Event::Transaction {
106+
from,
107+
to,
108+
data,
109+
sig,
110+
};
70111
self.historian.sender.send(event)
71112
}
72113

73114
pub fn transfer(
74115
self: &mut Self,
75116
n: u64,
76117
keypair: &Ed25519KeyPair,
77-
pubkey: PublicKey,
118+
to: PublicKey,
78119
) -> Result<(), SendError<Event<u64>>> {
79-
use log::transfer_hash;
80-
use generic_array::GenericArray;
120+
use log::{get_pubkey, sign_transaction_data};
81121

82-
let sender_pubkey = GenericArray::clone_from_slice(keypair.public_key_bytes());
83-
if self.get_balance(&sender_pubkey).unwrap() >= n {
84-
let event = transfer_hash(n, keypair, pubkey);
85-
return self.historian.sender.send(event);
86-
}
87-
Ok(())
122+
let from = get_pubkey(keypair);
123+
let sig = sign_transaction_data(&n, keypair, &to);
124+
self.transfer_signed(from, to, n, sig)
88125
}
89126

90127
pub fn get_balance(self: &mut Self, pubkey: &PublicKey) -> Result<u64, RecvError> {
@@ -98,9 +135,8 @@ mod tests {
98135
use super::*;
99136
use std::thread::sleep;
100137
use std::time::Duration;
101-
use log::generate_keypair;
138+
use log::{generate_keypair, get_pubkey};
102139
use historian::ExitReason;
103-
use generic_array::GenericArray;
104140

105141
#[test]
106142
fn test_accountant() {
@@ -112,7 +148,7 @@ mod tests {
112148
acc.deposit(1_000, &bob_keypair).unwrap();
113149

114150
sleep(Duration::from_millis(30));
115-
let bob_pubkey = GenericArray::clone_from_slice(bob_keypair.public_key_bytes());
151+
let bob_pubkey = get_pubkey(&bob_keypair);
116152
acc.transfer(500, &alice_keypair, bob_pubkey).unwrap();
117153

118154
sleep(Duration::from_millis(30));
@@ -135,11 +171,11 @@ mod tests {
135171
acc.deposit(1_000, &bob_keypair).unwrap();
136172

137173
sleep(Duration::from_millis(30));
138-
let bob_pubkey = GenericArray::clone_from_slice(bob_keypair.public_key_bytes());
174+
let bob_pubkey = get_pubkey(&bob_keypair);
139175
acc.transfer(10_001, &alice_keypair, bob_pubkey).unwrap();
140176

141177
sleep(Duration::from_millis(30));
142-
let alice_pubkey = GenericArray::clone_from_slice(alice_keypair.public_key_bytes());
178+
let alice_pubkey = get_pubkey(&alice_keypair);
143179
assert_eq!(acc.get_balance(&alice_pubkey).unwrap(), 10_000);
144180
assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_000);
145181

@@ -151,14 +187,14 @@ mod tests {
151187
}
152188

153189
#[test]
154-
fn test_mulitple_claims() {
190+
fn test_multiple_claims() {
155191
let zero = Sha256Hash::default();
156192
let mut acc = Accountant::new(&zero, Some(2));
157193
let keypair = generate_keypair();
158194
acc.deposit(1, &keypair).unwrap();
159195
acc.deposit(2, &keypair).unwrap();
160196

161-
let pubkey = GenericArray::clone_from_slice(keypair.public_key_bytes());
197+
let pubkey = get_pubkey(&keypair);
162198
sleep(Duration::from_millis(30));
163199
assert_eq!(acc.get_balance(&pubkey).unwrap(), 3);
164200

@@ -178,7 +214,7 @@ mod tests {
178214
acc.deposit(10_000, &alice_keypair).unwrap();
179215

180216
sleep(Duration::from_millis(30));
181-
let bob_pubkey = GenericArray::clone_from_slice(bob_keypair.public_key_bytes());
217+
let bob_pubkey = get_pubkey(&bob_keypair);
182218
acc.transfer(500, &alice_keypair, bob_pubkey).unwrap();
183219

184220
sleep(Duration::from_millis(30));

src/accountant_skel.rs

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use std::io;
2+
use accountant::Accountant;
3+
use log::{PublicKey, Signature};
4+
//use serde::Serialize;
5+
6+
pub struct AccountantSkel {
7+
pub obj: Accountant,
8+
}
9+
10+
#[derive(Serialize, Deserialize, Debug)]
11+
pub enum Request {
12+
Deposit {
13+
key: PublicKey,
14+
val: u64,
15+
sig: Signature,
16+
},
17+
Transfer {
18+
from: PublicKey,
19+
to: PublicKey,
20+
val: u64,
21+
sig: Signature,
22+
},
23+
GetBalance {
24+
key: PublicKey,
25+
},
26+
}
27+
28+
#[derive(Serialize, Deserialize, Debug)]
29+
pub enum Response {
30+
Balance { key: PublicKey, val: u64 },
31+
}
32+
33+
impl AccountantSkel {
34+
pub fn new(obj: Accountant) -> Self {
35+
AccountantSkel { obj }
36+
}
37+
38+
pub fn process_request(self: &mut Self, msg: Request) -> Option<Response> {
39+
match msg {
40+
Request::Deposit { key, val, sig } => {
41+
let _ = self.obj.deposit_signed(key, val, sig);
42+
None
43+
}
44+
Request::Transfer { from, to, val, sig } => {
45+
let _ = self.obj.transfer_signed(from, to, val, sig);
46+
None
47+
}
48+
Request::GetBalance { key } => {
49+
let val = self.obj.get_balance(&key).unwrap();
50+
Some(Response::Balance { key, val })
51+
}
52+
}
53+
}
54+
55+
/// TCP Server that forwards messages to Accountant methods.
56+
pub fn serve(self: &mut Self, addr: &str) -> io::Result<()> {
57+
use std::net::TcpListener;
58+
use std::io::{Read, Write};
59+
use bincode::{deserialize, serialize};
60+
let listener = TcpListener::bind(addr)?;
61+
let mut buf = vec![0u8; 1024];
62+
loop {
63+
//println!("skel: Waiting for incoming connections...");
64+
let (mut stream, _from_addr) = listener.accept()?;
65+
let _sz = stream.read(&mut buf)?;
66+
67+
// TODO: Return a descriptive error message if deserialization fails.
68+
let req = deserialize(&buf).expect("deserialize request");
69+
70+
if let Some(resp) = self.process_request(req) {
71+
stream.write(&serialize(&resp).expect("serialize response"))?;
72+
}
73+
}
74+
}
75+
}

src/accountant_stub.rs

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//! The `accountant` is a client of the `historian`. It uses the historian's
2+
//! event log to record transactions. Its users can deposit funds and
3+
//! transfer funds to other users.
4+
5+
use std::net::TcpStream;
6+
use std::io;
7+
use std::io::{Read, Write};
8+
use bincode::{deserialize, serialize};
9+
use log::{PublicKey, Signature};
10+
use ring::signature::Ed25519KeyPair;
11+
use accountant_skel::{Request, Response};
12+
13+
pub struct AccountantStub {
14+
pub addr: String,
15+
}
16+
17+
impl AccountantStub {
18+
pub fn new(addr: &str) -> Self {
19+
AccountantStub {
20+
addr: addr.to_string(),
21+
}
22+
}
23+
24+
pub fn deposit_signed(
25+
self: &mut Self,
26+
key: PublicKey,
27+
val: u64,
28+
sig: Signature,
29+
) -> io::Result<usize> {
30+
let req = Request::Deposit { key, val, sig };
31+
let data = serialize(&req).unwrap();
32+
let mut stream = TcpStream::connect(&self.addr)?;
33+
stream.write(&data)
34+
}
35+
36+
pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> io::Result<usize> {
37+
use log::{get_pubkey, sign_serialized};
38+
let key = get_pubkey(keypair);
39+
let sig = sign_serialized(&n, keypair);
40+
self.deposit_signed(key, n, sig)
41+
}
42+
43+
pub fn transfer_signed(
44+
self: &mut Self,
45+
from: PublicKey,
46+
to: PublicKey,
47+
val: u64,
48+
sig: Signature,
49+
) -> io::Result<usize> {
50+
let req = Request::Transfer { from, to, val, sig };
51+
let data = serialize(&req).unwrap();
52+
let mut stream = TcpStream::connect(&self.addr)?;
53+
stream.write(&data)
54+
}
55+
56+
pub fn transfer(
57+
self: &mut Self,
58+
n: u64,
59+
keypair: &Ed25519KeyPair,
60+
to: PublicKey,
61+
) -> io::Result<usize> {
62+
use log::{get_pubkey, sign_transaction_data};
63+
let from = get_pubkey(keypair);
64+
let sig = sign_transaction_data(&n, keypair, &to);
65+
self.transfer_signed(from, to, n, sig)
66+
}
67+
68+
pub fn get_balance(self: &mut Self, pubkey: &PublicKey) -> io::Result<u64> {
69+
let mut stream = TcpStream::connect(&self.addr)?;
70+
let req = Request::GetBalance { key: *pubkey };
71+
let data = serialize(&req).expect("serialize GetBalance");
72+
stream.write(&data)?;
73+
let mut buf = vec![0u8; 1024];
74+
stream.read(&mut buf)?;
75+
let resp = deserialize(&buf).expect("deserialize balance");
76+
let Response::Balance { key, val } = resp;
77+
assert_eq!(key, *pubkey);
78+
Ok(val)
79+
}
80+
}
81+
82+
#[cfg(test)]
83+
mod tests {
84+
use super::*;
85+
use accountant::Accountant;
86+
use accountant_skel::AccountantSkel;
87+
use std::thread::{sleep, spawn};
88+
use std::time::Duration;
89+
use log::{generate_keypair, get_pubkey, Sha256Hash};
90+
91+
#[test]
92+
fn test_accountant_stub() {
93+
let addr = "127.0.0.1:8000";
94+
spawn(move || {
95+
let zero = Sha256Hash::default();
96+
let acc = Accountant::new(&zero, None);
97+
let mut skel = AccountantSkel::new(acc);
98+
skel.serve(addr).unwrap();
99+
});
100+
101+
sleep(Duration::from_millis(30));
102+
103+
let mut acc = AccountantStub::new(addr);
104+
let alice_keypair = generate_keypair();
105+
let bob_keypair = generate_keypair();
106+
acc.deposit(10_000, &alice_keypair).unwrap();
107+
acc.deposit(1_000, &bob_keypair).unwrap();
108+
109+
sleep(Duration::from_millis(30));
110+
let bob_pubkey = get_pubkey(&bob_keypair);
111+
acc.transfer(500, &alice_keypair, bob_pubkey).unwrap();
112+
113+
sleep(Duration::from_millis(300));
114+
assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_500);
115+
}
116+
}

0 commit comments

Comments
 (0)