forked from hush/silentdragonlite-cli
Aditya Kulkarni
5 years ago
6 changed files with 181 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||
target/ |
|||
Cargo.lock |
@ -0,0 +1,22 @@ |
|||
[package] |
|||
name = "rust-lightclient" |
|||
version = "0.1.0" |
|||
edition = "2018" |
|||
|
|||
[dependencies] |
|||
tower-grpc = { git = "https://github.com/tower-rs/tower-grpc" } |
|||
futures = "0.1" |
|||
bytes = "0.4" |
|||
env_logger = { version = "0.5", default-features = false } |
|||
log = "0.4" |
|||
http = "0.1" |
|||
prost = "0.5" |
|||
tokio = "0.1" |
|||
tower-request-modifier = { git = "https://github.com/tower-rs/tower-http" } |
|||
tower-hyper = "0.1" |
|||
hyper = "0.12" |
|||
tower-service = "0.2" |
|||
tower-util = "0.1" |
|||
|
|||
[build-dependencies] |
|||
tower-grpc-build = { git = "https://github.com/tower-rs/tower-grpc", features = ["tower-hyper"] } |
@ -0,0 +1,12 @@ |
|||
fn main() { |
|||
// Build proto files
|
|||
tower_grpc_build::Config::new() |
|||
.enable_server(false) |
|||
.enable_client(true) |
|||
.build( |
|||
&["proto/service.proto", "proto/compact_formats.proto"], |
|||
&["proto"], |
|||
) |
|||
.unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); |
|||
println!("cargo:rerun-if-changed=proto/service.proto"); |
|||
} |
@ -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; |
|||
} |
@ -0,0 +1,49 @@ |
|||
syntax = "proto3"; |
|||
package cash.z.wallet.sdk.rpc; |
|||
option go_package = "walletrpc"; |
|||
|
|||
import "compact_formats.proto"; |
|||
|
|||
// A BlockID message contains identifiers to select a block: a height or a |
|||
// hash. If the hash is present it takes precedence. |
|||
message BlockID { |
|||
uint64 height = 1; |
|||
bytes hash = 2; |
|||
} |
|||
|
|||
// BlockRange technically allows ranging from hash to hash etc but this is not |
|||
// currently intended for support, though there is no reason you couldn't do |
|||
// it. Further permutations are left as an exercise. |
|||
message BlockRange { |
|||
BlockID start = 1; |
|||
BlockID end = 2; |
|||
} |
|||
|
|||
// A TxFilter contains the information needed to identify a particular |
|||
// transaction: either a block and an index, or a direct transaction hash. |
|||
message TxFilter { |
|||
BlockID block = 1; |
|||
uint64 index = 2; |
|||
bytes hash = 3; |
|||
} |
|||
|
|||
// RawTransaction contains the complete transaction data. |
|||
message RawTransaction { |
|||
bytes data = 1; |
|||
} |
|||
|
|||
message SendResponse { |
|||
int32 errorCode = 1; |
|||
string errorMessage = 2; |
|||
} |
|||
|
|||
// Empty placeholder. Someday we may want to specify e.g. a particular chain fork. |
|||
message ChainSpec {} |
|||
|
|||
service CompactTxStreamer { |
|||
rpc GetLatestBlock(ChainSpec) returns (BlockID) {} |
|||
rpc GetBlock(BlockID) returns (CompactBlock) {} |
|||
rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {} |
|||
rpc GetTransaction(TxFilter) returns (RawTransaction) {} |
|||
rpc SendTransaction(RawTransaction) returns (SendResponse) {} |
|||
} |
@ -0,0 +1,48 @@ |
|||
|
|||
use futures::Future; |
|||
use hyper::client::connect::{Destination, HttpConnector}; |
|||
use tower_grpc::Request; |
|||
use tower_hyper::{client, util}; |
|||
use tower_util::MakeService; |
|||
|
|||
pub mod grpc_client { |
|||
include!(concat!(env!("OUT_DIR"), "/cash.z.wallet.sdk.rpc.rs")); |
|||
} |
|||
|
|||
pub fn main() { |
|||
let uri: http::Uri = format!("http://127.0.0.1:9067").parse().unwrap(); |
|||
|
|||
let dst = Destination::try_from_uri(uri.clone()).unwrap(); |
|||
let connector = util::Connector::new(HttpConnector::new(4)); |
|||
let settings = client::Builder::new().http2_only(true).clone(); |
|||
let mut make_client = client::Connect::with_builder(connector, settings); |
|||
|
|||
let say_hello = make_client |
|||
.make_service(dst) |
|||
.map_err(|e| panic!("connect error: {:?}", e)) |
|||
.and_then(move |conn| { |
|||
use crate::grpc_client::client::CompactTxStreamer; |
|||
|
|||
let conn = tower_request_modifier::Builder::new() |
|||
.set_origin(uri) |
|||
.build(conn) |
|||
.unwrap(); |
|||
|
|||
// Wait until the client is ready...
|
|||
CompactTxStreamer::new(conn).ready() |
|||
}) |
|||
.and_then(|mut client| { |
|||
use crate::grpc_client::ChainSpec; |
|||
|
|||
client.get_latest_block(Request::new(ChainSpec {})) |
|||
}) |
|||
.and_then(|response| { |
|||
println!("RESPONSE = {:?}", response); |
|||
Ok(()) |
|||
}) |
|||
.map_err(|e| { |
|||
println!("ERR = {:?}", e); |
|||
}); |
|||
|
|||
tokio::run(say_hello); |
|||
} |
Loading…
Reference in new issue