Transactions now require a hash of the last entry they've seen
This ensures the transaction cannot be processed on a chain that forked before that ID. It will also provide a basis for expiration constraints. A client may want their transaction to expire, and the generators may want to reject transactions that have been floating in the ether for years.
This commit is contained in:
@ -2,7 +2,7 @@
|
|||||||
//! event log to record transactions. Its users can deposit funds and
|
//! event log to record transactions. Its users can deposit funds and
|
||||||
//! transfer funds to other users.
|
//! transfer funds to other users.
|
||||||
|
|
||||||
use log::{hash, Entry, Sha256Hash};
|
use log::Sha256Hash;
|
||||||
use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature};
|
use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature};
|
||||||
use genesis::Genesis;
|
use genesis::Genesis;
|
||||||
use historian::{reserve_signature, Historian};
|
use historian::{reserve_signature, Historian};
|
||||||
@ -23,16 +23,18 @@ pub type Result<T> = result::Result<T, AccountingError>;
|
|||||||
pub struct Accountant {
|
pub struct Accountant {
|
||||||
pub historian: Historian<u64>,
|
pub historian: Historian<u64>,
|
||||||
pub balances: HashMap<PublicKey, u64>,
|
pub balances: HashMap<PublicKey, u64>,
|
||||||
|
pub first_id: Sha256Hash,
|
||||||
pub last_id: Sha256Hash,
|
pub last_id: Sha256Hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Accountant {
|
impl Accountant {
|
||||||
pub fn new(gen: &Genesis, ms_per_tick: Option<u64>) -> Self {
|
pub fn new(gen: &Genesis, ms_per_tick: Option<u64>) -> Self {
|
||||||
let start_hash = hash(&gen.pkcs8);
|
let start_hash = gen.get_seed();
|
||||||
let hist = Historian::<u64>::new(&start_hash, ms_per_tick);
|
let hist = Historian::<u64>::new(&start_hash, ms_per_tick);
|
||||||
let mut acc = Accountant {
|
let mut acc = Accountant {
|
||||||
historian: hist,
|
historian: hist,
|
||||||
balances: HashMap::new(),
|
balances: HashMap::new(),
|
||||||
|
first_id: start_hash,
|
||||||
last_id: start_hash,
|
last_id: start_hash,
|
||||||
};
|
};
|
||||||
for (i, event) in gen.create_events().iter().enumerate() {
|
for (i, event) in gen.create_events().iter().enumerate() {
|
||||||
@ -41,17 +43,11 @@ impl Accountant {
|
|||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sync(self: &mut Self) -> Vec<Entry<u64>> {
|
pub fn sync(self: &mut Self) -> Sha256Hash {
|
||||||
let mut entries = vec![];
|
|
||||||
while let Ok(entry) = self.historian.receiver.try_recv() {
|
while let Ok(entry) = self.historian.receiver.try_recv() {
|
||||||
entries.push(entry);
|
self.last_id = entry.id;
|
||||||
}
|
}
|
||||||
|
self.last_id
|
||||||
if let Some(last_entry) = entries.last() {
|
|
||||||
self.last_id = last_entry.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
entries
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_deposit(allow_deposits: bool, from: &PublicKey, to: &PublicKey) -> bool {
|
fn is_deposit(allow_deposits: bool, from: &PublicKey, to: &PublicKey) -> bool {
|
||||||
@ -112,11 +108,13 @@ impl Accountant {
|
|||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
) -> Result<Signature> {
|
) -> Result<Signature> {
|
||||||
let from = get_pubkey(keypair);
|
let from = get_pubkey(keypair);
|
||||||
let sig = sign_transaction_data(&n, keypair, &to);
|
let last_id = self.last_id;
|
||||||
|
let sig = sign_transaction_data(&n, keypair, &to, &last_id);
|
||||||
let event = Event::Transaction {
|
let event = Event::Transaction {
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
data: n,
|
data: n,
|
||||||
|
last_id,
|
||||||
sig,
|
sig,
|
||||||
};
|
};
|
||||||
self.process_event(event).map(|_| sig)
|
self.process_event(event).map(|_| sig)
|
||||||
|
@ -6,7 +6,7 @@ use std::net::UdpSocket;
|
|||||||
use bincode::{deserialize, serialize};
|
use bincode::{deserialize, serialize};
|
||||||
|
|
||||||
pub struct AccountantSkel {
|
pub struct AccountantSkel {
|
||||||
pub obj: Accountant,
|
pub acc: Accountant,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@ -15,47 +15,67 @@ pub enum Request {
|
|||||||
from: PublicKey,
|
from: PublicKey,
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
val: u64,
|
val: u64,
|
||||||
|
last_id: Sha256Hash,
|
||||||
sig: Signature,
|
sig: Signature,
|
||||||
},
|
},
|
||||||
GetBalance {
|
GetBalance {
|
||||||
key: PublicKey,
|
key: PublicKey,
|
||||||
},
|
},
|
||||||
GetEntries {
|
GetEntries {
|
||||||
last_id: Option<Sha256Hash>,
|
last_id: Sha256Hash,
|
||||||
|
},
|
||||||
|
GetId {
|
||||||
|
is_last: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
Balance { key: PublicKey, val: u64 },
|
Balance { key: PublicKey, val: u64 },
|
||||||
Confirmed { sig: Signature },
|
|
||||||
Entries { entries: Vec<Entry<u64>> },
|
Entries { entries: Vec<Entry<u64>> },
|
||||||
|
Id { id: Sha256Hash, is_last: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AccountantSkel {
|
impl AccountantSkel {
|
||||||
pub fn new(obj: Accountant) -> Self {
|
pub fn new(acc: Accountant) -> Self {
|
||||||
AccountantSkel { obj }
|
AccountantSkel { acc }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_request(self: &mut Self, msg: Request) -> Option<Response> {
|
pub fn process_request(self: &mut Self, msg: Request) -> Option<Response> {
|
||||||
match msg {
|
match msg {
|
||||||
Request::Transfer { from, to, val, sig } => {
|
Request::Transfer {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
val,
|
||||||
|
last_id,
|
||||||
|
sig,
|
||||||
|
} => {
|
||||||
let event = Event::Transaction {
|
let event = Event::Transaction {
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
data: val,
|
data: val,
|
||||||
|
last_id,
|
||||||
sig,
|
sig,
|
||||||
};
|
};
|
||||||
if let Err(err) = self.obj.process_event(event) {
|
if let Err(err) = self.acc.process_event(event) {
|
||||||
println!("Transfer error: {:?}", err);
|
println!("Transfer error: {:?}", err);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Request::GetBalance { key } => {
|
Request::GetBalance { key } => {
|
||||||
let val = self.obj.get_balance(&key).unwrap();
|
let val = self.acc.get_balance(&key).unwrap();
|
||||||
Some(Response::Balance { key, val })
|
Some(Response::Balance { key, val })
|
||||||
}
|
}
|
||||||
Request::GetEntries { .. } => Some(Response::Entries { entries: vec![] }),
|
Request::GetEntries { .. } => Some(Response::Entries { entries: vec![] }),
|
||||||
|
Request::GetId { is_last } => Some(Response::Id {
|
||||||
|
id: if is_last {
|
||||||
|
self.acc.sync();
|
||||||
|
self.acc.last_id
|
||||||
|
} else {
|
||||||
|
self.acc.first_id
|
||||||
|
},
|
||||||
|
is_last,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,9 +30,16 @@ impl AccountantStub {
|
|||||||
from: PublicKey,
|
from: PublicKey,
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
val: u64,
|
val: u64,
|
||||||
|
last_id: Sha256Hash,
|
||||||
sig: Signature,
|
sig: Signature,
|
||||||
) -> io::Result<usize> {
|
) -> io::Result<usize> {
|
||||||
let req = Request::Transfer { from, to, val, sig };
|
let req = Request::Transfer {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
val,
|
||||||
|
last_id,
|
||||||
|
sig,
|
||||||
|
};
|
||||||
let data = serialize(&req).unwrap();
|
let data = serialize(&req).unwrap();
|
||||||
self.socket.send_to(&data, &self.addr)
|
self.socket.send_to(&data, &self.addr)
|
||||||
}
|
}
|
||||||
@ -42,10 +49,12 @@ impl AccountantStub {
|
|||||||
n: u64,
|
n: u64,
|
||||||
keypair: &Ed25519KeyPair,
|
keypair: &Ed25519KeyPair,
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
|
last_id: &Sha256Hash,
|
||||||
) -> io::Result<Signature> {
|
) -> io::Result<Signature> {
|
||||||
let from = get_pubkey(keypair);
|
let from = get_pubkey(keypair);
|
||||||
let sig = sign_transaction_data(&n, keypair, &to);
|
let sig = sign_transaction_data(&n, keypair, &to, last_id);
|
||||||
self.transfer_signed(from, to, n, sig).map(|_| sig)
|
self.transfer_signed(from, to, n, *last_id, sig)
|
||||||
|
.map(|_| sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_balance(&self, pubkey: &PublicKey) -> io::Result<u64> {
|
pub fn get_balance(&self, pubkey: &PublicKey) -> io::Result<u64> {
|
||||||
@ -62,10 +71,34 @@ impl AccountantStub {
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_id(&self, is_last: bool) -> io::Result<Sha256Hash> {
|
||||||
|
let req = Request::GetId { is_last };
|
||||||
|
let data = serialize(&req).expect("serialize GetId");
|
||||||
|
self.socket.send_to(&data, &self.addr)?;
|
||||||
|
let mut buf = vec![0u8; 1024];
|
||||||
|
self.socket.recv_from(&mut buf)?;
|
||||||
|
let resp = deserialize(&buf).expect("deserialize Id");
|
||||||
|
if let Response::Id { id, .. } = resp {
|
||||||
|
return Ok(id);
|
||||||
|
}
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_last_id(&self) -> io::Result<Sha256Hash> {
|
||||||
|
self.get_id(true)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn wait_on_signature(&mut self, wait_sig: &Signature) -> io::Result<()> {
|
pub fn wait_on_signature(&mut self, wait_sig: &Signature) -> io::Result<()> {
|
||||||
let req = Request::GetEntries {
|
let last_id = match self.last_id {
|
||||||
last_id: self.last_id,
|
None => {
|
||||||
|
let first_id = self.get_id(false)?;
|
||||||
|
self.last_id = Some(first_id);
|
||||||
|
first_id
|
||||||
|
}
|
||||||
|
Some(last_id) => last_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let req = Request::GetEntries { last_id };
|
||||||
let data = serialize(&req).unwrap();
|
let data = serialize(&req).unwrap();
|
||||||
self.socket.send_to(&data, &self.addr).map(|_| ())?;
|
self.socket.send_to(&data, &self.addr).map(|_| ())?;
|
||||||
|
|
||||||
@ -110,7 +143,9 @@ mod tests {
|
|||||||
|
|
||||||
let socket = UdpSocket::bind(send_addr).unwrap();
|
let socket = UdpSocket::bind(send_addr).unwrap();
|
||||||
let mut acc = AccountantStub::new(addr, socket);
|
let mut acc = AccountantStub::new(addr, socket);
|
||||||
let sig = acc.transfer(500, &alice.get_keypair(), bob_pubkey).unwrap();
|
let last_id = acc.get_last_id().unwrap();
|
||||||
|
let sig = acc.transfer(500, &alice.get_keypair(), bob_pubkey, &last_id)
|
||||||
|
.unwrap();
|
||||||
acc.wait_on_signature(&sig).unwrap();
|
acc.wait_on_signature(&sig).unwrap();
|
||||||
assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_500);
|
assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_500);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ fn main() {
|
|||||||
|
|
||||||
let socket = UdpSocket::bind(send_addr).unwrap();
|
let socket = UdpSocket::bind(send_addr).unwrap();
|
||||||
let mut acc = AccountantStub::new(addr, socket);
|
let mut acc = AccountantStub::new(addr, socket);
|
||||||
|
let last_id = acc.get_last_id().unwrap();
|
||||||
let alice_pubkey = get_pubkey(&alice_keypair);
|
let alice_pubkey = get_pubkey(&alice_keypair);
|
||||||
let one = 1;
|
let one = 1;
|
||||||
println!("Signing transactions...");
|
println!("Signing transactions...");
|
||||||
@ -37,7 +38,7 @@ fn main() {
|
|||||||
.map(|_| {
|
.map(|_| {
|
||||||
let rando_keypair = generate_keypair();
|
let rando_keypair = generate_keypair();
|
||||||
let rando_pubkey = get_pubkey(&rando_keypair);
|
let rando_pubkey = get_pubkey(&rando_keypair);
|
||||||
let sig = sign_transaction_data(&one, &alice_keypair, &rando_pubkey);
|
let sig = sign_transaction_data(&one, &alice_keypair, &rando_pubkey, &last_id);
|
||||||
(rando_pubkey, sig)
|
(rando_pubkey, sig)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@ -58,6 +59,7 @@ fn main() {
|
|||||||
from: alice_pubkey,
|
from: alice_pubkey,
|
||||||
to: k,
|
to: k,
|
||||||
data: one,
|
data: one,
|
||||||
|
last_id,
|
||||||
sig: s,
|
sig: s,
|
||||||
};
|
};
|
||||||
assert!(verify_event(&e));
|
assert!(verify_event(&e));
|
||||||
@ -76,7 +78,8 @@ fn main() {
|
|||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let mut sig = Default::default();
|
let mut sig = Default::default();
|
||||||
for (k, s) in sigs {
|
for (k, s) in sigs {
|
||||||
acc.transfer_signed(alice_pubkey, k, one, s).unwrap();
|
acc.transfer_signed(alice_pubkey, k, one, last_id, s)
|
||||||
|
.unwrap();
|
||||||
sig = s;
|
sig = s;
|
||||||
}
|
}
|
||||||
println!("Waiting for last transaction to be confirmed...",);
|
println!("Waiting for last transaction to be confirmed...",);
|
||||||
|
@ -7,11 +7,19 @@ use std::thread::sleep;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::sync::mpsc::SendError;
|
use std::sync::mpsc::SendError;
|
||||||
|
|
||||||
fn create_log(hist: &Historian<Sha256Hash>) -> Result<(), SendError<Event<Sha256Hash>>> {
|
fn create_log(
|
||||||
|
hist: &Historian<Sha256Hash>,
|
||||||
|
seed: &Sha256Hash,
|
||||||
|
) -> Result<(), SendError<Event<Sha256Hash>>> {
|
||||||
sleep(Duration::from_millis(15));
|
sleep(Duration::from_millis(15));
|
||||||
let data = Sha256Hash::default();
|
let data = Sha256Hash::default();
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let event0 = Event::new_claim(get_pubkey(&keypair), data, sign_claim_data(&data, &keypair));
|
let event0 = Event::new_claim(
|
||||||
|
get_pubkey(&keypair),
|
||||||
|
data,
|
||||||
|
*seed,
|
||||||
|
sign_claim_data(&data, &keypair, seed),
|
||||||
|
);
|
||||||
hist.sender.send(event0)?;
|
hist.sender.send(event0)?;
|
||||||
sleep(Duration::from_millis(10));
|
sleep(Duration::from_millis(10));
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -20,7 +28,7 @@ fn create_log(hist: &Historian<Sha256Hash>) -> Result<(), SendError<Event<Sha256
|
|||||||
fn main() {
|
fn main() {
|
||||||
let seed = Sha256Hash::default();
|
let seed = Sha256Hash::default();
|
||||||
let hist = Historian::new(&seed, Some(10));
|
let hist = Historian::new(&seed, Some(10));
|
||||||
create_log(&hist).expect("send error");
|
create_log(&hist, &seed).expect("send error");
|
||||||
drop(hist.sender);
|
drop(hist.sender);
|
||||||
let entries: Vec<Entry<Sha256Hash>> = hist.receiver.iter().collect();
|
let entries: Vec<Entry<Sha256Hash>> = hist.receiver.iter().collect();
|
||||||
for entry in &entries {
|
for entry in &entries {
|
||||||
|
26
src/event.rs
26
src/event.rs
@ -20,6 +20,7 @@ use ring::{rand, signature};
|
|||||||
use untrusted;
|
use untrusted;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
|
use log::Sha256Hash;
|
||||||
|
|
||||||
pub type PublicKey = GenericArray<u8, U32>;
|
pub type PublicKey = GenericArray<u8, U32>;
|
||||||
pub type Signature = GenericArray<u8, U64>;
|
pub type Signature = GenericArray<u8, U64>;
|
||||||
@ -36,16 +37,18 @@ pub enum Event<T> {
|
|||||||
from: PublicKey,
|
from: PublicKey,
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
data: T,
|
data: T,
|
||||||
|
last_id: Sha256Hash,
|
||||||
sig: Signature,
|
sig: Signature,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Event<T> {
|
impl<T> Event<T> {
|
||||||
pub fn new_claim(to: PublicKey, data: T, sig: Signature) -> Self {
|
pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self {
|
||||||
Event::Transaction {
|
Event::Transaction {
|
||||||
from: to,
|
from: to,
|
||||||
to,
|
to,
|
||||||
data,
|
data,
|
||||||
|
last_id,
|
||||||
sig,
|
sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,14 +77,19 @@ pub fn sign_transaction_data<T: Serialize>(
|
|||||||
data: &T,
|
data: &T,
|
||||||
keypair: &Ed25519KeyPair,
|
keypair: &Ed25519KeyPair,
|
||||||
to: &PublicKey,
|
to: &PublicKey,
|
||||||
|
last_id: &Sha256Hash,
|
||||||
) -> Signature {
|
) -> Signature {
|
||||||
let from = &get_pubkey(keypair);
|
let from = &get_pubkey(keypair);
|
||||||
sign_serialized(&(from, to, data), keypair)
|
sign_serialized(&(from, to, data, last_id), keypair)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a signature for the given data using the private key from the given keypair.
|
/// Return a signature for the given data using the private key from the given keypair.
|
||||||
pub fn sign_claim_data<T: Serialize>(data: &T, keypair: &Ed25519KeyPair) -> Signature {
|
pub fn sign_claim_data<T: Serialize>(
|
||||||
sign_transaction_data(data, keypair, &get_pubkey(keypair))
|
data: &T,
|
||||||
|
keypair: &Ed25519KeyPair,
|
||||||
|
last_id: &Sha256Hash,
|
||||||
|
) -> Signature {
|
||||||
|
sign_transaction_data(data, keypair, &get_pubkey(keypair), last_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a signed message with the given public key.
|
/// Verify a signed message with the given public key.
|
||||||
@ -104,10 +112,11 @@ pub fn verify_event<T: Serialize>(event: &Event<T>) -> bool {
|
|||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
ref data,
|
ref data,
|
||||||
|
last_id,
|
||||||
sig,
|
sig,
|
||||||
} = *event
|
} = *event
|
||||||
{
|
{
|
||||||
let sign_data = serialize(&(&from, &to, &data)).unwrap();
|
let sign_data = serialize(&(&from, &to, &data, &last_id)).unwrap();
|
||||||
if !verify_signature(&from, &sign_data, &sig) {
|
if !verify_signature(&from, &sign_data, &sig) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -122,7 +131,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_claim() {
|
fn test_serialize_claim() {
|
||||||
let claim0 = Event::new_claim(Default::default(), 0u8, Default::default());
|
let claim0 = Event::new_claim(
|
||||||
|
Default::default(),
|
||||||
|
0u8,
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
);
|
||||||
let buf = serialize(&claim0).unwrap();
|
let buf = serialize(&claim0).unwrap();
|
||||||
let claim1: Event<u8> = deserialize(&buf).unwrap();
|
let claim1: Event<u8> = deserialize(&buf).unwrap();
|
||||||
assert_eq!(claim1, claim0);
|
assert_eq!(claim1, claim0);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! A library for generating the chain's genesis block.
|
//! A library for generating the chain's genesis block.
|
||||||
|
|
||||||
use event::{generate_keypair, get_pubkey, sign_transaction_data, Event, PublicKey};
|
use event::{generate_keypair, get_pubkey, sign_transaction_data, Event, PublicKey};
|
||||||
|
use log::{hash, Sha256Hash};
|
||||||
use ring::rand::SystemRandom;
|
use ring::rand::SystemRandom;
|
||||||
use ring::signature::Ed25519KeyPair;
|
use ring::signature::Ed25519KeyPair;
|
||||||
use untrusted::Input;
|
use untrusted::Input;
|
||||||
@ -38,6 +39,10 @@ impl Genesis {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_seed(&self) -> Sha256Hash {
|
||||||
|
hash(&self.pkcs8)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_keypair(&self) -> Ed25519KeyPair {
|
pub fn get_keypair(&self) -> Ed25519KeyPair {
|
||||||
Ed25519KeyPair::from_pkcs8(Input::from(&self.pkcs8)).unwrap()
|
Ed25519KeyPair::from_pkcs8(Input::from(&self.pkcs8)).unwrap()
|
||||||
}
|
}
|
||||||
@ -47,12 +52,14 @@ impl Genesis {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_transaction(&self, data: u64, to: &PublicKey) -> Event<u64> {
|
pub fn create_transaction(&self, data: u64, to: &PublicKey) -> Event<u64> {
|
||||||
|
let last_id = self.get_seed();
|
||||||
let from = self.get_pubkey();
|
let from = self.get_pubkey();
|
||||||
let sig = sign_transaction_data(&data, &self.get_keypair(), to);
|
let sig = sign_transaction_data(&data, &self.get_keypair(), to, &last_id);
|
||||||
Event::Transaction {
|
Event::Transaction {
|
||||||
from,
|
from,
|
||||||
to: *to,
|
to: *to,
|
||||||
data,
|
data,
|
||||||
|
last_id,
|
||||||
sig,
|
sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,8 +114,9 @@ mod tests {
|
|||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let to = get_pubkey(&keypair);
|
let to = get_pubkey(&keypair);
|
||||||
let data = b"hello, world";
|
let data = b"hello, world";
|
||||||
let sig = sign_claim_data(&data, &keypair);
|
let zero = Sha256Hash::default();
|
||||||
let event0 = Event::new_claim(to, &data, sig);
|
let sig = sign_claim_data(&data, &keypair, &zero);
|
||||||
|
let event0 = Event::new_claim(to, &data, zero, sig);
|
||||||
let mut sigs = HashSet::new();
|
let mut sigs = HashSet::new();
|
||||||
assert!(reserve_signature(&mut sigs, &event0));
|
assert!(reserve_signature(&mut sigs, &event0));
|
||||||
assert!(!reserve_signature(&mut sigs, &event0));
|
assert!(!reserve_signature(&mut sigs, &event0));
|
||||||
|
41
src/log.rs
41
src/log.rs
@ -217,8 +217,18 @@ mod tests {
|
|||||||
|
|
||||||
// First, verify entries
|
// First, verify entries
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let event0 = Event::new_claim(get_pubkey(&keypair), zero, sign_claim_data(&zero, &keypair));
|
let event0 = Event::new_claim(
|
||||||
let event1 = Event::new_claim(get_pubkey(&keypair), one, sign_claim_data(&one, &keypair));
|
get_pubkey(&keypair),
|
||||||
|
zero,
|
||||||
|
zero,
|
||||||
|
sign_claim_data(&zero, &keypair, &zero),
|
||||||
|
);
|
||||||
|
let event1 = Event::new_claim(
|
||||||
|
get_pubkey(&keypair),
|
||||||
|
one,
|
||||||
|
zero,
|
||||||
|
sign_claim_data(&one, &keypair, &zero),
|
||||||
|
);
|
||||||
let events = vec![event0, event1];
|
let events = vec![event0, event1];
|
||||||
let mut entries = create_entries(&zero, events);
|
let mut entries = create_entries(&zero, events);
|
||||||
assert!(verify_slice(&entries, &zero));
|
assert!(verify_slice(&entries, &zero));
|
||||||
@ -235,8 +245,13 @@ mod tests {
|
|||||||
fn test_claim() {
|
fn test_claim() {
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let data = hash(b"hello, world");
|
let data = hash(b"hello, world");
|
||||||
let event0 = Event::new_claim(get_pubkey(&keypair), data, sign_claim_data(&data, &keypair));
|
|
||||||
let zero = Sha256Hash::default();
|
let zero = Sha256Hash::default();
|
||||||
|
let event0 = Event::new_claim(
|
||||||
|
get_pubkey(&keypair),
|
||||||
|
data,
|
||||||
|
zero,
|
||||||
|
sign_claim_data(&data, &keypair, &zero),
|
||||||
|
);
|
||||||
let entries = create_entries(&zero, vec![event0]);
|
let entries = create_entries(&zero, vec![event0]);
|
||||||
assert!(verify_slice(&entries, &zero));
|
assert!(verify_slice(&entries, &zero));
|
||||||
}
|
}
|
||||||
@ -244,18 +259,20 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_wrong_data_claim_attack() {
|
fn test_wrong_data_claim_attack() {
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
|
let zero = Sha256Hash::default();
|
||||||
let event0 = Event::new_claim(
|
let event0 = Event::new_claim(
|
||||||
get_pubkey(&keypair),
|
get_pubkey(&keypair),
|
||||||
hash(b"goodbye cruel world"),
|
hash(b"goodbye cruel world"),
|
||||||
sign_claim_data(&hash(b"hello, world"), &keypair),
|
zero,
|
||||||
|
sign_claim_data(&hash(b"hello, world"), &keypair, &zero),
|
||||||
);
|
);
|
||||||
let zero = Sha256Hash::default();
|
|
||||||
let entries = create_entries(&zero, vec![event0]);
|
let entries = create_entries(&zero, vec![event0]);
|
||||||
assert!(!verify_slice(&entries, &zero));
|
assert!(!verify_slice(&entries, &zero));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transfer() {
|
fn test_transfer() {
|
||||||
|
let zero = Sha256Hash::default();
|
||||||
let keypair0 = generate_keypair();
|
let keypair0 = generate_keypair();
|
||||||
let keypair1 = generate_keypair();
|
let keypair1 = generate_keypair();
|
||||||
let pubkey1 = get_pubkey(&keypair1);
|
let pubkey1 = get_pubkey(&keypair1);
|
||||||
@ -264,9 +281,9 @@ mod tests {
|
|||||||
from: get_pubkey(&keypair0),
|
from: get_pubkey(&keypair0),
|
||||||
to: pubkey1,
|
to: pubkey1,
|
||||||
data,
|
data,
|
||||||
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
last_id: zero,
|
||||||
|
sig: sign_transaction_data(&data, &keypair0, &pubkey1, &zero),
|
||||||
};
|
};
|
||||||
let zero = Sha256Hash::default();
|
|
||||||
let entries = create_entries(&zero, vec![event0]);
|
let entries = create_entries(&zero, vec![event0]);
|
||||||
assert!(verify_slice(&entries, &zero));
|
assert!(verify_slice(&entries, &zero));
|
||||||
}
|
}
|
||||||
@ -277,13 +294,14 @@ mod tests {
|
|||||||
let keypair1 = generate_keypair();
|
let keypair1 = generate_keypair();
|
||||||
let pubkey1 = get_pubkey(&keypair1);
|
let pubkey1 = get_pubkey(&keypair1);
|
||||||
let data = hash(b"hello, world");
|
let data = hash(b"hello, world");
|
||||||
|
let zero = Sha256Hash::default();
|
||||||
let event0 = Event::Transaction {
|
let event0 = Event::Transaction {
|
||||||
from: get_pubkey(&keypair0),
|
from: get_pubkey(&keypair0),
|
||||||
to: pubkey1,
|
to: pubkey1,
|
||||||
data: hash(b"goodbye cruel world"), // <-- attack!
|
data: hash(b"goodbye cruel world"), // <-- attack!
|
||||||
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
last_id: zero,
|
||||||
|
sig: sign_transaction_data(&data, &keypair0, &pubkey1, &zero),
|
||||||
};
|
};
|
||||||
let zero = Sha256Hash::default();
|
|
||||||
let entries = create_entries(&zero, vec![event0]);
|
let entries = create_entries(&zero, vec![event0]);
|
||||||
assert!(!verify_slice(&entries, &zero));
|
assert!(!verify_slice(&entries, &zero));
|
||||||
}
|
}
|
||||||
@ -295,13 +313,14 @@ mod tests {
|
|||||||
let thief_keypair = generate_keypair();
|
let thief_keypair = generate_keypair();
|
||||||
let pubkey1 = get_pubkey(&keypair1);
|
let pubkey1 = get_pubkey(&keypair1);
|
||||||
let data = hash(b"hello, world");
|
let data = hash(b"hello, world");
|
||||||
|
let zero = Sha256Hash::default();
|
||||||
let event0 = Event::Transaction {
|
let event0 = Event::Transaction {
|
||||||
from: get_pubkey(&keypair0),
|
from: get_pubkey(&keypair0),
|
||||||
to: get_pubkey(&thief_keypair), // <-- attack!
|
to: get_pubkey(&thief_keypair), // <-- attack!
|
||||||
data: hash(b"goodbye cruel world"),
|
data: hash(b"goodbye cruel world"),
|
||||||
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
last_id: zero,
|
||||||
|
sig: sign_transaction_data(&data, &keypair0, &pubkey1, &zero),
|
||||||
};
|
};
|
||||||
let zero = Sha256Hash::default();
|
|
||||||
let entries = create_entries(&zero, vec![event0]);
|
let entries = create_entries(&zero, vec![event0]);
|
||||||
assert!(!verify_slice(&entries, &zero));
|
assert!(!verify_slice(&entries, &zero));
|
||||||
}
|
}
|
||||||
|
@ -83,16 +83,22 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bad_event_signature() {
|
fn test_bad_event_signature() {
|
||||||
|
let zero = Sha256Hash::default();
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let sig = sign_claim_data(&hash(b"hello, world"), &keypair);
|
let sig = sign_claim_data(&hash(b"hello, world"), &keypair, &zero);
|
||||||
let event0 = Event::new_claim(get_pubkey(&keypair), hash(b"goodbye cruel world"), sig);
|
let event0 = Event::new_claim(
|
||||||
|
get_pubkey(&keypair),
|
||||||
|
hash(b"goodbye cruel world"),
|
||||||
|
zero,
|
||||||
|
sig,
|
||||||
|
);
|
||||||
assert!(!verify_event(&event0));
|
assert!(!verify_event(&event0));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_genesis(gen: Genesis) -> Vec<Entry<u64>> {
|
fn run_genesis(gen: Genesis) -> Vec<Entry<u64>> {
|
||||||
let (sender, event_receiver) = sync_channel(100);
|
let (sender, event_receiver) = sync_channel(100);
|
||||||
let (entry_sender, receiver) = sync_channel(100);
|
let (entry_sender, receiver) = sync_channel(100);
|
||||||
let mut logger = Logger::new(event_receiver, entry_sender, hash(&gen.pkcs8));
|
let mut logger = Logger::new(event_receiver, entry_sender, gen.get_seed());
|
||||||
for tx in gen.create_events() {
|
for tx in gen.create_events() {
|
||||||
sender.send(tx).unwrap();
|
sender.send(tx).unwrap();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user