Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ jobs:
toolchain: 1.37.0
override: true

# cargo fmt does not build the code, and running it in a fresh clone of
# the codebase will fail because the protobuf code has not been generated.
- name: cargo build
uses: actions-rs/cargo@v1
with:
command: build
args: --all

# Ensure all code has been formatted with rustfmt
- run: rustup component add rustfmt
- name: Check formatting
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ before_script:
- rustup component add rustfmt

script:
- cargo fmt --all -- --check
- cargo build --verbose --release --all
- cargo fmt --all -- --check
- cargo test --verbose --release --all
- cargo test --verbose --release --all -- --ignored

Expand Down
47 changes: 47 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions zcash_client_backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Protobufs
src/proto/
8 changes: 8 additions & 0 deletions zcash_client_backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ edition = "2018"

[dependencies]
bech32 = "0.7"
ff = { version = "0.5.0", path = "../ff" }
hex = "0.3"
pairing = { version = "0.15.0", path = "../pairing" }
protobuf = "2"
subtle = "2"
zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" }

[build-dependencies]
protobuf-codegen-pure = "2"

[dev-dependencies]
rand_core = "0.5"
rand_os = "0.2"
rand_xorshift = "0.2"

[badges]
Expand Down
11 changes: 11 additions & 0 deletions zcash_client_backend/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use protobuf_codegen_pure;

fn main() {
protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
out_dir: "src/proto",
input: &["proto/compact_formats.proto"],
includes: &["proto"],
customize: Default::default(),
})
.expect("protoc");
}
48 changes: 48 additions & 0 deletions zcash_client_backend/proto/compact_formats.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
syntax = "proto3";
package cash.z.wallet.sdk.rpc;
option go_package = "walletrpc";

// Remember that proto3 fields are all optional. A field that is not present will be set to its zero value.
// bytes fields of hashes are in canonical little-endian format.

// CompactBlock is a packaging of ONLY the data from a block that's needed to:
// 1. Detect a payment to your shielded Sapling address
// 2. Detect a spend of your shielded Sapling notes
// 3. Update your witnesses to generate new Sapling spend proofs.
message CompactBlock {
uint32 protoVersion = 1; // the version of this wire format, for storage
uint64 height = 2; // the height of this block
bytes hash = 3;
bytes prevHash = 4;
uint32 time = 5;
bytes header = 6; // (hash, prevHash, and time) OR (full header)
repeated CompactTx vtx = 7; // compact transactions from this block
}

message CompactTx {
// Index and hash will allow the receiver to call out to chain
// explorers or other data structures to retrieve more information
// about this transaction.
uint64 index = 1;
bytes hash = 2;

// The transaction fee: present if server can provide. In the case of a
// stateless server and a transaction with transparent inputs, this will be
// unset because the calculation requires reference to prior transactions.
// in a pure-Sapling context, the fee will be calculable as:
// valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut))
uint32 fee = 3;

repeated CompactSpend spends = 4;
repeated CompactOutput outputs = 5;
}

message CompactSpend {
bytes nf = 1;
}

message CompactOutput {
bytes cmu = 1;
bytes epk = 2;
bytes ciphertext = 3;
}
3 changes: 3 additions & 0 deletions zcash_client_backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
pub mod constants;
pub mod encoding;
pub mod keys;
pub mod proto;
pub mod wallet;
pub mod welding_rig;
83 changes: 83 additions & 0 deletions zcash_client_backend/src/proto/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//! Generated code for handling light client protobuf structs.

use ff::{PrimeField, PrimeFieldRepr};
use pairing::bls12_381::{Bls12, Fr, FrRepr};
use zcash_primitives::{
block::{BlockHash, BlockHeader},
jubjub::{edwards, PrimeOrder},
JUBJUB,
};

pub mod compact_formats;

