Skip to content

Commit 7f737b6

Browse files
hhanh00claude
andcommitted
fix: conditional NU7 activation and Orchard proving key selection
- Activate NU7 only when database name contains "zsa" for v6 transactions - Use OrchardVanilla proving key for non-ZSA transactions - Use OrchardZSA proving key for ZSA-enabled transactions - Prevent "bad tx header" error from LWD with non-ZSA databases - Prevent ConstraintSystemFailure during proof generation Fixes transaction compatibility issues after ZSA work: - Non-ZSA databases (regtest.db) now use v5 format with OrchardVanilla - ZSA databases use v6 format with OrchardZSA circuit - Both transaction versions work with their respective proving keys Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ddfa640 commit 7f737b6

10 files changed

Lines changed: 56 additions & 26 deletions

File tree

.github/workflows/build-graphql.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ jobs:
2525
sudo apt-get install -y pkg-config libudev-dev
2626
cd rust
2727
cargo build --release --bin zkool_graphql --features=graphql
28+
env:
29+
RUSTFLAGS: '--cfg zcash_unstable="nu7"'
2830
- name: Create Release
2931
if: startsWith(github.ref_name, 'zkool-v')
3032
uses: softprops/action-gh-release@v2

.github/workflows/wallet.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ jobs:
2929
sudo apt-get install -y pkg-config libudev-dev
3030
cd rust
3131
cargo build --release --bin zkool_graphql --features=graphql
32+
env:
33+
RUSTFLAGS: '--cfg zcash_unstable="nu7"'
3234
- name: Run pytest tests
3335
run: |
3436
cd tests

