Merge pull request #6048 from nuttycom/sapling-batch-validation
Use batch validation for Sapling proofs and signatures
This commit is contained in:
commit
9d93dff4c8
|
@ -120,9 +120,9 @@ checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bellman"
|
name = "bellman"
|
||||||
version = "0.13.0"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d96d7f4f3dc9a699bdef1d19648f6f20ef966b51892d224582a4475be669cb5"
|
checksum = "a4dd656ef4fdf7debb6d87d4dd92642fcbcdb78cbf6600c13e25c87e4d1a3807"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"blake2s_simd",
|
"blake2s_simd",
|
||||||
|
@ -1641,6 +1641,22 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redjubjub"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6039ff156887caf92df308cbaccdc058c9d3155a913da046add6e48c4cdbd91d"
|
||||||
|
dependencies = [
|
||||||
|
"blake2b_simd",
|
||||||
|
"byteorder",
|
||||||
|
"digest 0.9.0",
|
||||||
|
"jubjub",
|
||||||
|
"rand_core 0.6.3",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.13"
|
version = "0.2.13"
|
||||||
|
@ -2320,9 +2336,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zcash_proofs"
|
name = "zcash_proofs"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92c0928a33ab146a4e93e2a1141ce589de1bbe93c90219965dcccadc15f4e4e8"
|
checksum = "98bf5f6af051dd929263f279b21b9c04c1f30116c70f3c190de2566677f245ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bellman",
|
"bellman",
|
||||||
"blake2b_simd",
|
"blake2b_simd",
|
||||||
|
@ -2334,6 +2350,8 @@ dependencies = [
|
||||||
"jubjub",
|
"jubjub",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"rand_core 0.6.3",
|
"rand_core 0.6.3",
|
||||||
|
"redjubjub",
|
||||||
|
"tracing",
|
||||||
"zcash_primitives",
|
"zcash_primitives",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ zcash_encoding = "0.1"
|
||||||
zcash_history = "0.3"
|
zcash_history = "0.3"
|
||||||
zcash_note_encryption = "0.1"
|
zcash_note_encryption = "0.1"
|
||||||
zcash_primitives = { version = "0.7", features = ["transparent-inputs"] }
|
zcash_primitives = { version = "0.7", features = ["transparent-inputs"] }
|
||||||
zcash_proofs = "0.7"
|
zcash_proofs = "0.7.1"
|
||||||
ed25519-zebra = "3"
|
ed25519-zebra = "3"
|
||||||
zeroize = "1.4.2"
|
zeroize = "1.4.2"
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,12 @@ description = "The cryptographic code in this crate has been reviewed for correc
|
||||||
[criteria.license-reviewed]
|
[criteria.license-reviewed]
|
||||||
description = "The license of this crate has been reviewed for compatibility with its usage in this repository. If the crate is not available under the MIT license, `contrib/debian/copyright` has been updated with a corresponding copyright notice for files under `depends/*/vendored-sources/CRATE_NAME`."
|
description = "The license of this crate has been reviewed for compatibility with its usage in this repository. If the crate is not available under the MIT license, `contrib/debian/copyright` has been updated with a corresponding copyright notice for files under `depends/*/vendored-sources/CRATE_NAME`."
|
||||||
|
|
||||||
|
[[audits.bellman]]
|
||||||
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
|
delta = "0.13.0 -> 0.13.1"
|
||||||
|
notes = "Adds multi-threaded batch validation, which I checked against the existing single-threaded batch validation."
|
||||||
|
|
||||||
[[audits.equihash]]
|
[[audits.equihash]]
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
|
@ -21,25 +27,13 @@ notes = "The ECC core team maintains this crate, and we have reviewed every line
|
||||||
|
|
||||||
[[audits.f4jumble]]
|
[[audits.f4jumble]]
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
criteria = "crypto-reviewed"
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
version = "0.1.0"
|
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
|
||||||
|
|
||||||
[[audits.f4jumble]]
|
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
|
||||||
criteria = "safe-to-deploy"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
[[audits.halo2_gadgets]]
|
[[audits.halo2_gadgets]]
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
criteria = "crypto-reviewed"
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
version = "0.1.0"
|
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
|
||||||
|
|
||||||
[[audits.halo2_gadgets]]
|
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
|
||||||
criteria = "safe-to-deploy"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
|
@ -51,13 +45,7 @@ notes = "The ECC core team maintains this crate, and we have reviewed every line
|
||||||
|
|
||||||
[[audits.halo2_proofs]]
|
[[audits.halo2_proofs]]
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
criteria = "crypto-reviewed"
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
version = "0.1.0"
|
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
|
||||||
|
|
||||||
[[audits.halo2_proofs]]
|
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
|
||||||
criteria = "safe-to-deploy"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
|
@ -69,13 +57,7 @@ notes = "The ECC core team maintains this crate, and we have reviewed every line
|
||||||
|
|
||||||
[[audits.orchard]]
|
[[audits.orchard]]
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
criteria = "crypto-reviewed"
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
version = "0.1.0"
|
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
|
||||||
|
|
||||||
[[audits.orchard]]
|
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
|
||||||
criteria = "safe-to-deploy"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
|
@ -105,25 +87,13 @@ notes = "The ECC core team maintains this crate, and we have reviewed every line
|
||||||
|
|
||||||
[[audits.zcash_note_encryption]]
|
[[audits.zcash_note_encryption]]
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
criteria = "crypto-reviewed"
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
version = "0.1.0"
|
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
|
||||||
|
|
||||||
[[audits.zcash_note_encryption]]
|
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
|
||||||
criteria = "safe-to-deploy"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
[[audits.zcash_primitives]]
|
[[audits.zcash_primitives]]
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
criteria = "crypto-reviewed"
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
version = "0.6.0"
|
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
|
||||||
|
|
||||||
[[audits.zcash_primitives]]
|
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
|
||||||
criteria = "safe-to-deploy"
|
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
|
@ -135,13 +105,7 @@ notes = "The ECC core team maintains this crate, and we have reviewed every line
|
||||||
|
|
||||||
[[audits.zcash_proofs]]
|
[[audits.zcash_proofs]]
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
criteria = "crypto-reviewed"
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
version = "0.6.0"
|
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
|
||||||
|
|
||||||
[[audits.zcash_proofs]]
|
|
||||||
who = "Jack Grigg <jack@z.cash>"
|
|
||||||
criteria = "safe-to-deploy"
|
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
|
@ -151,3 +115,9 @@ criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
delta = "0.6.0 -> 0.7.0"
|
delta = "0.6.0 -> 0.7.0"
|
||||||
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
|
[[audits.zcash_proofs]]
|
||||||
|
who = "Jack Grigg <jack@z.cash>"
|
||||||
|
criteria = ["crypto-reviewed", "safe-to-deploy"]
|
||||||
|
delta = "0.7.0 -> 0.7.1"
|
||||||
|
notes = "The ECC core team maintains this crate, and we have reviewed every line."
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -176,6 +176,11 @@ def create_benchmark_archive(blk_hash):
|
||||||
|
|
||||||
unique_inputs = {}
|
unique_inputs = {}
|
||||||
for i in sorted(inputs):
|
for i in sorted(inputs):
|
||||||
|
if i[0] in blk['tx']:
|
||||||
|
# This is a child transaction spending the output of a parent transaction in
|
||||||
|
# the same block. We don't want to store the parent coin in the inputs table,
|
||||||
|
# or this will fail the BIP 30 consensus rule.
|
||||||
|
continue
|
||||||
if i[0] in unique_inputs:
|
if i[0] in unique_inputs:
|
||||||
unique_inputs[i[0]].append(i[1])
|
unique_inputs[i[0]].append(i[1])
|
||||||
else:
|
else:
|
||||||
|
@ -262,3 +267,4 @@ if __name__ == '__main__':
|
||||||
check_deps()
|
check_deps()
|
||||||
create_benchmark_archive('0000000007cdb809e48e51dd0b530e8f5073e0a9e9bd7ae920fe23e874658c74')
|
create_benchmark_archive('0000000007cdb809e48e51dd0b530e8f5073e0a9e9bd7ae920fe23e874658c74')
|
||||||
create_benchmark_archive('0000000000651d7fb11f0dd1be8dc87c29dca74cbf91140c6aafbacc09e7da04')
|
create_benchmark_archive('0000000000651d7fb11f0dd1be8dc87c29dca74cbf91140c6aafbacc09e7da04')
|
||||||
|
create_benchmark_archive('00000000012e0b5a8fb0d67c995b92e7c097ddeeab1151de61c4f484611fde11')
|
||||||
|
|
|
@ -164,6 +164,10 @@ function extract_benchmark_data_1708048 {
|
||||||
extract_benchmark_data block-1708048 bdae4b1baf528fa93d86b902e1032d4d1fc3d3080f76cd284635787e472f2534
|
extract_benchmark_data block-1708048 bdae4b1baf528fa93d86b902e1032d4d1fc3d3080f76cd284635787e472f2534
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extract_benchmark_data_1723244 {
|
||||||
|
extract_benchmark_data block-1723244 94acfef482103a61c848ddaa3129877cba987c4a00fa42425f4cf030b7c3fa4c
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if [ $# -lt 2 ]
|
if [ $# -lt 2 ]
|
||||||
then
|
then
|
||||||
|
@ -229,6 +233,10 @@ case "$1" in
|
||||||
extract_benchmark_data_107134
|
extract_benchmark_data_107134
|
||||||
zcash_rpc zcbenchmark connectblockslow 10
|
zcash_rpc zcbenchmark connectblockslow 10
|
||||||
;;
|
;;
|
||||||
|
connectblocksapling)
|
||||||
|
extract_benchmark_data_1723244
|
||||||
|
zcash_rpc zcbenchmark connectblocksapling 10
|
||||||
|
;;
|
||||||
connectblockorchard)
|
connectblockorchard)
|
||||||
extract_benchmark_data_1708048
|
extract_benchmark_data_1708048
|
||||||
zcash_rpc zcbenchmark connectblockorchard 10
|
zcash_rpc zcbenchmark connectblockorchard 10
|
||||||
|
@ -295,6 +303,10 @@ case "$1" in
|
||||||
extract_benchmark_data_107134
|
extract_benchmark_data_107134
|
||||||
zcash_rpc zcbenchmark connectblockslow 1
|
zcash_rpc zcbenchmark connectblockslow 1
|
||||||
;;
|
;;
|
||||||
|
connectblocksapling)
|
||||||
|
extract_benchmark_data_1723244
|
||||||
|
zcash_rpc zcbenchmark connectblocksapling 1
|
||||||
|
;;
|
||||||
connectblockorchard)
|
connectblockorchard)
|
||||||
extract_benchmark_data_1708048
|
extract_benchmark_data_1708048
|
||||||
zcash_rpc zcbenchmark connectblockorchard 1
|
zcash_rpc zcbenchmark connectblockorchard 1
|
||||||
|
@ -359,6 +371,10 @@ case "$1" in
|
||||||
extract_benchmark_data_107134
|
extract_benchmark_data_107134
|
||||||
zcash_rpc zcbenchmark connectblockslow 1
|
zcash_rpc zcbenchmark connectblockslow 1
|
||||||
;;
|
;;
|
||||||
|
connectblocksapling)
|
||||||
|
extract_benchmark_data_1723244
|
||||||
|
zcash_rpc zcbenchmark connectblocksapling 1
|
||||||
|
;;
|
||||||
connectblockorchard)
|
connectblockorchard)
|
||||||
extract_benchmark_data_1708048
|
extract_benchmark_data_1708048
|
||||||
zcash_rpc zcbenchmark connectblockorchard 1
|
zcash_rpc zcbenchmark connectblockorchard 1
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <librustzcash.h>
|
#include <librustzcash.h>
|
||||||
#include <rust/ed25519.h>
|
#include <rust/ed25519.h>
|
||||||
|
#include <rust/sapling.h>
|
||||||
#include <rust/orchard.h>
|
#include <rust/orchard.h>
|
||||||
|
|
||||||
// Subclass of CTransaction which doesn't call UpdateHash when constructing
|
// Subclass of CTransaction which doesn't call UpdateHash when constructing
|
||||||
|
@ -534,6 +535,7 @@ TEST(ChecktransactionTests, BadTxnsPrevoutNull) {
|
||||||
TEST(ContextualCheckShieldedInputsTest, BadTxnsInvalidJoinsplitSignature) {
|
TEST(ContextualCheckShieldedInputsTest, BadTxnsInvalidJoinsplitSignature) {
|
||||||
SelectParams(CBaseChainParams::REGTEST);
|
SelectParams(CBaseChainParams::REGTEST);
|
||||||
auto consensus = Params().GetConsensus();
|
auto consensus = Params().GetConsensus();
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>> saplingAuth = std::nullopt;
|
||||||
auto orchardAuth = orchard::AuthValidator::Disabled();
|
auto orchardAuth = orchard::AuthValidator::Disabled();
|
||||||
|
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
|
@ -551,20 +553,21 @@ TEST(ContextualCheckShieldedInputsTest, BadTxnsInvalidJoinsplitSignature) {
|
||||||
// during initial block download, for transactions being accepted into the
|
// during initial block download, for transactions being accepted into the
|
||||||
// mempool (and thus not mined), DoS ban score should be zero, else 10
|
// mempool (and thus not mined), DoS ban score should be zero, else 10
|
||||||
EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, 0, false, false, [](const Consensus::Params&) { return true; });
|
ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, 0, false, false, [](const Consensus::Params&) { return true; });
|
||||||
EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, 0, false, false, [](const Consensus::Params&) { return false; });
|
ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, 0, false, false, [](const Consensus::Params&) { return false; });
|
||||||
// for transactions that have been mined in a block, DoS ban score should
|
// for transactions that have been mined in a block, DoS ban score should
|
||||||
// always be 100.
|
// always be 100.
|
||||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, 0, false, true, [](const Consensus::Params&) { return true; });
|
ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, 0, false, true, [](const Consensus::Params&) { return true; });
|
||||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, 0, false, true, [](const Consensus::Params&) { return false; });
|
ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, 0, false, true, [](const Consensus::Params&) { return false; });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
|
TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
|
||||||
SelectParams(CBaseChainParams::REGTEST);
|
SelectParams(CBaseChainParams::REGTEST);
|
||||||
auto consensus = Params().GetConsensus();
|
auto consensus = Params().GetConsensus();
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>> saplingAuth = std::nullopt;
|
||||||
auto orchardAuth = orchard::AuthValidator::Disabled();
|
auto orchardAuth = orchard::AuthValidator::Disabled();
|
||||||
|
|
||||||
auto saplingBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId;
|
auto saplingBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId;
|
||||||
|
@ -585,7 +588,7 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
|
||||||
CCoinsViewCache view(&baseView);
|
CCoinsViewCache view(&baseView);
|
||||||
// Ensure that the transaction validates against Sapling.
|
// Ensure that the transaction validates against Sapling.
|
||||||
EXPECT_TRUE(ContextualCheckShieldedInputs(
|
EXPECT_TRUE(ContextualCheckShieldedInputs(
|
||||||
tx, txdata, state, view, orchardAuth, consensus, saplingBranchId, false, false,
|
tx, txdata, state, view, saplingAuth, orchardAuth, consensus, saplingBranchId, false, false,
|
||||||
[](const Consensus::Params&) { return false; }));
|
[](const Consensus::Params&) { return false; }));
|
||||||
|
|
||||||
// Attempt to validate the inputs against Blossom. We should be notified
|
// Attempt to validate the inputs against Blossom. We should be notified
|
||||||
|
@ -597,7 +600,7 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
|
||||||
HexInt(saplingBranchId)),
|
HexInt(saplingBranchId)),
|
||||||
false, "")).Times(1);
|
false, "")).Times(1);
|
||||||
EXPECT_FALSE(ContextualCheckShieldedInputs(
|
EXPECT_FALSE(ContextualCheckShieldedInputs(
|
||||||
tx, txdata, state, view, orchardAuth, consensus, blossomBranchId, false, false,
|
tx, txdata, state, view, saplingAuth, orchardAuth, consensus, blossomBranchId, false, false,
|
||||||
[](const Consensus::Params&) { return false; }));
|
[](const Consensus::Params&) { return false; }));
|
||||||
|
|
||||||
// Attempt to validate the inputs against Heartwood. All we should learn is
|
// Attempt to validate the inputs against Heartwood. All we should learn is
|
||||||
|
@ -607,13 +610,14 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
|
||||||
10, false, REJECT_INVALID,
|
10, false, REJECT_INVALID,
|
||||||
"bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
"bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
EXPECT_FALSE(ContextualCheckShieldedInputs(
|
EXPECT_FALSE(ContextualCheckShieldedInputs(
|
||||||
tx, txdata, state, view, orchardAuth, consensus, heartwoodBranchId, false, false,
|
tx, txdata, state, view, saplingAuth, orchardAuth, consensus, heartwoodBranchId, false, false,
|
||||||
[](const Consensus::Params&) { return false; }));
|
[](const Consensus::Params&) { return false; }));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ContextualCheckShieldedInputsTest, NonCanonicalEd25519Signature) {
|
TEST(ContextualCheckShieldedInputsTest, NonCanonicalEd25519Signature) {
|
||||||
SelectParams(CBaseChainParams::REGTEST);
|
SelectParams(CBaseChainParams::REGTEST);
|
||||||
auto consensus = Params().GetConsensus();
|
auto consensus = Params().GetConsensus();
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>> saplingAuth = std::nullopt;
|
||||||
auto orchardAuth = orchard::AuthValidator::Disabled();
|
auto orchardAuth = orchard::AuthValidator::Disabled();
|
||||||
|
|
||||||
AssumeShieldedInputsExistAndAreSpendable baseView;
|
AssumeShieldedInputsExistAndAreSpendable baseView;
|
||||||
|
@ -631,7 +635,7 @@ TEST(ContextualCheckShieldedInputsTest, NonCanonicalEd25519Signature) {
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
const PrecomputedTransactionData txdata(tx, allPrevOutputs);
|
const PrecomputedTransactionData txdata(tx, allPrevOutputs);
|
||||||
MockCValidationState state;
|
MockCValidationState state;
|
||||||
EXPECT_TRUE(ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, saplingBranchId, false, true));
|
EXPECT_TRUE(ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, saplingBranchId, false, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c
|
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c
|
||||||
|
@ -655,15 +659,15 @@ TEST(ContextualCheckShieldedInputsTest, NonCanonicalEd25519Signature) {
|
||||||
// during initial block download, for transactions being accepted into the
|
// during initial block download, for transactions being accepted into the
|
||||||
// mempool (and thus not mined), DoS ban score should be zero, else 10
|
// mempool (and thus not mined), DoS ban score should be zero, else 10
|
||||||
EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return true; });
|
ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return true; });
|
||||||
EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return false; });
|
ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return false; });
|
||||||
// for transactions that have been mined in a block, DoS ban score should
|
// for transactions that have been mined in a block, DoS ban score should
|
||||||
// always be 100.
|
// always be 100.
|
||||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, saplingBranchId, false, true, [](const Consensus::Params&) { return true; });
|
ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, saplingBranchId, false, true, [](const Consensus::Params&) { return true; });
|
||||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
|
||||||
ContextualCheckShieldedInputs(tx, txdata, state, view, orchardAuth, consensus, saplingBranchId, false, true, [](const Consensus::Params&) { return false; });
|
ContextualCheckShieldedInputs(tx, txdata, state, view, saplingAuth, orchardAuth, consensus, saplingBranchId, false, true, [](const Consensus::Params&) { return false; });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ChecktransactionTests, OverwinterConstructors) {
|
TEST(ChecktransactionTests, OverwinterConstructors) {
|
||||||
|
@ -1321,20 +1325,23 @@ TEST(ChecktransactionTests, HeartwoodEnforcesSaplingRulesOnShieldedCoinbase) {
|
||||||
// Coinbase transaction should pass contextual checks.
|
// Coinbase transaction should pass contextual checks.
|
||||||
EXPECT_TRUE(ContextualCheckTransaction(tx, state, chainparams, 10, 57));
|
EXPECT_TRUE(ContextualCheckTransaction(tx, state, chainparams, 10, 57));
|
||||||
|
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>> saplingAuth = sapling::init_batch_validator();
|
||||||
auto orchardAuth = orchard::AuthValidator::Disabled();
|
auto orchardAuth = orchard::AuthValidator::Disabled();
|
||||||
auto heartwoodBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_HEARTWOOD].nBranchId;
|
auto heartwoodBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_HEARTWOOD].nBranchId;
|
||||||
|
|
||||||
// Coinbase transaction does not pass shielded input checks, as bindingSig
|
// Coinbase transaction does not pass shielded input checks, as bindingSig
|
||||||
// consensus rule is enforced.
|
// consensus rule is enforced. ContextualCheckShieldedInputs passes because
|
||||||
|
// the rest of the input checks pass, but saplingAuth fails when it attempts
|
||||||
|
// to validate the batch of signatures that includes bindingSig.
|
||||||
// - Note that coinbase txs don't have a previous output corresponding to
|
// - Note that coinbase txs don't have a previous output corresponding to
|
||||||
// their transparent input; ZIP 244 handles this by making the coinbase
|
// their transparent input; ZIP 244 handles this by making the coinbase
|
||||||
// sighash the txid.
|
// sighash the txid.
|
||||||
PrecomputedTransactionData txdata(tx, {});
|
PrecomputedTransactionData txdata(tx, {});
|
||||||
AssumeShieldedInputsExistAndAreSpendable baseView;
|
AssumeShieldedInputsExistAndAreSpendable baseView;
|
||||||
CCoinsViewCache view(&baseView);
|
CCoinsViewCache view(&baseView);
|
||||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid", false, "")).Times(1);
|
EXPECT_TRUE(ContextualCheckShieldedInputs(
|
||||||
EXPECT_FALSE(ContextualCheckShieldedInputs(
|
tx, txdata, state, view, saplingAuth, orchardAuth, chainparams.GetConsensus(), heartwoodBranchId, false, true));
|
||||||
tx, txdata, state, view, orchardAuth, chainparams.GetConsensus(), heartwoodBranchId, false, true));
|
EXPECT_FALSE(saplingAuth.value()->validate());
|
||||||
|
|
||||||
RegtestDeactivateHeartwood();
|
RegtestDeactivateHeartwood();
|
||||||
}
|
}
|
||||||
|
|
57
src/main.cpp
57
src/main.cpp
|
@ -47,7 +47,6 @@
|
||||||
|
|
||||||
#include <rust/ed25519.h>
|
#include <rust/ed25519.h>
|
||||||
#include <rust/metrics.h>
|
#include <rust/metrics.h>
|
||||||
#include <rust/sapling.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -1246,6 +1245,7 @@ bool ContextualCheckShieldedInputs(
|
||||||
const PrecomputedTransactionData& txdata,
|
const PrecomputedTransactionData& txdata,
|
||||||
CValidationState &state,
|
CValidationState &state,
|
||||||
const CCoinsViewCache &view,
|
const CCoinsViewCache &view,
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>>& saplingAuth,
|
||||||
std::optional<orchard::AuthValidator>& orchardAuth,
|
std::optional<orchard::AuthValidator>& orchardAuth,
|
||||||
const Consensus::Params& consensus,
|
const Consensus::Params& consensus,
|
||||||
uint32_t consensusBranchId,
|
uint32_t consensusBranchId,
|
||||||
|
@ -1318,17 +1318,16 @@ bool ContextualCheckShieldedInputs(
|
||||||
if (!tx.vShieldedSpend.empty() ||
|
if (!tx.vShieldedSpend.empty() ||
|
||||||
!tx.vShieldedOutput.empty())
|
!tx.vShieldedOutput.empty())
|
||||||
{
|
{
|
||||||
auto ctx = sapling::init_verifier();
|
auto assembler = sapling::new_bundle_assembler();
|
||||||
|
|
||||||
for (const SpendDescription &spend : tx.vShieldedSpend) {
|
for (const SpendDescription &spend : tx.vShieldedSpend) {
|
||||||
if (!ctx->check_spend(
|
if (!assembler->add_spend(
|
||||||
spend.cv.GetRawBytes(),
|
spend.cv.GetRawBytes(),
|
||||||
spend.anchor.GetRawBytes(),
|
spend.anchor.GetRawBytes(),
|
||||||
spend.nullifier.GetRawBytes(),
|
spend.nullifier.GetRawBytes(),
|
||||||
spend.rk.GetRawBytes(),
|
spend.rk.GetRawBytes(),
|
||||||
spend.zkproof,
|
spend.zkproof,
|
||||||
spend.spendAuthSig,
|
spend.spendAuthSig
|
||||||
dataToBeSigned.GetRawBytes()
|
|
||||||
)) {
|
)) {
|
||||||
return state.DoS(
|
return state.DoS(
|
||||||
dosLevelPotentiallyRelaxing,
|
dosLevelPotentiallyRelaxing,
|
||||||
|
@ -1338,10 +1337,12 @@ bool ContextualCheckShieldedInputs(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const OutputDescription &output : tx.vShieldedOutput) {
|
for (const OutputDescription &output : tx.vShieldedOutput) {
|
||||||
if (!ctx->check_output(
|
if (!assembler->add_output(
|
||||||
output.cv.GetRawBytes(),
|
output.cv.GetRawBytes(),
|
||||||
output.cmu.GetRawBytes(),
|
output.cmu.GetRawBytes(),
|
||||||
output.ephemeralKey.GetRawBytes(),
|
output.ephemeralKey.GetRawBytes(),
|
||||||
|
output.encCiphertext,
|
||||||
|
output.outCiphertext,
|
||||||
output.zkproof
|
output.zkproof
|
||||||
)) {
|
)) {
|
||||||
// This should be a non-contextual check, but we check it here
|
// This should be a non-contextual check, but we check it here
|
||||||
|
@ -1352,15 +1353,19 @@ bool ContextualCheckShieldedInputs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx->final_check(
|
auto bundle = sapling::finish_bundle_assembly(
|
||||||
|
std::move(assembler),
|
||||||
tx.GetValueBalanceSapling(),
|
tx.GetValueBalanceSapling(),
|
||||||
tx.bindingSig,
|
tx.bindingSig);
|
||||||
dataToBeSigned.GetRawBytes()
|
|
||||||
)) {
|
// Queue Sapling bundle to be batch-validated. This also checks some consensus rules.
|
||||||
return state.DoS(
|
if (saplingAuth.has_value()) {
|
||||||
dosLevelPotentiallyRelaxing,
|
if (!saplingAuth.value()->check_bundle(std::move(bundle), dataToBeSigned.GetRawBytes())) {
|
||||||
error("ContextualCheckShieldedInputs(): Sapling binding signature invalid"),
|
return state.DoS(
|
||||||
REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid");
|
dosLevelPotentiallyRelaxing,
|
||||||
|
error("ContextualCheckShieldedInputs(): Sapling bundle invalid"),
|
||||||
|
REJECT_INVALID, "bad-txns-sapling-bundle-invalid");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1986,6 +1991,11 @@ bool AcceptToMemoryPool(
|
||||||
__func__, hash.ToString(), FormatStateMessage(state));
|
__func__, hash.ToString(), FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This will be a single-transaction batch, which will be more efficient
|
||||||
|
// than unbatched if the transaction contains at least one Sapling Spend
|
||||||
|
// or at least two Sapling Outputs.
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>> saplingAuth = sapling::init_batch_validator();
|
||||||
|
|
||||||
// This will be a single-transaction batch, which is still more efficient as every
|
// This will be a single-transaction batch, which is still more efficient as every
|
||||||
// Orchard bundle contains at least two signatures.
|
// Orchard bundle contains at least two signatures.
|
||||||
std::optional<orchard::AuthValidator> orchardAuth = orchard::AuthValidator::Batch();
|
std::optional<orchard::AuthValidator> orchardAuth = orchard::AuthValidator::Batch();
|
||||||
|
@ -1996,6 +2006,7 @@ bool AcceptToMemoryPool(
|
||||||
txdata,
|
txdata,
|
||||||
state,
|
state,
|
||||||
view,
|
view,
|
||||||
|
saplingAuth,
|
||||||
orchardAuth,
|
orchardAuth,
|
||||||
chainparams.GetConsensus(),
|
chainparams.GetConsensus(),
|
||||||
consensusBranchId,
|
consensusBranchId,
|
||||||
|
@ -2005,7 +2016,11 @@ bool AcceptToMemoryPool(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Orchard bundle authorizations. `orchardAuth` here is known to be non-null
|
// Check Sapling and Orchard bundle authorizations.
|
||||||
|
// `saplingAuth` and `orchardAuth` are known here to be non-null.
|
||||||
|
if (!saplingAuth.value()->validate()) {
|
||||||
|
return state.DoS(100, false, REJECT_INVALID, "bad-sapling-bundle-authorization");
|
||||||
|
}
|
||||||
if (!orchardAuth.value().Validate()) {
|
if (!orchardAuth.value().Validate()) {
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-orchard-bundle-authorization");
|
return state.DoS(100, false, REJECT_INVALID, "bad-orchard-bundle-authorization");
|
||||||
}
|
}
|
||||||
|
@ -3059,7 +3074,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
// proof verification is expensive, disable if possible
|
// proof verification is expensive, disable if possible
|
||||||
auto verifier = fExpensiveChecks ? ProofVerifier::Strict() : ProofVerifier::Disabled();
|
auto verifier = fExpensiveChecks ? ProofVerifier::Strict() : ProofVerifier::Disabled();
|
||||||
|
|
||||||
// Disable Orchard batch signature validation if possible.
|
// Disable Sapling and Orchard batch validation if possible.
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>> saplingAuth = fExpensiveChecks ?
|
||||||
|
std::optional(sapling::init_batch_validator()) : std::nullopt;
|
||||||
std::optional<orchard::AuthValidator> orchardAuth = fExpensiveChecks ?
|
std::optional<orchard::AuthValidator> orchardAuth = fExpensiveChecks ?
|
||||||
orchard::AuthValidator::Batch() : orchard::AuthValidator::Disabled();
|
orchard::AuthValidator::Batch() : orchard::AuthValidator::Disabled();
|
||||||
|
|
||||||
|
@ -3302,6 +3319,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
txdata.back(),
|
txdata.back(),
|
||||||
state,
|
state,
|
||||||
view,
|
view,
|
||||||
|
saplingAuth,
|
||||||
orchardAuth,
|
orchardAuth,
|
||||||
chainparams.GetConsensus(),
|
chainparams.GetConsensus(),
|
||||||
consensusBranchId,
|
consensusBranchId,
|
||||||
|
@ -3502,6 +3520,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
block.vtx[0].GetValueOut(), blockReward),
|
block.vtx[0].GetValueOut(), blockReward),
|
||||||
REJECT_INVALID, "bad-cb-amount");
|
REJECT_INVALID, "bad-cb-amount");
|
||||||
|
|
||||||
|
// Ensure Sapling authorizations are valid (if we are checking them)
|
||||||
|
if (saplingAuth.has_value() && !saplingAuth.value()->validate()) {
|
||||||
|
return state.DoS(100,
|
||||||
|
error("ConnectBlock(): a Sapling bundle within the block is invalid"),
|
||||||
|
REJECT_INVALID, "bad-sapling-bundle-authorization");
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure Orchard signatures are valid (if we are checking them)
|
// Ensure Orchard signatures are valid (if we are checking them)
|
||||||
if (orchardAuth.has_value() && !orchardAuth.value().Validate()) {
|
if (orchardAuth.has_value() && !orchardAuth.value().Validate()) {
|
||||||
return state.DoS(100,
|
return state.DoS(100,
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <rust/sapling.h>
|
||||||
#include <rust/orchard.h>
|
#include <rust/orchard.h>
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
|
@ -402,6 +403,7 @@ bool ContextualCheckShieldedInputs(
|
||||||
const PrecomputedTransactionData& txdata,
|
const PrecomputedTransactionData& txdata,
|
||||||
CValidationState &state,
|
CValidationState &state,
|
||||||
const CCoinsViewCache &view,
|
const CCoinsViewCache &view,
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>>& saplingAuth,
|
||||||
std::optional<orchard::AuthValidator>& orchardAuth,
|
std::optional<orchard::AuthValidator>& orchardAuth,
|
||||||
const Consensus::Params& consensus,
|
const Consensus::Params& consensus,
|
||||||
uint32_t consensusBranchId,
|
uint32_t consensusBranchId,
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
// See https://github.com/rust-lang/rfcs/pull/2585 for more background.
|
// See https://github.com/rust-lang/rfcs/pull/2585 for more background.
|
||||||
#![allow(clippy::not_unsafe_ptr_arg_deref)]
|
#![allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
|
||||||
use bellman::groth16::{Parameters, PreparedVerifyingKey};
|
use bellman::groth16::{self, prepare_verifying_key, Parameters, PreparedVerifyingKey};
|
||||||
use blake2s_simd::Params as Blake2sParams;
|
use blake2s_simd::Params as Blake2sParams;
|
||||||
use bls12_381::Bls12;
|
use bls12_381::Bls12;
|
||||||
use group::{cofactor::CofactorGroup, GroupEncoding};
|
use group::{cofactor::CofactorGroup, GroupEncoding};
|
||||||
|
@ -88,8 +88,8 @@ mod test_harness_ffi;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
static PROOF_PARAMETERS_LOADED: Once = Once::new();
|
static PROOF_PARAMETERS_LOADED: Once = Once::new();
|
||||||
static mut SAPLING_SPEND_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
static mut SAPLING_SPEND_VK: Option<groth16::VerifyingKey<Bls12>> = None;
|
||||||
static mut SAPLING_OUTPUT_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
static mut SAPLING_OUTPUT_VK: Option<groth16::VerifyingKey<Bls12>> = None;
|
||||||
static mut SPROUT_GROTH16_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
static mut SPROUT_GROTH16_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
||||||
|
|
||||||
static mut SAPLING_SPEND_PARAMS: Option<Parameters<Bls12>> = None;
|
static mut SAPLING_SPEND_PARAMS: Option<Parameters<Bls12>> = None;
|
||||||
|
@ -179,6 +179,11 @@ pub extern "C" fn librustzcash_init_zksnark_params(
|
||||||
let sapling_spend_params = params.spend_params;
|
let sapling_spend_params = params.spend_params;
|
||||||
let sapling_output_params = params.output_params;
|
let sapling_output_params = params.output_params;
|
||||||
|
|
||||||
|
// We need to clone these because we aren't necessarily storing the proving
|
||||||
|
// parameters in memory.
|
||||||
|
let sapling_spend_vk = sapling_spend_params.vk.clone();
|
||||||
|
let sapling_output_vk = sapling_output_params.vk.clone();
|
||||||
|
|
||||||
// Generate Orchard parameters.
|
// Generate Orchard parameters.
|
||||||
info!(target: "main", "Loading Orchard parameters");
|
info!(target: "main", "Loading Orchard parameters");
|
||||||
let orchard_pk = load_proving_keys.then(orchard::circuit::ProvingKey::build);
|
let orchard_pk = load_proving_keys.then(orchard::circuit::ProvingKey::build);
|
||||||
|
@ -191,8 +196,8 @@ pub extern "C" fn librustzcash_init_zksnark_params(
|
||||||
SAPLING_OUTPUT_PARAMS = load_proving_keys.then(|| sapling_output_params);
|
SAPLING_OUTPUT_PARAMS = load_proving_keys.then(|| sapling_output_params);
|
||||||
SPROUT_GROTH16_PARAMS_PATH = sprout_path.map(|p| p.to_owned());
|
SPROUT_GROTH16_PARAMS_PATH = sprout_path.map(|p| p.to_owned());
|
||||||
|
|
||||||
SAPLING_SPEND_VK = Some(params.spend_vk);
|
SAPLING_SPEND_VK = Some(sapling_spend_vk);
|
||||||
SAPLING_OUTPUT_VK = Some(params.output_vk);
|
SAPLING_OUTPUT_VK = Some(sapling_output_vk);
|
||||||
SPROUT_GROTH16_VK = params.sprout_vk;
|
SPROUT_GROTH16_VK = params.sprout_vk;
|
||||||
|
|
||||||
ORCHARD_PK = orchard_pk;
|
ORCHARD_PK = orchard_pk;
|
||||||
|
@ -845,7 +850,7 @@ pub extern "C" fn librustzcash_sapling_spend_proof(
|
||||||
anchor,
|
anchor,
|
||||||
merkle_path,
|
merkle_path,
|
||||||
unsafe { SAPLING_SPEND_PARAMS.as_ref() }.unwrap(),
|
unsafe { SAPLING_SPEND_PARAMS.as_ref() }.unwrap(),
|
||||||
unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(),
|
&prepare_verifying_key(unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap()),
|
||||||
)
|
)
|
||||||
.expect("proving should not fail");
|
.expect("proving should not fail");
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,19 @@
|
||||||
// on the entire module.
|
// on the entire module.
|
||||||
#![allow(clippy::too_many_arguments)]
|
#![allow(clippy::too_many_arguments)]
|
||||||
|
|
||||||
use bellman::groth16::Proof;
|
use bellman::groth16::{prepare_verifying_key, Proof};
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
|
|
||||||
|
use rand_core::OsRng;
|
||||||
|
use zcash_note_encryption::EphemeralKeyBytes;
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
sapling::redjubjub::{self, Signature},
|
sapling::{
|
||||||
transaction::components::Amount,
|
redjubjub::{self, Signature},
|
||||||
|
Nullifier,
|
||||||
|
},
|
||||||
|
transaction::components::{sapling, Amount},
|
||||||
};
|
};
|
||||||
use zcash_proofs::sapling::SaplingVerificationContext;
|
use zcash_proofs::sapling::{self as sapling_proofs, SaplingVerificationContext};
|
||||||
|
|
||||||
use super::GROTH_PROOF_SIZE;
|
use super::GROTH_PROOF_SIZE;
|
||||||
use super::{de_ct, SAPLING_OUTPUT_VK, SAPLING_SPEND_VK};
|
use super::{de_ct, SAPLING_OUTPUT_VK, SAPLING_SPEND_VK};
|
||||||
|
@ -22,11 +27,38 @@ use super::{de_ct, SAPLING_OUTPUT_VK, SAPLING_SPEND_VK};
|
||||||
#[cxx::bridge(namespace = "sapling")]
|
#[cxx::bridge(namespace = "sapling")]
|
||||||
mod ffi {
|
mod ffi {
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
|
type Bundle;
|
||||||
|
type BundleAssembler;
|
||||||
|
fn new_bundle_assembler() -> Box<BundleAssembler>;
|
||||||
|
fn add_spend(
|
||||||
|
self: &mut BundleAssembler,
|
||||||
|
cv: &[u8; 32],
|
||||||
|
anchor: &[u8; 32],
|
||||||
|
nullifier: [u8; 32],
|
||||||
|
rk: &[u8; 32],
|
||||||
|
zkproof: [u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
spend_auth_sig: &[u8; 64],
|
||||||
|
) -> bool;
|
||||||
|
fn add_output(
|
||||||
|
self: &mut BundleAssembler,
|
||||||
|
cv: &[u8; 32],
|
||||||
|
cmu: &[u8; 32],
|
||||||
|
ephemeral_key: [u8; 32],
|
||||||
|
enc_ciphertext: [u8; 580],
|
||||||
|
out_ciphertext: [u8; 80],
|
||||||
|
zkproof: [u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
) -> bool;
|
||||||
|
fn finish_bundle_assembly(
|
||||||
|
assembler: Box<BundleAssembler>,
|
||||||
|
value_balance: i64,
|
||||||
|
binding_sig: [u8; 64],
|
||||||
|
) -> Box<Bundle>;
|
||||||
|
|
||||||
type Verifier;
|
type Verifier;
|
||||||
|
|
||||||
fn init_verifier() -> Box<Verifier>;
|
fn init_verifier() -> Box<Verifier>;
|
||||||
fn check_spend(
|
fn check_spend(
|
||||||
&mut self,
|
self: &mut Verifier,
|
||||||
cv: &[u8; 32],
|
cv: &[u8; 32],
|
||||||
anchor: &[u8; 32],
|
anchor: &[u8; 32],
|
||||||
nullifier: &[u8; 32],
|
nullifier: &[u8; 32],
|
||||||
|
@ -36,21 +68,139 @@ mod ffi {
|
||||||
sighash_value: &[u8; 32],
|
sighash_value: &[u8; 32],
|
||||||
) -> bool;
|
) -> bool;
|
||||||
fn check_output(
|
fn check_output(
|
||||||
&mut self,
|
self: &mut Verifier,
|
||||||
cv: &[u8; 32],
|
cv: &[u8; 32],
|
||||||
cm: &[u8; 32],
|
cm: &[u8; 32],
|
||||||
ephemeral_key: &[u8; 32],
|
ephemeral_key: &[u8; 32],
|
||||||
zkproof: &[u8; 192], // GROTH_PROOF_SIZE
|
zkproof: &[u8; 192], // GROTH_PROOF_SIZE
|
||||||
) -> bool;
|
) -> bool;
|
||||||
fn final_check(
|
fn final_check(
|
||||||
&self,
|
self: &Verifier,
|
||||||
value_balance: i64,
|
value_balance: i64,
|
||||||
binding_sig: &[u8; 64],
|
binding_sig: &[u8; 64],
|
||||||
sighash_value: &[u8; 32],
|
sighash_value: &[u8; 32],
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
|
type BatchValidator;
|
||||||
|
fn init_batch_validator() -> Box<BatchValidator>;
|
||||||
|
fn check_bundle(self: &mut BatchValidator, bundle: Box<Bundle>, sighash: [u8; 32]) -> bool;
|
||||||
|
fn validate(self: &mut BatchValidator) -> bool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Bundle(sapling::Bundle<sapling::Authorized>);
|
||||||
|
|
||||||
|
struct BundleAssembler {
|
||||||
|
shielded_spends: Vec<sapling::SpendDescription<sapling::Authorized>>,
|
||||||
|
shielded_outputs: Vec<sapling::OutputDescription<[u8; 192]>>, // GROTH_PROOF_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_bundle_assembler() -> Box<BundleAssembler> {
|
||||||
|
Box::new(BundleAssembler {
|
||||||
|
shielded_spends: vec![],
|
||||||
|
shielded_outputs: vec![],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BundleAssembler {
|
||||||
|
fn add_spend(
|
||||||
|
self: &mut BundleAssembler,
|
||||||
|
cv: &[u8; 32],
|
||||||
|
anchor: &[u8; 32],
|
||||||
|
nullifier: [u8; 32],
|
||||||
|
rk: &[u8; 32],
|
||||||
|
zkproof: [u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
spend_auth_sig: &[u8; 64],
|
||||||
|
) -> bool {
|
||||||
|
// Deserialize the value commitment
|
||||||
|
let cv = match de_ct(jubjub::ExtendedPoint::from_bytes(cv)) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Deserialize the anchor, which should be an element
|
||||||
|
// of Fr.
|
||||||
|
let anchor = match de_ct(bls12_381::Scalar::from_bytes(anchor)) {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Deserialize rk
|
||||||
|
let rk = match redjubjub::PublicKey::read(&rk[..]) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(_) => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Deserialize the signature
|
||||||
|
let spend_auth_sig = match Signature::read(&spend_auth_sig[..]) {
|
||||||
|
Ok(sig) => sig,
|
||||||
|
Err(_) => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.shielded_spends.push(sapling::SpendDescription {
|
||||||
|
cv,
|
||||||
|
anchor,
|
||||||
|
nullifier: Nullifier(nullifier),
|
||||||
|
rk,
|
||||||
|
zkproof,
|
||||||
|
spend_auth_sig,
|
||||||
|
});
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_output(
|
||||||
|
self: &mut BundleAssembler,
|
||||||
|
cv: &[u8; 32],
|
||||||
|
cm: &[u8; 32],
|
||||||
|
ephemeral_key: [u8; 32],
|
||||||
|
enc_ciphertext: [u8; 580],
|
||||||
|
out_ciphertext: [u8; 80],
|
||||||
|
zkproof: [u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
) -> bool {
|
||||||
|
// Deserialize the value commitment
|
||||||
|
let cv = match de_ct(jubjub::ExtendedPoint::from_bytes(cv)) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Deserialize the commitment, which should be an element
|
||||||
|
// of Fr.
|
||||||
|
let cmu = match de_ct(bls12_381::Scalar::from_bytes(cm)) {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.shielded_outputs.push(sapling::OutputDescription {
|
||||||
|
cv,
|
||||||
|
cmu,
|
||||||
|
ephemeral_key: EphemeralKeyBytes(ephemeral_key),
|
||||||
|
enc_ciphertext,
|
||||||
|
out_ciphertext,
|
||||||
|
zkproof,
|
||||||
|
});
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::boxed_local)]
|
||||||
|
fn finish_bundle_assembly(
|
||||||
|
assembler: Box<BundleAssembler>,
|
||||||
|
value_balance: i64,
|
||||||
|
binding_sig: [u8; 64],
|
||||||
|
) -> Box<Bundle> {
|
||||||
|
let value_balance = Amount::from_i64(value_balance).expect("parsed elsewhere");
|
||||||
|
let binding_sig = redjubjub::Signature::read(&binding_sig[..]).expect("parsed elsewhere");
|
||||||
|
|
||||||
|
Box::new(Bundle(sapling::Bundle {
|
||||||
|
shielded_spends: assembler.shielded_spends,
|
||||||
|
shielded_outputs: assembler.shielded_outputs,
|
||||||
|
value_balance,
|
||||||
|
authorization: sapling::Authorized { binding_sig },
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
struct Verifier(SaplingVerificationContext);
|
struct Verifier(SaplingVerificationContext);
|
||||||
|
|
||||||
fn init_verifier() -> Box<Verifier> {
|
fn init_verifier() -> Box<Verifier> {
|
||||||
|
@ -110,7 +260,7 @@ impl Verifier {
|
||||||
sighash_value,
|
sighash_value,
|
||||||
spend_auth_sig,
|
spend_auth_sig,
|
||||||
zkproof,
|
zkproof,
|
||||||
unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(),
|
&prepare_verifying_key(unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn check_output(
|
fn check_output(
|
||||||
|
@ -134,7 +284,7 @@ impl Verifier {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Deserialize the ephemeral key
|
// Deserialize the ephemeral key
|
||||||
let ephemeral_key = match de_ct(jubjub::ExtendedPoint::from_bytes(ephemeral_key)) {
|
let epk = match de_ct(jubjub::ExtendedPoint::from_bytes(ephemeral_key)) {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
@ -148,9 +298,9 @@ impl Verifier {
|
||||||
self.0.check_output(
|
self.0.check_output(
|
||||||
cv,
|
cv,
|
||||||
cm,
|
cm,
|
||||||
ephemeral_key,
|
epk,
|
||||||
zkproof,
|
zkproof,
|
||||||
unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap(),
|
&prepare_verifying_key(unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn final_check(
|
fn final_check(
|
||||||
|
@ -174,3 +324,43 @@ impl Verifier {
|
||||||
.final_check(value_balance, sighash_value, binding_sig)
|
.final_check(value_balance, sighash_value, binding_sig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BatchValidator(Option<sapling_proofs::BatchValidator>);
|
||||||
|
|
||||||
|
fn init_batch_validator() -> Box<BatchValidator> {
|
||||||
|
Box::new(BatchValidator(Some(sapling_proofs::BatchValidator::new())))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BatchValidator {
|
||||||
|
/// Checks the bundle against Sapling-specific consensus rules, and queues its
|
||||||
|
/// authorization for validation.
|
||||||
|
///
|
||||||
|
/// Returns `false` if the bundle doesn't satisfy the checked consensus rules. This
|
||||||
|
/// `BatchValidator` can continue to be used regardless, but some or all of the proofs
|
||||||
|
/// and signatures from this bundle may have already been added to the batch even if
|
||||||
|
/// it fails other consensus rules.
|
||||||
|
///
|
||||||
|
/// `sighash` must be for the transaction this bundle is within.
|
||||||
|
#[allow(clippy::boxed_local)]
|
||||||
|
fn check_bundle(&mut self, bundle: Box<Bundle>, sighash: [u8; 32]) -> bool {
|
||||||
|
if let Some(validator) = &mut self.0 {
|
||||||
|
validator.check_bundle(bundle.0, sighash)
|
||||||
|
} else {
|
||||||
|
tracing::error!("sapling::BatchValidator has already been used");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&mut self) -> bool {
|
||||||
|
if let Some(validator) = self.0.take() {
|
||||||
|
validator.validate(
|
||||||
|
unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(),
|
||||||
|
unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap(),
|
||||||
|
OsRng,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
tracing::error!("sapling::BatchValidator has already been used");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <boost/test/data/test_case.hpp>
|
#include <boost/test/data/test_case.hpp>
|
||||||
|
|
||||||
#include <rust/ed25519.h>
|
#include <rust/ed25519.h>
|
||||||
|
#include <rust/sapling.h>
|
||||||
#include <rust/orchard.h>
|
#include <rust/orchard.h>
|
||||||
|
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
@ -356,6 +357,7 @@ void test_simple_sapling_invalidity(uint32_t consensusBranchId, CMutableTransact
|
||||||
void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransaction tx)
|
void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransaction tx)
|
||||||
{
|
{
|
||||||
auto verifier = ProofVerifier::Strict();
|
auto verifier = ProofVerifier::Strict();
|
||||||
|
std::optional<rust::Box<sapling::BatchValidator>> saplingAuth = std::nullopt;
|
||||||
auto orchardAuth = orchard::AuthValidator::Disabled();
|
auto orchardAuth = orchard::AuthValidator::Disabled();
|
||||||
{
|
{
|
||||||
// Ensure that empty vin/vout remain invalid without
|
// Ensure that empty vin/vout remain invalid without
|
||||||
|
@ -390,7 +392,13 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa
|
||||||
|
|
||||||
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
||||||
BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, true));
|
BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, true));
|
||||||
BOOST_CHECK(!ContextualCheckShieldedInputs(newTx, txdata, state, view, orchardAuth, Params().GetConsensus(), consensusBranchId, false, true));
|
BOOST_CHECK(!ContextualCheckShieldedInputs(
|
||||||
|
newTx, txdata,
|
||||||
|
state, view,
|
||||||
|
saplingAuth, orchardAuth,
|
||||||
|
Params().GetConsensus(),
|
||||||
|
consensusBranchId,
|
||||||
|
false, true));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
|
BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
|
||||||
|
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
|
@ -406,7 +414,13 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa
|
||||||
state = CValidationState();
|
state = CValidationState();
|
||||||
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
||||||
BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, true));
|
BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, true));
|
||||||
BOOST_CHECK(ContextualCheckShieldedInputs(newTx, txdata, state, view, orchardAuth, Params().GetConsensus(), consensusBranchId, false, true));
|
BOOST_CHECK(ContextualCheckShieldedInputs(
|
||||||
|
newTx, txdata,
|
||||||
|
state, view,
|
||||||
|
saplingAuth, orchardAuth,
|
||||||
|
Params().GetConsensus(),
|
||||||
|
consensusBranchId,
|
||||||
|
false, true));
|
||||||
BOOST_CHECK_EQUAL(state.GetRejectReason(), "");
|
BOOST_CHECK_EQUAL(state.GetRejectReason(), "");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
@ -92,7 +92,7 @@ public:
|
||||||
std::array<uint8_t, WIDTH> GetRawBytes() const
|
std::array<uint8_t, WIDTH> GetRawBytes() const
|
||||||
{
|
{
|
||||||
std::array<uint8_t, WIDTH> buf = {};
|
std::array<uint8_t, WIDTH> buf = {};
|
||||||
memcpy(buf.data(), this->begin(), WIDTH);
|
std::memcpy(buf.data(), this->begin(), WIDTH);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2890,6 +2890,11 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp)
|
||||||
throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
|
throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
|
||||||
}
|
}
|
||||||
sample_times.push_back(benchmark_connectblock_slow());
|
sample_times.push_back(benchmark_connectblock_slow());
|
||||||
|
} else if (benchmarktype == "connectblocksapling") {
|
||||||
|
if (Params().NetworkIDString() != "regtest") {
|
||||||
|
throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
|
||||||
|
}
|
||||||
|
sample_times.push_back(benchmark_connectblock_sapling());
|
||||||
} else if (benchmarktype == "connectblockorchard") {
|
} else if (benchmarktype == "connectblockorchard") {
|
||||||
if (Params().NetworkIDString() != "regtest") {
|
if (Params().NetworkIDString() != "regtest") {
|
||||||
throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
|
throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
|
||||||
|
|
|
@ -604,6 +604,57 @@ double benchmark_connectblock_slow()
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double benchmark_connectblock_sapling()
|
||||||
|
{
|
||||||
|
// Test for slowness encountered on 2022-07-01
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
CBlock block;
|
||||||
|
FILE* fp = fsbridge::fopen(GetDataDir() / "benchmark/block-1723244.dat", "rb");
|
||||||
|
if (!fp) throw new std::runtime_error("Failed to open block data file");
|
||||||
|
CAutoFile blkFile(fp, SER_DISK, CLIENT_VERSION);
|
||||||
|
blkFile >> block;
|
||||||
|
blkFile.fclose();
|
||||||
|
|
||||||
|
// Fake its inputs
|
||||||
|
auto hashPrev = uint256S("0000000001286c016284523a1b343e731539bdf1fac4159f96d70a711cf9c960");
|
||||||
|
FakeCoinsViewDB fakeDB("benchmark/block-1723244-inputs", hashPrev);
|
||||||
|
fakeDB.SetSaplingTrees({
|
||||||
|
"012380d4632f51d9aff726d9f2d0013691c86da31279e110e852d49e4737ce7c14001401c4dedf5f6a0e5be05be051fec4608153084b0fdb74cd92f01d8deb77e72b6a5f01d5891ebfeae46b30846a301f8aaba34d64428e91fc406d0db13fcf723100753100018b4af5e391e5720a2b7a20c289a7691bb6a29ffcda574e06eaf4d6597048fd2200017cc935f49a763d29f9e876fe0a85c6dbbd32ab5b632bc2da058c44c652f713190191cac78cfcb2ca0eaaad52778c93cc2549c6ae0460c37f0b304843ccf8c15e3301c4a86822bec7ea056f984aa72a059a566addd797c08be929289123f698a4631d01e7cbe9d650e4c7dfbc78b328744515345f3e0988ea8d0dd5ce2af025d56d710001278234295da81c7fbfbb336719718f78c16025032ef9cc6007bc49351213d701014656c38189b9f768a492ee90758c63d4be59c92e21b3e9d00916acf1e528774601add4db5d8e6357c91d3b1fc605c0961353b5aa683520923f47daa51b2864563c00000001a02e924803cc430e6360a63732092f621a116b1f156ccdc3e0f815c30a01b2510001bcefb8862360baae2a9a164c1367df2c27372d0c6963068c9ea4b1f84f5c526d00015ec9e9b1295908beed437df4126032ca57ada8e3ebb67067cd22a73c79a84009",
|
||||||
|
"0159a96b6b5a6dc61154f9b0cb66121ac04050978fdee3d1cf6deadac0b3118d4801318d4e70e26b35a2af00ee10cd4370553cfd6c058d762a9b37e7d43fba96a41f14013addafd08d0b8fcc60723f7ac79b589e6fd1e0209ec1865ef521ddc9537d010000018636e49531fdf3d5d7f817ed1488babf61ef0e750255e59f93cc111f521d800a0001a19338964f3cf13d3a74868b8a53c15dfd6b28f6aef345238372f0051dc3bc1d011f386f8123ec951aed8d51e25c549e3e007429c3d3882dc5daebf8d70e878e4d0001c4a86822bec7ea056f984aa72a059a566addd797c08be929289123f698a4631d01e7cbe9d650e4c7dfbc78b328744515345f3e0988ea8d0dd5ce2af025d56d710001278234295da81c7fbfbb336719718f78c16025032ef9cc6007bc49351213d701014656c38189b9f768a492ee90758c63d4be59c92e21b3e9d00916acf1e528774601add4db5d8e6357c91d3b1fc605c0961353b5aa683520923f47daa51b2864563c00000001a02e924803cc430e6360a63732092f621a116b1f156ccdc3e0f815c30a01b2510001bcefb8862360baae2a9a164c1367df2c27372d0c6963068c9ea4b1f84f5c526d00015ec9e9b1295908beed437df4126032ca57ada8e3ebb67067cd22a73c79a84009",
|
||||||
|
"0175638110ef078c9c5e45f34399131e652d7e7e4e3ea28fa13702854c3e889d38001401b445b70b61de6c561ae9203c5ddcd594c3da14550493154a4fb6e770bff2d65901981edfb711be11868d221643fdbc0403f607b8ec06f6c2b7968c8ddb2e0968080001b97e4e33d8c0c08cabf8ee7a897d09d1b2e6a395bc43214b61d7ae7cea560e650001060784c088dee8e54ec94a47e7de9308cab6069e77d7303e1ac9f8fbc920a45a000001e7cbe9d650e4c7dfbc78b328744515345f3e0988ea8d0dd5ce2af025d56d710001278234295da81c7fbfbb336719718f78c16025032ef9cc6007bc49351213d701014656c38189b9f768a492ee90758c63d4be59c92e21b3e9d00916acf1e528774601add4db5d8e6357c91d3b1fc605c0961353b5aa683520923f47daa51b2864563c00000001a02e924803cc430e6360a63732092f621a116b1f156ccdc3e0f815c30a01b2510001bcefb8862360baae2a9a164c1367df2c27372d0c6963068c9ea4b1f84f5c526d00015ec9e9b1295908beed437df4126032ca57ada8e3ebb67067cd22a73c79a84009",
|
||||||
|
"01ca5608a4c5e15340674e0a91ad1c128a49c04230141a955a9d87f2c84734ee2401ed8561fa9f71a0283dcc4865dc44dc886ceb8a91c36abbbb139795bc86cbba321401e2488b560f9f641e4371cadb8569776df9170f82888869c7902f80909aae5f1e01ad01014509c3242d3fbf6754e485f8c87eca413ceace72a742e033947e3f014c0001e6de90c780bf39b4a40dedee586a89686133013b138529eea245add88685e15c00013c16c0b1a41f32caebe41ec1322521b8eaf0303c3969044fa6daaa8a20948d2100000000000001591e0969b34ce995643b3f043be0b07f45b641dd90fce7f4713b90b4a545fa16000001a02e924803cc430e6360a63732092f621a116b1f156ccdc3e0f815c30a01b2510001bcefb8862360baae2a9a164c1367df2c27372d0c6963068c9ea4b1f84f5c526d00015ec9e9b1295908beed437df4126032ca57ada8e3ebb67067cd22a73c79a84009",
|
||||||
|
"01cb51537fbdc52f8c92ab7d14156dc3d81d9d433fa438d479f4b822924f4fb64500140139c4c235ce18df178bff8169c4d2ecd5c1eb1d112a0dbde3bc22349a2a7a1e590000014c998c0f24b3cc9640acccca4af19cba8c1dd728570fc7080ed7487e7a232c4100011f386f8123ec951aed8d51e25c549e3e007429c3d3882dc5daebf8d70e878e4d0001c4a86822bec7ea056f984aa72a059a566addd797c08be929289123f698a4631d01e7cbe9d650e4c7dfbc78b328744515345f3e0988ea8d0dd5ce2af025d56d710001278234295da81c7fbfbb336719718f78c16025032ef9cc6007bc49351213d701014656c38189b9f768a492ee90758c63d4be59c92e21b3e9d00916acf1e528774601add4db5d8e6357c91d3b1fc605c0961353b5aa683520923f47daa51b2864563c00000001a02e924803cc430e6360a63732092f621a116b1f156ccdc3e0f815c30a01b2510001bcefb8862360baae2a9a164c1367df2c27372d0c6963068c9ea4b1f84f5c526d00015ec9e9b1295908beed437df4126032ca57ada8e3ebb67067cd22a73c79a84009",
|
||||||
|
"01dffd4c5286c411a7efc955f740f311f979d6ceb39f37f12e2530e45610452b4200140001180211de427aaf56cc398c972a158fa0ac1a4fc79c76746972907fb2e7b668360001be1c46b85e67695418b39e799aa8bcc19a8634463e3fa293c3e75c471fb8475301072f3b28b20e0306b48c1b1fa25b2d845b6125069299df3028d58cfd360b4953010ed297014c2acf3d0840b3dad9038071e150935054c3dcc0f8981dfeb822821501b5cf5b5ac994c75a11e2e47a0d8077d39d01e79a9ac24a1b83b108128a86f35d0001e7cbe9d650e4c7dfbc78b328744515345f3e0988ea8d0dd5ce2af025d56d710001278234295da81c7fbfbb336719718f78c16025032ef9cc6007bc49351213d701014656c38189b9f768a492ee90758c63d4be59c92e21b3e9d00916acf1e528774601add4db5d8e6357c91d3b1fc605c0961353b5aa683520923f47daa51b2864563c00000001a02e924803cc430e6360a63732092f621a116b1f156ccdc3e0f815c30a01b2510001bcefb8862360baae2a9a164c1367df2c27372d0c6963068c9ea4b1f84f5c526d00015ec9e9b1295908beed437df4126032ca57ada8e3ebb67067cd22a73c79a84009"
|
||||||
|
});
|
||||||
|
fakeDB.SetOrchardTrees({
|
||||||
|
"01a8fb1700000000002b768d317551b491c8b993cd7e74c9196f3028b2a1a7a3f22971f7f4007c833e000e7005f57c540bf3e32695854f52d27a0456ca1be179bd073d9ca87acc92248413aeacb64a31a230338cfa6a2907f12bc5321a709ef298fb93ced3082c444f8a3814764dc108e86dc2c6d7c20a6e1759027d87029b5dc7e1e6b5be970ecbed913a186d95ac66b184f8844e57fece62a4d64cfeb73e7ed6e99146e79aacae7f5e002f9cd86767aea1f11147f65c588f94dce188315c40b22c0fa8751365ba453c28130cfb41380fdd7836985e2c4c488fdc3d1d1bd4390f350f0e1b8a448f47ac1c2bcbdd308beca04006b18928c4418aad2b3650677289b1b45ea5a21095c53103100ed4d0a8a440b03f1254ce1efb2d82a94cf001cffa0e7fd6ada813a2688b2430a69de998b87aebcd4c556503a45e559a422ecfbdf2f0e6318a8427e41a7b097676cfe97afff13797f82f8d631bd29edde424854139c64ab8241e2a23315514da371f0d3294843fd8f645019a04c07607342c70cf4cc793068355eaccdd6716bc79f0119f97113775379bf58f3f5d9d122766909b797947127b28248ff07205c1eb3aa1717c2a696ce0aba6c5b5bda44c4eda5cf69ae376cc8b334a2c23fb2b374feb2041bfd423c6cc3e064ee2b4705748a082836d39dd723515357fb06e30",
|
||||||
|
});
|
||||||
|
CCoinsViewCache view(&fakeDB);
|
||||||
|
|
||||||
|
// Fake the chain
|
||||||
|
CBlockIndex index(block);
|
||||||
|
index.nHeight = 1723244;
|
||||||
|
CBlockIndex indexPrev;
|
||||||
|
indexPrev.phashBlock = &hashPrev;
|
||||||
|
indexPrev.nHeight = index.nHeight - 1;
|
||||||
|
indexPrev.hashFinalSaplingRoot = uint256S("3922921f92d9abe9e440bb5a21fa901a0647057aa85c201e38d150a5e00043b8");
|
||||||
|
indexPrev.hashFinalOrchardRoot = uint256S("0e9a0a55e201062a5677b8ab15c96e9f4983726af31cd96b14b71ac6a931aea2");
|
||||||
|
index.pprev = &indexPrev;
|
||||||
|
mapBlockIndex.insert(std::make_pair(hashPrev, &indexPrev));
|
||||||
|
|
||||||
|
CValidationState state;
|
||||||
|
struct timeval tv_start;
|
||||||
|
timer_start(tv_start);
|
||||||
|
assert(ConnectBlock(block, state, &index, view, Params(), true, false));
|
||||||
|
auto duration = timer_stop(tv_start);
|
||||||
|
|
||||||
|
// Undo alterations to global state
|
||||||
|
mapBlockIndex.erase(hashPrev);
|
||||||
|
SelectParams(ChainNameFromCommandLine());
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
double benchmark_connectblock_orchard()
|
double benchmark_connectblock_orchard()
|
||||||
{
|
{
|
||||||
// Test for slowness encountered on 2022-06-20
|
// Test for slowness encountered on 2022-06-20
|
||||||
|
|
|
@ -17,6 +17,7 @@ extern double benchmark_try_decrypt_sapling_notes(size_t nAddrs);
|
||||||
extern double benchmark_increment_sprout_note_witnesses(size_t nTxs);
|
extern double benchmark_increment_sprout_note_witnesses(size_t nTxs);
|
||||||
extern double benchmark_increment_sapling_note_witnesses(size_t nTxs);
|
extern double benchmark_increment_sapling_note_witnesses(size_t nTxs);
|
||||||
extern double benchmark_connectblock_slow();
|
extern double benchmark_connectblock_slow();
|
||||||
|
extern double benchmark_connectblock_sapling();
|
||||||
extern double benchmark_connectblock_orchard();
|
extern double benchmark_connectblock_orchard();
|
||||||
extern double benchmark_sendtoaddress(CAmount amount);
|
extern double benchmark_sendtoaddress(CAmount amount);
|
||||||
extern double benchmark_loadwallet();
|
extern double benchmark_loadwallet();
|
||||||
|
|
Loading…
Reference in New Issue