Integration tests

This commit is contained in:
Hanh 2022-06-11 20:29:14 +08:00
parent e73fa4fca4
commit 22779ddf02
10 changed files with 307 additions and 290 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
docs/_site/
*.db
Cargo.lock
node_modules/

View File

@ -37,20 +37,30 @@ message CompactTx {
// valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut))
uint32 fee = 3;
repeated CompactSpend spends = 4; // inputs
repeated CompactOutput outputs = 5; // outputs
repeated CompactSaplingSpend spends = 4; // inputs
repeated CompactSaplingOutput outputs = 5; // outputs
repeated CompactOrchardAction actions = 6;
}
// CompactSpend is a Sapling Spend Description as described in 7.3 of the Zcash
// CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash
// protocol specification.
message CompactSpend {
message CompactSaplingSpend {
bytes nf = 1; // nullifier (see the Zcash protocol specification)
}
// output is a Sapling Output Description as described in section 7.4 of the
// Zcash protocol spec. Total size is 948.
message CompactOutput {
message CompactSaplingOutput {
bytes cmu = 1; // note commitment u-coordinate
bytes epk = 2; // ephemeral public key
bytes ciphertext = 3; // ciphertext and zkproof
bytes ciphertext = 3; // first 52 bytes of ciphertext
}
// https://github.com/zcash/zips/blob/main/zip-0225.rst#orchard-action-description-orchardaction
// (but not all fields are needed)
message CompactOrchardAction {
bytes nullifier = 1; // [32] The nullifier of the input note
bytes cmx = 2; // [32] The x-coordinate of the note commitment for the output note
bytes ephemeralKey = 3; // [32] An encoding of an ephemeral Pallas public key
bytes ciphertext = 4; // [52] The note plaintext component of the encCiphertext field
}

View File

@ -32,7 +32,8 @@ message TxFilter {
}
// RawTransaction contains the complete transaction data. It also optionally includes
// the block height in which the transaction was included.
// the block height in which the transaction was included, or, when returned
// by GetMempoolStream(), the latest block height.
message RawTransaction {
bytes data = 1; // exact data returned by Zcash 'getrawtransaction'
uint64 height = 2; // height that the transaction was mined (or -1)
@ -109,11 +110,12 @@ message Exclude {
// The TreeState is derived from the Zcash z_gettreestate rpc.
message TreeState {
string network = 1; // "main" or "test"
uint64 height = 2;
string hash = 3; // block id
uint32 time = 4; // Unix epoch time when the block was mined
string tree = 5; // sapling commitment tree state
string network = 1; // "main" or "test"
uint64 height = 2; // block height
string hash = 3; // block id
uint32 time = 4; // Unix epoch time when the block was mined
string saplingTree = 5; // sapling commitment tree state
string orchardTree = 6; // orchard commitment tree state
}
// Results are sorted by height, which makes it easy to issue another
@ -135,27 +137,6 @@ message GetAddressUtxosReplyList {
repeated GetAddressUtxosReply addressUtxos = 1;
}
message PriceRequest {
// List of timestamps(in sec) at which the price is being requested
uint64 timestamp = 1;
// 3 letter currency-code
string currency = 2;
}
message PriceResponse {
// Timestamp at which this price quote was fetched. Note, this may not be the same
// as the request timestamp, but the server will respond with the closest timestamp that it has/can fetch
int64 timestamp = 1;
// 3-letter currency code, matching the request
string currency = 2;
// price of ZEC
double price = 3;
}
service CompactTxStreamer {
// Return the height of the tip of the best chain
rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
@ -163,10 +144,6 @@ service CompactTxStreamer {
rpc GetBlock(BlockID) returns (CompactBlock) {}
// Return a list of consecutive compact blocks
rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {}
// Get the historical and current prices
rpc GetZECPrice(PriceRequest) returns (PriceResponse) {}
rpc GetCurrentZECPrice(Empty) returns (PriceResponse) {}
// Return the requested full (not compact) transaction (as from zcashd)
rpc GetTransaction(TxFilter) returns (RawTransaction) {}
@ -175,10 +152,6 @@ service CompactTxStreamer {
// Return the txids corresponding to the given t-address within the given block range
rpc GetTaddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
// Legacy API that is used as a fallback for t-Address support, if the server is running the old version (lwdv2)
rpc GetAddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
rpc GetTaddressBalance(AddressList) returns (Balance) {}
rpc GetTaddressBalanceStream(stream Address) returns (Balance) {}
@ -193,6 +166,10 @@ service CompactTxStreamer {
// in the exclude list that don't exist in the mempool are ignored.
rpc GetMempoolTx(Exclude) returns (stream CompactTx) {}
// Return a stream of current Mempool transactions. This will keep the output stream open while
// there are mempool transactions. It will close the returned stream when a new block is mined.
rpc GetMempoolStream(Empty) returns (stream RawTransaction) {}
// GetTreeState returns the note commitment tree state corresponding to the given block.
// See section 3.7 of the Zcash protocol specification. It returns several other useful
// values also (even though they can be obtained using GetBlock).

View File

@ -90,7 +90,7 @@ async fn fetch_and_store_tree_state(
.get_tree_state(Request::new(block_id))
.await?
.into_inner();
let tree = CTree::read(&*hex::decode(&tree_state.tree)?)?;
let tree = CTree::read(&*hex::decode(&tree_state.sapling_tree)?)?;
c.db()?
.store_block(height, &block.hash, block.time, &tree)?;
Ok(())

View File

@ -167,7 +167,7 @@ pub struct DecryptedNote {
pub output_index: usize,
}
pub fn to_output_description(co: &CompactOutput) -> CompactOutputDescription {
pub fn to_output_description(co: &CompactSaplingOutput) -> CompactOutputDescription {
let mut cmu = [0u8; 32];
cmu.copy_from_slice(&co.cmu);
let cmu = bls12_381::Scalar::from_repr(cmu).unwrap();
@ -201,7 +201,7 @@ impl<'a, N: Parameters> AccountOutput<'a, N> {
output_index: usize,
block_output_index: usize,
vtx: &'a CompactTx,
co: &CompactOutput,
co: &CompactSaplingOutput,
) -> Self {
let mut epk_bytes = [0u8; 32];
epk_bytes.copy_from_slice(&co.epk);
@ -355,7 +355,7 @@ async fn get_tree_state(client: &mut CompactTxStreamerClient<Channel>, height: u
.await
.unwrap()
.into_inner();
rep.tree
rep.sapling_tree
}
/* Using the IncrementalWitness */

View File

@ -46,15 +46,17 @@ pub struct CompactTx {
pub fee: u32,
/// inputs
#[prost(message, repeated, tag="4")]
pub spends: ::prost::alloc::vec::Vec<CompactSpend>,
pub spends: ::prost::alloc::vec::Vec<CompactSaplingSpend>,
/// outputs
#[prost(message, repeated, tag="5")]
pub outputs: ::prost::alloc::vec::Vec<CompactOutput>,
pub outputs: ::prost::alloc::vec::Vec<CompactSaplingOutput>,
#[prost(message, repeated, tag="6")]
pub actions: ::prost::alloc::vec::Vec<CompactOrchardAction>,
}
/// CompactSpend is a Sapling Spend Description as described in 7.3 of the Zcash
/// CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash
/// protocol specification.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CompactSpend {
pub struct CompactSaplingSpend {
/// nullifier (see the Zcash protocol specification)
#[prost(bytes="vec", tag="1")]
pub nf: ::prost::alloc::vec::Vec<u8>,
@ -62,17 +64,34 @@ pub struct CompactSpend {
/// output is a Sapling Output Description as described in section 7.4 of the
/// Zcash protocol spec. Total size is 948.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CompactOutput {
pub struct CompactSaplingOutput {
/// note commitment u-coordinate
#[prost(bytes="vec", tag="1")]
pub cmu: ::prost::alloc::vec::Vec<u8>,
/// ephemeral public key
#[prost(bytes="vec", tag="2")]
pub epk: ::prost::alloc::vec::Vec<u8>,
/// ciphertext and zkproof
/// first 52 bytes of ciphertext
#[prost(bytes="vec", tag="3")]
pub ciphertext: ::prost::alloc::vec::Vec<u8>,
}
/// <https://github.com/zcash/zips/blob/main/zip-0225.rst#orchard-action-description-orchardaction>
/// (but not all fields are needed)
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CompactOrchardAction {
/// \[32\] The nullifier of the input note
#[prost(bytes="vec", tag="1")]
pub nullifier: ::prost::alloc::vec::Vec<u8>,
/// \[32\] The x-coordinate of the note commitment for the output note
#[prost(bytes="vec", tag="2")]
pub cmx: ::prost::alloc::vec::Vec<u8>,
/// \[32\] An encoding of an ephemeral Pallas public key
#[prost(bytes="vec", tag="3")]
pub ephemeral_key: ::prost::alloc::vec::Vec<u8>,
/// \[52\] The note plaintext component of the encCiphertext field
#[prost(bytes="vec", tag="4")]
pub ciphertext: ::prost::alloc::vec::Vec<u8>,
}
/// A BlockID message contains identifiers to select a block: a height or a
/// hash. Specification by hash is not implemented, but may be in the future.
#[derive(Clone, PartialEq, ::prost::Message)]
@ -107,7 +126,8 @@ pub struct TxFilter {
pub hash: ::prost::alloc::vec::Vec<u8>,
}
/// RawTransaction contains the complete transaction data. It also optionally includes
/// the block height in which the transaction was included.
/// the block height in which the transaction was included, or, when returned
/// by GetMempoolStream(), the latest block height.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RawTransaction {
/// exact data returned by Zcash 'getrawtransaction'
@ -231,6 +251,7 @@ pub struct TreeState {
/// "main" or "test"
#[prost(string, tag="1")]
pub network: ::prost::alloc::string::String,
/// block height
#[prost(uint64, tag="2")]
pub height: u64,
/// block id
@ -241,7 +262,10 @@ pub struct TreeState {
pub time: u32,
/// sapling commitment tree state
#[prost(string, tag="5")]
pub tree: ::prost::alloc::string::String,
pub sapling_tree: ::prost::alloc::string::String,
/// orchard commitment tree state
#[prost(string, tag="6")]
pub orchard_tree: ::prost::alloc::string::String,
}
/// Results are sorted by height, which makes it easy to issue another
/// request that picks up from where the previous left off.
@ -275,28 +299,6 @@ pub struct GetAddressUtxosReplyList {
#[prost(message, repeated, tag="1")]
pub address_utxos: ::prost::alloc::vec::Vec<GetAddressUtxosReply>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PriceRequest {
/// List of timestamps(in sec) at which the price is being requested
#[prost(uint64, tag="1")]
pub timestamp: u64,
/// 3 letter currency-code
#[prost(string, tag="2")]
pub currency: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PriceResponse {
/// Timestamp at which this price quote was fetched. Note, this may not be the same
/// as the request timestamp, but the server will respond with the closest timestamp that it has/can fetch
#[prost(int64, tag="1")]
pub timestamp: i64,
/// 3-letter currency code, matching the request
#[prost(string, tag="2")]
pub currency: ::prost::alloc::string::String,
/// price of ZEC
#[prost(double, tag="3")]
pub price: f64,
}
/// Generated client implementations.
pub mod compact_tx_streamer_client {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
@ -406,9 +408,9 @@ pub mod compact_tx_streamer_client {
&mut self,
request: impl tonic::IntoRequest<super::BlockRange>,
) -> Result<
tonic::Response<tonic::codec::Streaming<super::CompactBlock>>,
tonic::Status,
> {
tonic::Response<tonic::codec::Streaming<super::CompactBlock>>,
tonic::Status,
> {
self.inner
.ready()
.await
@ -424,45 +426,6 @@ pub mod compact_tx_streamer_client {
);
self.inner.server_streaming(request.into_request(), path, codec).await
}
/// Get the historical and current prices
pub async fn get_zec_price(
&mut self,
request: impl tonic::IntoRequest<super::PriceRequest>,
) -> Result<tonic::Response<super::PriceResponse>, tonic::Status> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetZECPrice",
);
self.inner.unary(request.into_request(), path, codec).await
}
pub async fn get_current_zec_price(
&mut self,
request: impl tonic::IntoRequest<super::Empty>,
) -> Result<tonic::Response<super::PriceResponse>, tonic::Status> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetCurrentZECPrice",
);
self.inner.unary(request.into_request(), path, codec).await
}
/// Return the requested full (not compact) transaction (as from zcashd)
pub async fn get_transaction(
&mut self,
@ -508,9 +471,9 @@ pub mod compact_tx_streamer_client {
&mut self,
request: impl tonic::IntoRequest<super::TransparentAddressBlockFilter>,
) -> Result<
tonic::Response<tonic::codec::Streaming<super::RawTransaction>>,
tonic::Status,
> {
tonic::Response<tonic::codec::Streaming<super::RawTransaction>>,
tonic::Status,
> {
self.inner
.ready()
.await
@ -526,29 +489,6 @@ pub mod compact_tx_streamer_client {
);
self.inner.server_streaming(request.into_request(), path, codec).await
}
/// Legacy API that is used as a fallback for t-Address support, if the server is running the old version (lwdv2)
pub async fn get_address_txids(
&mut self,
request: impl tonic::IntoRequest<super::TransparentAddressBlockFilter>,
) -> Result<
tonic::Response<tonic::codec::Streaming<super::RawTransaction>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressTxids",
);
self.inner.server_streaming(request.into_request(), path, codec).await
}
pub async fn get_taddress_balance(
&mut self,
request: impl tonic::IntoRequest<super::AddressList>,
@ -602,9 +542,9 @@ pub mod compact_tx_streamer_client {
&mut self,
request: impl tonic::IntoRequest<super::Exclude>,
) -> Result<
tonic::Response<tonic::codec::Streaming<super::CompactTx>>,
tonic::Status,
> {
tonic::Response<tonic::codec::Streaming<super::CompactTx>>,
tonic::Status,
> {
self.inner
.ready()
.await
@ -620,6 +560,30 @@ pub mod compact_tx_streamer_client {
);
self.inner.server_streaming(request.into_request(), path, codec).await
}
/// Return a stream of current Mempool transactions. This will keep the output stream open while
/// there are mempool transactions. It will close the returned stream when a new block is mined.
pub async fn get_mempool_stream(
&mut self,
request: impl tonic::IntoRequest<super::Empty>,
) -> Result<
tonic::Response<tonic::codec::Streaming<super::RawTransaction>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetMempoolStream",
);
self.inner.server_streaming(request.into_request(), path, codec).await
}
/// GetTreeState returns the note commitment tree state corresponding to the given block.
/// See section 3.7 of the Zcash protocol specification. It returns several other useful
/// values also (even though they can be obtained using GetBlock).
@ -666,9 +630,9 @@ pub mod compact_tx_streamer_client {
&mut self,
request: impl tonic::IntoRequest<super::GetAddressUtxosArg>,
) -> Result<
tonic::Response<tonic::codec::Streaming<super::GetAddressUtxosReply>>,
tonic::Status,
> {
tonic::Response<tonic::codec::Streaming<super::GetAddressUtxosReply>>,
tonic::Status,
> {
self.inner
.ready()
.await
@ -754,15 +718,6 @@ pub mod compact_tx_streamer_server {
&self,
request: tonic::Request<super::BlockRange>,
) -> Result<tonic::Response<Self::GetBlockRangeStream>, tonic::Status>;
/// Get the historical and current prices
async fn get_zec_price(
&self,
request: tonic::Request<super::PriceRequest>,
) -> Result<tonic::Response<super::PriceResponse>, tonic::Status>;
async fn get_current_zec_price(
&self,
request: tonic::Request<super::Empty>,
) -> Result<tonic::Response<super::PriceResponse>, tonic::Status>;
/// Return the requested full (not compact) transaction (as from zcashd)
async fn get_transaction(
&self,
@ -784,17 +739,6 @@ pub mod compact_tx_streamer_server {
&self,
request: tonic::Request<super::TransparentAddressBlockFilter>,
) -> Result<tonic::Response<Self::GetTaddressTxidsStream>, tonic::Status>;
///Server streaming response type for the GetAddressTxids method.
type GetAddressTxidsStream: futures_core::Stream<
Item = Result<super::RawTransaction, tonic::Status>,
>
+ Send
+ 'static;
/// Legacy API that is used as a fallback for t-Address support, if the server is running the old version (lwdv2)
async fn get_address_txids(
&self,
request: tonic::Request<super::TransparentAddressBlockFilter>,
) -> Result<tonic::Response<Self::GetAddressTxidsStream>, tonic::Status>;
async fn get_taddress_balance(
&self,
request: tonic::Request<super::AddressList>,
@ -822,6 +766,18 @@ pub mod compact_tx_streamer_server {
&self,
request: tonic::Request<super::Exclude>,
) -> Result<tonic::Response<Self::GetMempoolTxStream>, tonic::Status>;
///Server streaming response type for the GetMempoolStream method.
type GetMempoolStreamStream: futures_core::Stream<
Item = Result<super::RawTransaction, tonic::Status>,
>
+ Send
+ 'static;
/// Return a stream of current Mempool transactions. This will keep the output stream open while
/// there are mempool transactions. It will close the returned stream when a new block is mined.
async fn get_mempool_stream(
&self,
request: tonic::Request<super::Empty>,
) -> Result<tonic::Response<Self::GetMempoolStreamStream>, tonic::Status>;
/// GetTreeState returns the note commitment tree state corresponding to the given block.
/// See section 3.7 of the Zcash protocol specification. It returns several other useful
/// values also (even though they can be obtained using GetBlock).
@ -1020,84 +976,6 @@ pub mod compact_tx_streamer_server {
};
Box::pin(fut)
}
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetZECPrice" => {
#[allow(non_camel_case_types)]
struct GetZECPriceSvc<T: CompactTxStreamer>(pub Arc<T>);
impl<
T: CompactTxStreamer,
> tonic::server::UnaryService<super::PriceRequest>
for GetZECPriceSvc<T> {
type Response = super::PriceResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::PriceRequest>,
) -> Self::Future {
let inner = self.0.clone();
let fut = async move {
(*inner).get_zec_price(request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = GetZECPriceSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetCurrentZECPrice" => {
#[allow(non_camel_case_types)]
struct GetCurrentZECPriceSvc<T: CompactTxStreamer>(pub Arc<T>);
impl<T: CompactTxStreamer> tonic::server::UnaryService<super::Empty>
for GetCurrentZECPriceSvc<T> {
type Response = super::PriceResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::Empty>,
) -> Self::Future {
let inner = self.0.clone();
let fut = async move {
(*inner).get_current_zec_price(request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = GetCurrentZECPriceSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTransaction" => {
#[allow(non_camel_case_types)]
struct GetTransactionSvc<T: CompactTxStreamer>(pub Arc<T>);
@ -1220,48 +1098,6 @@ pub mod compact_tx_streamer_server {
};
Box::pin(fut)
}
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressTxids" => {
#[allow(non_camel_case_types)]
struct GetAddressTxidsSvc<T: CompactTxStreamer>(pub Arc<T>);
impl<
T: CompactTxStreamer,
> tonic::server::ServerStreamingService<
super::TransparentAddressBlockFilter,
> for GetAddressTxidsSvc<T> {
type Response = super::RawTransaction;
type ResponseStream = T::GetAddressTxidsStream;
type Future = BoxFuture<
tonic::Response<Self::ResponseStream>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::TransparentAddressBlockFilter>,
) -> Self::Future {
let inner = self.0.clone();
let fut = async move {
(*inner).get_address_txids(request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = GetAddressTxidsSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
);
let res = grpc.server_streaming(method, req).await;
Ok(res)
};
Box::pin(fut)
}
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalance" => {
#[allow(non_camel_case_types)]
struct GetTaddressBalanceSvc<T: CompactTxStreamer>(pub Arc<T>);
@ -1383,6 +1219,47 @@ pub mod compact_tx_streamer_server {
};
Box::pin(fut)
}
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetMempoolStream" => {
#[allow(non_camel_case_types)]
struct GetMempoolStreamSvc<T: CompactTxStreamer>(pub Arc<T>);
impl<
T: CompactTxStreamer,
> tonic::server::ServerStreamingService<super::Empty>
for GetMempoolStreamSvc<T> {
type Response = super::RawTransaction;
type ResponseStream = T::GetMempoolStreamStream;
type Future = BoxFuture<
tonic::Response<Self::ResponseStream>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::Empty>,
) -> Self::Future {
let inner = self.0.clone();
let fut = async move {
(*inner).get_mempool_stream(request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = GetMempoolStreamSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
);
let res = grpc.server_streaming(method, req).await;
Ok(res)
};
Box::pin(fut)
}
"/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTreeState" => {
#[allow(non_camel_case_types)]
struct GetTreeStateSvc<T: CompactTxStreamer>(pub Arc<T>);

View File

@ -243,7 +243,7 @@ pub fn new_diversified_address() -> Result<String, Error> {
Ok(address)
}
#[get("/make_payment_uri", data = "<payment>")]
#[post("/make_payment_uri", data = "<payment>")]
pub fn make_payment_uri(payment: Json<PaymentURI>) -> Result<String, Error> {
let uri = warp_api_ffi::api::payment_uri::make_payment_uri(
&payment.address,

12
test-scripts/package.json Normal file
View File

@ -0,0 +1,12 @@
{
"name": "test-scripts",
"version": "1.0.0",
"main": "test.js",
"license": "MIT",
"devDependencies": {
"chakram": "^1.5.0"
},
"dependencies": {
"mocha": "^10.0.0"
}
}

18
test-scripts/rpc.sh Normal file
View File

@ -0,0 +1,18 @@
curl -X POST -H 'Content-Type: application/json' -d '{"coin": 0, "name": "test", "key": "zxviews1qvq5u9dnqqqqpqyc3wd00lql5njzdqx3xk670z5ldjuqkxm3lcphkvcyvpg2kavcze2edwj4f27k0s62q48dqdlnxlnr7jhczv2d8c9y2hw4uxgqrx9sluja52jqjtlqqsl65hd6p9xrdhzh7spgd0s4zud9xtv7sqepahchq06ng6w5vm36l9zjg0n2upkdv4k4yd7mhfsdpu9lqra0mnyq0k8v8f23j8pqq0ekr4f4aa7gf538eudpwck0yw3l74s37z4hf2xkyfq8eswwx"}' http://localhost:8000/new_account
curl -X GET http://localhost:8000/accounts
curl -X POST 'http://localhost:8000/set_active?coin=0&id_account=1'
curl -X GET http://localhost:8000/backup
curl -X GET http://localhost:8000/latest_height
curl -X GET http://localhost:8000/balance
curl -X GET http://localhost:8000/tx_history
curl -X GET http://localhost:8000/new_diversified_address
curl -X POST 'http://localhost:8000/sync?offset=0'
curl -X POST 'http://localhost:8000/rewind?height=1600000'
# Sync to latest height - 20 to calculate the witnesses for later
curl -X POST 'http://localhost:8000/sync?offset=20'
curl -X POST http://localhost:8000/mark_synced
curl -X POST -H 'Content-Type: application/json' -d '{"address": "zs1hn7qwpjz6p5n24hjhks73y6vn0tpk3c2cfu8wzgtgl4j9ht8ycjgjr47c94scce3uahaje9jkxn", "amount": 100000, "memo": "Hello"}' http://localhost:8000/make_payment_uri
curl -X GET http://localhost:8000/parse_payment_uri?uri=zcash%3Azs1hn7qwpjz6p5n24hjhks73y6vn0tpk3c2cfu8wzgtgl4j9ht8ycjgjr47c94scce3uahaje9jkxn%3Famount%3D0.001%26memo%3DSGVsbG8
curl -X POST -H 'Content-Type: application/json' -d '{"recipients": [{"address": "zs1hn7qwpjz6p5n24hjhks73y6vn0tpk3c2cfu8wzgtgl4j9ht8ycjgjr47c94scce3uahaje9jkxn", "amount": 100000, "memo": "Hello", "reply_to": false, "subject": "hello", "max_amount_per_note": 0}], "confirmations": 10}' http://localhost:8000/create_offline_tx
// offline signing and pay need an account with a secret key

122
test-scripts/test.js Normal file
View File

@ -0,0 +1,122 @@
const chakram = require('chakram'), expect = chakram.expect;
describe('warp', async function () {
var id_account;
it("should allow creating new accounts", async function () {
const account = await chakram.post('http://localhost:8000/new_account', {
coin: 0,
name: 'zecpages',
key: 'zxviews1q0duytgcqqqqpqre26wkl45gvwwwd706xw608hucmvfalr759ejwf7qshjf5r9aa7323zulvz6plhttp5mltqcgs9t039cx2d09mgq05ts63n8u35hyv6h9nc9ctqqtue2u7cer2mqegunuulq2luhq3ywjcz35yyljewa4mgkgjzyfwh6fr6jd0dzd44ghk0nxdv2hnv4j5nxfwv24rwdmgllhe0p8568sgqt9ckt02v2kxf5ahtql6s0ltjpkckw8gtymxtxuu9gcr0swvz'
})
expect(account).to.have.status(200)
id_account = account.body
await chakram.post(`http://localhost:8000/set_active?coin=0&id_account=${id_account}`)
})
it("should give you the backup info", async function () {
const backup = await chakram.get('http://localhost:8000/backup')
expect(backup.body).to.deep.equal({
"fvk": "zxviews1q0duytgcqqqqpqre26wkl45gvwwwd706xw608hucmvfalr759ejwf7qshjf5r9aa7323zulvz6plhttp5mltqcgs9t039cx2d09mgq05ts63n8u35hyv6h9nc9ctqqtue2u7cer2mqegunuulq2luhq3ywjcz35yyljewa4mgkgjzyfwh6fr6jd0dzd44ghk0nxdv2hnv4j5nxfwv24rwdmgllhe0p8568sgqt9ckt02v2kxf5ahtql6s0ltjpkckw8gtymxtxuu9gcr0swvz",
"seed": null,
"sk": null
})
})
it("should give you the latest block height", async function () {
const heights = await chakram.get('http://localhost:8000/latest_height')
expect(heights.body.latest > 1000000)
})
it("should not have balance because we didn't sync", async function () {
const balance = await chakram.get('http://localhost:8000/balance')
expect(balance.body).to.equals(0)
})
it("should not have a tx history because we didn't sync", async function () {
const tx_history = await chakram.get('http://localhost:8000/tx_history')
expect(tx_history.body.length).to.equals(0)
})
it("should sync", async function () {
this.timeout(120000)
await chakram.post('http://localhost:8000/sync?offset=0')
})
it("should rewind and resync", async function () {
this.timeout(120000)
await chakram.post('http://localhost:8000/rewind?height=419200')
await chakram.post('http://localhost:8000/sync?offset=0')
const balance = await chakram.get('http://localhost:8000/balance')
expect(balance.body).to.not.equals(0)
})
it("should rewind to a past block", async function () {
this.timeout(120000)
await chakram.post('http://localhost:8000/rewind?height=1000000')
const balance = await chakram.get('http://localhost:8000/balance')
expect(balance.body).to.equals(364779600) // that's the balance at this block
})
it("can skip blocks", async function () {
await chakram.post('http://localhost:8000/rewind?height=1000000')
await chakram.post('http://localhost:8000/mark_synced')
const balance = await chakram.get('http://localhost:8000/balance')
expect(balance.body).to.equals(364779600) // that's the balance at this block
})
it("should create and parse payment uri", async function () {
const p = {
address: "zs1hn7qwpjz6p5n24hjhks73y6vn0tpk3c2cfu8wzgtgl4j9ht8ycjgjr47c94scce3uahaje9jkxn",
amount: 100000,
memo: "Hello"
}
const p_uri = await chakram.post('http://localhost:8000/make_payment_uri', p)
expect(p_uri.body).to.equals('zcash:zs1hn7qwpjz6p5n24hjhks73y6vn0tpk3c2cfu8wzgtgl4j9ht8ycjgjr47c94scce3uahaje9jkxn?amount=0.001&memo=SGVsbG8')
const payment = await chakram.get('http://localhost:8000/parse_payment_uri?uri=zcash%3Azs1hn7qwpjz6p5n24hjhks73y6vn0tpk3c2cfu8wzgtgl4j9ht8ycjgjr47c94scce3uahaje9jkxn%3Famount%3D0.001%26memo%3DSGVsbG8')
expect(payment.body).to.deep.equal(p)
})
it("should create offline payment requests", async function () {
this.timeout(120000)
await chakram.post('http://localhost:8000/rewind?height=1600000')
await chakram.post('http://localhost:8000/sync?offset=10') // sync to compute note witnesses
const payment_request = {
recipients: [{
address: "zs1hn7qwpjz6p5n24hjhks73y6vn0tpk3c2cfu8wzgtgl4j9ht8ycjgjr47c94scce3uahaje9jkxn",
amount: 100000,
memo: "Hello",
reply_to: false,
subject: "hello",
max_amount_per_note: 0
}],
confirmations: 10
}
const unsigned_tx = await chakram.post('http://localhost:8000/create_offline_tx', payment_request)
expect(unsigned_tx.body.outputs).to.deep.equal( // we cannot check the other fields because they change from run to run
[
{
"addr": "zs1hn7qwpjz6p5n24hjhks73y6vn0tpk3c2cfu8wzgtgl4j9ht8ycjgjr47c94scce3uahaje9jkxn",
"amount": 100000,
"memo": "f09f9ba14d53470a0a68656c6c6f0a48656c6c6f",
"ovk": "459121112ebe923d49af689b5aa2f67cccd62af3656549992e62aa373768ffef"
}
]
)
})
it("should give you the tx_history", async function () {
const txs = await chakram.get('http://localhost:8000/tx_history')
expect(txs.body.length).to.not.equals(0)
})
// cannot test signing without a secret key
// need to setup a dummy account
})