Merge branch 'master' into shield-funds-poc

This commit is contained in:
Francisco Gindre 2021-03-29 14:53:01 -03:00
commit 477f7cc69f
29 changed files with 1560 additions and 371 deletions

296
Cargo.lock generated
View File

@ -11,39 +11,38 @@ dependencies = [
[[package]]
name = "adler"
version = "0.2.3"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aes"
version = "0.5.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd2bc6d3f370b5666245ff421e231cba4353df936e26986d2918e61a8fd6aef6"
checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561"
dependencies = [
"aes-soft",
"aesni",
"block-cipher",
"cipher",
]
[[package]]
name = "aes-soft"
version = "0.5.0"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63dd91889c49327ad7ef3b500fd1109dbd3c509a03db0d4a9ce413b79f575cb6"
checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
dependencies = [
"block-cipher",
"byteorder",
"cipher",
"opaque-debug 0.3.0",
]
[[package]]
name = "aesni"
version = "0.8.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6fe808308bb07d393e2ea47780043ec47683fcf19cf5efc8ca51c50cc8c68a"
checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
dependencies = [
"block-cipher",
"cipher",
"opaque-debug 0.3.0",
]
@ -117,12 +116,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
[[package]]
name = "base64"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
[[package]]
name = "base64"
version = "0.13.0"
@ -131,9 +124,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bech32"
version = "0.7.3"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1"
checksum = "6c7f7096bc256f5e5cb960f60dfc4f4ef979ca65abe7fb9d5a4f77150d3783d4"
[[package]]
name = "bellman"
@ -141,7 +134,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7089887635778eabf0038a166f586eee5413fb85c8fa6c9a754914f0f644f49f"
dependencies = [
"bitvec",
"bitvec 0.18.5",
"blake2s_simd",
"byteorder",
"ff",
@ -160,12 +153,24 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bitvec"
version = "0.18.4"
version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2838fdd79e8776dbe07a106c784b0f8dda571a21b2750a092cc4cbaa653c8e"
checksum = "98fcd36dda4e17b7d7abc64cb549bf0201f4ab71e00700c798ca7e62ed3761fa"
dependencies = [
"funty",
"radium",
"radium 0.3.0",
"wyz",
]
[[package]]
name = "bitvec"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
dependencies = [
"funty",
"radium 0.5.3",
"tap",
"wyz",
]
@ -200,7 +205,7 @@ dependencies = [
"block-padding 0.1.5",
"byte-tools",
"byteorder",
"generic-array 0.12.3",
"generic-array 0.12.4",
]
[[package]]
@ -212,23 +217,14 @@ dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "block-cipher"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f337a3e6da609650eb74e02bc9fac7b735049f7623ab12f2e4c719316fcc7e80"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "block-modes"
version = "0.6.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9b14fd8a4739e6548d4b6018696cf991dcf8c6effd9ef9eb33b29b8a650972"
checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0"
dependencies = [
"block-cipher",
"block-padding 0.2.1",
"cipher",
]
[[package]]
@ -252,7 +248,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4caf0101205582491f772d60a6fcb6bcec19963e68209cb631851eeadb01421f"
dependencies = [
"bitvec",
"bitvec 0.18.5",
"ff",
"group",
"pairing",
@ -270,10 +266,19 @@ dependencies = [
]
[[package]]
name = "bumpalo"
version = "3.6.0"
name = "bs58"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9"
checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
dependencies = [
"sha2 0.9.3",
]
[[package]]
name = "bumpalo"
version = "3.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
[[package]]
name = "byte-tools"
@ -283,9 +288,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.4.2"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cbindgen"
@ -307,9 +312,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.41"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-if"
@ -317,6 +322,15 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "clap"
version = "2.33.3"
@ -334,9 +348,9 @@ dependencies = [
[[package]]
name = "const_fn"
version = "0.4.5"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
checksum = "076a6803b0dacd6a88cfe64deba628b01533ff5ef265687e6938280c1afd0a28"
[[package]]
name = "constant_time_eq"
@ -352,9 +366,9 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
dependencies = [
"autocfg",
"cfg-if",
@ -382,7 +396,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array 0.12.3",
"generic-array 0.12.4",
]
[[package]]
@ -423,6 +437,7 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "equihash"
version = "0.1.0"
source = "git+https://github.com/nuttycom/librustzcash?branch=autoshield-poc-daa#111161b47ee788867989c3c52627034659799be8"
dependencies = [
"blake2b_simd",
"byteorder",
@ -474,7 +489,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01646e077d4ebda82b73f1bca002ea1e91561a77df2431a9e79729bcc31950ef"
dependencies = [
"bitvec",
"bitvec 0.18.5",
"rand_core 0.5.1",
"subtle",
]
@ -492,9 +507,9 @@ dependencies = [
[[package]]
name = "fpe"
version = "0.3.1"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef2196a22f6d98bbde79ae510eb4f397bd446cfbd6c26425e25ec81442a31bab"
checksum = "a25080721bbcd2cd4d765b7d607ea350425fa087ce53cd3e31afcacdab850352"
dependencies = [
"aes",
"block-modes",
@ -511,15 +526,15 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]]
name = "futures"
version = "0.1.30"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed"
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
[[package]]
name = "generic-array"
version = "0.12.3"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
@ -592,17 +607,6 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "hdwallet"
version = "0.2.5"
source = "git+https://github.com/nuttycom/hdwallet?rev=72f1f7a56c114eed484cefd6d402b7ef28158712#72f1f7a56c114eed484cefd6d402b7ef28158712"
dependencies = [
"lazy_static",
"rand_core 0.6.2",
"ring",
"secp256k1",
]
[[package]]
name = "hdwallet"
version = "0.3.0"
@ -635,9 +639,9 @@ dependencies = [
[[package]]
name = "hex"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "itoa"
@ -647,9 +651,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "js-sys"
version = "0.3.47"
version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
dependencies = [
"wasm-bindgen",
]
@ -660,7 +664,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "620638af3b80d23f4df0cae21e3cc9809ac8826767f345066f010bcea66a2c55"
dependencies = [
"bitvec",
"bitvec 0.18.5",
"bls12_381",
"ff",
"group",
@ -689,9 +693,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.86"
version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
[[package]]
name = "libsqlite3-sys"
@ -706,15 +710,16 @@ dependencies = [
[[package]]
name = "libzcashlc"
version = "0.0.5"
version = "0.0.6"
dependencies = [
"base58",
"bs58",
"bitvec 0.18.5",
"bs58 0.3.1",
"cbindgen",
"failure",
"ffi_helpers",
"funty",
"hdwallet 0.3.0",
"hdwallet",
"hex",
"ripemd160",
"secp256k1",
@ -743,9 +748,9 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "miniz_oxide"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
dependencies = [
"adler",
"autocfg",
@ -753,10 +758,12 @@ dependencies = [
[[package]]
name = "nom"
version = "5.1.2"
version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
dependencies = [
"bitvec 0.19.5",
"funty",
"lexical-core",
"memchr",
"version_check",
@ -764,9 +771,9 @@ dependencies = [
[[package]]
name = "num-bigint"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf"
checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba"
dependencies = [
"autocfg",
"num-integer",
@ -798,6 +805,12 @@ version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
[[package]]
name = "once_cell"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]]
name = "opaque-debug"
version = "0.2.3"
@ -855,24 +868,24 @@ dependencies = [
[[package]]
name = "protobuf"
version = "2.22.0"
version = "2.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f72884896d22e0da0e5b266cb9a780b791f6c3b2f5beab6368d6cd4f0dbb86"
checksum = "1b7f4a129bb3754c25a4e04032a90173c68f85168f77118ac4cb4936e7f06f92"
[[package]]
name = "protobuf-codegen"
version = "2.22.0"
version = "2.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8217a1652dbc91d19c509c558234145faed729191a966896414e5889f62d543"
checksum = "e5d2fa3a461857508103b914da60dd7b489c1a834967c2e214ecc1496f0c486a"
dependencies = [
"protobuf",
]
[[package]]
name = "protobuf-codegen-pure"
version = "2.22.0"
version = "2.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f239d71417bdc5f8d83c07aeb265f911346e5540a1a6c4285f9c3d1966ed6e3"
checksum = "b3a2520307dbb0df861ed77603770dc23b0ec15e5048272416d6447de98e862b"
dependencies = [
"protobuf",
"protobuf-codegen",
@ -889,9 +902,15 @@ dependencies = [
[[package]]
name = "radium"
version = "0.4.1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64de9a0c5361e034f1aefc9f71a86871ec870e766fe31a009734a989b329286a"
checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac"
[[package]]
name = "radium"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]]
name = "rand"
@ -1011,13 +1030,13 @@ dependencies = [
[[package]]
name = "ring"
version = "0.16.12"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba5a8ec64ee89a76c98c549af81ff14813df09c3e6dc4766c3856da48597a0c"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"lazy_static",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
@ -1057,7 +1076,7 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
"base64 0.13.0",
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
@ -1119,18 +1138,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.123"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.123"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
dependencies = [
"proc-macro2",
"quote",
@ -1139,9 +1158,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.62"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
dependencies = [
"itoa",
"ryu",
@ -1193,9 +1212,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "standback"
version = "0.2.15"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2beb4d1860a61f571530b3f855a1b538d0200f7871c63331ecd6f17b1f014f8"
checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
dependencies = [
"version_check",
]
@ -1269,9 +1288,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
[[package]]
name = "syn"
version = "1.0.60"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702"
dependencies = [
"proc-macro2",
"quote",
@ -1290,6 +1309,12 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tempfile"
version = "3.2.0"
@ -1315,9 +1340,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.2.25"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1195b046942c221454c2539395f85413b33383a067449d78aab2b7b052a142f7"
checksum = "08a8cbfbf47955132d0202d1662f49b2423ae35862aee471f3ba4b133358f372"
dependencies = [
"const_fn",
"libc",
@ -1362,9 +1387,9 @@ dependencies = [
[[package]]
name = "typenum"
version = "1.12.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "unicode-segmentation"
@ -1404,9 +1429,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "wasi"
@ -1422,9 +1447,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.70"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@ -1432,9 +1457,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.70"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
dependencies = [
"bumpalo",
"lazy_static",
@ -1447,9 +1472,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.70"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -1457,9 +1482,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.70"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
dependencies = [
"proc-macro2",
"quote",
@ -1470,15 +1495,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.70"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
[[package]]
name = "web-sys"
version = "0.3.47"
version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -1514,15 +1539,16 @@ checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "zcash_client_backend"
version = "0.4.0"
version = "0.5.0"
source = "git+https://github.com/nuttycom/librustzcash?branch=autoshield-poc-daa#111161b47ee788867989c3c52627034659799be8"
dependencies = [
"base64 0.12.3",
"base64",
"bech32",
"bls12_381",
"bs58",
"bs58 0.4.0",
"ff",
"group",
"hdwallet 0.2.5",
"hdwallet",
"hex",
"jubjub",
"nom",
@ -1540,10 +1566,11 @@ dependencies = [
[[package]]
name = "zcash_client_sqlite"
version = "0.2.1"
version = "0.3.0"
source = "git+https://github.com/nuttycom/librustzcash?branch=autoshield-poc-daa#111161b47ee788867989c3c52627034659799be8"
dependencies = [
"bech32",
"bs58",
"bs58 0.4.0",
"ff",
"group",
"jubjub",
@ -1557,10 +1584,11 @@ dependencies = [
[[package]]
name = "zcash_primitives"
version = "0.4.0"
version = "0.5.0"
source = "git+https://github.com/nuttycom/librustzcash?branch=autoshield-poc-daa#111161b47ee788867989c3c52627034659799be8"
dependencies = [
"aes",
"bitvec",
"bitvec 0.18.5",
"blake2b_simd",
"blake2s_simd",
"bls12_381",
@ -1569,6 +1597,7 @@ dependencies = [
"equihash",
"ff",
"fpe",
"funty",
"group",
"hex",
"jubjub",
@ -1584,7 +1613,8 @@ dependencies = [
[[package]]
name = "zcash_proofs"
version = "0.4.0"
version = "0.5.0"
source = "git+https://github.com/nuttycom/librustzcash?branch=autoshield-poc-daa#111161b47ee788867989c3c52627034659799be8"
dependencies = [
"bellman",
"blake2b_simd",

View File

@ -1,6 +1,6 @@
[package]
name = "libzcashlc"
version = "0.0.5"
version = "0.0.6"
authors = ["Jack Grigg <jack@z.cash>",
"Francisco Gindre <francisco@z.cash>",
]
@ -11,11 +11,12 @@ build = "rust/build.rs"
failure = "0.1"
ffi_helpers = "0.2"
hex = "0.4"
zcash_client_backend = { version = "0.4", features = ["transparent-inputs"] }
zcash_client_sqlite = { version = "0.2.1", features = ["transparent-inputs"] }
zcash_primitives = { version = "0.4", features = ["transparent-inputs"] }
zcash_client_backend = "0.5"
zcash_client_sqlite = "0.3.0"
zcash_primitives = "0.5"
#### Temporary additions: ####################################
bitvec = "0.18"
base58 = "0.1.0"
sha2 = "0.9"
bs58 = { version = "0.3", features = ["check"] }
@ -26,9 +27,8 @@ time = "0.2"
funty = "=1.1.0"
##############################################################
[dependencies.zcash_proofs]
version = "0.4"
version = "0.5"
default-features = false
features = ["local-prover"]
@ -44,16 +44,18 @@ crate-type = ["staticlib"]
lto = true
[patch.crates-io]
#zcash_client_backend = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
#zcash_client_sqlite = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
#zcash_primitives = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
#zcash_proofs = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
zcash_client_backend = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
zcash_client_sqlite = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
zcash_primitives = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
zcash_proofs = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
#zcash_client_backend = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_client_backend" }
#zcash_client_sqlite = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_client_sqlite" }
#zcash_primitives = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_primitives" }
#zcash_proofs = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_proofs" }
zcash_client_backend = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_client_backend" }
zcash_client_sqlite = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_client_sqlite" }
zcash_primitives = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_primitives" }
zcash_proofs = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_proofs" }
[features]
mainnet = ["zcash_client_sqlite/mainnet", "zcash_client_sqlite/transparent-inputs", "zcash_client_backend/transparent-inputs", "zcash_primitives/transparent-inputs"]
testnet = ["zcash_client_backend/transparent-inputs", "zcash_primitives/transparent-inputs"]
testnet = ["zcash_client_sqlite/transparent-inputs", "zcash_client_backend/transparent-inputs", "zcash_primitives/transparent-inputs"]

78
Cargo.toml.orig Normal file
View File

@ -0,0 +1,78 @@
[package]
name = "libzcashlc"
version = "0.0.6"
authors = ["Jack Grigg <jack@z.cash>",
"Francisco Gindre <francisco@z.cash>",
]
edition = "2018"
build = "rust/build.rs"
[dependencies]
failure = "0.1"
ffi_helpers = "0.2"
hex = "0.4"
<<<<<<< HEAD
zcash_client_backend = { version = "0.4", features = ["transparent-inputs"] }
zcash_client_sqlite = { version = "0.2.1", features = ["transparent-inputs"] }
zcash_primitives = { version = "0.4", features = ["transparent-inputs"] }
=======
zcash_client_backend = "0.5"
zcash_client_sqlite = "0.3.0"
zcash_primitives = "0.5"
>>>>>>> master
#### Temporary additions: ####################################
bitvec = "0.18"
base58 = "0.1.0"
sha2 = "0.9"
bs58 = { version = "0.3", features = ["check"] }
hdwallet = "0.3.0"
ripemd160 = "0.9"
<<<<<<< HEAD
secp256k1 = "0.19"
time = "0.2"
=======
secp256k1 = "0.17.2"
# Temporary workaround for https://github.com/myrrlyn/funty/issues/3
>>>>>>> master
funty = "=1.1.0"
##############################################################
[dependencies.zcash_proofs]
version = "0.5"
default-features = false
features = ["local-prover"]
[build-dependencies]
cbindgen = "0.14"
[lib]
name = "zcashlc"
path = "rust/src/lib.rs"
crate-type = ["staticlib"]
[profile.release]
lto = true
<<<<<<< HEAD
[patch.crates-io]
#zcash_client_backend = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
#zcash_client_sqlite = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
#zcash_primitives = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
#zcash_proofs = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
zcash_client_backend = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_client_backend" }
zcash_client_sqlite = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_client_sqlite" }
zcash_primitives = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_primitives" }
zcash_proofs = { path = "/Users/pacu/Repos/ECC/pacu-librustzcash/zcash_proofs" }
[features]
mainnet = ["zcash_client_sqlite/mainnet", "zcash_client_sqlite/transparent-inputs", "zcash_client_backend/transparent-inputs", "zcash_primitives/transparent-inputs"]
testnet = ["zcash_client_backend/transparent-inputs", "zcash_primitives/transparent-inputs"]
=======
[features]
mainnet = ["zcash_client_sqlite/mainnet"]
>>>>>>> master

View File

@ -10,7 +10,7 @@ target 'ZcashLightClientSample' do
pod 'PaginatedTableView'
pod 'NotificationBubbles'
pod 'MnemonicSwift', '~> 2.0.0'
pod 'gRPC-Swift-Plugins', '= 1.0.0-alpha.19'
pod 'gRPC-Swift-Plugins', '= 1.0.0-alpha.19'
target 'ZcashLightClientSampleTests' do
use_frameworks!
inherit! :search_paths

View File

@ -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,8 +145,8 @@ SPEC CHECKSUMS:
SwiftNIOTLS: 46bb3a0ff37d6b52ae6baf5207ec3cd411da327c
SwiftNIOTransportServices: 801923921fbecdcde1e1c1ff38e812167d01ead1
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
ZcashLightClientKit: 7f144177deece40fb9075bf6024028026255f75b
ZcashLightClientKit: a1a36be74ca95e2802ba3d6bcc40e9b2753eb0da
PODFILE CHECKSUM: 7d5095283dc02470f40ab06564d94076ba16d570
PODFILE CHECKSUM: db5fd49340d00419df0653aac7d56eaeb37d71b6
COCOAPODS: 1.10.1

View File

@ -19,44 +19,54 @@ class SampleLogger: ZcashLightClientKit.Logger {
case info
}
enum LoggerType {
case osLog
case printerLog
}
var level: LogLevel
init(logLevel: LogLevel) {
var loggerType: LoggerType
init(logLevel: LogLevel, type: LoggerType = .osLog) {
self.level = logLevel
self.loggerType = type
}
private static let subsystem = Bundle.main.bundleIdentifier!
static let oslog = OSLog(subsystem: subsystem, category: "sample-logs")
static let oslog = OSLog(subsystem: subsystem, category: "logs")
func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func debug(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue == LogLevel.debug.rawValue else { return }
log(level: "DEBUG 🐞", message: message, file: file, function: function, line: line)
}
func error(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func error(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.error.rawValue else { return }
log(level: "ERROR 💥", message: message, file: file, function: function, line: line)
}
func warn(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func warn(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.warning.rawValue else { return }
log(level: "WARNING ⚠️", message: message, file: file, function: function, line: line)
}
func event(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func event(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.event.rawValue else { return }
log(level: "EVENT ⏱", message: message, file: file, function: function, line: line)
}
func info(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func info(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.info.rawValue else { return }
log(level: "INFO ", message: message, file: file, function: function, line: line)
}
private func log(level: String, message: String, file: String, function: String, line: Int) {
let fileName = file as NSString
os_log("[%@] %@ - %@ - Line: %d -> %@", log: Self.oslog, type: .default, level, fileName.lastPathComponent, function, line, message)
private func log(level: String, message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
let fileName = (String(describing: file) as NSString).lastPathComponent
switch loggerType {
case .printerLog:
print("[\(level)] \(fileName) - \(function) - line: \(line) -> \(message)")
default:
os_log("[%{public}@] %{public}@ - %{public}@ - Line: %{public}d -> %{public}@", level, fileName, String(describing: function), line, message)
}
}
}

View File

@ -242,6 +242,15 @@ If you worked with ZcashLightClientKit 0.6.6 or below you might have had to set
make sure that the directory that you are working on has the correct rust environment.
You can do so by calling `rustup show` in the working directory.
### Building in Apple Silicon
So far we have come up with this set up (april 2021)
* Clone a terminal and run it in rosetta mode
* Clone your Xcode of choice and run it in rosetta mode
* Installing the right toolchain for cargo
* `rustup toolchain add stable-x86_64-apple-darwin`
* `rustup target add aarch64-apple-ios x86_64-apple-darwin x86_64-apple-ios`
## Versioning
This project follows [semantic versioning](https://semver.org/) with pre-release versions. An example of a valid version number is `1.0.4-alpha11` denoting the `11th` iteration of the `alpha` pre-release of version `1.0.4`. Stable releases, such as `1.0.4` will not contain any pre-release identifiers. Pre-releases include the following, in order of stability: `alpha`, `beta`, `rc`. Version codes offer a numeric representation of the build name that always increases. The first six significant digits represent the major, minor and patch number (two digits each) and the last 3 significant digits represent the pre-release identifier. The first digit of the identifier signals the build type. Lastly, each new build has a higher version code than all previous builds. The following table breaks this down:

View File

@ -3,7 +3,7 @@
BASEPATH="${PWD}"
TARGET_DIR="target"
FEATURE_FLAGS=""
FEATURE_FLAGS="--features=mainnet"
NETWORK_TYPE="TESTNET"
FLAVOR_FOLDER="Testnet"

View File

@ -29,7 +29,7 @@ fi
if is_mainnet; then
FEATURE_FLAGS="--features=mainnet"
else
FEATURE_FLAGS=""
FEATURE_FLAGS="--features=testnet"
fi
echo "Building Rust backend"
@ -42,8 +42,18 @@ else
ZCASH_ACTIVE_ARCHITECTURE="aarch64-apple-ios"
fi
echo "cargo lipo --manifest-path ${PODS_TARGET_SRCROOT}/Cargo.toml $FEATURE_FLAGS --targets $ZCASH_ACTIVE_ARCHITECTURE --release"
echo "fix 'permission denied issue'"
chmod -R +w ${PODS_TARGET_SRCROOT}
echo "cargo lipo --manifest-path ${PODS_TARGET_SRCROOT}/Cargo.toml $FEATURE_FLAGS --targets $ZCASH_ACTIVE_ARCHITECTURE --release"
if [[ -n "${DEVELOPER_SDK_DIR:-}" ]]; then
# Assume we're in Xcode, which means we're probably cross-compiling.
# In this case, we need to add an extra library search path for build scripts and proc-macros,
# which run on the host instead of the target.
# (macOS Big Sur does not have linkable libraries in /usr/lib/.)
echo "export LIBRARY_PATH=\"${DEVELOPER_SDK_DIR}/MacOSX.sdk/usr/lib:${LIBRARY_PATH:-}\""
export LIBRARY_PATH="${DEVELOPER_SDK_DIR}/MacOSX.sdk/usr/lib:${LIBRARY_PATH:-}"
fi
if [ ! -f ${ZCASH_LIB_RUST_BUILD_PATH}/universal/release/${ZCASH_LIB_RUST_NAME} ]; then
cargo lipo --manifest-path ${PODS_TARGET_SRCROOT}/Cargo.toml $FEATURE_FLAGS --targets $ZCASH_ACTIVE_ARCHITECTURE --release
persist_environment

View File

@ -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

View File

@ -78,7 +78,7 @@ class CompactBlockEnhancementOperation: ZcashOperation {
}
func enhance(transaction: TransactionEntity) throws {
LoggerProxy.debug("Zoom.... Enhance... Tx: \(transaction.transactionId.toHexStringTxId()) Block: \(String(describing: transaction.minedHeight))")
LoggerProxy.debug("Zoom.... Enhance... Tx: \(transaction.transactionId.toHexStringTxId())")
let tx = try downloader.fetchTransaction(txId: transaction.transactionId)

View File

@ -196,7 +196,7 @@ public class CompactBlockProcessor {
private var downloader: CompactBlockDownloading
private var transactionRepository: TransactionRepository
private var rustBackend: ZcashRustBackendWelding.Type
private var config: Configuration = Configuration.standard
private(set) var config: Configuration = Configuration.standard
private var queue: OperationQueue = {
let q = OperationQueue()
q.name = "CompactBlockProcessorQueue"
@ -370,6 +370,19 @@ public class CompactBlockProcessor {
self.state = .stopped
}
public func rewindTo(_ height: BlockHeight) throws {
self.stop()
guard rustBackend.rewindToHeight(dbData: config.dataDb, height: Int32(height)) else {
fail(rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)"))
return
}
// clear cache
try downloader.rewind(to: height)
}
private func nextBatch() throws {
// get latest block height
@ -468,9 +481,7 @@ public class CompactBlockProcessor {
}
validateChainOperation.startedHandler = { [weak self] in
self?.state = .validating
}
let scanBlocksOperation = CompactBlockScanningOperation(rustWelding: self.rustBackend, cacheDb: cfg.cacheDb, dataDb: cfg.dataDb)

View File

@ -56,6 +56,18 @@ public extension TransactionEntity {
return true
}
var anchor: BlockHeight? {
if let minedHeight = self.minedHeight, minedHeight != -1 {
return max(minedHeight - ZcashSDK.DEFAULT_STALE_TOLERANCE, ZcashSDK.SAPLING_ACTIVATION_HEIGHT)
}
if let expiryHeight = self.expiryHeight, expiryHeight != -1 {
return max(expiryHeight - ZcashSDK.EXPIRY_OFFSET - ZcashSDK.DEFAULT_STALE_TOLERANCE, ZcashSDK.SAPLING_ACTIVATION_HEIGHT)
}
return nil
}
}
/**
Abstract representation of all transaction types

View File

@ -54,7 +54,6 @@ public protocol ZcashRustBackendWelding {
*/
static func isValidExtendedFullViewingKey(_ key: String) throws -> Bool
/**
initialize the accounts table from a given seed and a number of accounts
- Parameters:

View File

@ -0,0 +1,117 @@
// Copyright (c) 2019-2020 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
syntax = "proto3";
package cash.z.wallet.sdk.rpc;
option go_package = ".;walletrpc";
option swift_prefix = "";
import "service.proto";
message DarksideMetaState {
int32 saplingActivation = 1;
string branchID = 2;
string chainName = 3;
}
// A block is a hex-encoded string.
message DarksideBlock {
string block = 1;
}
// DarksideBlocksURL is typically something like:
// https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/before-reorg.txt
message DarksideBlocksURL {
string url = 1;
}
// DarksideTransactionsURL refers to an HTTP source that contains a list
// of hex-encoded transactions, one per line, that are to be associated
// with the given height (fake-mined into the block at that height)
message DarksideTransactionsURL {
int32 height = 1;
string url = 2;
}
message DarksideHeight {
int32 height = 1;
}
message DarksideEmptyBlocks {
int32 height = 1;
int32 nonce = 2;
int32 count = 3;
}
// Darksidewalletd maintains two staging areas, blocks and transactions. The
// Stage*() gRPCs add items to the staging area; ApplyStaged() "applies" everything
// in the staging area to the working (operational) state that the mock zcashd
// serves; transactions are placed into their corresponding blocks (by height).
service DarksideStreamer {
// 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(). 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. Order is important, see ApplyStaged.
rpc StageBlocksStream(stream DarksideBlock) returns (Empty) {}
// StageBlocks is the same as StageBlocksStream() except the blocks are fetched
// from the given URL. Blocks are one per line, hex-encoded (not JSON).
rpc StageBlocks(DarksideBlocksURL) returns (Empty) {}
// 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 identical blocks (same transactions and height), but with
// different hashes.
rpc StageBlocksCreate(DarksideEmptyBlocks) returns (Empty) {}
// 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. 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
// also be used to simply advance the latest block height presented by mock
// zcashd. That is, there doesn't need to be anything in the staging area.
rpc ApplyStaged(DarksideHeight) returns (Empty) {}
// Calls to the production gRPC SendTransaction() store the transaction in
// a separate area (not the staging area); this method returns all transactions
// in this separate area, which is then cleared. The height returned
// with each transaction is -1 (invalid) since these transactions haven't
// been mined yet. The intention is that the transactions returned here can
// then, for example, be given to StageTransactions() to get them "mined"
// into a specified block on the next ApplyStaged().
rpc GetIncomingTransactions(Empty) returns (stream RawTransaction) {}
// Clear the incoming transaction pool.
rpc ClearIncomingTransactions(Empty) returns (Empty) {}
}

View File

@ -34,7 +34,7 @@ message TxFilter {
// RawTransaction contains the complete transaction data. It also optionally includes
// the block height in which the transaction was included.
message RawTransaction {
bytes data = 1; // exact data returned by zcash 'getrawtransaction'
bytes data = 1; // exact data returned by Zcash 'getrawtransaction'
uint64 height = 2; // height that the transaction was mined (or -1)
}
@ -66,6 +66,9 @@ message LightdInfo {
string branch = 9;
string buildDate = 10;
string buildUser = 11;
uint64 estimatedHeight = 12; // less than tip height if zcashd is syncing
string zcashdBuild = 13; // example: "v4.1.1-877212414"
string zcashdSubversion = 14; // example: "/MagicBean:4.1.1/"
}
// TransparentAddressBlockFilter restricts the results to the given address
@ -104,7 +107,7 @@ message Exclude {
repeated bytes txid = 1;
}
// The TreeState is derived from the zcash z_gettreestate rpc.
// The TreeState is derived from the Zcash z_gettreestate rpc.
message TreeState {
string network = 1; // "main" or "test"
uint64 height = 2;
@ -139,7 +142,7 @@ service CompactTxStreamer {
// Return the requested full (not compact) transaction (as from zcashd)
rpc GetTransaction(TxFilter) returns (RawTransaction) {}
// Submit the given transaction to the zcash network
// Submit the given transaction to the Zcash network
rpc SendTransaction(RawTransaction) returns (SendResponse) {}
// Return the txids corresponding to the given t-address within the given block range
@ -159,7 +162,7 @@ service CompactTxStreamer {
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
// 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) {}

View File

@ -175,7 +175,7 @@ extension CompactTxStreamerClientProtocol {
)
}
/// Submit the given transaction to the zcash network
/// Submit the given transaction to the Zcash network
///
/// - Parameters:
/// - request: Request to send to SendTransaction.
@ -275,7 +275,7 @@ extension CompactTxStreamerClientProtocol {
}
/// 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
/// 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.
///

View File

@ -111,7 +111,7 @@ struct RawTransaction {
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// exact data returned by zcash 'getrawtransaction'
/// exact data returned by Zcash 'getrawtransaction'
var data: Data = SwiftProtobuf.Internal.emptyData
/// height that the transaction was mined (or -1)
@ -195,6 +195,15 @@ struct LightdInfo {
var buildUser: String = String()
/// less than tip height if zcashd is syncing
var estimatedHeight: UInt64 = 0
/// example: "v4.1.1-877212414"
var zcashdBuild: String = String()
/// example: "/MagicBean:4.1.1/"
var zcashdSubversion: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
@ -307,7 +316,7 @@ struct Exclude {
init() {}
}
/// The TreeState is derived from the zcash z_gettreestate rpc.
/// 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
@ -618,6 +627,9 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
9: .same(proto: "branch"),
10: .same(proto: "buildDate"),
11: .same(proto: "buildUser"),
12: .same(proto: "estimatedHeight"),
13: .same(proto: "zcashdBuild"),
14: .same(proto: "zcashdSubversion"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -634,6 +646,9 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
case 9: try decoder.decodeSingularStringField(value: &self.branch)
case 10: try decoder.decodeSingularStringField(value: &self.buildDate)
case 11: try decoder.decodeSingularStringField(value: &self.buildUser)
case 12: try decoder.decodeSingularUInt64Field(value: &self.estimatedHeight)
case 13: try decoder.decodeSingularStringField(value: &self.zcashdBuild)
case 14: try decoder.decodeSingularStringField(value: &self.zcashdSubversion)
default: break
}
}
@ -673,6 +688,15 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
if !self.buildUser.isEmpty {
try visitor.visitSingularStringField(value: self.buildUser, fieldNumber: 11)
}
if self.estimatedHeight != 0 {
try visitor.visitSingularUInt64Field(value: self.estimatedHeight, fieldNumber: 12)
}
if !self.zcashdBuild.isEmpty {
try visitor.visitSingularStringField(value: self.zcashdBuild, fieldNumber: 13)
}
if !self.zcashdSubversion.isEmpty {
try visitor.visitSingularStringField(value: self.zcashdSubversion, fieldNumber: 14)
}
try unknownFields.traverse(visitor: &visitor)
}
@ -688,6 +712,9 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
if lhs.branch != rhs.branch {return false}
if lhs.buildDate != rhs.buildDate {return false}
if lhs.buildUser != rhs.buildUser {return false}
if lhs.estimatedHeight != rhs.estimatedHeight {return false}
if lhs.zcashdBuild != rhs.zcashdBuild {return false}
if lhs.zcashdSubversion != rhs.zcashdSubversion {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}

View File

@ -22,6 +22,8 @@ public enum SynchronizerError: Error {
case uncategorized(underlyingError: Error)
case criticalError
case parameterMissing(underlyingError: Error)
case rewindError(underlyingError: Error)
case rewindErrorUnknownArchorHeight
}
public enum ShieldFundsError: Error {
@ -211,6 +213,15 @@ public protocol Synchronizer {
*/
func getShieldedVerifiedBalance(accountIndex: Int) -> Int64
/**
Stops the synchronizer and rescans the known blocks with the current keys.
- Parameter policy: the rewind policy
- Throws rewindErrorUnknownArchorHeight when the rewind points to an invalid height
- Throws rewindError for other errors
- Note rewind does not trigger notifications as a reorg would. You need to restart the synchronizer afterwards
*/
func rewind(_ policy: RewindPolicy) throws
}
/**
@ -251,3 +262,17 @@ public enum TransactionKind {
case received
case all
}
/**
Type of rewind available
birthday: rewinds the local state to this wallet's birthday
height: rewinds to an arbitrary blockheight
transaction: rewinds to the mined height of the provided transaction.
*/
public enum RewindPolicy {
case birthday
case height(blockheight: BlockHeight)
case transaction(_ transaction: TransactionEntity)
}

View File

@ -529,6 +529,37 @@ public class SDKSynchronizer: Synchronizer {
}
}
public func rewind(_ policy: RewindPolicy) throws {
self.stop()
var height: BlockHeight?
switch policy {
case .birthday:
let birthday = self.blockProcessor.config.walletBirthday
height = birthday
case .height(let rewindHeight):
height = rewindHeight
case .transaction(let tx):
guard let txHeight = tx.anchor else {
throw SynchronizerError.rewindErrorUnknownArchorHeight
}
height = txHeight
}
guard let h = height else {
throw SynchronizerError.rewindErrorUnknownArchorHeight
}
do {
try self.blockProcessor.rewindTo(h)
try self.transactionManager.handleReorg(at: h)
} catch {
throw SynchronizerError.rewindError(underlyingError: error)
}
}
// MARK: notify state
private func notify(progress: Float, height: BlockHeight) {
NotificationCenter.default.post(name: Notification.Name.synchronizerProgressUpdated, object: self, userInfo: [

View File

@ -12,15 +12,15 @@ import Foundation
*/
public protocol Logger {
func debug(_ message: String, file: String, function: String, line: Int)
func debug(_ message: String, file: StaticString, function: StaticString, line: Int)
func info(_ message: String, file: String, function: String, line: Int)
func info(_ message: String, file: StaticString, function: StaticString, line: Int)
func event(_ message: String, file: String, function: String, line: Int)
func event(_ message: String, file: StaticString, function: StaticString, line: Int)
func warn(_ message: String, file: String, function: String, line: Int)
func warn(_ message: String, file: StaticString, function: StaticString, line: Int)
func error(_ message: String, file: String, function: String, line: Int)
func error(_ message: String, file: StaticString, function: StaticString, line: Int)
}
@ -28,23 +28,23 @@ var logger: Logger?
class LoggerProxy {
static func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
static func debug(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
logger?.debug(message, file: file, function: function, line: line)
}
static func info(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
static func info(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
logger?.info(message, file: file, function: function, line: line)
}
static func event(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
static func event(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
logger?.event(message, file: file, function: function, line: line)
}
static func warn(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
static func warn(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
logger?.warn(message, file: file, function: function, line: line)
}
static func error(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
static func error(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
logger?.error(message, file: file, function: function, line: line)
}

View File

@ -223,6 +223,9 @@ bool zcashlc_is_valid_shielded_address(const char *address);
*/
bool zcashlc_is_valid_transparent_address(const char *address);
/**
* returns whether the given viewing key is valid or not
*/
bool zcashlc_is_valid_viewing_key(const char *key);
/**

View File

@ -418,7 +418,7 @@ class AdvancedReOrgTests: XCTestCase {
firstSyncExpectation.fulfill()
}, error: self.handleError)
wait(for: [firstSyncExpectation], timeout: 5)
wait(for: [firstSyncExpectation], timeout: 10)
/*

View File

@ -30,6 +30,417 @@ class BalanceTests: XCTestCase {
}
/**
verify that when sending the maximum amount, the transactions are broadcasted properly
*/
func testMaxAmountSend() throws {
let notificationHandler = SDKSynchonizerListener()
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
// 0 subscribe to updated transactions events
notificationHandler.subscribeToSynchronizer(coordinator.synchronizer)
// 1 sync and get spendable funds
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service)
try coordinator.applyStaged(blockheight: defaultLatestHeight + 10)
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
firstSyncExpectation.fulfill()
}, error: handleError)
wait(for: [firstSyncExpectation], timeout: 12)
// 2 check that there are no unconfirmed funds
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee())
XCTAssertEqual(verifiedBalance, totalBalance)
let maxBalance = verifiedBalance - Int64(ZcashSDK.defaultFee())
// 3 create a transaction for the max amount possible
// 4 send the transaction
guard let spendingKey = coordinator.spendingKeys?.first else {
XCTFail("failed to create spending keys")
return
}
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
zatoshi: maxBalance,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
switch result {
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
case .success(let transaction):
pendingTx = transaction
}
self.sentTransactionExpectation.fulfill()
}
wait(for: [sentTransactionExpectation], timeout: 20)
guard let pendingTx = pendingTx else {
XCTFail("transaction creation failed")
return
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTAssertNotNil(tx.rawTransactionId)
XCTAssertNotNil(pendingTx.rawTransactionId)
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
transactionMinedExpectation.fulfill()
}
// 5 apply to height
// 6 mine the block
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("no incoming transaction after")
return
}
let latestHeight = try coordinator.latestHeight()
let sentTxHeight = latestHeight + 1
notificationHandler.transactionsFound = { txs in
let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(foundTx)
XCTAssertEqual(foundTx?.minedHeight, sentTxHeight)
foundTransactionsExpectation.fulfill()
}
try coordinator.stageBlockCreate(height: sentTxHeight, count: 100)
sleep(1)
try coordinator.stageTransaction(rawTx, at: sentTxHeight)
try coordinator.applyStaged(blockheight: sentTxHeight)
sleep(2) // add enhance breakpoint here
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { (synchronizer) in
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(p, "pending transaction should have been mined by now")
XCTAssertTrue(p?.isMined ?? false)
XCTAssertEqual(p?.minedHeight, sentTxHeight)
mineExpectation.fulfill()
}, error: { (error) in
guard let e = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(e)")
})
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
// 7 advance to confirmation
try coordinator.applyStaged(blockheight: sentTxHeight + 10)
sleep(2)
let confirmExpectation = XCTestExpectation(description: "confirm expectation")
notificationHandler.transactionsFound = { txs in
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTFail("We shouldn't find any mined transactions at this point but found \(tx)")
}
try coordinator.sync(completion: { synchronizer in
confirmExpectation.fulfill()
}, error: { e in
self.handleError(e)
})
wait(for: [confirmExpectation], timeout: 5)
let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 0)
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0)
}
/**
verify that when sending the maximum amount minus one zatoshi, the transactions are broadcasted properly
*/
func testMaxAmountMinusOneSend() throws {
let notificationHandler = SDKSynchonizerListener()
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
// 0 subscribe to updated transactions events
notificationHandler.subscribeToSynchronizer(coordinator.synchronizer)
// 1 sync and get spendable funds
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service)
try coordinator.applyStaged(blockheight: defaultLatestHeight + 10)
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
firstSyncExpectation.fulfill()
}, error: handleError)
wait(for: [firstSyncExpectation], timeout: 12)
// 2 check that there are no unconfirmed funds
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee())
XCTAssertEqual(verifiedBalance, totalBalance)
let maxBalanceMinusOne = verifiedBalance - Int64(ZcashSDK.defaultFee()) - 1
// 3 create a transaction for the max amount possible
// 4 send the transaction
guard let spendingKey = coordinator.spendingKeys?.first else {
XCTFail("failed to create spending keys")
return
}
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
zatoshi: maxBalanceMinusOne,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
switch result {
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
case .success(let transaction):
pendingTx = transaction
}
self.sentTransactionExpectation.fulfill()
}
wait(for: [sentTransactionExpectation], timeout: 20)
guard let pendingTx = pendingTx else {
XCTFail("transaction creation failed")
return
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTAssertNotNil(tx.rawTransactionId)
XCTAssertNotNil(pendingTx.rawTransactionId)
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
transactionMinedExpectation.fulfill()
}
// 5 apply to height
// 6 mine the block
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("no incoming transaction after")
return
}
let latestHeight = try coordinator.latestHeight()
let sentTxHeight = latestHeight + 1
notificationHandler.transactionsFound = { txs in
let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(foundTx)
XCTAssertEqual(foundTx?.minedHeight, sentTxHeight)
foundTransactionsExpectation.fulfill()
}
try coordinator.stageBlockCreate(height: sentTxHeight, count: 100)
sleep(1)
try coordinator.stageTransaction(rawTx, at: sentTxHeight)
try coordinator.applyStaged(blockheight: sentTxHeight)
sleep(2) // add enhance breakpoint here
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { (synchronizer) in
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(p, "pending transaction should have been mined by now")
XCTAssertTrue(p?.isMined ?? false)
XCTAssertEqual(p?.minedHeight, sentTxHeight)
mineExpectation.fulfill()
}, error: { (error) in
guard let e = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(e)")
})
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
// 7 advance to confirmation
try coordinator.applyStaged(blockheight: sentTxHeight + 10)
sleep(2)
let confirmExpectation = XCTestExpectation(description: "confirm expectation")
notificationHandler.transactionsFound = { txs in
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTFail("We shouldn't find any mined transactions at this point but found \(tx)")
}
try coordinator.sync(completion: { synchronizer in
confirmExpectation.fulfill()
}, error: { e in
self.handleError(e)
})
wait(for: [confirmExpectation], timeout: 5)
let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 1)
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 1)
}
/**
verify that when sending the a no change transaction, the transactions are broadcasted properly
*/
func testSingleNoteNoChangeTransaction() throws {
let notificationHandler = SDKSynchonizerListener()
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
// 0 subscribe to updated transactions events
notificationHandler.subscribeToSynchronizer(coordinator.synchronizer)
// 1 sync and get spendable funds
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service)
try coordinator.applyStaged(blockheight: defaultLatestHeight + 10)
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
firstSyncExpectation.fulfill()
}, error: handleError)
wait(for: [firstSyncExpectation], timeout: 12)
// 2 check that there are no unconfirmed funds
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee())
XCTAssertEqual(verifiedBalance, totalBalance)
let maxBalanceMinusOne = 100000 - ZcashSDK.defaultFee()
// 3 create a transaction for the max amount possible
// 4 send the transaction
guard let spendingKey = coordinator.spendingKeys?.first else {
XCTFail("failed to create spending keys")
return
}
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
zatoshi: maxBalanceMinusOne,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
switch result {
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
case .success(let transaction):
pendingTx = transaction
}
self.sentTransactionExpectation.fulfill()
}
wait(for: [sentTransactionExpectation], timeout: 20)
guard let pendingTx = pendingTx else {
XCTFail("transaction creation failed")
return
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTAssertNotNil(tx.rawTransactionId)
XCTAssertNotNil(pendingTx.rawTransactionId)
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
transactionMinedExpectation.fulfill()
}
// 5 apply to height
// 6 mine the block
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("no incoming transaction after")
return
}
let latestHeight = try coordinator.latestHeight()
let sentTxHeight = latestHeight + 1
notificationHandler.transactionsFound = { txs in
let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(foundTx)
XCTAssertEqual(foundTx?.minedHeight, sentTxHeight)
foundTransactionsExpectation.fulfill()
}
try coordinator.stageBlockCreate(height: sentTxHeight, count: 100)
sleep(1)
try coordinator.stageTransaction(rawTx, at: sentTxHeight)
try coordinator.applyStaged(blockheight: sentTxHeight)
sleep(2) // add enhance breakpoint here
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { (synchronizer) in
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(p, "pending transaction should have been mined by now")
XCTAssertTrue(p?.isMined ?? false)
XCTAssertEqual(p?.minedHeight, sentTxHeight)
mineExpectation.fulfill()
}, error: { (error) in
guard let e = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(e)")
})
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
// 7 advance to confirmation
try coordinator.applyStaged(blockheight: sentTxHeight + 10)
sleep(2)
let confirmExpectation = XCTestExpectation(description: "confirm expectation")
notificationHandler.transactionsFound = { txs in
XCTFail("We shouldn't find any transactions at this point but found \(txs)")
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTFail("We shouldn't find any mined transactions at this point but found \(tx)")
}
try coordinator.sync(completion: { synchronizer in
confirmExpectation.fulfill()
}, error: { e in
self.handleError(e)
})
wait(for: [confirmExpectation], timeout: 5)
let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 100000)
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 100000)
}
/**
Verify available balance is correct in all wallet states during a send
@ -103,6 +514,7 @@ class BalanceTests: XCTestCase {
XCTFail("no incoming transaction after")
return
}
let latestHeight = try coordinator.latestHeight()
let sentTxHeight = latestHeight + 1
try coordinator.stageBlockCreate(height: sentTxHeight)
@ -615,3 +1027,39 @@ class BalanceTests: XCTestCase {
}
}
class SDKSynchonizerListener {
var transactionsFound: (([ConfirmedTransactionEntity]) -> ())?
var synchronizerMinedTransaction: ((PendingTransactionEntity) -> ())?
func subscribeToSynchronizer(_ synchronizer: SDKSynchronizer) {
NotificationCenter.default.addObserver(self, selector: #selector(txFound(_:)), name: .synchronizerFoundTransactions, object: synchronizer)
NotificationCenter.default.addObserver(self, selector: #selector(txMined(_:)), name: .synchronizerMinedTransaction, object: synchronizer)
}
func unsubscribe() {
NotificationCenter.default.removeObserver(self)
}
@objc func txFound(_ notification: Notification) {
DispatchQueue.main.async { [weak self] in
guard let txs = notification.userInfo?[SDKSynchronizer.NotificationKeys.foundTransactions] as? [ConfirmedTransactionEntity] else {
XCTFail("expected [ConfirmedTransactionEntity] array")
return
}
self?.transactionsFound?(txs)
}
}
@objc func txMined(_ notification: Notification) {
DispatchQueue.main.async { [weak self] in
guard let tx = notification.userInfo?[SDKSynchronizer.NotificationKeys.minedTransaction] as? PendingTransactionEntity else {
XCTFail("expected transaction")
return
}
self?.synchronizerMinedTransaction?(tx)
}
}
}

View File

@ -0,0 +1,337 @@
//
// XCTRewindRescanTests.swift
// ZcashLightClientKit-Unit-Tests
//
// Created by Francisco Gindre on 3/25/21.
//
import XCTest
@testable import ZcashLightClientKit
class RewindRescanTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
let defaultLatestHeight: BlockHeight = 663175
var coordinator: TestCoordinator!
var syncedExpectation = XCTestExpectation(description: "synced")
var sentTransactionExpectation = XCTestExpectation(description: "sent")
var expectedReorgHeight: BlockHeight = 665188
var expectedRewindHeight: BlockHeight = 665188
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
override func setUpWithError() throws {
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
channelProvider: ChannelProvider()
)
try coordinator.reset(saplingActivation: 663150)
}
override func tearDownWithError() throws {
NotificationCenter.default.removeObserver(self)
try coordinator.stop()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
}
func handleError(_ error: Error?) {
guard let testError = error else {
XCTFail("failed with nil error")
return
}
XCTFail("Failed with error: \(testError)")
}
func testBirthdayRescan() throws {
// 1 sync and get spendable funds
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service)
try coordinator.applyStaged(blockheight: defaultLatestHeight + 50)
let initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let initialTotalBalance = coordinator.synchronizer.initializer.getBalance()
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
firstSyncExpectation.fulfill()
}, error: handleError)
wait(for: [firstSyncExpectation], timeout: 12)
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance()
// 2 check that there are no unconfirmed funds
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee())
XCTAssertEqual(verifiedBalance, totalBalance)
// rewind to birthday
try coordinator.synchronizer.rewind(.birthday)
// assert that after the new height is
XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),self.birthday)
// check that the balance is cleared
XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
XCTAssertEqual(initialTotalBalance, coordinator.synchronizer.initializer.getBalance())
let secondScanExpectation = XCTestExpectation(description: "rescan")
try coordinator.sync(completion: { (synchronizer) in
secondScanExpectation.fulfill()
}, error: handleError)
wait(for: [secondScanExpectation], timeout: 12)
// verify that the balance still adds up
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
}
func testRescanToHeight() throws {
// 1 sync and get spendable funds
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service)
try coordinator.applyStaged(blockheight: defaultLatestHeight + 50)
let initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let initialTotalBalance = coordinator.synchronizer.initializer.getBalance()
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
firstSyncExpectation.fulfill()
}, error: handleError)
wait(for: [firstSyncExpectation], timeout: 12)
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance()
// 2 check that there are no unconfirmed funds
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee())
XCTAssertEqual(verifiedBalance, totalBalance)
// rewind to birthday
let targetHeight: BlockHeight = 663160
try coordinator.synchronizer.rewind(.height(blockheight: targetHeight))
// assert that after the new height is
XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),targetHeight)
// check that the balance is cleared
XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
XCTAssertEqual(initialTotalBalance, coordinator.synchronizer.initializer.getBalance())
let secondScanExpectation = XCTestExpectation(description: "rescan")
try coordinator.sync(completion: { (synchronizer) in
secondScanExpectation.fulfill()
}, error: handleError)
wait(for: [secondScanExpectation], timeout: 12)
// verify that the balance still adds up
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
}
func testRescanToTransaction() throws {
// 1 sync and get spendable funds
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service)
try coordinator.applyStaged(blockheight: defaultLatestHeight + 50)
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
firstSyncExpectation.fulfill()
}, error: handleError)
wait(for: [firstSyncExpectation], timeout: 12)
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance()
// 2 check that there are no unconfirmed funds
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee())
XCTAssertEqual(verifiedBalance, totalBalance)
// rewind to transaction
guard let transaction = try coordinator.synchronizer.allClearedTransactions().first else {
XCTFail("failed to get a transaction to rewind to")
return
}
try coordinator.synchronizer.rewind(.transaction(transaction.transactionEntity))
// assert that after the new height is
XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),transaction.transactionEntity.anchor)
let secondScanExpectation = XCTestExpectation(description: "rescan")
try coordinator.sync(completion: { (synchronizer) in
secondScanExpectation.fulfill()
}, error: handleError)
wait(for: [secondScanExpectation], timeout: 12)
// verify that the balance still adds up
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
}
func testRewindAfterSendingTransaction() throws {
let notificationHandler = SDKSynchonizerListener()
let foundTransactionsExpectation = XCTestExpectation(description: "found transactions expectation")
let transactionMinedExpectation = XCTestExpectation(description: "transaction mined expectation")
// 0 subscribe to updated transactions events
notificationHandler.subscribeToSynchronizer(coordinator.synchronizer)
// 1 sync and get spendable funds
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service)
try coordinator.applyStaged(blockheight: defaultLatestHeight + 10)
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
firstSyncExpectation.fulfill()
}, error: handleError)
wait(for: [firstSyncExpectation], timeout: 12)
// 2 check that there are no unconfirmed funds
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee())
XCTAssertEqual(verifiedBalance, totalBalance)
let maxBalance = verifiedBalance - Int64(ZcashSDK.defaultFee())
// 3 create a transaction for the max amount possible
// 4 send the transaction
guard let spendingKey = coordinator.spendingKeys?.first else {
XCTFail("failed to create spending keys")
return
}
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
zatoshi: maxBalance,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
switch result {
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
case .success(let transaction):
pendingTx = transaction
}
self.sentTransactionExpectation.fulfill()
}
wait(for: [sentTransactionExpectation], timeout: 20)
guard let pendingTx = pendingTx else {
XCTFail("transaction creation failed")
return
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTAssertNotNil(tx.rawTransactionId)
XCTAssertNotNil(pendingTx.rawTransactionId)
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
transactionMinedExpectation.fulfill()
}
// 5 apply to height
// 6 mine the block
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("no incoming transaction after")
return
}
let latestHeight = try coordinator.latestHeight()
let sentTxHeight = latestHeight + 1
notificationHandler.transactionsFound = { txs in
let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(foundTx)
XCTAssertEqual(foundTx?.minedHeight, sentTxHeight)
foundTransactionsExpectation.fulfill()
}
try coordinator.stageBlockCreate(height: sentTxHeight, count: 100)
sleep(1)
try coordinator.stageTransaction(rawTx, at: sentTxHeight)
try coordinator.applyStaged(blockheight: sentTxHeight)
sleep(2)
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { (synchronizer) in
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(p, "pending transaction should have been mined by now")
XCTAssertTrue(p?.isMined ?? false)
XCTAssertEqual(p?.minedHeight, sentTxHeight)
mineExpectation.fulfill()
}, error: { (error) in
guard let e = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
XCTFail("Error: \(e)")
})
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
// 7 advance to confirmation
try coordinator.applyStaged(blockheight: sentTxHeight + 10)
sleep(2)
// rewind 5 blocks prior to sending
try coordinator.synchronizer.rewind(.height(blockheight: sentTxHeight - 5))
guard let np = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) else {
XCTFail("sent pending transaction not found after rewind")
return
}
XCTAssertFalse(np.isMined)
let confirmExpectation = XCTestExpectation(description: "confirm expectation")
notificationHandler.transactionsFound = { txs in
XCTAssertEqual(txs.count, 1)
guard let t = txs.first else {
XCTFail("should have found sent transaction but didn't")
return
}
XCTAssertEqual(t.rawTransactionId, pendingTx.rawTransactionId,"should have mined sent transaction but didn't")
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTFail("We shouldn't find any mined transactions at this point but found \(tx)")
}
try coordinator.sync(completion: { synchronizer in
confirmExpectation.fulfill()
}, error: { e in
self.handleError(e)
})
wait(for: [confirmExpectation], timeout: 10)
let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 0)
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0)
}
}

View File

@ -23,7 +23,7 @@
import GRPC
import NIO
import SwiftProtobuf
@testable import ZcashLightClientKit
/// Usage: instantiate DarksideStreamerClient, then call methods of this protocol to make API calls.
internal protocol DarksideStreamerClientProtocol: GRPCClient {

View File

@ -7,8 +7,9 @@
//
import Foundation
import os
import ZcashLightClientKit
import os
class SampleLogger: ZcashLightClientKit.Logger {
enum LogLevel: Int {
case debug
@ -18,44 +19,54 @@ class SampleLogger: ZcashLightClientKit.Logger {
case info
}
enum LoggerType {
case osLog
case printerLog
}
var level: LogLevel
init(logLevel: LogLevel) {
var loggerType: LoggerType
init(logLevel: LogLevel, type: LoggerType = .osLog) {
self.level = logLevel
self.loggerType = type
}
private static let subsystem = Bundle.main.bundleIdentifier!
static let oslog = OSLog(subsystem: subsystem, category: "test-logs")
static let oslog = OSLog(subsystem: subsystem, category: "logs")
func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func debug(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue == LogLevel.debug.rawValue else { return }
log(level: "DEBUG 🐞", message: message, file: file, function: function, line: line)
}
func error(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func error(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.error.rawValue else { return }
log(level: "ERROR 💥", message: message, file: file, function: function, line: line)
}
func warn(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func warn(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.warning.rawValue else { return }
log(level: "WARNING ⚠️", message: message, file: file, function: function, line: line)
}
func event(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func event(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.event.rawValue else { return }
log(level: "EVENT ⏱", message: message, file: file, function: function, line: line)
}
func info(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
func info(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.info.rawValue else { return }
log(level: "INFO ", message: message, file: file, function: function, line: line)
}
private func log(level: String, message: String, file: String, function: String, line: Int) {
let fileName = file as NSString
os_log("[%@] %@ - %@ - Line: %d -> %@", log: Self.oslog, type: .default, level, fileName.lastPathComponent, function, line, message)
private func log(level: String, message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
let fileName = (String(describing: file) as NSString).lastPathComponent
switch loggerType {
case .printerLog:
print("[\(level)] \(fileName) - \(function) - line: \(line) -> \(message)")
default:
os_log("[%{public}@] %{public}@ - %{public}@ - Line: %{public}d -> %{public}@", level, fileName, String(describing: function), line, message)
}
}
}

View File

@ -1,3 +1,11 @@
# 0.10.0
* [critical] Fix #255 #261 outgoing no-change transactions not reported as mined
* [NEW] Rewind API. Allow Wallet developers to rewind synchronizer and (eventually) rescan
* [NEW] Rust Welding 0.0.6 - using rust crates 0.5 and Data Access API
* [NEW] updated Logger API to use StaticString on line and function as many logging libraries do
* [FIX] Mac OS BIG SUR build fixed
# 0.9.4
* New: added viewing key derivation to Derivation Tool
* Issue #252 - blockheight progress is latest height instead of upperbound of last scanned range

View File

@ -12,7 +12,7 @@ use zcash_client_backend::{
chain::{scan_cached_blocks, validate_chain},
error::Error,
wallet::{create_spend_to_address, decrypt_and_store_transaction, shield_funds, ANCHOR_OFFSET},
WalletRead, WalletWrite,
WalletRead,
},
encoding::{
AddressCodec,
@ -32,22 +32,18 @@ use zcash_client_backend::{
use zcash_client_sqlite::{
error::SqliteClientError,
wallet::{
rewind_to_height,
put_received_transparent_utxo,
init::{init_accounts_table, init_blocks_table, init_wallet_db,}
},
BlockDB, NoteId, WalletDB,
};
use zcash_primitives::{
block::BlockHash,
consensus::{self,BlockHeight, BranchId, Parameters},
note_encryption::Memo,
transaction::{
Transaction,
components::{Amount, OutPoint},
},
zip32::{ExtendedFullViewingKey},
consensus::{BlockHeight, BranchId, Parameters},
memo::{Memo, MemoBytes},
transaction::{components::Amount, components::OutPoint, Transaction},
zip32::ExtendedFullViewingKey,
legacy::TransparentAddress,
};
@ -62,7 +58,6 @@ use base58::ToBase58;
use sha2::{Digest, Sha256};
use secp256k1::key::SecretKey;
fn unwrap_exc_or<T>(exc: Result<T, ()>, def: T) -> T {
match exc {
Ok(value) => value,
@ -86,26 +81,36 @@ pub const NETWORK: MainNetwork = MAIN_NETWORK;
#[cfg(not(feature = "mainnet"))]
pub const NETWORK: TestNetwork = TEST_NETWORK;
fn wallet_db<P: consensus::Parameters>(params: P,db_data: *const u8,
db_data_len: usize) -> Result<WalletDB<P>, failure::Error> {
#[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, params)
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> {
#[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))
.map_err(|e| format_err!("Error opening block source database connection: {}", e))
}
/// Returns the length of the last error message to be logged.
@ -133,11 +138,11 @@ pub extern "C" fn zcashlc_init_data_database(db_data: *const u8, db_data_len: us
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(|db| init_wallet_db(&db))
.map(|_| 1)
.map_err(|e| format_err!("Error while initializing data DB: {}", e))
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)
}
@ -158,7 +163,7 @@ pub extern "C" fn zcashlc_init_accounts_table(
capacity_ret: *mut usize,
) -> *mut *mut c_char {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, 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
@ -173,15 +178,17 @@ pub extern "C" fn zcashlc_init_accounts_table(
init_accounts_table(&db_data, &extfvks)
.map(|_| {
// Return the ExtendedSpendingKeys for the created accounts.
// 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();
.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();
@ -189,7 +196,6 @@ pub extern "C" fn zcashlc_init_accounts_table(
return p;
})
.map_err(|e| format_err!("Error while initializing accounts: {}", e))
});
unwrap_exc_or_null(res)
}
@ -204,22 +210,27 @@ pub extern "C" fn zcashlc_init_accounts_table_with_keys(
extfvks_len: usize,
) -> bool {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, 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(NETWORK.hrp_sapling_extended_full_viewing_key(), &vkstr)
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<_>>() };
})
.collect::<Vec<_>>()
};
match init_accounts_table(&db_data, &extfvks) {
Ok(()) => Ok(true),
Err(e) => Err(format_err!("Error while initializing accounts: {}", e)),
}
});
unwrap_exc_or(res, false)
}
@ -252,8 +263,10 @@ pub unsafe extern "C" fn zcashlc_derive_extended_spending_keys(
let mut v: Vec<_> = extsks
.iter()
.map(|extsk| {
let encoded =
encode_extended_spending_key(NETWORK.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();
@ -286,15 +299,19 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_keys(
};
let extsks: Vec<_> = (0..accounts)
.map(|account| ExtendedFullViewingKey::from(&spending_key(&seed, NETWORK.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(NETWORK.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();
@ -306,7 +323,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(
@ -321,18 +338,14 @@ 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_str = derive_shielded_address_from_seed(&NETWORK, &seed, account_index);
Ok(CString::new(address_str).unwrap().into_raw())
});
unwrap_exc_or_null(res)
}
fn derive_shielded_address_from_seed<P: Parameters>(params: &P, seed: &[u8], account_index: u32) -> String {
let address = spending_key(&seed, NETWORK.coin_type(), account_index)
let address = spending_key(&seed, NETWORK.coin_type(), account_index)
.default_address()
.unwrap()
.1;
encode_payment_address(params.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)
}
// fn derive_shielded_address_from_spending_k<P: Parameters>(params: &P, extsk: &ExtendedSpendingKey) -> String {
@ -346,7 +359,6 @@ fn derive_shielded_address_from_seed<P: Parameters>(params: &P, seed: &[u8], acc
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(
@ -371,7 +383,7 @@ pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_viewing_key(
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(
@ -379,20 +391,26 @@ 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(NETWORK.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."));
},
}
Err(e) => {
return Err(format_err!(
"Error while deriving viewing key from spending key: {}",
e
));
},
}
};
let encoded = encode_extended_full_viewing_key(NETWORK.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())
});
@ -413,7 +431,7 @@ pub extern "C" fn zcashlc_init_blocks_table(
sapling_tree_hex: *const c_char,
) -> i32 {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, 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();
@ -422,7 +440,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, BlockHeight::from_u32(height as u32), 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)),
}
@ -440,7 +464,7 @@ pub extern "C" fn zcashlc_get_address(
account: i32,
) -> *mut c_char {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let db_data = wallet_db(db_data, db_data_len)?;
let account = if account >= 0 {
account as u32
} else {
@ -454,7 +478,7 @@ pub extern "C" fn zcashlc_get_address(
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
@ -497,7 +521,7 @@ 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(|| {
@ -527,34 +551,25 @@ fn is_valid_transparent_address(address: &str) -> bool {
#[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 = wallet_db(NETWORK, db_data, db_data_len)?;
let db_data = wallet_db(db_data, db_data_len)?;
let account = if account >= 0 {
account as u32
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 {
return Err(format_err!("account argument must be positive"));
};
let account = AccountId(account);
// match db_data.get_balance(account) {
// Ok(balance) => Ok(balance.into()),
// Err(e) => Err(format_err!("Error while fetching balance: {}", e)),
// }
(&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(|(h, _)| h)
.ok_or(format_err!("height not available; scan required."))
})
.and_then(|height| {
(&db_data)
.get_balance_at(account, height)
.map_err(|e| format_err!("Error while fetching verified balance: {}", e))
})
.map(|amount| amount.into())
Err(format_err!("account argument must be positive"))
}
});
unwrap_exc_or(res, -1)
}
@ -568,27 +583,25 @@ pub extern "C" fn zcashlc_get_verified_balance(
account: i32,
) -> i64 {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, 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"));
};
let account = AccountId(account);
(&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(account, anchor)
.map_err(|e| format_err!("Error while fetching verified balance: {}", e))
})
.map(|amount| amount.into())
Err(format_err!("account argument must be positive"))
}
});
unwrap_exc_or(res, -1)
}
@ -602,7 +615,7 @@ pub extern "C" fn zcashlc_get_verified_transparent_balance(
address: *const c_char,
) -> i64 {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let db_data = wallet_db(db_data, db_data_len)?;
let addr = unsafe { CStr::from_ptr(address).to_str()? };
let taddr = TransparentAddress::decode(&NETWORK, &addr).unwrap();
let amount = (&db_data)
@ -636,7 +649,7 @@ pub extern "C" fn zcashlc_get_total_transparent_balance(
address: *const c_char,
) -> i64 {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let db_data = wallet_db(db_data, db_data_len)?;
let addr = unsafe { CStr::from_ptr(address).to_str()? };
let taddr = TransparentAddress::decode(&NETWORK, &addr).unwrap();
let amount = (&db_data)
@ -661,6 +674,7 @@ pub extern "C" fn zcashlc_get_total_transparent_balance(
unwrap_exc_or(res, -1)
}
/// Returns the memo for a received note, if it is known and a valid UTF-8 string.
///
/// The note is identified by its row index in the `received_notes` table within the data
@ -674,12 +688,17 @@ pub extern "C" fn zcashlc_get_received_memo_as_utf8(
id_note: i64,
) -> *mut c_char {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let db_data = wallet_db(db_data, db_data_len)?;
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)),
};
let memo = (&db_data).get_memo(NoteId::ReceivedNoteId(id_note))
.map_err(|e| format_err!("An error occurred retrieving the memo, {}", e))
.and_then(|memo| {
match memo {
Memo::Empty => Ok("".to_string()),
Memo::Text(memo) => Ok(memo.into()),
_ => Err(format_err!("This memo does not contain UTF-8 text")),
}
})?;
Ok(CString::new(memo).unwrap().into_raw())
});
@ -699,13 +718,18 @@ pub extern "C" fn zcashlc_get_sent_memo_as_utf8(
id_note: i64,
) -> *mut c_char {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
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))?;
let db_data = wallet_db(db_data, db_data_len)?;
let memo = (&db_data).get_memo(NoteId::SentNoteId(id_note))
.map_err(|e| format_err!("An error occurred retrieving the memo, {}", e))
.and_then(|memo| {
match memo {
Memo::Empty => Ok("".to_string()),
Memo::Text(memo) => Ok(memo.into()),
_ => Err(format_err!("This memo does not contain UTF-8 text")),
}
})?;
Ok(CString::new(memo).unwrap().into_raw())
});
unwrap_exc_or_null(res)
@ -736,12 +760,12 @@ pub extern "C" fn zcashlc_validate_combined_chain(
) -> i32 {
let res = catch_panic(|| {
let block_db = block_db(db_cache, db_cache_len)?;
let db_data = wallet_db(NETWORK, db_data, db_data_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 {
@ -771,18 +795,17 @@ pub extern "C" fn zcashlc_rewind_to_height(
height: i32,
) -> i32 {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let db_data = wallet_db(db_data, db_data_len)?;
// let mut update_ops = (&db_data)
// .get_update_ops()
// .map_err(|e| format_err!("Could not obtain a writable database connection: {}", 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))
rewind_to_height(&db_data, height)
.map(|_| 1)
.map_err(|e| format_err!("Error while rewinding data DB to height {}: {}", height, e))
});
unwrap_exc_or_null(res)
}
@ -810,8 +833,8 @@ pub extern "C" fn zcashlc_scan_blocks(
) -> i32 {
let res = catch_panic(|| {
let block_db = block_db(db_cache, db_cache_len)?;
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let mut db_data = db_data.get_update_ops()?;
let db_read = wallet_db(db_data, db_data_len)?;
let mut db_data = db_read.get_update_ops()?;
match scan_cached_blocks(&NETWORK, &block_db, &mut db_data, None) {
Ok(()) => Ok(1),
@ -835,7 +858,7 @@ pub extern "C" fn zcashlc_put_utxo(
height: i32,
) -> bool {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let db_data = wallet_db(db_data, db_data_len)?;
let mut db_data = db_data.get_update_ops()?;
let addr = unsafe {CStr::from_ptr(address_str).to_str()? };
@ -871,8 +894,8 @@ pub extern "C" fn zcashlc_decrypt_and_store_transaction(
tx_len: usize,
) -> i32 {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let mut db_data = db_data.get_update_ops()?;
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[..])?;
@ -907,9 +930,8 @@ pub extern "C" fn zcashlc_create_to_address(
output_params_len: usize,
) -> i64 {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let mut db_data = db_data.get_update_ops()?;
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 {
@ -936,17 +958,17 @@ pub extern "C" fn zcashlc_create_to_address(
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) {
Some(to) => to,
None => {
return Err(format_err!("PaymentAddress is for the wrong network"));
},
}
};
let memo = Memo::from_str(&memo).map_err(|_| format_err!("Invalid memo"))?;
@ -961,7 +983,7 @@ pub extern "C" fn zcashlc_create_to_address(
&extsk,
&to,
value,
Some(memo),
Some(MemoBytes::from(memo)),
OvkPolicy::Sender,
)
.map_err(|e| format_err!("Error while sending funds: {}", e))
@ -1046,7 +1068,6 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_seed(
account: i32,
index: i32,
) -> *mut c_char {
let res = catch_panic(|| {
let seed = slice::from_raw_parts(seed, seed_len);
let account = if account >= 0 {
@ -1134,7 +1155,7 @@ pub extern "C" fn zcashlc_shield_funds(
) -> i64 {
let res = catch_panic(|| {
let db_data = wallet_db(NETWORK, db_data, db_data_len)?;
let db_data = wallet_db(db_data, db_data_len)?;
let mut update_ops = (&db_data)
.get_update_ops()
.map_err(|e| format_err!("Could not obtain a writable database connection: {}", e))?;
@ -1168,12 +1189,9 @@ pub extern "C" fn zcashlc_shield_funds(
return Err(format_err!("Invalid ExtendedSpendingKey: {}", e));
},
};
let memo = match Memo::from_str(&memo) {
Ok(memo) => memo,
Err(_) => {
return Err(format_err!("Invalid memo input"));
}
};
let memo = Memo::from_str(&memo).map_err(|_| format_err!("Invalid memo"))?;
let memo_bytes = MemoBytes::from(memo);
// shield_funds(&db_cache, &db_data, account, &tsk, &extsk, &memo, &spend_params, &output_params)
shield_funds(&mut update_ops,
&NETWORK,
@ -1181,7 +1199,7 @@ pub extern "C" fn zcashlc_shield_funds(
AccountId(account),
&sk,
&extsk,
&memo,
&memo_bytes,
ANCHOR_OFFSET)
.map_err(|e| format_err!("Error while shielding transaction: {}", e))
});