Explorar o código

Merge branch 'master' of github.com:darkrenaissance/darkfi

narodnik %!s(int64=5) %!d(string=hai) anos
pai
achega
6cc6af0f0f
Modificáronse 11 ficheiros con 402 adicións e 189 borrados
  1. 2 2
      README.md
  2. 7 3
      src/bin/demoservices.rs
  3. 50 26
      src/bin/demowallet.rs
  4. 7 5
      src/bin/tx.rs
  5. 8 16
      src/error.rs
  6. 0 18
      src/service/error.rs
  7. 109 85
      src/service/gateway.rs
  8. 0 3
      src/service/mod.rs
  9. 144 30
      src/service/reqrep.rs
  10. 69 0
      src/state.rs
  11. 6 1
      src/tx.rs

+ 2 - 2
README.md

@@ -1,8 +1,8 @@
 Not even an alpha product. Just a mere prototype(s).
 
-Lets liberate people from the claws of big tech and create the democratic paradigm of technology.
+Let's liberate people from the claws of big tech and create the democratic paradigm of technology.
 
-Self defense is integral to any organism's survival and growth.
+Self-defense is integral to any organism's survival and growth.
 
 Power to the minuteman.
 

+ 7 - 3
src/bin/demoservices.rs

@@ -4,11 +4,15 @@ use std::sync::Arc;
 
 use sapvi::Result;
 
-use sapvi::service::{gateway, reqrep};
+use sapvi::service::gateway;
 
 async fn start(executor: Arc<Executor<'_>>) -> Result<()> {
-    executor.clone().spawn(reqrep::ReqRepAPI::start()).detach();
-    gateway::GatewayService::start(executor.clone()).await?;
+    let gateway = gateway::GatewayService::new(
+        String::from("tcp://127.0.0.1:3333"),
+        String::from("tcp://127.0.0.1:4444"),
+    );
+
+    gateway.start(executor.clone()).await?;
     Ok(())
 }
 

+ 50 - 26
src/bin/demowallet.rs

