Data Access Api integration (#227)
* add cargo dependencies for data access api * Imports + init_accounts_table * ported init_accounts_table and init_accounts_table_with_keys * ported zcashlc_derive_extended_spending_keys * ported zcashlc_derive_extended_full_viewing_keys * ported zcashlc_derive_shielded_address_from_seed * ported zcashlc_derive_shielded_address_from_viewing_key * ported zcashlc_derive_extended_full_viewing_key * ported zcashlc_init_blocks_table * port zcashlc_get_address * port zcashlc_is_valid_transparent_address * port zcashlc_get_balance * fix u32 try_into error * ported zcashlc_get_received_memo_as_utf8 * fixed zcashlc_init_blocks_table, ported zcashlc_get_sent_memo_as_utf8 * ported zcashlc_validate_combined_chain * ported zcashlc_rewind_to_height * ported zcashlc_rewind_to_height * ported zcashlc_decrypt_and_store_transaction * ported zcashlc_branch_id_for_height * ported zcashlc_derive_transparent_address_from_seed * Compiled lib.rs * lib.rs compiles * fix AccountId import * Fix: send fails with missing params. cargo update * Fix: demo app fails to initialize * fix AdvancedReOrgTests * deprecate default FEE * Add fee for height helper for UI purposes * default fee for heightwq * update proto files and compiled files * Update to librustzcash master. * add latests changes from rust on master * merge with master * fix merge error Co-authored-by: Kris Nuttycombe <kris@electriccoin.co>
This commit is contained in:
parent
ca722571d0
commit
c69b54db9e
File diff suppressed because it is too large
Load Diff
16
Cargo.toml
16
Cargo.toml
|
@ -16,12 +16,16 @@ zcash_client_sqlite = "0.2.1"
|
|||
zcash_primitives = "0.4"
|
||||
|
||||
#### Temporary additions: ####################################
|
||||
bitvec = "0.18"
|
||||
base58 = "0.1.0"
|
||||
sha2 = "0.9"
|
||||
bs58 = { version = "0.3", features = ["check"] }
|
||||
hdwallet = "0.2.2"
|
||||
ripemd160 = "0.9"
|
||||
secp256k1 = "0.17.2"
|
||||
|
||||
# Temporary workaround for https://github.com/myrrlyn/funty/issues/3
|
||||
funty = "=1.1.0"
|
||||
##############################################################
|
||||
|
||||
[dependencies.zcash_proofs]
|
||||
|
@ -40,11 +44,11 @@ crate-type = ["staticlib"]
|
|||
[profile.release]
|
||||
lto = true
|
||||
|
||||
[patch.crates-io]
|
||||
zcash_client_backend = {git = "https://github.com/zcash/librustzcash", branch = "master"}
|
||||
zcash_client_sqlite = {git = "https://github.com/zcash/librustzcash", branch = "master"}
|
||||
zcash_primitives = {git = "https://github.com/zcash/librustzcash", branch = "master"}
|
||||
zcash_proofs = {git = "https://github.com/zcash/librustzcash", branch = "master"}
|
||||
|
||||
[features]
|
||||
mainnet = ["zcash_client_sqlite/mainnet"]
|
||||
|
||||
[patch.crates-io]
|
||||
zcash_client_backend = { git = 'https://github.com/zcash/librustzcash', rev = 'c289cf9d4b46d330c265006e5f796543f2744fe5' }
|
||||
zcash_client_sqlite = { git = 'https://github.com/zcash/librustzcash', rev = 'c289cf9d4b46d330c265006e5f796543f2744fe5' }
|
||||
zcash_primitives = { git = 'https://github.com/zcash/librustzcash', rev = 'c289cf9d4b46d330c265006e5f796543f2744fe5' }
|
||||
zcash_proofs = { git = 'https://github.com/zcash/librustzcash', rev = 'c289cf9d4b46d330c265006e5f796543f2744fe5' }
|
||||
|
|
|
@ -66,10 +66,10 @@ PODS:
|
|||
- SwiftNIOFoundationCompat (< 3, >= 2.22.0)
|
||||
- SwiftNIOTLS (< 3, >= 2.22.0)
|
||||
- SwiftProtobuf (1.12.0)
|
||||
- ZcashLightClientKit (0.9.4):
|
||||
- ZcashLightClientKit (0.10.0):
|
||||
- gRPC-Swift (= 1.0.0-alpha.19)
|
||||
- SQLite.swift (~> 0.12.2)
|
||||
- ZcashLightClientKit/Tests (0.9.4):
|
||||
- ZcashLightClientKit/Tests (0.10.0):
|
||||
- gRPC-Swift (= 1.0.0-alpha.19)
|
||||
- SQLite.swift (~> 0.12.2)
|
||||
|
||||
|
@ -145,7 +145,7 @@ SPEC CHECKSUMS:
|
|||
SwiftNIOTLS: 46bb3a0ff37d6b52ae6baf5207ec3cd411da327c
|
||||
SwiftNIOTransportServices: 801923921fbecdcde1e1c1ff38e812167d01ead1
|
||||
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
|
||||
ZcashLightClientKit: 7f144177deece40fb9075bf6024028026255f75b
|
||||
ZcashLightClientKit: a1a36be74ca95e2802ba3d6bcc40e9b2753eb0da
|
||||
|
||||
PODFILE CHECKSUM: 7d5095283dc02470f40ab06564d94076ba16d570
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'ZcashLightClientKit'
|
||||
s.version = '0.9.4'
|
||||
s.version = '0.10.0'
|
||||
s.summary = 'Zcash Light Client wallet SDK for iOS'
|
||||
|
||||
s.description = <<-DESC
|
||||
|
|
|
@ -198,7 +198,13 @@ public class Initializer {
|
|||
transactionRepository: transactionRepository,
|
||||
backend: rustBackend)
|
||||
|
||||
guard try rustBackend.initAccountsTable(dbData: dataDbURL, exfvks: viewingKeys) else {
|
||||
do {
|
||||
guard try rustBackend.initAccountsTable(dbData: dataDbURL, exfvks: viewingKeys) else {
|
||||
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
||||
}
|
||||
} catch RustWeldingError.dataDbNotEmpty {
|
||||
// this is fine
|
||||
}catch {
|
||||
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
||||
}
|
||||
|
||||
|
|
|
@ -215,7 +215,6 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
|||
dbData.1,
|
||||
account,
|
||||
[CChar](extsk.utf8CString),
|
||||
consensusBranchId,
|
||||
[CChar](to.utf8CString),
|
||||
value,
|
||||
[CChar](memoBytes.utf8CString),
|
||||
|
|
|
@ -62,6 +62,10 @@ message LightdInfo {
|
|||
uint64 saplingActivationHeight = 5; // depends on mainnet or testnet
|
||||
string consensusBranchId = 6; // protocol identifier, see consensus/upgrades.cpp
|
||||
uint64 blockHeight = 7; // latest block on the best chain
|
||||
string gitCommit = 8;
|
||||
string branch = 9;
|
||||
string buildDate = 10;
|
||||
string buildUser = 11;
|
||||
}
|
||||
|
||||
// TransparentAddressBlockFilter restricts the results to the given address
|
||||
|
@ -86,6 +90,45 @@ message PingResponse {
|
|||
int64 exit = 2;
|
||||
}
|
||||
|
||||
message Address {
|
||||
string address = 1;
|
||||
}
|
||||
message AddressList {
|
||||
repeated string addresses = 1;
|
||||
}
|
||||
message Balance {
|
||||
int64 valueZat = 1;
|
||||
}
|
||||
|
||||
message Exclude {
|
||||
repeated bytes txid = 1;
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
message GetAddressUtxosArg {
|
||||
string address = 1;
|
||||
uint64 startHeight = 2;
|
||||
uint32 maxEntries = 3; // zero means unlimited
|
||||
}
|
||||
message GetAddressUtxosReply {
|
||||
bytes txid = 1;
|
||||
int32 index = 2;
|
||||
bytes script = 3;
|
||||
int64 valueZat = 4;
|
||||
uint64 height = 5;
|
||||
}
|
||||
message GetAddressUtxosReplyList {
|
||||
repeated GetAddressUtxosReply addressUtxos = 1;
|
||||
}
|
||||
|
||||
service CompactTxStreamer {
|
||||
// Return the height of the tip of the best chain
|
||||
rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
|
||||
|
@ -100,7 +143,29 @@ service CompactTxStreamer {
|
|||
rpc SendTransaction(RawTransaction) returns (SendResponse) {}
|
||||
|
||||
// Return the txids corresponding to the given t-address within the given block range
|
||||
rpc GetAddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
|
||||
rpc GetTaddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
|
||||
rpc GetTaddressBalance(AddressList) returns (Balance) {}
|
||||
rpc GetTaddressBalanceStream(stream Address) returns (Balance) {}
|
||||
|
||||
// Return the compact transactions currently in the mempool; the results
|
||||
// can be a few seconds out of date. If the Exclude list is empty, return
|
||||
// all transactions; otherwise return all *except* those in the Exclude list
|
||||
// (if any); this allows the client to avoid receiving transactions that it
|
||||
// already has (from an earlier call to this rpc). The transaction IDs in the
|
||||
// Exclude list can be shortened to any number of bytes to make the request
|
||||
// more bandwidth-efficient; if two or more transactions in the mempool
|
||||
// match a shortened txid, they are all sent (none is excluded). Transactions
|
||||
// in the exclude list that don't exist in the mempool are ignored.
|
||||
rpc GetMempoolTx(Exclude) returns (stream CompactTx) {}
|
||||
|
||||
// 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).
|
||||
// The block can be specified by either height or hash.
|
||||
rpc GetTreeState(BlockID) returns (TreeState) {}
|
||||
|
||||
rpc GetAddressUtxos(GetAddressUtxosArg) returns (GetAddressUtxosReplyList) {}
|
||||
rpc GetAddressUtxosStream(GetAddressUtxosArg) returns (stream GetAddressUtxosReply) {}
|
||||
|
||||
// Return information about this lightwalletd instance and the blockchain
|
||||
rpc GetLightdInfo(Empty) returns (LightdInfo) {}
|
||||
|
|
|
@ -53,12 +53,43 @@ internal protocol CompactTxStreamerClientProtocol: GRPCClient {
|
|||
callOptions: CallOptions?
|
||||
) -> UnaryCall<RawTransaction, SendResponse>
|
||||
|
||||
func getAddressTxids(
|
||||
func getTaddressTxids(
|
||||
_ request: TransparentAddressBlockFilter,
|
||||
callOptions: CallOptions?,
|
||||
handler: @escaping (RawTransaction) -> Void
|
||||
) -> ServerStreamingCall<TransparentAddressBlockFilter, RawTransaction>
|
||||
|
||||
func getTaddressBalance(
|
||||
_ request: AddressList,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<AddressList, Balance>
|
||||
|
||||
func getTaddressBalanceStream(
|
||||
callOptions: CallOptions?
|
||||
) -> ClientStreamingCall<Address, Balance>
|
||||
|
||||
func getMempoolTx(
|
||||
_ request: Exclude,
|
||||
callOptions: CallOptions?,
|
||||
handler: @escaping (CompactTx) -> Void
|
||||
) -> ServerStreamingCall<Exclude, CompactTx>
|
||||
|
||||
func getTreeState(
|
||||
_ request: BlockID,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<BlockID, TreeState>
|
||||
|
||||
func getAddressUtxos(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<GetAddressUtxosArg, GetAddressUtxosReplyList>
|
||||
|
||||
func getAddressUtxosStream(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions?,
|
||||
handler: @escaping (GetAddressUtxosReply) -> Void
|
||||
) -> ServerStreamingCall<GetAddressUtxosArg, GetAddressUtxosReply>
|
||||
|
||||
func getLightdInfo(
|
||||
_ request: Empty,
|
||||
callOptions: CallOptions?
|
||||
|
@ -164,17 +195,136 @@ extension CompactTxStreamerClientProtocol {
|
|||
/// Return the txids corresponding to the given t-address within the given block range
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to GetAddressTxids.
|
||||
/// - request: Request to send to GetTaddressTxids.
|
||||
/// - callOptions: Call options.
|
||||
/// - handler: A closure called when each response is received from the server.
|
||||
/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.
|
||||
internal func getAddressTxids(
|
||||
internal func getTaddressTxids(
|
||||
_ request: TransparentAddressBlockFilter,
|
||||
callOptions: CallOptions? = nil,
|
||||
handler: @escaping (RawTransaction) -> Void
|
||||
) -> ServerStreamingCall<TransparentAddressBlockFilter, RawTransaction> {
|
||||
return self.makeServerStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressTxids",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressTxids",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
handler: handler
|
||||
)
|
||||
}
|
||||
|
||||
/// Unary call to GetTaddressBalance
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to GetTaddressBalance.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func getTaddressBalance(
|
||||
_ request: AddressList,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<AddressList, Balance> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalance",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// Client streaming call to GetTaddressBalanceStream
|
||||
///
|
||||
/// Callers should use the `send` method on the returned object to send messages
|
||||
/// to the server. The caller should send an `.end` after the final message has been sent.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `ClientStreamingCall` with futures for the metadata, status and response.
|
||||
internal func getTaddressBalanceStream(
|
||||
callOptions: CallOptions? = nil
|
||||
) -> ClientStreamingCall<Address, Balance> {
|
||||
return self.makeClientStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalanceStream",
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// Return the compact transactions currently in the mempool; the results
|
||||
/// can be a few seconds out of date. If the Exclude list is empty, return
|
||||
/// all transactions; otherwise return all *except* those in the Exclude list
|
||||
/// (if any); this allows the client to avoid receiving transactions that it
|
||||
/// already has (from an earlier call to this rpc). The transaction IDs in the
|
||||
/// Exclude list can be shortened to any number of bytes to make the request
|
||||
/// more bandwidth-efficient; if two or more transactions in the mempool
|
||||
/// match a shortened txid, they are all sent (none is excluded). Transactions
|
||||
/// in the exclude list that don't exist in the mempool are ignored.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to GetMempoolTx.
|
||||
/// - callOptions: Call options.
|
||||
/// - handler: A closure called when each response is received from the server.
|
||||
/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.
|
||||
internal func getMempoolTx(
|
||||
_ request: Exclude,
|
||||
callOptions: CallOptions? = nil,
|
||||
handler: @escaping (CompactTx) -> Void
|
||||
) -> ServerStreamingCall<Exclude, CompactTx> {
|
||||
return self.makeServerStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetMempoolTx",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
handler: handler
|
||||
)
|
||||
}
|
||||
|
||||
/// 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).
|
||||
/// The block can be specified by either height or hash.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to GetTreeState.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func getTreeState(
|
||||
_ request: BlockID,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<BlockID, TreeState> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTreeState",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// Unary call to GetAddressUtxos
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to GetAddressUtxos.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func getAddressUtxos(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<GetAddressUtxosArg, GetAddressUtxosReplyList> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressUtxos",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// Server streaming call to GetAddressUtxosStream
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to GetAddressUtxosStream.
|
||||
/// - callOptions: Call options.
|
||||
/// - handler: A closure called when each response is received from the server.
|
||||
/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.
|
||||
internal func getAddressUtxosStream(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions? = nil,
|
||||
handler: @escaping (GetAddressUtxosReply) -> Void
|
||||
) -> ServerStreamingCall<GetAddressUtxosArg, GetAddressUtxosReply> {
|
||||
return self.makeServerStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressUtxosStream",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
handler: handler
|
||||
|
|
|
@ -187,6 +187,14 @@ struct LightdInfo {
|
|||
/// latest block on the best chain
|
||||
var blockHeight: UInt64 = 0
|
||||
|
||||
var gitCommit: String = String()
|
||||
|
||||
var branch: String = String()
|
||||
|
||||
var buildDate: String = String()
|
||||
|
||||
var buildUser: String = String()
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
@ -251,6 +259,128 @@ struct PingResponse {
|
|||
init() {}
|
||||
}
|
||||
|
||||
struct Address {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var address: String = String()
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct AddressList {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var addresses: [String] = []
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct Balance {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var valueZat: Int64 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct Exclude {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var txid: [Data] = []
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
/// The TreeState is derived from the zcash z_gettreestate rpc.
|
||||
struct TreeState {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// "main" or "test"
|
||||
var network: String = String()
|
||||
|
||||
var height: UInt64 = 0
|
||||
|
||||
/// block id
|
||||
var hash: String = String()
|
||||
|
||||
/// Unix epoch time when the block was mined
|
||||
var time: UInt32 = 0
|
||||
|
||||
/// sapling commitment tree state
|
||||
var tree: String = String()
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct GetAddressUtxosArg {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var address: String = String()
|
||||
|
||||
var startHeight: UInt64 = 0
|
||||
|
||||
/// zero means unlimited
|
||||
var maxEntries: UInt32 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct GetAddressUtxosReply {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var txid: Data = SwiftProtobuf.Internal.emptyData
|
||||
|
||||
var index: Int32 = 0
|
||||
|
||||
var script: Data = SwiftProtobuf.Internal.emptyData
|
||||
|
||||
var valueZat: Int64 = 0
|
||||
|
||||
var height: UInt64 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct GetAddressUtxosReplyList {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var addressUtxos: [GetAddressUtxosReply] = []
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "cash.z.wallet.sdk.rpc"
|
||||
|
@ -484,6 +614,10 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
5: .same(proto: "saplingActivationHeight"),
|
||||
6: .same(proto: "consensusBranchId"),
|
||||
7: .same(proto: "blockHeight"),
|
||||
8: .same(proto: "gitCommit"),
|
||||
9: .same(proto: "branch"),
|
||||
10: .same(proto: "buildDate"),
|
||||
11: .same(proto: "buildUser"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
@ -496,6 +630,10 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
case 5: try decoder.decodeSingularUInt64Field(value: &self.saplingActivationHeight)
|
||||
case 6: try decoder.decodeSingularStringField(value: &self.consensusBranchID)
|
||||
case 7: try decoder.decodeSingularUInt64Field(value: &self.blockHeight)
|
||||
case 8: try decoder.decodeSingularStringField(value: &self.gitCommit)
|
||||
case 9: try decoder.decodeSingularStringField(value: &self.branch)
|
||||
case 10: try decoder.decodeSingularStringField(value: &self.buildDate)
|
||||
case 11: try decoder.decodeSingularStringField(value: &self.buildUser)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -523,6 +661,18 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
if self.blockHeight != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.blockHeight, fieldNumber: 7)
|
||||
}
|
||||
if !self.gitCommit.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.gitCommit, fieldNumber: 8)
|
||||
}
|
||||
if !self.branch.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.branch, fieldNumber: 9)
|
||||
}
|
||||
if !self.buildDate.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.buildDate, fieldNumber: 10)
|
||||
}
|
||||
if !self.buildUser.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.buildUser, fieldNumber: 11)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
|
@ -534,6 +684,10 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
if lhs.saplingActivationHeight != rhs.saplingActivationHeight {return false}
|
||||
if lhs.consensusBranchID != rhs.consensusBranchID {return false}
|
||||
if lhs.blockHeight != rhs.blockHeight {return false}
|
||||
if lhs.gitCommit != rhs.gitCommit {return false}
|
||||
if lhs.branch != rhs.branch {return false}
|
||||
if lhs.buildDate != rhs.buildDate {return false}
|
||||
if lhs.buildUser != rhs.buildUser {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
@ -637,3 +791,295 @@ extension PingResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Address: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".Address"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "address"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self.address)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.address.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.address, fieldNumber: 1)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Address, rhs: Address) -> Bool {
|
||||
if lhs.address != rhs.address {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension AddressList: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".AddressList"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "addresses"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeRepeatedStringField(value: &self.addresses)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.addresses.isEmpty {
|
||||
try visitor.visitRepeatedStringField(value: self.addresses, fieldNumber: 1)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: AddressList, rhs: AddressList) -> Bool {
|
||||
if lhs.addresses != rhs.addresses {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Balance: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".Balance"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "valueZat"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularInt64Field(value: &self.valueZat)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.valueZat != 0 {
|
||||
try visitor.visitSingularInt64Field(value: self.valueZat, fieldNumber: 1)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Balance, rhs: Balance) -> Bool {
|
||||
if lhs.valueZat != rhs.valueZat {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Exclude: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".Exclude"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "txid"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeRepeatedBytesField(value: &self.txid)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.txid.isEmpty {
|
||||
try visitor.visitRepeatedBytesField(value: self.txid, fieldNumber: 1)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Exclude, rhs: Exclude) -> Bool {
|
||||
if lhs.txid != rhs.txid {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension TreeState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".TreeState"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "network"),
|
||||
2: .same(proto: "height"),
|
||||
3: .same(proto: "hash"),
|
||||
4: .same(proto: "time"),
|
||||
5: .same(proto: "tree"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self.network)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.height)
|
||||
case 3: try decoder.decodeSingularStringField(value: &self.hash)
|
||||
case 4: try decoder.decodeSingularUInt32Field(value: &self.time)
|
||||
case 5: try decoder.decodeSingularStringField(value: &self.tree)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.network.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.network, fieldNumber: 1)
|
||||
}
|
||||
if self.height != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.height, fieldNumber: 2)
|
||||
}
|
||||
if !self.hash.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.hash, fieldNumber: 3)
|
||||
}
|
||||
if self.time != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.time, fieldNumber: 4)
|
||||
}
|
||||
if !self.tree.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.tree, fieldNumber: 5)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: TreeState, rhs: TreeState) -> Bool {
|
||||
if lhs.network != rhs.network {return false}
|
||||
if lhs.height != rhs.height {return false}
|
||||
if lhs.hash != rhs.hash {return false}
|
||||
if lhs.time != rhs.time {return false}
|
||||
if lhs.tree != rhs.tree {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension GetAddressUtxosArg: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".GetAddressUtxosArg"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "address"),
|
||||
2: .same(proto: "startHeight"),
|
||||
3: .same(proto: "maxEntries"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self.address)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.startHeight)
|
||||
case 3: try decoder.decodeSingularUInt32Field(value: &self.maxEntries)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.address.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.address, fieldNumber: 1)
|
||||
}
|
||||
if self.startHeight != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.startHeight, fieldNumber: 2)
|
||||
}
|
||||
if self.maxEntries != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.maxEntries, fieldNumber: 3)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: GetAddressUtxosArg, rhs: GetAddressUtxosArg) -> Bool {
|
||||
if lhs.address != rhs.address {return false}
|
||||
if lhs.startHeight != rhs.startHeight {return false}
|
||||
if lhs.maxEntries != rhs.maxEntries {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension GetAddressUtxosReply: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".GetAddressUtxosReply"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "txid"),
|
||||
2: .same(proto: "index"),
|
||||
3: .same(proto: "script"),
|
||||
4: .same(proto: "valueZat"),
|
||||
5: .same(proto: "height"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularBytesField(value: &self.txid)
|
||||
case 2: try decoder.decodeSingularInt32Field(value: &self.index)
|
||||
case 3: try decoder.decodeSingularBytesField(value: &self.script)
|
||||
case 4: try decoder.decodeSingularInt64Field(value: &self.valueZat)
|
||||
case 5: try decoder.decodeSingularUInt64Field(value: &self.height)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.txid.isEmpty {
|
||||
try visitor.visitSingularBytesField(value: self.txid, fieldNumber: 1)
|
||||
}
|
||||
if self.index != 0 {
|
||||
try visitor.visitSingularInt32Field(value: self.index, fieldNumber: 2)
|
||||
}
|
||||
if !self.script.isEmpty {
|
||||
try visitor.visitSingularBytesField(value: self.script, fieldNumber: 3)
|
||||
}
|
||||
if self.valueZat != 0 {
|
||||
try visitor.visitSingularInt64Field(value: self.valueZat, fieldNumber: 4)
|
||||
}
|
||||
if self.height != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.height, fieldNumber: 5)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: GetAddressUtxosReply, rhs: GetAddressUtxosReply) -> Bool {
|
||||
if lhs.txid != rhs.txid {return false}
|
||||
if lhs.index != rhs.index {return false}
|
||||
if lhs.script != rhs.script {return false}
|
||||
if lhs.valueZat != rhs.valueZat {return false}
|
||||
if lhs.height != rhs.height {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension GetAddressUtxosReplyList: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".GetAddressUtxosReplyList"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "addressUtxos"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeRepeatedMessageField(value: &self.addressUtxos)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.addressUtxos.isEmpty {
|
||||
try visitor.visitRepeatedMessageField(value: self.addressUtxos, fieldNumber: 1)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: GetAddressUtxosReplyList, rhs: GetAddressUtxosReplyList) -> Bool {
|
||||
if lhs.addressUtxos != rhs.addressUtxos {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ int64_t zcashlc_create_to_address(const uint8_t *db_data,
|
|||
uintptr_t db_data_len,
|
||||
int32_t account,
|
||||
const char *extsk,
|
||||
int32_t consensus_branch_id,
|
||||
const char *to,
|
||||
int64_t value,
|
||||
const char *memo,
|
||||
|
@ -192,6 +191,11 @@ bool zcashlc_is_valid_transparent_address(const char *address);
|
|||
|
||||
bool zcashlc_is_valid_viewing_key(const char *key);
|
||||
|
||||
/**
|
||||
* returns whether the given viewing key is valid or not
|
||||
*/
|
||||
bool zcashlc_is_valid_viewing_key(const char *key);
|
||||
|
||||
/**
|
||||
* Returns the length of the last error message to be logged.
|
||||
*/
|
||||
|
|
|
@ -77,7 +77,7 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
let receivedTxHeight: BlockHeight = 663188
|
||||
var initialTotalBalance: Int64 = -1
|
||||
var initialVerifiedBalance: Int64 = -1
|
||||
self.expectedReorgHeight = receivedTxHeight
|
||||
self.expectedReorgHeight = receivedTxHeight + 1
|
||||
|
||||
/*
|
||||
precondition:know balances before tx at received_Tx_height arrives
|
||||
|
@ -402,7 +402,7 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
|
||||
func testIncomingTransactionIndexChange() throws {
|
||||
hookToReOrgNotification()
|
||||
self.expectedReorgHeight = 663195
|
||||
self.expectedReorgHeight = 663196
|
||||
self.expectedRewindHeight = 663175
|
||||
try coordinator.reset(saplingActivation: birthday)
|
||||
try coordinator.resetBlocks(dataset: .predefined(dataset: .txIndexChangeBefore))
|
||||
|
@ -779,7 +779,7 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
/*
|
||||
9. sync to latest height
|
||||
*/
|
||||
self.expectedReorgHeight = sentTxHeight
|
||||
self.expectedReorgHeight = sentTxHeight + 1
|
||||
let afterReorgExpectation = XCTestExpectation(description: "after reorg sync")
|
||||
|
||||
try coordinator.sync(completion: { (s) in
|
||||
|
@ -1062,7 +1062,7 @@ class AdvancedReOrgTests: XCTestCase {
|
|||
return
|
||||
}
|
||||
|
||||
self.expectedReorgHeight = sentTxHeight
|
||||
self.expectedReorgHeight = sentTxHeight + 1
|
||||
/*
|
||||
4. stage transaction at sentTxHeight
|
||||
*/
|
||||
|
|
|
@ -20,71 +20,101 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
import Foundation
|
||||
import GRPC
|
||||
import NIO
|
||||
import NIOHTTP1
|
||||
import SwiftProtobuf
|
||||
@testable import ZcashLightClientKit
|
||||
|
||||
|
||||
/// Usage: instantiate DarksideStreamerClient, then call methods of this protocol to make API calls.
|
||||
internal protocol DarksideStreamerClientProtocol {
|
||||
func reset(_ request: DarksideMetaState, callOptions: CallOptions?) -> UnaryCall<DarksideMetaState, Empty>
|
||||
func stageBlocksStream(callOptions: CallOptions?) -> ClientStreamingCall<DarksideBlock, Empty>
|
||||
func stageBlocks(_ request: DarksideBlocksURL, callOptions: CallOptions?) -> UnaryCall<DarksideBlocksURL, Empty>
|
||||
func stageBlocksCreate(_ request: DarksideEmptyBlocks, callOptions: CallOptions?) -> UnaryCall<DarksideEmptyBlocks, Empty>
|
||||
func stageTransactionsStream(callOptions: CallOptions?) -> ClientStreamingCall<RawTransaction, Empty>
|
||||
func stageTransactions(_ request: DarksideTransactionsURL, callOptions: CallOptions?) -> UnaryCall<DarksideTransactionsURL, Empty>
|
||||
func applyStaged(_ request: DarksideHeight, callOptions: CallOptions?) -> UnaryCall<DarksideHeight, Empty>
|
||||
func getIncomingTransactions(_ request: Empty, callOptions: CallOptions?, handler: @escaping (RawTransaction) -> Void) -> ServerStreamingCall<Empty, RawTransaction>
|
||||
func clearIncomingTransactions(_ request: Empty, callOptions: CallOptions?) -> UnaryCall<Empty, Empty>
|
||||
internal protocol DarksideStreamerClientProtocol: GRPCClient {
|
||||
func reset(
|
||||
_ request: DarksideMetaState,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<DarksideMetaState, Empty>
|
||||
|
||||
func stageBlocksStream(
|
||||
callOptions: CallOptions?
|
||||
) -> ClientStreamingCall<DarksideBlock, Empty>
|
||||
|
||||
func stageBlocks(
|
||||
_ request: DarksideBlocksURL,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<DarksideBlocksURL, Empty>
|
||||
|
||||
func stageBlocksCreate(
|
||||
_ request: DarksideEmptyBlocks,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<DarksideEmptyBlocks, Empty>
|
||||
|
||||
func stageTransactionsStream(
|
||||
callOptions: CallOptions?
|
||||
) -> ClientStreamingCall<RawTransaction, Empty>
|
||||
|
||||
func stageTransactions(
|
||||
_ request: DarksideTransactionsURL,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<DarksideTransactionsURL, Empty>
|
||||
|
||||
func applyStaged(
|
||||
_ request: DarksideHeight,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<DarksideHeight, Empty>
|
||||
|
||||
func getIncomingTransactions(
|
||||
_ request: Empty,
|
||||
callOptions: CallOptions?,
|
||||
handler: @escaping (RawTransaction) -> Void
|
||||
) -> ServerStreamingCall<Empty, RawTransaction>
|
||||
|
||||
func clearIncomingTransactions(
|
||||
_ request: Empty,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<Empty, Empty>
|
||||
|
||||
}
|
||||
|
||||
internal final class DarksideStreamerClient: GRPCClient, DarksideStreamerClientProtocol {
|
||||
internal let channel: GRPCChannel
|
||||
internal var defaultCallOptions: CallOptions
|
||||
|
||||
/// Creates a client for the cash.z.wallet.sdk.rpc.DarksideStreamer service.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - channel: `GRPCChannel` to the service host.
|
||||
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
|
||||
internal init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) {
|
||||
self.channel = channel
|
||||
self.defaultCallOptions = defaultCallOptions
|
||||
}
|
||||
extension DarksideStreamerClientProtocol {
|
||||
|
||||
/// Reset reverts all darksidewalletd state (active block range, latest height,
|
||||
/// staged blocks and transactions) and lightwalletd state (cache) to empty,
|
||||
/// the same as the initial state. This occurs synchronously and instantaneously;
|
||||
/// no reorg happens in lightwalletd. This is good to do before each independent
|
||||
/// test so that no state leaks from one test to another.
|
||||
/// Also sets (some of) the values returned by GetLightdInfo().
|
||||
/// Also sets (some of) the values returned by GetLightdInfo(). The Sapling
|
||||
/// activation height specified here must be where the block range starts.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to Reset.
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func reset(_ request: DarksideMetaState, callOptions: CallOptions? = nil) -> UnaryCall<DarksideMetaState, Empty> {
|
||||
return self.makeUnaryCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/Reset",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions)
|
||||
internal func reset(
|
||||
_ request: DarksideMetaState,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<DarksideMetaState, Empty> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/Reset",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// StageBlocksStream accepts a list of blocks and saves them into the blocks
|
||||
/// staging area until ApplyStaged() is called; there is no immediate effect on
|
||||
/// the mock zcashd. Blocks are hex-encoded.
|
||||
/// the mock zcashd. Blocks are hex-encoded. Order is important, see ApplyStaged.
|
||||
///
|
||||
/// Callers should use the `send` method on the returned object to send messages
|
||||
/// to the server. The caller should send an `.end` after the final message has been sent.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `ClientStreamingCall` with futures for the metadata, status and response.
|
||||
internal func stageBlocksStream(callOptions: CallOptions? = nil) -> ClientStreamingCall<DarksideBlock, Empty> {
|
||||
return self.makeClientStreamingCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocksStream",
|
||||
callOptions: callOptions ?? self.defaultCallOptions)
|
||||
internal func stageBlocksStream(
|
||||
callOptions: CallOptions? = nil
|
||||
) -> ClientStreamingCall<DarksideBlock, Empty> {
|
||||
return self.makeClientStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocksStream",
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// StageBlocks is the same as StageBlocksStream() except the blocks are fetched
|
||||
|
@ -92,31 +122,41 @@ internal final class DarksideStreamerClient: GRPCClient, DarksideStreamerClientP
|
|||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to StageBlocks.
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func stageBlocks(_ request: DarksideBlocksURL, callOptions: CallOptions? = nil) -> UnaryCall<DarksideBlocksURL, Empty> {
|
||||
return self.makeUnaryCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocks",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions)
|
||||
internal func stageBlocks(
|
||||
_ request: DarksideBlocksURL,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<DarksideBlocksURL, Empty> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocks",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// StageBlocksCreate is like the previous two, except it creates 'count'
|
||||
/// empty blocks at consecutive heights starting at height 'height'. The
|
||||
/// 'nonce' is part of the header, so it contributes to the block hash; this
|
||||
/// lets you create two fake blocks with the same transactions (or no
|
||||
/// transactions) and same height, with two different hashes.
|
||||
/// lets you create identical blocks (same transactions and height), but with
|
||||
/// different hashes.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to StageBlocksCreate.
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func stageBlocksCreate(_ request: DarksideEmptyBlocks, callOptions: CallOptions? = nil) -> UnaryCall<DarksideEmptyBlocks, Empty> {
|
||||
return self.makeUnaryCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocksCreate",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions)
|
||||
internal func stageBlocksCreate(
|
||||
_ request: DarksideEmptyBlocks,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<DarksideEmptyBlocks, Empty> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocksCreate",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// StageTransactions stores the given transaction-height pairs in the
|
||||
/// StageTransactionsStream stores the given transaction-height pairs in the
|
||||
/// staging area until ApplyStaged() is called. Note that these transactions
|
||||
/// are not returned by the production GetTransaction() gRPC until they
|
||||
/// appear in a "mined" block (contained in the active blockchain presented
|
||||
|
@ -126,34 +166,47 @@ internal final class DarksideStreamerClient: GRPCClient, DarksideStreamerClientP
|
|||
/// to the server. The caller should send an `.end` after the final message has been sent.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `ClientStreamingCall` with futures for the metadata, status and response.
|
||||
internal func stageTransactionsStream(callOptions: CallOptions? = nil) -> ClientStreamingCall<RawTransaction, Empty> {
|
||||
return self.makeClientStreamingCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageTransactionsStream",
|
||||
callOptions: callOptions ?? self.defaultCallOptions)
|
||||
internal func stageTransactionsStream(
|
||||
callOptions: CallOptions? = nil
|
||||
) -> ClientStreamingCall<RawTransaction, Empty> {
|
||||
return self.makeClientStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageTransactionsStream",
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// Unary call to StageTransactions
|
||||
/// StageTransactions is the same except the transactions are fetched from
|
||||
/// the given url. They are all staged into the block at the given height.
|
||||
/// Staging transactions to different heights requires multiple calls.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to StageTransactions.
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func stageTransactions(_ request: DarksideTransactionsURL, callOptions: CallOptions? = nil) -> UnaryCall<DarksideTransactionsURL, Empty> {
|
||||
return self.makeUnaryCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageTransactions",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions)
|
||||
internal func stageTransactions(
|
||||
_ request: DarksideTransactionsURL,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<DarksideTransactionsURL, Empty> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/StageTransactions",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// ApplyStaged iterates the list of blocks that were staged by the
|
||||
/// StageBlocks*() gRPCs, in the order they were staged, and "merges" each
|
||||
/// into the active, working blocks list that the mock zcashd is presenting
|
||||
/// to lightwalletd. The resulting working block list can't have gaps; if the
|
||||
/// working block range is 1000-1006, and the staged block range is 1003-1004,
|
||||
/// the resulting range is 1000-1004, with 1000-1002 unchanged, blocks
|
||||
/// 1003-1004 from the new range, and 1005-1006 dropped. After merging all
|
||||
/// blocks, ApplyStaged() appends staged transactions (in the order received)
|
||||
/// into each one's corresponding block. The staging area is then cleared.
|
||||
/// to lightwalletd. Even as each block is applied, the active list can't
|
||||
/// have gaps; if the active block range is 1000-1006, and the staged block
|
||||
/// range is 1003-1004, the resulting range is 1000-1004, with 1000-1002
|
||||
/// unchanged, blocks 1003-1004 from the new range, and 1005-1006 dropped.
|
||||
///
|
||||
/// After merging all blocks, ApplyStaged() appends staged transactions (in
|
||||
/// the order received) into each one's corresponding (by height) block
|
||||
/// The staging area is then cleared.
|
||||
///
|
||||
/// The argument specifies the latest block height that mock zcashd reports
|
||||
/// (i.e. what's returned by GetLatestBlock). Note that ApplyStaged() can
|
||||
|
@ -162,12 +215,17 @@ internal final class DarksideStreamerClient: GRPCClient, DarksideStreamerClientP
|
|||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to ApplyStaged.
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func applyStaged(_ request: DarksideHeight, callOptions: CallOptions? = nil) -> UnaryCall<DarksideHeight, Empty> {
|
||||
return self.makeUnaryCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/ApplyStaged",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions)
|
||||
internal func applyStaged(
|
||||
_ request: DarksideHeight,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<DarksideHeight, Empty> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/ApplyStaged",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
|
||||
/// Calls to the production gRPC SendTransaction() store the transaction in
|
||||
|
@ -180,27 +238,52 @@ internal final class DarksideStreamerClient: GRPCClient, DarksideStreamerClientP
|
|||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to GetIncomingTransactions.
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - handler: A closure called when each response is received from the server.
|
||||
/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.
|
||||
internal func getIncomingTransactions(_ request: Empty, callOptions: CallOptions? = nil, handler: @escaping (RawTransaction) -> Void) -> ServerStreamingCall<Empty, RawTransaction> {
|
||||
return self.makeServerStreamingCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/GetIncomingTransactions",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
handler: handler)
|
||||
internal func getIncomingTransactions(
|
||||
_ request: Empty,
|
||||
callOptions: CallOptions? = nil,
|
||||
handler: @escaping (RawTransaction) -> Void
|
||||
) -> ServerStreamingCall<Empty, RawTransaction> {
|
||||
return self.makeServerStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/GetIncomingTransactions",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
handler: handler
|
||||
)
|
||||
}
|
||||
|
||||
/// Clear the incoming transaction pool.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to ClearIncomingTransactions.
|
||||
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
internal func clearIncomingTransactions(_ request: Empty, callOptions: CallOptions? = nil) -> UnaryCall<Empty, Empty> {
|
||||
return self.makeUnaryCall(path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/ClearIncomingTransactions",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions)
|
||||
internal func clearIncomingTransactions(
|
||||
_ request: Empty,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<Empty, Empty> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.DarksideStreamer/ClearIncomingTransactions",
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal final class DarksideStreamerClient: DarksideStreamerClientProtocol {
|
||||
internal let channel: GRPCChannel
|
||||
internal var defaultCallOptions: CallOptions
|
||||
|
||||
/// Creates a client for the cash.z.wallet.sdk.rpc.DarksideStreamer service.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - channel: `GRPCChannel` to the service host.
|
||||
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
|
||||
internal init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) {
|
||||
self.channel = channel
|
||||
self.defaultCallOptions = defaultCallOptions
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// DO NOT EDIT.
|
||||
// swift-format-ignore-file
|
||||
//
|
||||
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||
// Source: darkside.proto
|
||||
|
|
|
@ -53,12 +53,13 @@ service DarksideStreamer {
|
|||
// the same as the initial state. This occurs synchronously and instantaneously;
|
||||
// no reorg happens in lightwalletd. This is good to do before each independent
|
||||
// test so that no state leaks from one test to another.
|
||||
// Also sets (some of) the values returned by GetLightdInfo().
|
||||
// Also sets (some of) the values returned by GetLightdInfo(). The Sapling
|
||||
// activation height specified here must be where the block range starts.
|
||||
rpc Reset(DarksideMetaState) returns (Empty) {}
|
||||
|
||||
// StageBlocksStream accepts a list of blocks and saves them into the blocks
|
||||
// staging area until ApplyStaged() is called; there is no immediate effect on
|
||||
// the mock zcashd. Blocks are hex-encoded.
|
||||
// the mock zcashd. Blocks are hex-encoded. Order is important, see ApplyStaged.
|
||||
rpc StageBlocksStream(stream DarksideBlock) returns (Empty) {}
|
||||
|
||||
// StageBlocks is the same as StageBlocksStream() except the blocks are fetched
|
||||
|
@ -68,29 +69,33 @@ service DarksideStreamer {
|
|||
// StageBlocksCreate is like the previous two, except it creates 'count'
|
||||
// empty blocks at consecutive heights starting at height 'height'. The
|
||||
// 'nonce' is part of the header, so it contributes to the block hash; this
|
||||
// lets you create two fake blocks with the same transactions (or no
|
||||
// transactions) and same height, with two different hashes.
|
||||
// lets you create identical blocks (same transactions and height), but with
|
||||
// different hashes.
|
||||
rpc StageBlocksCreate(DarksideEmptyBlocks) returns (Empty) {}
|
||||
|
||||
// StageTransactions stores the given transaction-height pairs in the
|
||||
// StageTransactionsStream stores the given transaction-height pairs in the
|
||||
// staging area until ApplyStaged() is called. Note that these transactions
|
||||
// are not returned by the production GetTransaction() gRPC until they
|
||||
// appear in a "mined" block (contained in the active blockchain presented
|
||||
// by the mock zcashd).
|
||||
rpc StageTransactionsStream(stream RawTransaction) returns (Empty) {}
|
||||
|
||||
// StageTransactions is the same except the transactions are fetched from
|
||||
// the given url. They are all staged into the block at the given height.
|
||||
// Staging transactions to different heights requires multiple calls.
|
||||
rpc StageTransactions(DarksideTransactionsURL) returns (Empty) {}
|
||||
|
||||
|
||||
// ApplyStaged iterates the list of blocks that were staged by the
|
||||
// StageBlocks*() gRPCs, in the order they were staged, and "merges" each
|
||||
// into the active, working blocks list that the mock zcashd is presenting
|
||||
// to lightwalletd. The resulting working block list can't have gaps; if the
|
||||
// working block range is 1000-1006, and the staged block range is 1003-1004,
|
||||
// the resulting range is 1000-1004, with 1000-1002 unchanged, blocks
|
||||
// 1003-1004 from the new range, and 1005-1006 dropped. After merging all
|
||||
// blocks, ApplyStaged() appends staged transactions (in the order received)
|
||||
// into each one's corresponding block. The staging area is then cleared.
|
||||
// to lightwalletd. Even as each block is applied, the active list can't
|
||||
// have gaps; if the active block range is 1000-1006, and the staged block
|
||||
// range is 1003-1004, the resulting range is 1000-1004, with 1000-1002
|
||||
// unchanged, blocks 1003-1004 from the new range, and 1005-1006 dropped.
|
||||
//
|
||||
// After merging all blocks, ApplyStaged() appends staged transactions (in
|
||||
// the order received) into each one's corresponding (by height) block
|
||||
// The staging area is then cleared.
|
||||
//
|
||||
// The argument specifies the latest block height that mock zcashd reports
|
||||
// (i.e. what's returned by GetLatestBlock). Note that ApplyStaged() can
|
||||
|
|
458
rust/src/lib.rs
458
rust/src/lib.rs
|
@ -6,55 +6,42 @@ use std::os::unix::ffi::OsStrExt;
|
|||
use std::path::Path;
|
||||
use std::slice;
|
||||
use std::str::FromStr;
|
||||
use std::convert::Into;
|
||||
use zcash_client_backend::{
|
||||
address::RecipientAddress,
|
||||
data_api::{
|
||||
chain::{scan_cached_blocks, validate_chain},
|
||||
error::Error,
|
||||
wallet::{create_spend_to_address, decrypt_and_store_transaction},
|
||||
WalletRead, WalletWrite,
|
||||
},
|
||||
encoding::{
|
||||
decode_extended_full_viewing_key, decode_extended_spending_key,
|
||||
encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address,
|
||||
},
|
||||
keys::spending_key,
|
||||
wallet::AccountId,
|
||||
wallet::OvkPolicy,
|
||||
};
|
||||
|
||||
|
||||
use zcash_client_sqlite::{
|
||||
chain::{rewind_to_height, validate_combined_chain},
|
||||
error::ErrorKind,
|
||||
init::{init_accounts_table, init_blocks_table, init_data_database},
|
||||
query::{
|
||||
get_address, get_balance, get_received_memo_as_utf8, get_sent_memo_as_utf8,
|
||||
get_verified_balance,
|
||||
},
|
||||
scan::{decrypt_and_store_transaction, scan_cached_blocks},
|
||||
transact::{create_to_address, OvkPolicy},
|
||||
error::SqliteClientError,
|
||||
wallet::init::{init_accounts_table, init_blocks_table, init_wallet_db},
|
||||
BlockDB, NoteId, WalletDB,
|
||||
};
|
||||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::BranchId,
|
||||
consensus::BlockHeight,
|
||||
consensus::{BlockHeight, BranchId, Parameters},
|
||||
note_encryption::Memo,
|
||||
transaction::{components::Amount, Transaction},
|
||||
zip32::ExtendedFullViewingKey,
|
||||
};
|
||||
|
||||
#[cfg(feature = "mainnet")]
|
||||
use zcash_primitives::consensus::MainNetwork as Network;
|
||||
use zcash_primitives::consensus::{MainNetwork, MAIN_NETWORK};
|
||||
#[cfg(not(feature = "mainnet"))]
|
||||
use zcash_primitives::consensus::TestNetwork as Network;
|
||||
use zcash_primitives::consensus::{TestNetwork, TEST_NETWORK};
|
||||
|
||||
use zcash_proofs::prover::LocalTxProver;
|
||||
|
||||
#[cfg(feature = "mainnet")]
|
||||
use zcash_primitives::constants::mainnet::{
|
||||
COIN_TYPE, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_EXTENDED_SPENDING_KEY,
|
||||
HRP_SAPLING_PAYMENT_ADDRESS,
|
||||
};
|
||||
#[cfg(not(feature = "mainnet"))]
|
||||
use zcash_primitives::constants::testnet::{
|
||||
COIN_TYPE, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_EXTENDED_SPENDING_KEY,
|
||||
HRP_SAPLING_PAYMENT_ADDRESS,
|
||||
};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -64,12 +51,10 @@ use sha2::{Digest, Sha256};
|
|||
// use zcash_primitives::legacy::TransparentAddress;
|
||||
use hdwallet::{ExtendedPrivKey, KeyIndex};
|
||||
use secp256k1::{PublicKey, Secp256k1};
|
||||
use zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX;
|
||||
|
||||
// use crate::extended_key::{key_index::KeyIndex, ExtendedPrivKey, ExtendedPubKey, KeySeed};
|
||||
// /////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
fn unwrap_exc_or<T>(exc: Result<T, ()>, def: T) -> T {
|
||||
match exc {
|
||||
Ok(value) => value,
|
||||
|
@ -87,6 +72,44 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "mainnet")]
|
||||
pub const NETWORK: MainNetwork = MAIN_NETWORK;
|
||||
|
||||
#[cfg(not(feature = "mainnet"))]
|
||||
pub const NETWORK: TestNetwork = TEST_NETWORK;
|
||||
|
||||
#[cfg(feature = "mainnet")]
|
||||
fn wallet_db(
|
||||
db_data: *const u8,
|
||||
db_data_len: usize,
|
||||
) -> Result<WalletDB<MainNetwork>, failure::Error> {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
WalletDB::for_path(db_data, NETWORK)
|
||||
.map_err(|e| format_err!("Error opening wallet database connection: {}", e))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "mainnet"))]
|
||||
fn wallet_db(
|
||||
db_data: *const u8,
|
||||
db_data_len: usize,
|
||||
) -> Result<WalletDB<TestNetwork>, failure::Error> {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
WalletDB::for_path(db_data, NETWORK)
|
||||
.map_err(|e| format_err!("Error opening wallet database connection: {}", e))
|
||||
}
|
||||
|
||||
fn block_db(cache_db: *const u8, cache_db_len: usize) -> Result<BlockDB, failure::Error> {
|
||||
let cache_db = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(cache_db, cache_db_len)
|
||||
}));
|
||||
BlockDB::for_path(cache_db)
|
||||
.map_err(|e| format_err!("Error opening block source database connection: {}", e))
|
||||
}
|
||||
|
||||
/// Returns the length of the last error message to be logged.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn zcashlc_last_error_length() -> i32 {
|
||||
|
@ -113,8 +136,9 @@ pub extern "C" fn zcashlc_init_data_database(db_data: *const u8, db_data_len: us
|
|||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
|
||||
init_data_database(&db_data)
|
||||
.map(|()| 1)
|
||||
WalletDB::for_path(db_data, NETWORK)
|
||||
.map(|db| init_wallet_db(&db))
|
||||
.map(|_| 1)
|
||||
.map_err(|e| format_err!("Error while initializing data DB: {}", e))
|
||||
});
|
||||
unwrap_exc_or_null(res)
|
||||
|
@ -136,9 +160,7 @@ pub extern "C" fn zcashlc_init_accounts_table(
|
|||
capacity_ret: *mut usize,
|
||||
) -> *mut *mut c_char {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
let seed = unsafe { slice::from_raw_parts(seed, seed_len) };
|
||||
let accounts = if accounts >= 0 {
|
||||
accounts as u32
|
||||
|
@ -147,34 +169,30 @@ pub extern "C" fn zcashlc_init_accounts_table(
|
|||
};
|
||||
|
||||
let extsks: Vec<_> = (0..accounts)
|
||||
.map(|account| spending_key(&seed, COIN_TYPE, account))
|
||||
.map(|account| spending_key(&seed, NETWORK.coin_type(), account))
|
||||
.collect();
|
||||
let extfvks: Vec<_> = extsks.iter().map(ExtendedFullViewingKey::from).collect();
|
||||
|
||||
match init_accounts_table(&db_data, &Network, &extfvks) {
|
||||
Ok(()) => (),
|
||||
Err(e) => match e.kind() {
|
||||
ErrorKind::TableNotEmpty => {
|
||||
// Ignore this error.
|
||||
}
|
||||
_ => return Err(format_err!("Error while initializing accounts: {}", e)),
|
||||
},
|
||||
}
|
||||
|
||||
// Return the ExtendedSpendingKeys for the created accounts.
|
||||
let mut v: Vec<_> = extsks
|
||||
.iter()
|
||||
.map(|extsk| {
|
||||
let encoded =
|
||||
encode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, extsk);
|
||||
CString::new(encoded).unwrap().into_raw()
|
||||
init_accounts_table(&db_data, &extfvks)
|
||||
.map(|_| {
|
||||
// Return the ExtendedSpendingKeys for the created accounts.
|
||||
let mut v: Vec<_> = extsks
|
||||
.iter()
|
||||
.map(|extsk| {
|
||||
let encoded = encode_extended_spending_key(
|
||||
NETWORK.hrp_sapling_extended_spending_key(),
|
||||
extsk,
|
||||
);
|
||||
CString::new(encoded).unwrap().into_raw()
|
||||
})
|
||||
.collect();
|
||||
assert!(v.len() == accounts as usize);
|
||||
unsafe { *capacity_ret.as_mut().unwrap() = v.capacity() };
|
||||
let p = v.as_mut_ptr();
|
||||
std::mem::forget(v);
|
||||
return p;
|
||||
})
|
||||
.collect();
|
||||
assert!(v.len() == accounts as usize);
|
||||
unsafe { *capacity_ret.as_mut().unwrap() = v.capacity() };
|
||||
let p = v.as_mut_ptr();
|
||||
std::mem::forget(v);
|
||||
Ok(p)
|
||||
.map_err(|e| format_err!("Error while initializing accounts: {}", e))
|
||||
});
|
||||
unwrap_exc_or_null(res)
|
||||
}
|
||||
|
@ -189,30 +207,27 @@ pub extern "C" fn zcashlc_init_accounts_table_with_keys(
|
|||
extfvks_len: usize,
|
||||
) -> bool {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
|
||||
let extfvks = unsafe { std::slice::from_raw_parts(extfvks, extfvks_len)
|
||||
.into_iter()
|
||||
.map(|s| CStr::from_ptr(*s).to_str().unwrap())
|
||||
.map( |vkstr|
|
||||
decode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, &vkstr)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
).collect::<Vec<_>>() };
|
||||
|
||||
match init_accounts_table(&db_data, &Network, &extfvks) {
|
||||
let extfvks = unsafe {
|
||||
std::slice::from_raw_parts(extfvks, extfvks_len)
|
||||
.into_iter()
|
||||
.map(|s| CStr::from_ptr(*s).to_str().unwrap())
|
||||
.map(|vkstr| {
|
||||
decode_extended_full_viewing_key(
|
||||
NETWORK.hrp_sapling_extended_full_viewing_key(),
|
||||
&vkstr,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
match init_accounts_table(&db_data, &extfvks) {
|
||||
Ok(()) => Ok(true),
|
||||
Err(e) => match e.kind() {
|
||||
ErrorKind::TableNotEmpty => {
|
||||
// Ignore this error.
|
||||
Ok(true)
|
||||
}
|
||||
_ => return Err(format_err!("Error while initializing accounts: {}", e)),
|
||||
},
|
||||
Err(e) => Err(format_err!("Error while initializing accounts: {}", e)),
|
||||
}
|
||||
|
||||
});
|
||||
unwrap_exc_or(res, false)
|
||||
}
|
||||
|
@ -238,15 +253,17 @@ pub unsafe extern "C" fn zcashlc_derive_extended_spending_keys(
|
|||
};
|
||||
|
||||
let extsks: Vec<_> = (0..accounts)
|
||||
.map(|account| spending_key(&seed, COIN_TYPE, account))
|
||||
.map(|account| spending_key(&seed, NETWORK.coin_type(), account))
|
||||
.collect();
|
||||
|
||||
// Return the ExtendedSpendingKeys for the created accounts.
|
||||
let mut v: Vec<_> = extsks
|
||||
.iter()
|
||||
.map(|extsk| {
|
||||
let encoded =
|
||||
encode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, extsk);
|
||||
let encoded = encode_extended_spending_key(
|
||||
NETWORK.hrp_sapling_extended_spending_key(),
|
||||
extsk,
|
||||
);
|
||||
CString::new(encoded).unwrap().into_raw()
|
||||
})
|
||||
.collect();
|
||||
|
@ -279,15 +296,19 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_keys(
|
|||
};
|
||||
|
||||
let extsks: Vec<_> = (0..accounts)
|
||||
.map(|account| ExtendedFullViewingKey::from(&spending_key(&seed, COIN_TYPE, account)))
|
||||
.map(|account| {
|
||||
ExtendedFullViewingKey::from(&spending_key(&seed, NETWORK.coin_type(), account))
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Return the ExtendedSpendingKeys for the created accounts.
|
||||
let mut v: Vec<_> = extsks
|
||||
.iter()
|
||||
.map(|extsk| {
|
||||
let encoded =
|
||||
encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, extsk);
|
||||
let encoded = encode_extended_full_viewing_key(
|
||||
NETWORK.hrp_sapling_extended_full_viewing_key(),
|
||||
extsk,
|
||||
);
|
||||
CString::new(encoded).unwrap().into_raw()
|
||||
})
|
||||
.collect();
|
||||
|
@ -299,7 +320,7 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_keys(
|
|||
});
|
||||
unwrap_exc_or_null(res)
|
||||
}
|
||||
/// derives a shielded address from the given seed.
|
||||
/// derives a shielded address from the given seed.
|
||||
/// call zcashlc_string_free with the returned pointer when done using it
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_seed(
|
||||
|
@ -314,26 +335,25 @@ pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_seed(
|
|||
} else {
|
||||
return Err(format_err!("accounts argument must be greater than zero"));
|
||||
};
|
||||
let address = spending_key(&seed, COIN_TYPE, account_index)
|
||||
let address = spending_key(&seed, NETWORK.coin_type(), account_index)
|
||||
.default_address()
|
||||
.unwrap()
|
||||
.1;
|
||||
let address_str = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &address);
|
||||
let address_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &address);
|
||||
Ok(CString::new(address_str).unwrap().into_raw())
|
||||
});
|
||||
unwrap_exc_or_null(res)
|
||||
}
|
||||
/// derives a shielded address from the given viewing key.
|
||||
/// derives a shielded address from the given viewing key.
|
||||
/// call zcashlc_string_free with the returned pointer when done using it
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_viewing_key(
|
||||
extfvk: *const c_char,
|
||||
) -> *mut c_char {
|
||||
|
||||
let res = catch_panic(|| {
|
||||
let extfvk_string = CStr::from_ptr(extfvk).to_str()?;
|
||||
let extfvk = match decode_extended_full_viewing_key(
|
||||
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||
NETWORK.hrp_sapling_extended_full_viewing_key(),
|
||||
&extfvk_string,
|
||||
) {
|
||||
Ok(Some(extfvk)) => extfvk,
|
||||
|
@ -348,13 +368,13 @@ pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_viewing_key(
|
|||
}
|
||||
};
|
||||
let address = extfvk.default_address().unwrap().1;
|
||||
let address_str = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &address);
|
||||
let address_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &address);
|
||||
Ok(CString::new(address_str).unwrap().into_raw())
|
||||
});
|
||||
unwrap_exc_or_null(res)
|
||||
}
|
||||
|
||||
/// derives a shielded address from the given extended full viewing key.
|
||||
/// derives a shielded address from the given extended full viewing key.
|
||||
/// call zcashlc_string_free with the returned pointer when done using it
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_key(
|
||||
|
@ -362,7 +382,10 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_key(
|
|||
) -> *mut c_char {
|
||||
let res = catch_panic(|| {
|
||||
let extsk = CStr::from_ptr(extsk).to_str()?;
|
||||
let extfvk = match decode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, &extsk) {
|
||||
let extfvk = match decode_extended_spending_key(
|
||||
NETWORK.hrp_sapling_extended_spending_key(),
|
||||
&extsk,
|
||||
) {
|
||||
Ok(Some(extsk)) => ExtendedFullViewingKey::from(&extsk),
|
||||
Ok(None) => {
|
||||
return Err(format_err!("Deriving viewing key from spending key returned no results. Encoding was valid but type was incorrect."));
|
||||
|
@ -375,8 +398,10 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_key(
|
|||
}
|
||||
};
|
||||
|
||||
let encoded =
|
||||
encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, &extfvk);
|
||||
let encoded = encode_extended_full_viewing_key(
|
||||
NETWORK.hrp_sapling_extended_full_viewing_key(),
|
||||
&extfvk,
|
||||
);
|
||||
|
||||
Ok(CString::new(encoded).unwrap().into_raw())
|
||||
});
|
||||
|
@ -397,9 +422,7 @@ pub extern "C" fn zcashlc_init_blocks_table(
|
|||
sapling_tree_hex: *const c_char,
|
||||
) -> i32 {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
let hash = {
|
||||
let mut hash = hex::decode(unsafe { CStr::from_ptr(hash_hex) }.to_str()?).unwrap();
|
||||
hash.reverse();
|
||||
|
@ -408,7 +431,13 @@ pub extern "C" fn zcashlc_init_blocks_table(
|
|||
let sapling_tree =
|
||||
hex::decode(unsafe { CStr::from_ptr(sapling_tree_hex) }.to_str()?).unwrap();
|
||||
|
||||
match init_blocks_table(&db_data, height, hash, time, &sapling_tree) {
|
||||
match init_blocks_table(
|
||||
&db_data,
|
||||
BlockHeight::from_u32(height as u32),
|
||||
hash,
|
||||
time,
|
||||
&sapling_tree,
|
||||
) {
|
||||
Ok(()) => Ok(1),
|
||||
Err(e) => Err(format_err!("Error while initializing blocks table: {}", e)),
|
||||
}
|
||||
|
@ -426,20 +455,25 @@ pub extern "C" fn zcashlc_get_address(
|
|||
account: i32,
|
||||
) -> *mut c_char {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
let account = if account >= 0 {
|
||||
account as u32
|
||||
} else {
|
||||
return Err(format_err!("accounts argument must be positive"));
|
||||
};
|
||||
|
||||
match get_address(&db_data, account) {
|
||||
Ok(addr) => {
|
||||
let c_str_addr = CString::new(addr).unwrap();
|
||||
let account = AccountId(account);
|
||||
|
||||
match (&db_data).get_address(account) {
|
||||
Ok(Some(addr)) => {
|
||||
let addr_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &addr);
|
||||
let c_str_addr = CString::new(addr_str).unwrap();
|
||||
Ok(c_str_addr.into_raw())
|
||||
}
|
||||
Ok(None) => Err(format_err!(
|
||||
"No payment address was available for account {:?}",
|
||||
account
|
||||
)),
|
||||
Err(e) => Err(format_err!("Error while fetching address: {}", e)),
|
||||
}
|
||||
});
|
||||
|
@ -454,7 +488,7 @@ pub unsafe extern "C" fn zcashlc_is_valid_shielded_address(address: *const c_cha
|
|||
let res = catch_panic(|| {
|
||||
let addr = CStr::from_ptr(address).to_str()?;
|
||||
|
||||
match RecipientAddress::decode(&Network, &addr) {
|
||||
match RecipientAddress::decode(&NETWORK, &addr) {
|
||||
Some(addr) => match addr {
|
||||
RecipientAddress::Shielded(_) => Ok(true),
|
||||
RecipientAddress::Transparent(_) => Ok(false),
|
||||
|
@ -472,7 +506,7 @@ pub unsafe extern "C" fn zcashlc_is_valid_transparent_address(address: *const c_
|
|||
let res = catch_panic(|| {
|
||||
let addr = CStr::from_ptr(address).to_str()?;
|
||||
|
||||
match RecipientAddress::decode(&Network, &addr) {
|
||||
match RecipientAddress::decode(&NETWORK, &addr) {
|
||||
Some(addr) => match addr {
|
||||
RecipientAddress::Shielded(_) => Ok(false),
|
||||
RecipientAddress::Transparent(_) => Ok(true),
|
||||
|
@ -482,13 +516,13 @@ pub unsafe extern "C" fn zcashlc_is_valid_transparent_address(address: *const c_
|
|||
});
|
||||
unwrap_exc_or(res, false)
|
||||
}
|
||||
|
||||
/// returns whether the given viewing key is valid or not
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char) -> bool {
|
||||
let res = catch_panic(|| {
|
||||
let vkstr = CStr::from_ptr(key).to_str()?;
|
||||
|
||||
match decode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, &vkstr) {
|
||||
match decode_extended_full_viewing_key(&NETWORK.hrp_sapling_extended_full_viewing_key(), &vkstr) {
|
||||
Ok(s) => match s {
|
||||
None => Ok(false),
|
||||
_ => Ok(true),
|
||||
|
@ -498,24 +532,32 @@ pub unsafe extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char) -> boo
|
|||
});
|
||||
unwrap_exc_or(res, false)
|
||||
}
|
||||
|
||||
/// Returns the balance for the account, including all unspent notes that we know about.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn zcashlc_get_balance(db_data: *const u8, db_data_len: usize, account: i32) -> i64 {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let account = if account >= 0 {
|
||||
account as u32
|
||||
} else {
|
||||
return Err(format_err!("account argument must be positive"));
|
||||
};
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
|
||||
match get_balance(&db_data, account) {
|
||||
Ok(balance) => Ok(balance.into()),
|
||||
Err(e) => Err(format_err!("Error while fetching balance: {}", e)),
|
||||
if account >= 0 {
|
||||
let (_, max_height) = (&db_data)
|
||||
.block_height_extrema()
|
||||
.map_err(|e| format_err!("Error while fetching max block height: {}", e))
|
||||
.and_then(|opt| {
|
||||
opt.ok_or(format_err!(
|
||||
"No blockchain information available; scan required."
|
||||
))
|
||||
})?;
|
||||
|
||||
(&db_data)
|
||||
.get_balance_at(AccountId(account as u32), max_height)
|
||||
.map(|b| b.into())
|
||||
.map_err(|e| format_err!("Error while fetching balance: {}", e))
|
||||
} else {
|
||||
Err(format_err!("account argument must be positive"))
|
||||
}
|
||||
});
|
||||
|
||||
unwrap_exc_or(res, -1)
|
||||
}
|
||||
|
||||
|
@ -528,20 +570,27 @@ pub extern "C" fn zcashlc_get_verified_balance(
|
|||
account: i32,
|
||||
) -> i64 {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let account = if account >= 0 {
|
||||
account as u32
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
if account >= 0 {
|
||||
(&db_data)
|
||||
.get_target_and_anchor_heights()
|
||||
.map_err(|e| format_err!("Error while fetching anchor height: {}", e))
|
||||
.and_then(|opt_anchor| {
|
||||
opt_anchor
|
||||
.map(|(_, a)| a)
|
||||
.ok_or(format_err!("Anchor height not available; scan required."))
|
||||
})
|
||||
.and_then(|anchor| {
|
||||
(&db_data)
|
||||
.get_balance_at(AccountId(account as u32), anchor)
|
||||
.map_err(|e| format_err!("Error while fetching verified balance: {}", e))
|
||||
})
|
||||
.map(|amount| amount.into())
|
||||
} else {
|
||||
return Err(format_err!("account argument must be positive"));
|
||||
};
|
||||
|
||||
match get_verified_balance(&db_data, account) {
|
||||
Ok(balance) => Ok(balance.into()),
|
||||
Err(e) => Err(format_err!("Error while fetching verified balance: {}", e)),
|
||||
Err(format_err!("account argument must be positive"))
|
||||
}
|
||||
});
|
||||
|
||||
unwrap_exc_or(res, -1)
|
||||
}
|
||||
|
||||
|
@ -558,11 +607,9 @@ pub extern "C" fn zcashlc_get_received_memo_as_utf8(
|
|||
id_note: i64,
|
||||
) -> *mut c_char {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
|
||||
let memo = match get_received_memo_as_utf8(db_data, id_note) {
|
||||
let memo = match (&db_data).get_memo_as_utf8(NoteId::ReceivedNoteId(id_note)) {
|
||||
Ok(memo) => memo.unwrap_or_default(),
|
||||
Err(e) => return Err(format_err!("Error while fetching memo: {}", e)),
|
||||
};
|
||||
|
@ -585,14 +632,12 @@ pub extern "C" fn zcashlc_get_sent_memo_as_utf8(
|
|||
id_note: i64,
|
||||
) -> *mut c_char {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
|
||||
let memo = match get_sent_memo_as_utf8(db_data, id_note) {
|
||||
Ok(memo) => memo.unwrap_or_default(),
|
||||
Err(e) => return Err(format_err!("Error while fetching memo: {}", e)),
|
||||
};
|
||||
let memo = (&db_data)
|
||||
.get_memo_as_utf8(NoteId::SentNoteId(id_note))
|
||||
.map(|memo| memo.unwrap_or_default())
|
||||
.map_err(|e| format_err!("Error while fetching memo: {}", e))?;
|
||||
|
||||
Ok(CString::new(memo).unwrap().into_raw())
|
||||
});
|
||||
|
@ -623,16 +668,21 @@ pub extern "C" fn zcashlc_validate_combined_chain(
|
|||
db_data_len: usize,
|
||||
) -> i32 {
|
||||
let res = catch_panic(|| {
|
||||
let db_cache = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_cache, db_cache_len)
|
||||
}));
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
|
||||
if let Err(e) = validate_combined_chain(Network, &db_cache, &db_data) {
|
||||
match e.kind() {
|
||||
ErrorKind::InvalidChain(upper_bound, _) => Ok(u32::from(*upper_bound) as i32),
|
||||
let block_db = block_db(db_cache, db_cache_len)?;
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
|
||||
let validate_from = (&db_data)
|
||||
.get_max_height_hash()
|
||||
.map_err(|e| format_err!("Error while validating chain: {}", e))?;
|
||||
|
||||
let val_res = validate_chain(&NETWORK, &block_db, validate_from);
|
||||
|
||||
if let Err(e) = val_res {
|
||||
match e {
|
||||
SqliteClientError::BackendError(Error::InvalidChain(upper_bound, _)) => {
|
||||
let upper_bound_u32 = u32::from(upper_bound);
|
||||
Ok(upper_bound_u32 as i32)
|
||||
}
|
||||
_ => Err(format_err!("Error while validating chain: {}", e)),
|
||||
}
|
||||
} else {
|
||||
|
@ -654,18 +704,17 @@ pub extern "C" fn zcashlc_rewind_to_height(
|
|||
height: i32,
|
||||
) -> i32 {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_data = wallet_db(db_data, db_data_len)?;
|
||||
|
||||
match rewind_to_height(Network,&db_data, BlockHeight::from(height as u32)) {
|
||||
Ok(()) => Ok(1),
|
||||
Err(e) => Err(format_err!(
|
||||
"Error while rewinding data DB to height {}: {}",
|
||||
height,
|
||||
e
|
||||
)),
|
||||
}
|
||||
let mut update_ops = (&db_data)
|
||||
.get_update_ops()
|
||||
.map_err(|e| format_err!("Could not obtain a writable database connection: {}", e))?;
|
||||
|
||||
let height = BlockHeight::try_from(height)?;
|
||||
(&mut update_ops)
|
||||
.transactionally(|ops| ops.rewind_to_height(height))
|
||||
.map(|_| 1)
|
||||
.map_err(|e| format_err!("Error while rewinding data DB to height {}: {}", height, e))
|
||||
});
|
||||
unwrap_exc_or_null(res)
|
||||
}
|
||||
|
@ -692,14 +741,11 @@ pub extern "C" fn zcashlc_scan_blocks(
|
|||
db_data_len: usize,
|
||||
) -> i32 {
|
||||
let res = catch_panic(|| {
|
||||
let db_cache = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_cache, db_cache_len)
|
||||
}));
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let block_db = block_db(db_cache, db_cache_len)?;
|
||||
let db_read = wallet_db(db_data, db_data_len)?;
|
||||
let mut db_data = db_read.get_update_ops()?;
|
||||
|
||||
match scan_cached_blocks(&Network, &db_cache, &db_data, None) {
|
||||
match scan_cached_blocks(&NETWORK, &block_db, &mut db_data, None) {
|
||||
Ok(()) => Ok(1),
|
||||
Err(e) => Err(format_err!("Error while scanning blocks: {}", e)),
|
||||
}
|
||||
|
@ -715,13 +761,12 @@ pub extern "C" fn zcashlc_decrypt_and_store_transaction(
|
|||
tx_len: usize,
|
||||
) -> i32 {
|
||||
let res = catch_panic(|| {
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_read = wallet_db(db_data, db_data_len)?;
|
||||
let mut db_data = db_read.get_update_ops()?;
|
||||
let tx_bytes = unsafe { slice::from_raw_parts(tx, tx_len) };
|
||||
let tx = Transaction::read(&tx_bytes[..])?;
|
||||
|
||||
match decrypt_and_store_transaction(&db_data, &Network, &tx) {
|
||||
match decrypt_and_store_transaction(&NETWORK, &mut db_data, &tx) {
|
||||
Ok(()) => Ok(1),
|
||||
Err(e) => Err(format_err!("Error while decrypting transaction: {}", e)),
|
||||
}
|
||||
|
@ -743,7 +788,6 @@ pub extern "C" fn zcashlc_create_to_address(
|
|||
db_data_len: usize,
|
||||
account: i32,
|
||||
extsk: *const c_char,
|
||||
consensus_branch_id: i32,
|
||||
to: *const c_char,
|
||||
value: i64,
|
||||
memo: *const c_char,
|
||||
|
@ -753,16 +797,8 @@ pub extern "C" fn zcashlc_create_to_address(
|
|||
output_params_len: usize,
|
||||
) -> i64 {
|
||||
let res = catch_panic(|| {
|
||||
let branch_id = match BranchId::try_from(consensus_branch_id as u32) {
|
||||
Ok(extsk) => extsk,
|
||||
Err(e) => {
|
||||
return Err(format_err!("Invalid consensus branch id: {}", e));
|
||||
}
|
||||
};
|
||||
|
||||
let db_data = Path::new(OsStr::from_bytes(unsafe {
|
||||
slice::from_raw_parts(db_data, db_data_len)
|
||||
}));
|
||||
let db_read = wallet_db(db_data, db_data_len)?;
|
||||
let mut db_data = db_read.get_update_ops()?;
|
||||
let account = if account >= 0 {
|
||||
account as u32
|
||||
} else {
|
||||
|
@ -783,17 +819,19 @@ pub extern "C" fn zcashlc_create_to_address(
|
|||
slice::from_raw_parts(output_params, output_params_len)
|
||||
}));
|
||||
|
||||
let extsk = match decode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, &extsk) {
|
||||
Ok(Some(extsk)) => extsk,
|
||||
Ok(None) => {
|
||||
return Err(format_err!("ExtendedSpendingKey is for the wrong network"));
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(format_err!("Invalid ExtendedSpendingKey: {}", e));
|
||||
}
|
||||
};
|
||||
let extsk =
|
||||
match decode_extended_spending_key(NETWORK.hrp_sapling_extended_spending_key(), &extsk)
|
||||
{
|
||||
Ok(Some(extsk)) => extsk,
|
||||
Ok(None) => {
|
||||
return Err(format_err!("ExtendedSpendingKey is for the wrong network"));
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(format_err!("Invalid ExtendedSpendingKey: {}", e));
|
||||
}
|
||||
};
|
||||
|
||||
let to = match RecipientAddress::decode(&Network, &to) {
|
||||
let to = match RecipientAddress::decode(&NETWORK, &to) {
|
||||
Some(to) => to,
|
||||
None => {
|
||||
return Err(format_err!("PaymentAddress is for the wrong network"));
|
||||
|
@ -804,12 +842,12 @@ pub extern "C" fn zcashlc_create_to_address(
|
|||
|
||||
let prover = LocalTxProver::new(spend_params, output_params);
|
||||
|
||||
create_to_address(
|
||||
&db_data,
|
||||
&Network,
|
||||
branch_id,
|
||||
create_spend_to_address(
|
||||
&mut db_data,
|
||||
&NETWORK,
|
||||
prover,
|
||||
(account, &extsk),
|
||||
AccountId(account),
|
||||
&extsk,
|
||||
&to,
|
||||
value,
|
||||
Some(memo),
|
||||
|
@ -823,7 +861,7 @@ pub extern "C" fn zcashlc_create_to_address(
|
|||
#[no_mangle]
|
||||
pub extern "C" fn zcashlc_branch_id_for_height(height: i32) -> i32 {
|
||||
let res = catch_panic(|| {
|
||||
let branch: BranchId = BranchId::for_height(&Network, BlockHeight::from(height as u32));
|
||||
let branch: BranchId = BranchId::for_height(&NETWORK, BlockHeight::from(height as u32));
|
||||
let branch_id: u32 = u32::from(branch);
|
||||
Ok(branch_id as i32)
|
||||
});
|
||||
|
@ -854,25 +892,25 @@ pub extern "C" fn zcashlc_vec_string_free(v: *mut *mut c_char, len: usize, capac
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
/// TEST TEST 123 TEST
|
||||
/// Derives a transparent address from the given seed
|
||||
/// TEST TEST 123 TEST
|
||||
/// Derives a transparent address from the given seed
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_seed(
|
||||
seed: *const u8,
|
||||
seed_len: usize,
|
||||
) -> *mut c_char {
|
||||
|
||||
let res = catch_panic(|| {
|
||||
let seed = slice::from_raw_parts(seed, seed_len);
|
||||
|
||||
|
||||
// modified from: https://github.com/adityapk00/zecwallet-light-cli/blob/master/lib/src/lightwallet.rs
|
||||
|
||||
let ext_t_key = ExtendedPrivKey::with_seed(&seed).unwrap();
|
||||
let address_sk = ext_t_key
|
||||
.derive_private_key(KeyIndex::hardened_from_normalize_index(44).unwrap())
|
||||
.unwrap()
|
||||
.derive_private_key(KeyIndex::hardened_from_normalize_index(COIN_TYPE).unwrap())
|
||||
.derive_private_key(
|
||||
KeyIndex::hardened_from_normalize_index(NETWORK.coin_type()).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
.derive_private_key(KeyIndex::hardened_from_normalize_index(0).unwrap())
|
||||
.unwrap()
|
||||
|
@ -887,7 +925,7 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_seed(
|
|||
hash160.update(Sha256::digest(&pk.serialize()[..].to_vec()));
|
||||
let address_string = hash160
|
||||
.finalize()
|
||||
.to_base58check(&B58_PUBKEY_ADDRESS_PREFIX, &[]);
|
||||
.to_base58check(&NETWORK.b58_pubkey_address_prefix(), &[]);
|
||||
|
||||
Ok(CString::new(address_string).unwrap().into_raw())
|
||||
});
|
||||
|
@ -922,4 +960,4 @@ pub fn double_sha256(payload: &[u8]) -> Vec<u8> {
|
|||
let h1 = Sha256::digest(&payload);
|
||||
let h2 = Sha256::digest(&h1);
|
||||
h2.to_vec()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue