zcash_client_sqlite: Read rcm correctly from data DB after Canopy

ZIP 212 alters the note plaintext to store a seed from which rcm is
derived, rather than storing rcm directly. In the mobile SDKs we only
need rcm, so for post-ZIP 212 notes, we derive rcm from the seed and
store rcm in the data DB.

However, when selecting notes to spend, `create_to_address` was using the
transaction's target height to determine if Canopy is active, and parsing
the rcm value as the seed if so. This effectively applied a seed->rcm
derivation to all selected notes' rcms once Canopy activated on the
chain. As a result, the note commitments were incorrect, and thus the
anchors derived from the witness paths were also incorrect. This caused
two kinds of observed failures:

- If more than one note was selected, the builder would fail with
  "anchor mismatch", as the note commitments would be effectively
  randomised, causing the derived anchors to also randomise.
- If a single note was selected, the transaction would be built using
  the randomised anchor, and then rejected when sent to the network.

The fix is to "pretend" in `create_to_address` that all notes are
pre-ZIP 212 notes. This works fine because we never need to serialize
back to the note plaintext while spending a note.
This commit is contained in:
Jack Grigg 2020-10-23 22:21:59 +01:00
parent 37b5d67d33
commit 524cc2e979
1 changed files with 11 additions and 14 deletions

View File

@ -7,7 +7,7 @@ use std::convert::TryInto;
use std::path::Path;
use zcash_client_backend::encoding::encode_extended_full_viewing_key;
use zcash_primitives::{
consensus::{self, NetworkUpgrade, Parameters},
consensus,
keys::OutgoingViewingKey,
merkle_tree::{IncrementalWitness, MerklePath},
note_encryption::Memo,
@ -227,19 +227,16 @@ pub fn create_to_address<P: AsRef<Path>>(
let rseed = {
let d: Vec<_> = row.get(2)?;
if Network::is_nu_active(NetworkUpgrade::Canopy, height) {
let mut r = [0u8; 32];
r.copy_from_slice(&d[..]);
Rseed::AfterZip212(r)
} else {
let r = jubjub::Fr::from_repr(
d[..]
.try_into()
.map_err(|_| Error(ErrorKind::InvalidNote))?,
)
.ok_or(Error(ErrorKind::InvalidNote))?;
Rseed::BeforeZip212(r)
}
// We store rcm directly in the data DB, regardless of whether the note
// used a v1 or v2 note plaintext, so for the purposes of spending let's
// pretend this is a pre-ZIP 212 note.
let r = jubjub::Fr::from_repr(
d[..]
.try_into()
.map_err(|_| Error(ErrorKind::InvalidNote))?,
)
.ok_or(Error(ErrorKind::InvalidNote))?;
Rseed::BeforeZip212(r)
};
let from = extfvk.fvk.vk.to_payment_address(diversifier).unwrap();