@@ -1,30 +1,54 @@
-use sapvi::service::reqrep::{Reply, Request};
-use sapvi::{serial, Result};
-
-use bytes::Bytes;
-use zeromq::*;
-
-async fn connect() -> Result<()> {
-    let mut requester = zeromq::ReqSocket::new();
-    requester.connect("tcp://127.0.0.1:3333").await?;
-
-    println!("connected");
-
-    for request_nbr in 0..10 {
-        println!("start sending");
-        let req = Request::new(0, "test".as_bytes().to_vec());
-        let req = serial::serialize(&req);
-        let req = bytes::Bytes::from(req);
-        requester.send(req.into()).await?;
-        let message: zeromq::ZmqMessage = requester.recv().await?;
-        let message: &Bytes = message.get(0).unwrap();
-        let message: Vec<u8> = message.to_vec();
-        let rep: Reply = serial::deserialize(&message).unwrap();
-        println!("Received reply {:?} {:?}", request_nbr, rep);
-    }
+use async_executor::Executor;
+use async_std::sync::{Arc, Mutex};
+use easy_parallel::Parallel;
+
+use sapvi::service::gateway::GatewayClient;
+use sapvi::Result;
+
+async fn start(executor: Arc<Executor<'_>>) -> Result<()> {
+    let mut client = GatewayClient::new(String::from("tcp://127.0.0.1:3333"));
+
+    client.start().await?;
+    println!("connected to a server");
+
+    let slabs = Arc::new(Mutex::new(vec![]));
+
+    let subscriber = client
+        .subscribe(String::from("tcp://127.0.0.1:4444"))
+        .await?;
+
+    println!("subscription ready");
+
+    let fetch_loop_task = executor.spawn(GatewayClient::fetch_slabs_loop(
+        subscriber.clone(),
+        slabs.clone(),
+    ));
+
+    client.put_slab(vec![0, 0, 0, 0]).await?;
+    client.put_slab(vec![0, 0, 0, 0]).await?;
+    client.put_slab(vec![0, 0, 0, 0]).await?;
+
+    fetch_loop_task.cancel().await;
+
     Ok(())
 }
 
-fn main() {
-    futures::executor::block_on(connect()).unwrap();
+fn main() -> Result<()> {
+    let ex = Arc::new(Executor::new());
+    let (signal, shutdown) = async_channel::unbounded::<()>();
+    let ex2 = ex.clone();
+
+    let (_, result) = Parallel::new()
+        // Run four executor threads.
+        .each(0..3, |_| smol::future::block_on(ex.run(shutdown.recv())))
+        // Run the main future on the current thread.
+        .finish(|| {
+            smol::future::block_on(async move {
+                start(ex2).await?;
+                drop(signal);
+                Ok::<(), sapvi::Error>(())
+            })
+        });
+
+    result
 }

+ 7 - 5
src/bin/tx.rs

@@ -22,7 +22,7 @@ use sapvi::tx;
 struct MemoryState {
     mint_pvk: groth16::PreparedVerifyingKey<Bls12>,
     spend_pvk: groth16::PreparedVerifyingKey<Bls12>,
-    cashier_public: jubjub::SubgroupPoint
+    cashier_public: jubjub::SubgroupPoint,
 }
 
 impl ProgramState for MemoryState {
@@ -39,8 +39,7 @@ impl ProgramState for MemoryState {
 }
 
 impl MemoryState {
-    fn apply(updates: StateUpdates) {
-    }
+    fn apply(updates: StateUpdates) {}
 }
 
 fn main() {
@@ -66,7 +65,7 @@ fn main() {
     let state = MemoryState {
         mint_pvk,
         spend_pvk,
-        cashier_public
+        cashier_public,
     };
 
     // Wallet 1 creates a secret key
@@ -193,7 +192,10 @@ fn main() {
         }],
         // We can add more outputs to this list.
         // The only constraint is that sum(value in) == sum(value out)
-        outputs: vec![tx::TransactionBuilderOutputInfo { value: 110, public: public2 }],
+        outputs: vec![tx::TransactionBuilderOutputInfo {
+            value: 110,
+            public: public2,
+        }],
     };
     // Build the tx
     let mut tx_data = vec![];

+ 8 - 16
src/error.rs

@@ -1,8 +1,7 @@
-use std::fmt;
 use rusqlite;
+use std::fmt;
 
 use crate::net::error::NetError;
-use crate::service::ServicesError;
 use crate::state;
 use crate::vm::ZKVMError;
 
@@ -25,7 +24,7 @@ pub enum Error {
     /// Parsing error
     ParseFailed(&'static str),
     ParseIntError,
-    AsyncChannelError,
+    AsyncChannelError(String),
     MalformedPacket,
     AddrParseError,
     BadVariableRefType,
@@ -45,7 +44,7 @@ pub enum Error {
     ServiceStopped,
     Utf8Error,
     NoteDecryptionFailed,
-    ServicesError(ServicesError),
+    ServicesError(&'static str),
     ZMQError(zeromq::ZmqError),
     VerifyFailed(state::VerifyFailed),
 }
@@ -72,7 +71,7 @@ impl fmt::Display for Error {
             Error::NonMinimalVarInt => f.write_str("non-minimal varint"),
             Error::ParseFailed(ref err) => write!(f, "parse failed: {}", err),
             Error::ParseIntError => f.write_str("Parse int error"),
-            Error::AsyncChannelError => f.write_str("async_channel error"),
+            Error::AsyncChannelError(ref err) => write!(f, "async_channel error: {}", err),
             Error::MalformedPacket => f.write_str("Malformed packet"),
             Error::AddrParseError => f.write_str("Unable to parse address"),
             Error::BadVariableRefType => f.write_str("Bad variable ref type byte"),
@@ -99,12 +98,6 @@ impl fmt::Display for Error {
     }
 }
 
-impl From<ServicesError> for Error {
-    fn from(err: ServicesError) -> Error {
-        Error::ServicesError(err)
-    }
-}
-
 impl From<zeromq::ZmqError> for Error {
     fn from(err: zeromq::ZmqError) -> Error {
         Error::ZMQError(err)
@@ -136,14 +129,14 @@ impl From<bellman::SynthesisError> for Error {
 }
 
 impl<T> From<async_channel::SendError<T>> for Error {
-    fn from(_err: async_channel::SendError<T>) -> Error {
-        Error::AsyncChannelError
+    fn from(err: async_channel::SendError<T>) -> Error {
+        Error::AsyncChannelError(err.to_string())
     }
 }
 
 impl From<async_channel::RecvError> for Error {
-    fn from(_err: async_channel::RecvError) -> Error {
-        Error::AsyncChannelError
+    fn from(err: async_channel::RecvError) -> Error {
+        Error::AsyncChannelError(err.to_string())
     }
 }
 
@@ -183,4 +176,3 @@ impl From<state::VerifyFailed> for Error {
         Error::VerifyFailed(err)
     }
 }
-

+ 0 - 18
src/service/error.rs

@@ -1,18 +0,0 @@
-use std::fmt;
-
-pub type Result<T> = std::result::Result<T, ServicesError>;
-
-#[derive(Debug, Copy, Clone)]
-pub enum ServicesError {
-    ResonseError(&'static str),
-}
-
-impl std::error::Error for ServicesError {}
-
-impl fmt::Display for ServicesError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
-        match *self {
-            ServicesError::ResonseError(ref err) => write!(f, "Response: {}", err),
-        }
-    }
-}

+ 109 - 85
src/service/gateway.rs

@@ -1,132 +1,156 @@
+use async_std::sync::{Arc, Mutex};
 use std::convert::TryInto;
 
-use super::reqrep::{Reply, Request};
-use super::ServicesError;
-use crate::serial::{deserialize, serialize};
-use crate::Result;
+use super::reqrep::{Publisher, RepProtocol, Reply, ReqProtocol, Request, Subscriber};
+use crate::{Error, Result};
 
 use async_executor::Executor;
-use async_std::sync::Arc;
-use bytes::Bytes;
-use futures::FutureExt;
-use zeromq::*;
 
 pub type Slabs = Vec<Vec<u8>>;
 
 pub struct GatewayService {
-    slabs: Slabs,
-}
-
-enum NetEvent {
-    RECEIVE(zeromq::ZmqMessage),
-    SEND(zeromq::ZmqMessage),
+    slabs: Mutex<Slabs>,
+    addr: String,
+    publisher: Mutex<Publisher>,
 }
 
 impl GatewayService {
-    pub async fn start(executor: Arc<Executor<'_>>) -> Result<()> {
-        let mut worker = zeromq::RepSocket::new();
-        worker.connect("tcp://127.0.0.1:4444").await?;
+    pub fn new(addr: String, pub_addr: String) -> Arc<GatewayService> {
+        let slabs = Mutex::new(vec![]);
+        let publisher = Mutex::new(Publisher::new(pub_addr));
+        Arc::new(GatewayService {
+            slabs,
+            addr,
+            publisher,
+        })
+    }
 
-        let (send_queue_s, send_queue_r) = async_channel::unbounded::<zeromq::ZmqMessage>();
+    pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
+        let (send_queue_s, send_queue_r) = async_channel::unbounded::<Reply>();
+        let (recv_queue_s, recv_queue_r) = async_channel::unbounded::<Request>();
 
-        let ex2 = executor.clone();
-        loop {
-            let event = futures::select! {
-                request = worker.recv().fuse() => NetEvent::RECEIVE(request?),
-                reply = send_queue_r.recv().fuse() => NetEvent::SEND(reply?)
-            };
-
-            match event {
-                NetEvent::RECEIVE(request) => {
-                    ex2.spawn(Self::handle_request(send_queue_s.clone(), request))
-                        .detach();
-                }
-                NetEvent::SEND(reply) => {
-                    worker.send(reply).await?;
-                }
-            }
-        }
-    }
+        let mut reqrep = RepProtocol::new(
+            self.addr.clone(),
+            send_queue_r.clone(),
+            recv_queue_s.clone(),
+        );
 
-    async fn handle_request(
-        send_queue: async_channel::Sender<zeromq::ZmqMessage>,
-        request: zeromq::ZmqMessage,
-    ) -> Result<()> {
-        let request: &Bytes = request.get(0).unwrap();
-        let request: Vec<u8> = request.to_vec();
-        let req: Request = deserialize(&request)?;
+        reqrep.start().await?;
+        println!("server started");
+
+        self.publisher.lock().await.start().await?;
 
-        // TODO
-        // do things
+        println!("publisher started");
 
-        println!("Gateway service received a msg {:?}", req);
+        let handle_request_task =
+            executor.spawn(self.handle_request(send_queue_s.clone(), recv_queue_r.clone()));
 
-        let rep = Reply::from(&req, 0, "text".as_bytes().to_vec());
-        let rep: Vec<u8> = serialize(&rep);
-        let rep = Bytes::from(rep);
-        send_queue.send(rep.into()).await?;
+        reqrep.run().await?;
+
+        handle_request_task.cancel().await;
         Ok(())
     }
+
+    async fn handle_request(
+        self: Arc<Self>,
+        send_queue: async_channel::Sender<Reply>,
+        recv_queue: async_channel::Receiver<Request>,
+    ) -> Result<()> {
+        let data = vec![];
+
+        loop {
+            match recv_queue.recv().await {
+                Ok(request) => {
+                    match request.get_command() {
+                        0 => {
+                            // PUTSLAB
+                            let slab = request.get_payload();
+                            self.slabs.lock().await.push(slab.clone());
+
+                            // publish to all subscribes
+                            self.publisher.lock().await.publish(slab).await?;
+
+                            println!("received putslab msg");
+                        }
+                        1 => {
+                            // GETSLAB
+                            println!("received getslab msg");
+                        }
+                        2 => {
+                            // GETLASTINDEX
+                            println!("received getlastindex msg");
+                        }
+                        _ => {
+                            return Err(Error::ServicesError("wrong command"));
+                        }
+                    }
+                    let rep = Reply::from(&request, 0, data.clone());
+                    send_queue.send(rep.into()).await?;
+                }
+                Err(_) => {}
+            }
+        }
+    }
 }
 
-struct GatewayClient {
-    slabs: Slabs,
-    sender: zeromq::ReqSocket,
+pub struct GatewayClient {
+    protocol: ReqProtocol,
 }
 
 impl GatewayClient {
-    pub fn new() -> GatewayClient {
-        let sender = zeromq::ReqSocket::new();
-        GatewayClient {
-            slabs: vec![],
-            sender,
-        }
+    pub fn new(addr: String) -> GatewayClient {
+        let protocol = ReqProtocol::new(addr);
+        GatewayClient { protocol }
     }
     pub async fn start(&mut self) -> Result<()> {
-        self.sender.connect("tcp://127.0.0.1:3333").await?;
+        self.protocol.start().await?;
         Ok(())
     }
-    async fn request(&mut self, command: GatewayCommand, data: Vec<u8>) -> Result<Vec<u8>> {
-        let request = Request::new(command as u8, data);
-        let req = serialize(&request);
-        let req = bytes::Bytes::from(req);
 
-        self.sender.send(req.into()).await?;
-
-        let rep: zeromq::ZmqMessage = self.sender.recv().await?;
-        let rep: &Bytes = rep.get(0).unwrap();
-        let rep: Vec<u8> = rep.to_vec();
-
-        let reply: Reply = deserialize(&rep)?;
-
-        if reply.has_error() {
-            return Err(ServicesError::ResonseError("response has an error").into());
-        }
-
-        assert!(reply.get_id() == request.get_id());
-
-        Ok(reply.get_payload())
+    pub async fn subscribe(&self, sub_addr: String) -> Result<Arc<Mutex<Subscriber>>> {
+        let mut subscriber = Subscriber::new(sub_addr);
+        subscriber.start().await?;
+        Ok(Arc::new(Mutex::new(subscriber)))
     }
 
     pub async fn get_slab(&mut self, index: u32) -> Result<Vec<u8>> {
-        self.request(GatewayCommand::GETSLAB, index.to_be_bytes().to_vec())
+        self.protocol
+            .request(GatewayCommand::GetSlab as u8, index.to_be_bytes().to_vec())
             .await
     }
 
     pub async fn put_slab(&mut self, data: Vec<u8>) -> Result<()> {
-        self.request(GatewayCommand::GETSLAB, data).await?;
+        self.protocol
+            .request(GatewayCommand::PutSlab as u8, data.clone())
+            .await?;
         Ok(())
     }
     pub async fn get_last_index(&mut self) -> Result<u32> {
-        let rep = self.request(GatewayCommand::GETLASTINDEX, vec![]).await?;
+        let rep = self
+            .protocol
+            .request(GatewayCommand::GetLastIndex as u8, vec![])
+            .await?;
         let rep: [u8; 4] = rep.try_into().unwrap();
         Ok(u32::from_be_bytes(rep))
     }
+
+    pub async fn fetch_slabs_loop(
+        subscriber: Arc<Mutex<Subscriber>>,
+        slabs: Arc<Mutex<Slabs>>,
+    ) -> Result<()> {
+        loop {
+            let mut subscriber = subscriber.lock().await;
+            let slab = subscriber.fetch().await?;
+
+            println!("received new slab from subscriber");
+            slabs.lock().await.push(slab);
+        }
+    }
 }
 
 #[repr(u8)]
 enum GatewayCommand {
-    PUTSLAB,
-    GETSLAB,
-    GETLASTINDEX,
+    PutSlab,
+    GetSlab,
+    GetLastIndex,
 }

+ 0 - 3
src/service/mod.rs

@@ -1,5 +1,2 @@
-mod error;
 pub mod gateway;
 pub mod reqrep;
-
-pub use error::ServicesError;

+ 144 - 30
src/service/reqrep.rs

@@ -1,50 +1,156 @@
 use std::io;
 
+use crate::serial::{deserialize, serialize};
 use crate::{Decodable, Encodable, Result};
 
+use bytes::Bytes;
 use futures::FutureExt;
 use rand::Rng;
 use zeromq::*;
 
-pub struct ReqRepAPI;
+enum NetEvent {
+    Receive(zeromq::ZmqMessage),
+    Send(Reply),
+}
 
-impl ReqRepAPI {
-    pub async fn start() -> Result<()> {
-        println!("start reqrep");
+pub struct RepProtocol {
+    addr: String,
+    socket: zeromq::RepSocket,
+    recv_queue: async_channel::Receiver<Reply>,
+    send_queue: async_channel::Sender<Request>,
+}
 
-        let mut frontend = zeromq::RouterSocket::new();
-        frontend.bind("tcp://127.0.0.1:3333").await?;
+impl RepProtocol {
+    pub fn new(
+        addr: String,
+        recv_queue: async_channel::Receiver<Reply>,
+        send_queue: async_channel::Sender<Request>,
+    ) -> RepProtocol {
+        let socket = zeromq::RepSocket::new();
+        RepProtocol {
+            addr,
+            socket,
+            recv_queue,
+            send_queue,
+        }
+    }
+    pub async fn start(&mut self) -> Result<()> {
+        self.socket.bind(self.addr.as_str()).await?;
+        Ok(())
+    }
 
-        let mut backend = zeromq::DealerSocket::new();
-        backend.bind("tcp://127.0.0.1:4444").await?;
+    pub async fn run(&mut self) -> Result<()> {
         loop {
-            println!("start reqrep loop");
-            futures::select! {
-                frontend_mess = frontend.recv().fuse() => {
-                    match frontend_mess {
-                        Ok(message) => {
-                            backend.send(message).await?;
-                        }
-                        Err(_) => {
-                            // TODO
-                        }
-                    }
-                },
-                backend_mess = backend.recv().fuse() => {
-                    match backend_mess {
-                        Ok(message) => {
-                            frontend.send(message).await?;
-                        }
-                        Err(_) => {
-                            // TODO
-                        }
-                    }
-                }
+            let event = futures::select! {
+                request = self.socket.recv().fuse() => NetEvent::Receive(request?),
+                reply = self.recv_queue.recv().fuse() => NetEvent::Send(reply?)
             };
+
+            match event {
+                NetEvent::Receive(request) => {
+                    let request: &Bytes = request.get(0).unwrap();
+                    let request: Vec<u8> = request.to_vec();
+                    let req: Request = deserialize(&request)?;
+                    self.send_queue.send(req).await?;
+                }
+                NetEvent::Send(reply) => {
+                    let reply: Vec<u8> = serialize(&reply);
+                    let reply = Bytes::from(reply);
+                    self.socket.send(reply.into()).await?;
+                }
+            }
         }
     }
 }
 
+pub struct ReqProtocol {
+    addr: String,
+    socket: zeromq::ReqSocket,
+}
+
+impl ReqProtocol {
+    pub fn new(addr: String) -> ReqProtocol {
+        let socket = zeromq::ReqSocket::new();
+        ReqProtocol { addr, socket }
+    }
+
+    pub async fn start(&mut self) -> Result<()> {
+        self.socket.connect(self.addr.as_str()).await?;
+        Ok(())
+    }
+
+    pub async fn request(&mut self, command: u8, data: Vec<u8>) -> Result<Vec<u8>> {
+        let request = Request::new(command, data);
+        let req = serialize(&request);
+        let req = bytes::Bytes::from(req);
+
+        self.socket.send(req.into()).await?;
+
+        let rep: zeromq::ZmqMessage = self.socket.recv().await?;
+        let rep: &Bytes = rep.get(0).unwrap();
+        let rep: Vec<u8> = rep.to_vec();
+
+        let reply: Reply = deserialize(&rep)?;
+
+        if reply.has_error() {
+            return Err(crate::Error::ServicesError("response has an error"));
+        }
+
+        assert!(reply.get_id() == request.get_id());
+
+        Ok(reply.get_payload())
+    }
+}
+
+pub struct Publisher {
+    addr: String,
+    socket: zeromq::PubSocket,
+}
+
+impl Publisher {
+    pub fn new(addr: String) -> Publisher {
+        let socket = zeromq::PubSocket::new();
+        Publisher { addr, socket }
+    }
+    pub async fn start(&mut self) -> Result<()> {
+        self.socket.bind(self.addr.as_str()).await?;
+        Ok(())
+    }
+
+    pub async fn publish(&mut self, data: Vec<u8>) -> Result<()> {
+        let data = Bytes::from(data);
+        self.socket.send(data.into()).await?;
+        Ok(())
+    }
+}
+
+pub struct Subscriber {
+    addr: String,
+    socket: zeromq::SubSocket,
+}
+
+impl Subscriber {
+    pub fn new(addr: String) -> Subscriber {
+        let socket = zeromq::SubSocket::new();
+        Subscriber { addr, socket }
+    }
+
+    pub async fn start(&mut self) -> Result<()> {
+        self.socket.connect(self.addr.as_str()).await?;
+
+        self.socket.subscribe("").await?;
+
+        Ok(())
+    }
+
+    pub async fn fetch(&mut self) -> Result<Vec<u8>> {
+        let data = self.socket.recv().await?;
+        let data: &Bytes = data.get(0).unwrap();
+        let data = data.to_vec();
+        Ok(data)
+    }
+}
+
 #[derive(Debug, PartialEq)]
 pub struct Request {
     command: u8,
@@ -69,6 +175,14 @@ impl Request {
     pub fn get_id(&self) -> u32 {
         self.id
     }
+
+    pub fn get_command(&self) -> u8 {
+        self.command
+    }
+
+    pub fn get_payload(&self) -> Vec<u8> {
+        self.payload.clone()
+    }
 }
 
 #[derive(Debug, PartialEq)]

+ 69 - 0
src/state.rs

@@ -0,0 +1,69 @@
+use bellman::groth16;
+use bls12_381::Bls12;
+use std::fmt;
+
+use crate::error::{Error, Result};
+use crate::tx;
+
+pub trait ProgramState {
+    fn is_valid_cashier_public_key(&self, public: &jubjub::SubgroupPoint) -> bool;
+
+    fn mint_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12>;
+    fn spend_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12>;
+}
+
+pub struct StateUpdates {}
+
+#[derive(Debug)]
+pub enum VerifyFailed {
+    SpendProof(usize),
+    MintProof(usize),
+    ClearInputSignature(usize),
+    InputSignature(usize),
+    MissingFunds,
+}
+
+impl std::error::Error for VerifyFailed {}
+
+impl fmt::Display for VerifyFailed {
+    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
+        match *self {
+            VerifyFailed::SpendProof(i) => write!(f, "Spend proof for input {}", i),
+            VerifyFailed::MintProof(i) => write!(f, "Mint proof for input {}", i),
+            VerifyFailed::ClearInputSignature(i) => {
+                write!(f, "Invalid signature for clear input {}", i)
+            }
+            VerifyFailed::InputSignature(i) => write!(f, "Invalid signature for input {}", i),
+            VerifyFailed::MissingFunds => {
+                f.write_str("Money in does not match money out (value commits)")
+            }
+        }
+    }
+}
+
+pub fn state_transition<S: ProgramState>(state: &S, tx: tx::Transaction) -> Result<StateUpdates> {
+    tx.verify(state.mint_pvk(), state.spend_pvk())?;
+
+    /*
+    // Check the public key in the clear inputs
+    // It should be a valid public key for the cashier
+    assert_eq!(tx.clear_inputs[0].signature_public, cashier_public);
+    // Check the tx verifies correctly
+    assert!(tx.verify(&mint_pvk, &spend_pvk));
+    // Add the new coins to the merkle tree
+    tree.append(Coin::new(tx.outputs[0].revealed.coin))
+        .expect("append merkle");
+
+    // Now for every new tx we receive, the wallets should iterate over all outputs
+    // and try to decrypt the coin's note.
+    // If they can successfully decrypt it, then it's a coin destined for us.
+
+    // Try to decrypt output note
+    let note = tx.outputs[0]
+        .enc_note
+        .decrypt(&secret)
+        .expect("note should be destined for us");
+    // This contains the secret attributes so we can spend the coin
+    */
+    Ok(StateUpdates {})
+}

+ 6 - 1
src/tx.rs

@@ -178,6 +178,11 @@ impl TransactionBuilder {
     }
 }
 
+pub struct TransactionBuilderClearOutputInfo {
+    pub value: u64,
+    pub instructions: String,
+}
+
 pub struct TransactionBuilderClearInputInfo {
     pub value: u64,
     pub signature_secret: jubjub::Fr,
@@ -307,7 +312,7 @@ impl Transaction {
             }
         }
 
-            Ok(())
+        Ok(())
     }
 }