impl compact_formats::CompactBlock {
/// Returns the [`BlockHash`] for this block.
///
/// # Panics
///
/// This function will panic if [`CompactBlock.header`] is not set and
/// [`CompactBlock.hash`] is not exactly 32 bytes.
///
/// [`CompactBlock.header`]: #structfield.header
/// [`CompactBlock.hash`]: #structfield.hash
pub fn hash(&self) -> BlockHash {
if let Some(header) = self.header() {
header.hash()
} else {
BlockHash::from_slice(&self.hash)
}
}

/// Returns the [`BlockHash`] for this block's parent.
///
/// # Panics
///
/// This function will panic if [`CompactBlock.header`] is not set and
/// [`CompactBlock.prevHash`] is not exactly 32 bytes.
///
/// [`CompactBlock.header`]: #structfield.header
/// [`CompactBlock.prevHash`]: #structfield.prevHash
pub fn prev_hash(&self) -> BlockHash {
if let Some(header) = self.header() {
header.prev_block
} else {
BlockHash::from_slice(&self.prevHash)
}
}

/// Returns the [`BlockHeader`] for this block if present.
///
/// A convenience method that parses [`CompactBlock.header`] if present.
///
/// [`CompactBlock.header`]: #structfield.header
pub fn header(&self) -> Option<BlockHeader> {
if self.header.is_empty() {
None
} else {
BlockHeader::read(&self.header[..]).ok()
}
}
}

impl compact_formats::CompactOutput {
/// Returns the note commitment for this output.
///
/// A convenience method that parses [`CompactOutput.cmu`].
///
/// [`CompactOutput.cmu`]: #structfield.cmu
pub fn cmu(&self) -> Result<Fr, ()> {
let mut repr = FrRepr::default();
repr.read_le(&self.cmu[..]).map_err(|_| ())?;
Fr::from_repr(repr).map_err(|_| ())
}

/// Returns the ephemeral public key for this output.
///
/// A convenience method that parses [`CompactOutput.epk`].
///
/// [`CompactOutput.epk`]: #structfield.epk
pub fn epk(&self) -> Result<edwards::Point<Bls12, PrimeOrder>, ()> {
let p = edwards::Point::<Bls12, _>::read(&self.epk[..], &JUBJUB).map_err(|_| ())?;
p.as_prime_order(&JUBJUB).ok_or(())
}
}
46 changes: 46 additions & 0 deletions zcash_client_backend/src/wallet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//! Structs representing transaction data scanned from the block chain by a wallet or
//! light client.

use pairing::bls12_381::{Bls12, Fr};
use zcash_primitives::{
jubjub::{edwards, PrimeOrder},
merkle_tree::IncrementalWitness,
primitives::{Note, PaymentAddress},
sapling::Node,
transaction::TxId,
};

/// A subset of a [`Transaction`] relevant to wallets and light clients.
///
/// [`Transaction`]: zcash_primitives::transaction::Transaction
pub struct WalletTx {
pub txid: TxId,
pub index: usize,
pub num_spends: usize,
pub num_outputs: usize,
pub shielded_spends: Vec<WalletShieldedSpend>,
pub shielded_outputs: Vec<WalletShieldedOutput>,
}

/// A subset of a [`SpendDescription`] relevant to wallets and light clients.
///
/// [`SpendDescription`]: zcash_primitives::transaction::components::SpendDescription
pub struct WalletShieldedSpend {
pub index: usize,
pub nf: Vec<u8>,
pub account: usize,
}

/// A subset of an [`OutputDescription`] relevant to wallets and light clients.
///
/// [`OutputDescription`]: zcash_primitives::transaction::components::OutputDescription
pub struct WalletShieldedOutput {
pub index: usize,
pub cmu: Fr,
pub epk: edwards::Point<Bls12, PrimeOrder>,
pub account: usize,
pub note: Note<Bls12>,
pub to: PaymentAddress<Bls12>,
pub is_change: bool,
pub witness: IncrementalWitness<Node>,
}
Loading