Skip to content

Commit

Permalink
Add a protobuf representation for transaction proposals.
Browse files Browse the repository at this point in the history
Co-authored-by: Kris Nuttycombe <[email protected]>
  • Loading branch information
softminus and nuttycom committed Aug 8, 2023
1 parent 5fbce5f commit 46aa420
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 1 deletion.
13 changes: 12 additions & 1 deletion zcash_client_backend/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::path::{Path, PathBuf};

const COMPACT_FORMATS_PROTO: &str = "proto/compact_formats.proto";

const PROPOSAL_PROTO: &str = "proto/proposal.proto";

#[cfg(feature = "lightwalletd-tonic")]
const SERVICE_PROTO: &str = "proto/service.proto";

Expand Down Expand Up @@ -34,12 +36,21 @@ fn build() -> io::Result<()> {
// Build the compact format types.
tonic_build::compile_protos(COMPACT_FORMATS_PROTO)?;

// Copy the generated types into the source tree so changes can be committed.
// Copy the generated compact formats types into the source tree so changes can be committed.
fs::copy(
out.join("cash.z.wallet.sdk.rpc.rs"),
"src/proto/compact_formats.rs",
)?;

// Build the proposal types.
tonic_build::compile_protos(PROPOSAL_PROTO)?;

// Copy the generated proposal types into the source tree so changes can be committed.
fs::copy(
out.join("cash.z.wallet.sdk.ffi.rs"),
"src/proto/proposal.rs",
)?;

#[cfg(feature = "lightwalletd-tonic")]
{
// Build the gRPC types and client.
Expand Down
80 changes: 80 additions & 0 deletions zcash_client_backend/proto/proposal.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) 2023 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .

syntax = "proto3";
package cash.z.wallet.sdk.ffi;

// A data structure that describes the inputs to be consumed and outputs to
// be produced in a proposed transaction.
message Proposal {
uint32 protoVersion = 1;
// ZIP 321 serialized transaction request
string transactionRequest = 2;
// The unique identifier and amount for each proposed input
repeated ProposedInput inputs = 3;
// The total value, fee amount, and change outputs of the proposed
// transaction
TransactionBalance balance = 4;
// The fee rule used in constructing this proposal
FeeRule feeRule = 6;
// The target height for which the proposal was constructed
//
// The chain must contain at least this many blocks in order for the proposal to
// be executed.
uint32 minTargetHeight = 7;
// Returns the anchor height used in preparing the proposal.
//
// If, at the time that the proposal is executed, the anchor height
// required to satisfy / the minimum confirmation depth is less than this
// height, the proposal execution / API will return an error.
uint32 minAnchorHeight = 8;
// A flag indicating whether the proposal is for a shielding transaction,
// used for determining which OVK to select for wallet-internal outputs.
bool isShielding = 9;
}

// The value pool from which a particular proposed input is drawn
enum ValuePool {
Transparent = 0;
Sapling = 2;
}

// The unique identifier, value pool, and amount for each proposed input
message ProposedInput {
bytes txid = 1;
ValuePool pool = 2;
uint32 index = 3;
int64 value = 4;
}

// The fee rule used in constructing a Proposal
enum FeeRule {
// 10000 ZAT
PreZip313 = 0;
// 1000 ZAT
Zip313 = 1;
// MAX(10000, 5000 * logical_actions) ZAT
Zip317 = 2;
}

// The total value, fee amount, and change outputs of the proposed
// transaction
message TransactionBalance {
repeated ChangeValue proposedChange = 1;
int64 feeRequired = 2;
}

// An enumeration of change value types.
message ChangeValue {
oneof value {
SaplingChange saplingValue = 1;
}
}

// The amount and memo for a proposed Sapling change output.
message SaplingChange {
int64 amount = 1;
bytes memo = 2;
}

5 changes: 5 additions & 0 deletions zcash_client_backend/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ use zcash_note_encryption::{EphemeralKeyBytes, COMPACT_NOTE_SIZE};
#[allow(clippy::derive_partial_eq_without_eq)]
pub mod compact_formats;

#[rustfmt::skip]
#[allow(unknown_lints)]
#[allow(clippy::derive_partial_eq_without_eq)]
pub mod proposal;

#[cfg(feature = "lightwalletd-tonic")]
#[rustfmt::skip]
#[allow(unknown_lints)]
Expand Down
146 changes: 146 additions & 0 deletions zcash_client_backend/src/proto/proposal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/// A data structure that describes the inputs to be consumed and outputs to
/// be produced in a proposed transaction.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Proposal {
#[prost(uint32, tag = "1")]
pub proto_version: u32,
/// ZIP 321 serialized transaction request
#[prost(string, tag = "2")]
pub transaction_request: ::prost::alloc::string::String,
/// The unique identifier and amount for each proposed input
#[prost(message, repeated, tag = "3")]
pub inputs: ::prost::alloc::vec::Vec<ProposedInput>,
/// The total value, fee amount, and change outputs of the proposed
/// transaction
#[prost(message, optional, tag = "4")]
pub balance: ::core::option::Option<TransactionBalance>,
/// The fee rule used in constructing this proposal
#[prost(enumeration = "FeeRule", tag = "6")]
pub fee_rule: i32,
/// The target height for which the proposal was constructed
///
/// The chain must contain at least this many blocks in order for the proposal to
/// be executed.
#[prost(uint32, tag = "7")]
pub min_target_height: u32,
/// Returns the anchor height used in preparing the proposal.
///
/// If, at the time that the proposal is executed, the anchor height
/// required to satisfy / the minimum confirmation depth is less than this
/// height, the proposal execution / API will return an error.
#[prost(uint32, tag = "8")]
pub min_anchor_height: u32,
/// A flag indicating whether the proposal is for a shielding transaction,
/// used for determining which OVK to select for wallet-internal outputs.
#[prost(bool, tag = "9")]
pub is_shielding: bool,
}
/// The unique identifier, value pool, and amount for each proposed input
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProposedInput {
#[prost(bytes = "vec", tag = "1")]
pub txid: ::prost::alloc::vec::Vec<u8>,
#[prost(enumeration = "ValuePool", tag = "2")]
pub pool: i32,
#[prost(uint32, tag = "3")]
pub index: u32,
#[prost(int64, tag = "4")]
pub value: i64,
}
/// The total value, fee amount, and change outputs of the proposed
/// transaction
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TransactionBalance {
#[prost(message, repeated, tag = "1")]
pub proposed_change: ::prost::alloc::vec::Vec<ChangeValue>,
#[prost(int64, tag = "2")]
pub fee_required: i64,
}
/// An enumeration of change value types.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ChangeValue {
#[prost(oneof = "change_value::Value", tags = "1")]
pub value: ::core::option::Option<change_value::Value>,
}
/// Nested message and enum types in `ChangeValue`.
pub mod change_value {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Value {
#[prost(message, tag = "1")]
SaplingValue(super::SaplingChange),
}
}
/// The amount and memo for a proposed Sapling change output.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SaplingChange {
#[prost(int64, tag = "1")]
pub amount: i64,
#[prost(bytes = "vec", tag = "2")]
pub memo: ::prost::alloc::vec::Vec<u8>,
}
/// The value pool from which a particular proposed input is drawn
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ValuePool {
Transparent = 0,
Sapling = 2,
}
impl ValuePool {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
ValuePool::Transparent => "Transparent",
ValuePool::Sapling => "Sapling",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"Transparent" => Some(Self::Transparent),
"Sapling" => Some(Self::Sapling),
_ => None,
}
}
}
/// The fee rule used in constructing a Proposal
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum FeeRule {
/// 10000 ZAT
PreZip313 = 0,
/// 1000 ZAT
Zip313 = 1,
/// MAX(10000, 5000 * logical_actions) ZAT
Zip317 = 2,
}
impl FeeRule {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
FeeRule::PreZip313 => "PreZip313",
FeeRule::Zip313 => "Zip313",
FeeRule::Zip317 => "Zip317",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"PreZip313" => Some(Self::PreZip313),
"Zip313" => Some(Self::Zip313),
"Zip317" => Some(Self::Zip317),
_ => None,
}
}
}
36 changes: 36 additions & 0 deletions zcash_primitives/src/transaction/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,39 @@ pub trait FutureFeeRule: FeeRule {
tze_outputs: &[impl tze::OutputView],
) -> Result<Amount, Self::Error>;
}

/// An enumeration of the standard fee rules supported by the wallet.
pub enum StandardFeeRule {
PreZip313,
Zip313,
Zip317,
}

impl FeeRule for StandardFeeRule {
type Error = zip317::FeeError;

fn fee_required<P: consensus::Parameters>(
&self,
params: &P,
target_height: BlockHeight,
transparent_inputs: &[impl transparent::InputView],
transparent_outputs: &[impl transparent::OutputView],
sapling_input_count: usize,
sapling_output_count: usize,
orchard_action_count: usize,
) -> Result<Amount, Self::Error> {
match self {
Self::PreZip313 => Ok(zip317::MINIMUM_FEE),
Self::Zip313 => Ok(Amount::from_u64(1000).unwrap()),
Self::Zip317 => zip317::FeeRule::standard().fee_required(
params,
target_height,
transparent_inputs,
transparent_outputs,
sapling_input_count,
sapling_output_count,
orchard_action_count,
),
}
}
}

0 comments on commit 46aa420

Please sign in to comment.