From b3d90c92e8a1e70c8d5e7c679cce369b03761dd6 Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Tue, 21 Nov 2023 13:51:46 +0000 Subject: [PATCH] [Contracts] Slatepack v5 Deserialization fix (#698) * add V5 deserialization test + fixes * clarify comment * upwrap fix during v4 deserialization * further unwrap removal --- controller/tests/contract_early_proofs_rsr.rs | 20 ++++++++++-- libwallet/src/slate.rs | 2 +- libwallet/src/slate_versions/mod.rs | 31 +++++++++++++++++-- libwallet/src/slate_versions/v5_bin.rs | 13 ++++++-- libwallet/src/slatepack/packer.rs | 2 +- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/controller/tests/contract_early_proofs_rsr.rs b/controller/tests/contract_early_proofs_rsr.rs index e1b42e67..5a01ea0e 100644 --- a/controller/tests/contract_early_proofs_rsr.rs +++ b/controller/tests/contract_early_proofs_rsr.rs @@ -27,7 +27,7 @@ use grin_wallet_libwallet as libwallet; use impls::test_framework::{self}; use libwallet::contract::my_fee_contribution; use libwallet::contract::types::{ContractNewArgsAPI, ContractSetupArgsAPI}; -use libwallet::{Slate, SlateState, TxLogEntryType}; +use libwallet::{Slate, SlateState, Slatepack, Slatepacker, SlatepackerArgs, TxLogEntryType}; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; @@ -66,12 +66,27 @@ fn contract_early_proofs_rsr_test_impl(test_dir: &'static str) -> Result<(), lib ..Default::default() }; args.setup_args.proof_args.sender_address = sender_address; + println!("SENDER ADDRESS: {:?}", sender_address); slate = api.contract_new(m, args)?; recipient_address = Some(api.get_slatepack_address(recv_mask, 0)?.pub_key); Ok(()) })?; assert_eq!(slate.state, SlateState::Invoice1); + println!("I1 State slate: {}", slate); + + // Serialize slate into slatepack + let slatepacker_args = SlatepackerArgs { + sender: None, + recipients: vec![], + dec_key: None, + }; + + let slate_packer = Slatepacker::new(slatepacker_args); + let slate_packed = slate_packer.create_slatepack(&slate).unwrap(); + + let slate_unpacked = slate_packer.get_slate(&slate_packed).unwrap(); + println!("I2 Slate unpacked: {}", slate_unpacked); wallet::controller::owner_single_use(Some(send_wallet.clone()), send_mask, None, |api, m| { // Sending wallet (invoice) signs @@ -79,9 +94,10 @@ fn contract_early_proofs_rsr_test_impl(test_dir: &'static str) -> Result<(), lib net_change: Some(-5_000_000_000), ..Default::default() }; - slate = api.contract_sign(m, &slate, args)?; + slate = api.contract_sign(m, &slate_unpacked, args)?; Ok(()) })?; + println!("I2 State slate: {}", slate); assert_eq!(slate.state, SlateState::Invoice2); diff --git a/libwallet/src/slate.rs b/libwallet/src/slate.rs index 486827d0..4c0d9772 100644 --- a/libwallet/src/slate.rs +++ b/libwallet/src/slate.rs @@ -59,7 +59,7 @@ pub struct PaymentMemo { pub memo: [u8; 32], } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct PaymentInfo { /// Sender address pub sender_address: Option, diff --git a/libwallet/src/slate_versions/mod.rs b/libwallet/src/slate_versions/mod.rs index 12fd5917..acb2f92c 100644 --- a/libwallet/src/slate_versions/mod.rs +++ b/libwallet/src/slate_versions/mod.rs @@ -94,11 +94,13 @@ impl From for Slate { #[serde(untagged)] /// Binary versions, can only be parsed 1:1 into the appropriate /// version, and VersionedSlate can up/downgrade from there +/// NB (IMPORTANT): Ensure the slates are listed in reverse chronological +/// order (latest first) pub enum VersionedBinSlate { - /// Version 4, binary - V4(SlateV4Bin), /// Version 5, binary V5(SlateV5Bin), + /// Version 4, binary + V4(SlateV4Bin), } impl TryFrom for VersionedBinSlate { @@ -149,7 +151,9 @@ pub mod tests { use crate::grin_util::secp::Signature; use crate::slate::{KernelFeaturesArgs, ParticipantData, PaymentInfo, PaymentMemo}; use crate::slate_versions::v5::{CommitsV5, SlateV5}; - use crate::{slate, Error, Slate, VersionedBinSlate, VersionedSlate}; + use crate::{ + slate, Error, Slate, Slatepacker, SlatepackerArgs, VersionedBinSlate, VersionedSlate, + }; use chrono::{DateTime, NaiveDateTime, Utc}; use ed25519_dalek::PublicKey as DalekPublicKey; use ed25519_dalek::Signature as DalekSignature; @@ -242,6 +246,27 @@ pub mod tests { Ok(slate_internal) } + #[test] + fn ser_deser_current_slate() -> Result<(), Error> { + let slate_internal = populate_test_slate()?; + // Serialize slate into slatepack + let slatepacker_args = SlatepackerArgs { + sender: None, + recipients: vec![], + dec_key: None, + }; + + let slate_packer = Slatepacker::new(slatepacker_args); + let slate_packed = slate_packer.create_slatepack(&slate_internal).unwrap(); + + let slate_unpacked = slate_packer.get_slate(&slate_packed).unwrap(); + + // Just verifying payment proof for now, extend later to cover EQ for full slate if needs + // be + assert_eq!(slate_internal.payment_proof, slate_unpacked.payment_proof); + Ok(()) + } + #[test] fn slatepack_version_v4_v5() -> Result<(), Error> { set_local_chain_type(ChainTypes::Mainnet); diff --git a/libwallet/src/slate_versions/v5_bin.rs b/libwallet/src/slate_versions/v5_bin.rs index 441ce3aa..d0330297 100644 --- a/libwallet/src/slate_versions/v5_bin.rs +++ b/libwallet/src/slate_versions/v5_bin.rs @@ -25,6 +25,7 @@ use chrono::{DateTime, NaiveDateTime, Utc}; use ed25519_dalek::PublicKey as DalekPublicKey; use ed25519_dalek::Signature as DalekSignature; use std::convert::{TryFrom, TryInto}; +use std::f64::consts::E; use crate::slate_versions::v5::{ CommitsV5, KernelFeaturesArgsV5, ParticipantDataV5, PaymentInfoV5, PaymentMemoV5, SlateStateV5, @@ -246,9 +247,15 @@ impl Readable for ProofWrap { fn read(reader: &mut R) -> Result { let saddr = DalekPublicKey::from_bytes(&reader.read_fixed_bytes(32)?).unwrap(); let raddr = DalekPublicKey::from_bytes(&reader.read_fixed_bytes(32)?).unwrap(); - let ts_raw: i64 = reader.read_i64().unwrap(); - let ts = - DateTime::::from_utc(NaiveDateTime::from_timestamp_opt(ts_raw, 0).unwrap(), Utc); + let ts_raw: i64 = match reader.read_i64() { + Ok(v) => v, + Err(_) => return Err(grin_ser::Error::CorruptedData), + }; + let ts_opt = match NaiveDateTime::from_timestamp_opt(ts_raw, 0) { + Some(o) => o, + None => return Err(grin_ser::Error::CorruptedData), + }; + let ts = DateTime::::from_utc(ts_opt, Utc); let psig = match reader.read_u8()? { 0 => None, 1 | _ => Some(DalekSignature::try_from(&reader.read_fixed_bytes(64)?[..]).unwrap()), diff --git a/libwallet/src/slatepack/packer.rs b/libwallet/src/slatepack/packer.rs index f1c54e92..d44f5c6c 100644 --- a/libwallet/src/slatepack/packer.rs +++ b/libwallet/src/slatepack/packer.rs @@ -94,7 +94,7 @@ impl<'a> Slatepacker<'a> { /// Create slatepack from slate and args pub fn create_slatepack(&self, slate: &Slate) -> Result { - let out_slate = VersionedSlate::into_version(slate.clone(), SlateVersion::V4)?; + let out_slate = VersionedSlate::into_version(slate.clone(), SlateVersion::V5)?; let bin_slate = VersionedBinSlate::try_from(out_slate).map_err(|_| Error::SlatepackSer)?; let mut slatepack = Slatepack::default(); slatepack.payload = byte_ser::to_bytes(&bin_slate).map_err(|_| Error::SlatepackSer)?;