Boot genesis block helper

Before this change, if you wanted to use a new Transaction
feature in the genesis block, you'd need to extend its
Creator object and associated methods.  With yesterday's
addtions to Transcation, it's now so easy to work with
Transactions directly that we can get rid of the middleman.

Also added a KeyPair type alias, so that ring could be easily swapped
out with a competing library, if needed.
This commit is contained in:
Greg Fitzgerald 2018-03-07 11:05:06 -07:00
parent 54340ed4c6
commit 9834c251d0
6 changed files with 61 additions and 98 deletions

View File

@ -6,10 +6,9 @@ use hash::Hash;
use entry::Entry;
use event::Event;
use transaction::Transaction;
use signature::{PublicKey, Signature};
use signature::{KeyPair, PublicKey, Signature};
use genesis::Genesis;
use historian::{reserve_signature, Historian};
use ring::signature::Ed25519KeyPair;
use std::sync::mpsc::SendError;
use std::collections::HashMap;
use std::result;
@ -131,7 +130,7 @@ impl Accountant {
pub fn transfer(
self: &mut Self,
n: i64,
keypair: &Ed25519KeyPair,
keypair: &KeyPair,
to: PublicKey,
) -> Result<Signature> {
let tr = Transaction::new(keypair, to, n, self.last_id);
@ -149,14 +148,15 @@ mod tests {
use super::*;
use signature::{generate_keypair, get_pubkey};
use logger::ExitReason;
use genesis::Creator;
#[test]
fn test_accountant() {
let bob = Creator::new(1_000);
let bob_pubkey = bob.pubkey;
let alice = Genesis::new(10_000, vec![bob]);
let alice = Genesis::new(10_000);
let bob_pubkey = get_pubkey(&generate_keypair());
let mut acc = Accountant::new(&alice, Some(2));
acc.transfer(1_000, &alice.get_keypair(), bob_pubkey)
.unwrap();
assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_000);
acc.transfer(500, &alice.get_keypair(), bob_pubkey).unwrap();
assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_500);
@ -170,10 +170,11 @@ mod tests {
#[test]
fn test_invalid_transfer() {
let bob = Creator::new(1_000);
let bob_pubkey = bob.pubkey;
let alice = Genesis::new(11_000, vec![bob]);
let alice = Genesis::new(11_000);
let mut acc = Accountant::new(&alice, Some(2));
let bob_pubkey = get_pubkey(&generate_keypair());
acc.transfer(1_000, &alice.get_keypair(), bob_pubkey)
.unwrap();
assert_eq!(
acc.transfer(10_001, &alice.get_keypair(), bob_pubkey),
Err(AccountingError::InsufficientFunds)
@ -192,11 +193,10 @@ mod tests {
#[test]
fn test_transfer_to_newb() {
let alice = Genesis::new(10_000, vec![]);
let alice = Genesis::new(10_000);
let mut acc = Accountant::new(&alice, Some(2));
let alice_keypair = alice.get_keypair();
let bob_keypair = generate_keypair();
let bob_pubkey = get_pubkey(&bob_keypair);
let bob_pubkey = get_pubkey(&generate_keypair());
acc.transfer(500, &alice_keypair, bob_pubkey).unwrap();
assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 500);

View File

@ -6,10 +6,9 @@ use std::net::UdpSocket;
use std::io;
use bincode::{deserialize, serialize};
use transaction::Transaction;
use signature::{PublicKey, Signature};
use signature::{KeyPair, PublicKey, Signature};
use hash::Hash;
use entry::Entry;
use ring::signature::Ed25519KeyPair;
use accountant_skel::{Request, Response};
pub struct AccountantStub {
@ -36,7 +35,7 @@ impl AccountantStub {
pub fn transfer(
&self,
n: i64,
keypair: &Ed25519KeyPair,
keypair: &KeyPair,
to: PublicKey,
last_id: &Hash,
) -> io::Result<Signature> {
@ -116,16 +115,16 @@ mod tests {
use accountant_skel::AccountantSkel;
use std::thread::{sleep, spawn};
use std::time::Duration;
use genesis::{Creator, Genesis};
use genesis::Genesis;
use signature::{generate_keypair, get_pubkey};
#[test]
fn test_accountant_stub() {
let addr = "127.0.0.1:9000";
let send_addr = "127.0.0.1:9001";
let bob = Creator::new(1_000);
let bob_pubkey = bob.pubkey;
let alice = Genesis::new(10_000, vec![bob]);
let alice = Genesis::new(10_000);
let acc = Accountant::new(&alice, None);
let bob_pubkey = get_pubkey(&generate_keypair());
spawn(move || AccountantSkel::new(acc).serve(addr).unwrap());
sleep(Duration::from_millis(30));
@ -135,6 +134,6 @@ mod tests {
let sig = acc.transfer(500, &alice.get_keypair(), bob_pubkey, &last_id)
.unwrap();
acc.wait_on_signature(&sig).unwrap();
assert_eq!(acc.get_balance(&bob_pubkey).unwrap().unwrap(), 1_500);
assert_eq!(acc.get_balance(&bob_pubkey).unwrap().unwrap(), 500);
}
}

View File

@ -1,19 +1,28 @@
extern crate serde_json;
extern crate silk;
use silk::genesis::{Creator, Genesis};
use silk::signature::{generate_keypair, get_pubkey};
use silk::genesis::Genesis;
use silk::event::Event;
use silk::transaction::Transaction;
use silk::log::create_entries;
use silk::signature::{generate_keypair, get_pubkey, KeyPair, PublicKey};
use silk::hash::Hash;
fn transfer(from: &KeyPair, (to, tokens): (PublicKey, i64), last_id: Hash) -> Event {
Event::Transaction(Transaction::new(&from, to, tokens, last_id))
}
fn main() {
let alice = Creator {
tokens: 200,
pubkey: get_pubkey(&generate_keypair()),
};
let bob = Creator {
tokens: 100,
pubkey: get_pubkey(&generate_keypair()),
};
let creators = vec![alice, bob];
let gen = Genesis::new(500, creators);
let alice = (get_pubkey(&generate_keypair()), 200);
let bob = (get_pubkey(&generate_keypair()), 100);
let gen = Genesis::new(500);
let from = gen.get_keypair();
let seed = gen.get_seed();
let mut events = gen.create_events();
events.push(transfer(&from, alice, seed));
events.push(transfer(&from, bob, seed));
create_entries(&seed, events);
println!("{}", serde_json::to_string(&gen).unwrap());
}

View File

@ -2,7 +2,7 @@
use event::Event;
use transaction::Transaction;
use signature::{generate_keypair, get_pubkey, PublicKey};
use signature::{get_pubkey, PublicKey};
use entry::Entry;
use log::create_entries;
use hash::{hash, Hash};
@ -10,37 +10,17 @@ use ring::rand::SystemRandom;
use ring::signature::Ed25519KeyPair;
use untrusted::Input;
#[derive(Serialize, Deserialize, Debug)]
pub struct Creator {
pub pubkey: PublicKey,
pub tokens: i64,
}
impl Creator {
pub fn new(tokens: i64) -> Self {
Creator {
pubkey: get_pubkey(&generate_keypair()),
tokens,
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Genesis {
pub pkcs8: Vec<u8>,
pub tokens: i64,
pub creators: Vec<Creator>,
}
impl Genesis {
pub fn new(tokens: i64, creators: Vec<Creator>) -> Self {
pub fn new(tokens: i64) -> Self {
let rnd = SystemRandom::new();
let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rnd).unwrap().to_vec();
Genesis {
pkcs8,
tokens,
creators,
}
Genesis { pkcs8, tokens }
}
pub fn get_seed(&self) -> Hash {
@ -55,23 +35,14 @@ impl Genesis {
get_pubkey(&self.get_keypair())
}
pub fn create_transaction(&self, asset: i64, to: &PublicKey) -> Event {
let tr = Transaction::new(&self.get_keypair(), *to, asset, self.get_seed());
Event::Transaction(tr)
}
pub fn create_events(&self) -> Vec<Event> {
let pubkey = self.get_pubkey();
let event0 = Event::Tick;
let event1 = self.create_transaction(self.tokens, &pubkey);
let mut events = vec![event0, event1];
for x in &self.creators {
let tx = self.create_transaction(x.tokens, &x.pubkey);
events.push(tx);
}
events
let tr = Transaction::new(
&self.get_keypair(),
self.get_pubkey(),
self.tokens,
self.get_seed(),
);
vec![Event::Tick, Event::Transaction(tr)]
}
pub fn create_entries(&self) -> Vec<Entry> {
@ -86,35 +57,19 @@ mod tests {
#[test]
fn test_create_events() {
let mut events = Genesis::new(100, vec![]).create_events().into_iter();
let mut events = Genesis::new(100).create_events().into_iter();
assert_eq!(events.next().unwrap(), Event::Tick);
if let Event::Transaction(Transaction { from, to, .. }) = events.next().unwrap() {
assert_eq!(from, to);
if let Event::Transaction(tr) = events.next().unwrap() {
assert_eq!(tr.from, tr.to);
} else {
assert!(false);
}
assert_eq!(events.next(), None);
}
#[test]
fn test_create_creator() {
assert_eq!(
Genesis::new(100, vec![Creator::new(42)])
.create_events()
.len(),
3
);
}
#[test]
fn test_verify_entries() {
let entries = Genesis::new(100, vec![]).create_entries();
assert!(verify_slice(&entries, &entries[0].id));
}
#[test]
fn test_verify_entries_with_transactions() {
let entries = Genesis::new(100, vec![Creator::new(42)]).create_entries();
let entries = Genesis::new(100).create_entries();
assert!(verify_slice(&entries, &entries[0].id));
}
}

View File

@ -6,18 +6,19 @@ use ring::signature::Ed25519KeyPair;
use ring::{rand, signature};
use untrusted;
pub type KeyPair = Ed25519KeyPair;
pub type PublicKey = GenericArray<u8, U32>;
pub type Signature = GenericArray<u8, U64>;
/// Return a new ED25519 keypair
pub fn generate_keypair() -> Ed25519KeyPair {
pub fn generate_keypair() -> KeyPair {
let rng = rand::SystemRandom::new();
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).unwrap()
}
/// Return the public key for the given keypair
pub fn get_pubkey(keypair: &Ed25519KeyPair) -> PublicKey {
pub fn get_pubkey(keypair: &KeyPair) -> PublicKey {
GenericArray::clone_from_slice(keypair.public_key_bytes())
}

View File

@ -1,7 +1,6 @@
//! The `transaction` crate provides functionality for creating log transactions.
use signature::{get_pubkey, verify_signature, PublicKey, Signature};
use ring::signature::Ed25519KeyPair;
use signature::{get_pubkey, verify_signature, KeyPair, PublicKey, Signature};
use serde::Serialize;
use bincode::serialize;
use hash::Hash;
@ -16,7 +15,7 @@ pub struct Transaction<T> {
}
impl<T: Serialize> Transaction<T> {
pub fn new(from_keypair: &Ed25519KeyPair, to: PublicKey, asset: T, last_id: Hash) -> Self {
pub fn new(from_keypair: &KeyPair, to: PublicKey, asset: T, last_id: Hash) -> Self {
let mut tr = Transaction {
from: get_pubkey(&from_keypair),
to,
@ -32,7 +31,7 @@ impl<T: Serialize> Transaction<T> {
serialize(&(&self.from, &self.to, &self.asset, &self.last_id)).unwrap()
}
pub fn sign(&mut self, keypair: &Ed25519KeyPair) {
pub fn sign(&mut self, keypair: &KeyPair) {
let sign_data = self.get_sign_data();
self.sig = Signature::clone_from_slice(keypair.sign(&sign_data).as_ref());
}