rust/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ hidapi = {version = "2.6.3", optional = true, default-features = false, features
129129
hidapi = {version = "2.6.3", optional = true, default-features = false, features = ["windows-native"]}
130130

131131
[lints.rust]
132-
unexpected_cfgs = {level = "warn", check-cfg = ['cfg(frb_expand)']}
132+
unexpected_cfgs = {level = "warn", check-cfg = ['cfg(frb_expand)', 'cfg(zcash_unstable, values("nu7"))']}
133133

134134
[dev-dependencies]
135135
chrono = "0.4"

rust/src/api/coin.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,26 @@ impl Coin {
8282
match self.coin {
8383
0 => Network::Main,
8484
1 => Network::Test,
85-
2 => REGTEST,
85+
2 => {
86+
#[cfg(zcash_unstable = "nu7")]
87+
let nu7 = if self.db_filepath.to_lowercase().contains("zsa") {
88+
Some(BlockHeight::from_u32(1))
89+
} else {
90+
None
91+
};
92+
Network::Regtest(LocalNetwork {
93+
overwinter: Some(BlockHeight::from_u32(1)),
94+
sapling: Some(BlockHeight::from_u32(1)),
95+
blossom: Some(BlockHeight::from_u32(1)),
96+
heartwood: Some(BlockHeight::from_u32(1)),
97+
canopy: Some(BlockHeight::from_u32(1)),
98+
nu5: Some(BlockHeight::from_u32(1)),
99+
nu6: Some(BlockHeight::from_u32(1)),
100+
nu6_1: Some(BlockHeight::from_u32(1)),
101+
#[cfg(zcash_unstable = "nu7")]
102+
nu7,
103+
})
104+
}
86105
_ => Network::Main,
87106
}
88107
}
@@ -261,20 +280,6 @@ fn get_connect_options(db_filepath: &str, password: &Option<String>) -> SqliteCo
261280

262281
pub(crate) use zcash_trees::network::Network;
263282

264-
pub(crate) const fn _regtest() -> LocalNetwork {
265-
LocalNetwork {
266-
overwinter: Some(BlockHeight::from_u32(1)),
267-
sapling: Some(BlockHeight::from_u32(1)),
268-
blossom: Some(BlockHeight::from_u32(1)),
269-
heartwood: Some(BlockHeight::from_u32(1)),
270-
canopy: Some(BlockHeight::from_u32(1)),
271-
nu5: Some(BlockHeight::from_u32(1)),
272-
nu6: Some(BlockHeight::from_u32(1)),
273-
nu6_1: Some(BlockHeight::from_u32(1)),
274-
nu7: Some(BlockHeight::from_u32(1)),
275-
}
276-
}
277-
278283
pub async fn init_datadir(directory: &str) -> Result<()> {
279284
let _ = DATADIR.set(directory.to_string());
280285
Ok(())
@@ -296,6 +301,5 @@ pub async fn get_tor_client() -> &'static Mutex<TorClient<PreferredRuntime>> {
296301

297302
pub static TOR: OnceCell<Mutex<TorClient<PreferredRuntime>>> = OnceCell::const_new();
298303
pub static DATADIR: OnceLock<String> = OnceLock::new();
299-
pub static REGTEST: Network = Network::Regtest(_regtest());
300304
pub static POOLS: LazyLock<std::sync::Mutex<HashMap<String, SqlitePool>>> =
301305
LazyLock::new(|| std::sync::Mutex::new(HashMap::new()));

rust/src/api/pay.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ pub async fn prepare(recipients: &[Recipient], options: PaymentOptions, c: &Coin
4343
pub async fn sign_transaction(pczt: &PcztPackage, c: &Coin) -> Result<PcztPackage> {
4444
let account = c.account;
4545
let mut connection = c.get_connection().await?;
46+
let network = c.network();
4647

47-
let tx = crate::pay::plan::sign_transaction(&mut *connection, account, pczt).await?;
48+
let tx = crate::pay::plan::sign_transaction(&mut *connection, account, &network, pczt).await?;
4849

4950
Ok(tx)
5051
}

rust/src/frost/protocol.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ pub async fn publish(
482482
)
483483
.await
484484
.unwrap();
485-
let pczt = sign_transaction(connection, account, &pczt).await?;
485+
let pczt = sign_transaction(connection, account, network, &pczt).await?;
486486
let txb = extract_transaction(&pczt).await?;
487487
let result = crate::pay::send(client, height, &txb).await?;
488488
if hex::decode(&result).is_err() {

rust/src/frost/sign.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use crate::{
4747
get_mailbox_account, publish,
4848
},
4949
pay::{
50-
plan::{ORCHARD_PK, SAPLING_PROVER},
50+
plan::{get_orchard_pk, SAPLING_PROVER},
5151
send,
5252
},
5353
Client, Sink,
@@ -693,7 +693,7 @@ pub async fn do_sign_impl(
693693
let pczt = Prover::new(pczt)
694694
.create_sapling_proofs(sapling_prover, sapling_prover)
695695
.unwrap()
696-
.create_orchard_proof(&ORCHARD_PK)
696+
.create_orchard_proof(get_orchard_pk(network))
697697
.unwrap()
698698
.finish();
699699
info!("Proved");

rust/src/graphql/mutation.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ impl Mutation {
166166
let mut connection = coin.get_connection().await?;
167167
let mut client = coin.client().await?;
168168
let height = client.latest_height().await?;
169-
let signed_pczt = sign_transaction(&mut connection, id_account as u32, &pczt).await?;
169+
let network = coin.network();
170+
let signed_pczt = sign_transaction(&mut connection, id_account as u32, &network, &pczt).await?;
170171
let tx_bytes = extract_transaction(&signed_pczt).await?;
171172
let txid = crate::pay::send(&mut client, height, &tx_bytes).await?;
172173
Ok(txid)

rust/src/graphql/query.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,9 @@ impl Query {
277277
let pczt = hex::decode(&pczt)?;
278278
let (pczt, _) =
279279
bincode::decode_from_slice::<PcztPackage, _>(&pczt, bincode::config::standard())?;
280+
let network = context.coin.network();
280281
let signed =
281-
crate::pay::plan::sign_transaction(&mut connection, id_account as u32, &pczt).await?;
282+
crate::pay::plan::sign_transaction(&mut connection, id_account as u32, &network, &pczt).await?;
282283
let tx_bin = crate::pay::plan::extract_transaction(&signed).await?;
283284
let tx = hex::encode(&tx_bin);
284285
Ok(tx)

rust/src/pay/plan.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use bip32::PrivateKey;
66
use itertools::Itertools;
77
use orchard::{
88
circuit::ProvingKey,
9-
flavor::OrchardZSA,
9+
flavor::{OrchardVanilla, OrchardZSA},
1010
keys::{Scope, SpendAuthorizingKey},
1111
note::{AssetBase, ExtractedNoteCommitment},
1212
Address,
@@ -903,6 +903,7 @@ fn encode_memo(recipient: &Recipient) -> Result<Option<MemoBytes>> {
903903
pub async fn sign_transaction(
904904
connection: &mut SqliteConnection,
905905
account: u32,
906+
network: &crate::api::coin::Network,
906907
pczt: &PcztPackage,
907908
) -> Result<PcztPackage> {
908909
let span = span!(Level::INFO, "transaction");
@@ -1068,7 +1069,7 @@ pub async fn sign_transaction(
10681069
let pczt = Prover::new(pczt)
10691070
.create_sapling_proofs(sapling_prover, sapling_prover)
10701071
.unwrap()
1071-
.create_orchard_proof(&ORCHARD_PK)
1072+
.create_orchard_proof(get_orchard_pk(network))
10721073
.unwrap()
10731074
.finish();
10741075
debug!("Proved");
@@ -1416,4 +1417,22 @@ pub async fn fetch_unspent_notes_grouped_by_pool(
14161417
}
14171418

14181419
pub static SAPLING_PROVER: LazyLock<LocalTxProver> = LazyLock::new(LocalTxProver::bundled);
1419-
pub static ORCHARD_PK: LazyLock<ProvingKey> = LazyLock::new(ProvingKey::build::<OrchardZSA>);
1420+
pub static ORCHARD_VANILLA_PK: LazyLock<ProvingKey> = LazyLock::new(|| ProvingKey::build::<OrchardVanilla>());
1421+
pub static ORCHARD_ZSA_PK: LazyLock<ProvingKey> = LazyLock::new(|| ProvingKey::build::<OrchardZSA>());
1422+
1423+
pub fn get_orchard_pk(network: &crate::api::coin::Network) -> &'static ProvingKey {
1424+
// Check if NU7 is active (ZSA-enabled)
1425+
let uses_orchard_zsa = match network {
1426+
crate::api::coin::Network::Regtest(config) => {
1427+
// NU7 active means ZSA transactions
1428+
config.nu7.is_some()
1429+
}
1430+
_ => false,
1431+
};
1432+
1433+
if uses_orchard_zsa {
1434+
&ORCHARD_ZSA_PK
1435+
} else {
1436+
&ORCHARD_VANILLA_PK
1437+
}
1438+
}

0 commit comments

Comments
 (0)