From 9c2177e3d9919ba0fbdadfaf85e76d35b98dee04 Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Wed, 20 Nov 2019 11:01:38 +0000 Subject: [PATCH] HF2 Slate Changes (#258) * Update slate version to V3, define PaymentInfoV3 and add needed serialization * rustfmt * add ttl and payment proof info to slate * rustfmt * add documentation for updated fields * doc test fixes --- Cargo.lock | 1 + api/src/foreign_rpc.rs | 14 +- api/src/owner_rpc.rs | 68 +++-- api/src/owner_rpc_s.rs | 70 +++-- controller/src/command.rs | 10 +- impls/src/adapters/http.rs | 2 +- impls/src/test_framework/testclient.rs | 10 +- libwallet/Cargo.toml | 1 + libwallet/src/slate.rs | 244 ++++++++++++------ libwallet/src/slate_versions/mod.rs | 30 ++- libwallet/src/slate_versions/ser.rs | 132 ++++++++++ libwallet/src/slate_versions/{v2.rs => v3.rs} | 86 +++--- tests/owner_v3_lifecycle.rs | 2 +- 13 files changed, 470 insertions(+), 200 deletions(-) create mode 100644 libwallet/src/slate_versions/ser.rs rename libwallet/src/slate_versions/{v2.rs => v3.rs} (78%) diff --git a/Cargo.lock b/Cargo.lock index 80921a79..84588241 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1022,6 +1022,7 @@ version = "3.0.0-alpha.1" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "grin_wallet_config 3.0.0-alpha.1", diff --git a/api/src/foreign_rpc.rs b/api/src/foreign_rpc.rs index b90ee50c..252985f1 100644 --- a/api/src/foreign_rpc.rs +++ b/api/src/foreign_rpc.rs @@ -53,7 +53,7 @@ pub trait ForeignRpc { "Ok": { "foreign_api_version": 2, "supported_slate_versions": [ - "V2" + "V3" ] } } @@ -133,6 +133,8 @@ pub trait ForeignRpc { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "4", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -251,6 +253,8 @@ pub trait ForeignRpc { "fee": "7000000", "height": "5", "lock_height": "0", + "ttl_cutoff_height": "0", + "payment_proof": null, "participant_data": [ { "id": "0", @@ -279,6 +283,8 @@ pub trait ForeignRpc { "height": "5", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -414,6 +420,8 @@ pub trait ForeignRpc { "fee": "7000000", "height": "5", "lock_height": "0", + "ttl_cutoff_height": "0", + "payment_proof": null, "participant_data": [ { "id": "1", @@ -447,6 +455,8 @@ pub trait ForeignRpc { "height": "5", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -529,7 +539,7 @@ where fn build_coinbase(&self, block_fees: &BlockFees) -> Result { let cb: CbData = Foreign::build_coinbase(self, block_fees).map_err(|e| e.kind())?; - Ok(VersionedCoinbase::into_version(cb, SlateVersion::V2)) + Ok(VersionedCoinbase::into_version(cb, SlateVersion::V3)) } fn verify_slate_messages(&self, slate: VersionedSlate) -> Result<(), ErrorKind> { diff --git a/api/src/owner_rpc.rs b/api/src/owner_rpc.rs index c2db3ac2..35717b5f 100644 --- a/api/src/owner_rpc.rs +++ b/api/src/owner_rpc.rs @@ -17,7 +17,7 @@ use uuid::Uuid; use crate::core::core::Transaction; use crate::keychain::{Identifier, Keychain}; -use crate::libwallet::slate_versions::v2::TransactionV2; +use crate::libwallet::slate_versions::v3::TransactionV3; use crate::libwallet::{ AcctPathMapping, ErrorKind, InitTxArgs, IssueInvoiceTxArgs, NodeClient, NodeHeightResult, OutputCommitMapping, Slate, SlateVersion, TxLogEntry, VersionedSlate, WalletInfo, @@ -358,6 +358,8 @@ pub trait OwnerRpc: Sync + Send { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -397,8 +399,8 @@ pub trait OwnerRpc: Sync + Send { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 1 } } @@ -443,6 +445,8 @@ pub trait OwnerRpc: Sync + Send { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -477,8 +481,8 @@ pub trait OwnerRpc: Sync + Send { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 1 } } @@ -507,6 +511,8 @@ pub trait OwnerRpc: Sync + Send { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -541,8 +547,8 @@ pub trait OwnerRpc: Sync + Send { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } }, @@ -573,6 +579,8 @@ pub trait OwnerRpc: Sync + Send { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -625,8 +633,8 @@ pub trait OwnerRpc: Sync + Send { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } } @@ -659,6 +667,8 @@ pub trait OwnerRpc: Sync + Send { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "4", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -698,8 +708,8 @@ pub trait OwnerRpc: Sync + Send { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } }, @@ -740,12 +750,14 @@ pub trait OwnerRpc: Sync + Send { "params": [ { "version_info": { - "version": 2, - "orig_version": 2, + "version": 3, + "orig_version": 3, "block_header_version": 2 }, "num_participants": 2, "id": "0436430c-2b02-624c-2032-570501212b00", + "ttl_cutoff_height": "0", + "payment_proof": null, "tx": { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000", "body": { @@ -819,6 +831,8 @@ pub trait OwnerRpc: Sync + Send { "fee": "7000000", "height": "5", "id": "0436430c-2b02-624c-2032-570501212b00", + "ttl_cutoff_height": "0", + "payment_proof": null, "lock_height": "0", "num_participants": 2, "participant_data": [ @@ -876,8 +890,8 @@ pub trait OwnerRpc: Sync + Send { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } } @@ -954,7 +968,7 @@ pub trait OwnerRpc: Sync + Send { ``` */ - fn post_tx(&self, tx: TransactionV2, fluff: bool) -> Result<(), ErrorKind>; + fn post_tx(&self, tx: TransactionV3, fluff: bool) -> Result<(), ErrorKind>; /** Networked version of [Owner::cancel_tx](struct.Owner.html#method.cancel_tx). @@ -1080,7 +1094,7 @@ pub trait OwnerRpc: Sync + Send { # , false, 5, true, true, false); ``` */ - fn get_stored_tx(&self, tx: &TxLogEntry) -> Result, ErrorKind>; + fn get_stored_tx(&self, tx: &TxLogEntry) -> Result, ErrorKind>; /** Networked version of [Owner::verify_slate_messages](struct.Owner.html#method.verify_slate_messages). @@ -1098,6 +1112,8 @@ pub trait OwnerRpc: Sync + Send { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "4", + "ttl_cutoff_height": "0", + "payment_proof": null, "num_participants": 2, "participant_data": [ { @@ -1137,8 +1153,8 @@ pub trait OwnerRpc: Sync + Send { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } } @@ -1271,13 +1287,13 @@ where fn init_send_tx(&self, args: InitTxArgs) -> Result { let slate = Owner::init_send_tx(self, None, args).map_err(|e| e.kind())?; - let version = SlateVersion::V2; + let version = SlateVersion::V3; Ok(VersionedSlate::into_version(slate, version)) } fn issue_invoice_tx(&self, args: IssueInvoiceTxArgs) -> Result { let slate = Owner::issue_invoice_tx(self, None, args).map_err(|e| e.kind())?; - let version = SlateVersion::V2; + let version = SlateVersion::V3; Ok(VersionedSlate::into_version(slate, version)) } @@ -1288,14 +1304,14 @@ where ) -> Result { let out_slate = Owner::process_invoice_tx(self, None, &Slate::from(in_slate), args) .map_err(|e| e.kind())?; - let version = SlateVersion::V2; + let version = SlateVersion::V3; Ok(VersionedSlate::into_version(out_slate, version)) } fn finalize_tx(&self, in_slate: VersionedSlate) -> Result { let out_slate = Owner::finalize_tx(self, None, &Slate::from(in_slate)).map_err(|e| e.kind())?; - let version = SlateVersion::V2; + let version = SlateVersion::V3; Ok(VersionedSlate::into_version(out_slate, version)) } @@ -1312,13 +1328,13 @@ where Owner::cancel_tx(self, None, tx_id, tx_slate_id).map_err(|e| e.kind()) } - fn get_stored_tx(&self, tx: &TxLogEntry) -> Result, ErrorKind> { + fn get_stored_tx(&self, tx: &TxLogEntry) -> Result, ErrorKind> { Owner::get_stored_tx(self, None, tx) - .map(|x| x.map(|y| TransactionV2::from(y))) + .map(|x| x.map(|y| TransactionV3::from(y))) .map_err(|e| e.kind()) } - fn post_tx(&self, tx: TransactionV2, fluff: bool) -> Result<(), ErrorKind> { + fn post_tx(&self, tx: TransactionV3, fluff: bool) -> Result<(), ErrorKind> { Owner::post_tx(self, None, &Transaction::from(tx), fluff).map_err(|e| e.kind()) } diff --git a/api/src/owner_rpc_s.rs b/api/src/owner_rpc_s.rs index 11d56ba0..6ef663c3 100644 --- a/api/src/owner_rpc_s.rs +++ b/api/src/owner_rpc_s.rs @@ -19,7 +19,7 @@ use crate::config::{TorConfig, WalletConfig}; use crate::core::core::Transaction; use crate::core::global; use crate::keychain::{Identifier, Keychain}; -use crate::libwallet::slate_versions::v2::TransactionV2; +use crate::libwallet::slate_versions::v3::TransactionV3; use crate::libwallet::{ AcctPathMapping, ErrorKind, InitTxArgs, IssueInvoiceTxArgs, NodeClient, NodeHeightResult, OutputCommitMapping, Slate, SlateVersion, StatusMessage, TxLogEntry, VersionedSlate, @@ -389,7 +389,9 @@ pub trait OwnerRpcS { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", "num_participants": 2, + "payment_proof": null, "participant_data": [ { "id": "0", @@ -428,8 +430,8 @@ pub trait OwnerRpcS { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 1 } } @@ -475,7 +477,9 @@ pub trait OwnerRpcS { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", "num_participants": 2, + "payment_proof": null, "participant_data": [ { "id": "1", @@ -509,8 +513,8 @@ pub trait OwnerRpcS { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 1 } } @@ -544,7 +548,9 @@ pub trait OwnerRpcS { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", "num_participants": 2, + "payment_proof": null, "participant_data": [ { "id": "1", @@ -578,8 +584,8 @@ pub trait OwnerRpcS { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } }, @@ -610,7 +616,9 @@ pub trait OwnerRpcS { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", "num_participants": 2, + "payment_proof": null, "participant_data": [ { "id": "1", @@ -662,8 +670,8 @@ pub trait OwnerRpcS { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } } @@ -699,7 +707,9 @@ pub trait OwnerRpcS { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "4", + "ttl_cutoff_height": "0", "num_participants": 2, + "payment_proof": null, "participant_data": [ { "id": "0", @@ -738,8 +748,8 @@ pub trait OwnerRpcS { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } }, @@ -782,12 +792,13 @@ pub trait OwnerRpcS { "token": "d202964900000000d302964900000000d402964900000000d502964900000000", "slate": { "version_info": { - "version": 2, - "orig_version": 2, + "version": 3, + "orig_version": 3, "block_header_version": 2 }, "num_participants": 2, "id": "0436430c-2b02-624c-2032-570501212b00", + "payment_proof": null, "tx": { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000", "body": { @@ -828,6 +839,7 @@ pub trait OwnerRpcS { "fee": "7000000", "height": "5", "lock_height": "0", + "ttl_cutoff_height": "0", "participant_data": [ { "id": "0", @@ -862,7 +874,9 @@ pub trait OwnerRpcS { "height": "5", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "0", + "ttl_cutoff_height": "0", "num_participants": 2, + "payment_proof": null, "participant_data": [ { "id": "0", @@ -918,8 +932,8 @@ pub trait OwnerRpcS { "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } } @@ -998,7 +1012,7 @@ pub trait OwnerRpcS { ``` */ - fn post_tx(&self, token: Token, tx: TransactionV2, fluff: bool) -> Result<(), ErrorKind>; + fn post_tx(&self, token: Token, tx: TransactionV3, fluff: bool) -> Result<(), ErrorKind>; /** Networked version of [Owner::cancel_tx](struct.Owner.html#method.cancel_tx). @@ -1138,7 +1152,7 @@ pub trait OwnerRpcS { &self, token: Token, tx: &TxLogEntry, - ) -> Result, ErrorKind>; + ) -> Result, ErrorKind>; /** Networked version of [Owner::verify_slate_messages](struct.Owner.html#method.verify_slate_messages). @@ -1158,6 +1172,7 @@ pub trait OwnerRpcS { "height": "4", "id": "0436430c-2b02-624c-2032-570501212b00", "lock_height": "4", + "ttl_cutoff_height": "0", "num_participants": 2, "participant_data": [ { @@ -1194,11 +1209,12 @@ pub trait OwnerRpcS { } ] }, - "offset": "d202964900000000d302964900000000d402964900000000d502964900000000" + "offset": "d202964900000000d302964900000000d402964900000000d502964900000000", + "payment_proof": null }, "version_info": { - "orig_version": 2, - "version": 2, + "orig_version": 3, + "version": 3, "block_header_version": 2 } } @@ -1834,7 +1850,7 @@ where fn init_send_tx(&self, token: Token, args: InitTxArgs) -> Result { let slate = Owner::init_send_tx(self, (&token.keychain_mask).as_ref(), args) .map_err(|e| e.kind())?; - let version = SlateVersion::V2; + let version = SlateVersion::V3; Ok(VersionedSlate::into_version(slate, version)) } @@ -1845,7 +1861,7 @@ where ) -> Result { let slate = Owner::issue_invoice_tx(self, (&token.keychain_mask).as_ref(), args) .map_err(|e| e.kind())?; - let version = SlateVersion::V2; + let version = SlateVersion::V3; Ok(VersionedSlate::into_version(slate, version)) } @@ -1862,7 +1878,7 @@ where args, ) .map_err(|e| e.kind())?; - let version = SlateVersion::V2; + let version = SlateVersion::V3; Ok(VersionedSlate::into_version(out_slate, version)) } @@ -1877,7 +1893,7 @@ where &Slate::from(in_slate), ) .map_err(|e| e.kind())?; - let version = SlateVersion::V2; + let version = SlateVersion::V3; Ok(VersionedSlate::into_version(out_slate, version)) } @@ -1910,13 +1926,13 @@ where &self, token: Token, tx: &TxLogEntry, - ) -> Result, ErrorKind> { + ) -> Result, ErrorKind> { Owner::get_stored_tx(self, (&token.keychain_mask).as_ref(), tx) - .map(|x| x.map(|y| TransactionV2::from(y))) + .map(|x| x.map(|y| TransactionV3::from(y))) .map_err(|e| e.kind()) } - fn post_tx(&self, token: Token, tx: TransactionV2, fluff: bool) -> Result<(), ErrorKind> { + fn post_tx(&self, token: Token, tx: TransactionV3, fluff: bool) -> Result<(), ErrorKind> { Owner::post_tx( self, (&token.keychain_mask).as_ref(), diff --git a/controller/src/command.rs b/controller/src/command.rs index a0ef94f1..064e6bbf 100644 --- a/controller/src/command.rs +++ b/controller/src/command.rs @@ -736,15 +736,15 @@ pub struct PostArgs { pub fluff: bool, } -pub fn post<'a, L, C, K>( - wallet: Arc>>>, +pub fn post( + wallet: Arc>>>, keychain_mask: Option<&SecretKey>, args: PostArgs, ) -> Result<(), Error> where - L: WalletLCProvider<'a, C, K>, - C: NodeClient + 'a, - K: keychain::Keychain + 'a, + L: WalletLCProvider<'static, C, K> + 'static, + C: NodeClient + 'static, + K: keychain::Keychain + 'static, { let slate = PathToSlate((&args.input).into()).get_tx()?; diff --git a/impls/src/adapters/http.rs b/impls/src/adapters/http.rs index 4f64fd87..15d9b837 100644 --- a/impls/src/adapters/http.rs +++ b/impls/src/adapters/http.rs @@ -111,7 +111,7 @@ impl HttpSlateSender { return Err(ErrorKind::ClientCallback(report).into()); } - if !supported_slate_versions.contains(&"V2".to_owned()) { + if !supported_slate_versions.contains(&"V3".to_owned()) { let report = format!("Unable to negotiate slate format with other wallet."); error!("{}", report); return Err(ErrorKind::ClientCallback(report).into()); diff --git a/impls/src/test_framework/testclient.rs b/impls/src/test_framework/testclient.rs index 591404c3..119157b8 100644 --- a/impls/src/test_framework/testclient.rs +++ b/impls/src/test_framework/testclient.rs @@ -26,7 +26,7 @@ use crate::core::{pow, ser}; use crate::keychain::Keychain; use crate::libwallet; use crate::libwallet::api_impl::foreign; -use crate::libwallet::slate_versions::v2::SlateV2; +use crate::libwallet::slate_versions::v3::SlateV3; use crate::libwallet::{ NodeClient, NodeVersionInfo, Slate, TxWrapper, WalletInst, WalletLCProvider, }; @@ -216,7 +216,7 @@ where Some(w) => w, }; - let slate: SlateV2 = serde_json::from_str(&m.body).context( + let slate: SlateV3 = serde_json::from_str(&m.body).context( libwallet::ErrorKind::ClientCallback("Error parsing TxWrapper".to_owned()), )?; @@ -239,7 +239,7 @@ where sender_id: m.dest, dest: m.sender_id, method: m.method, - body: serde_json::to_string(&SlateV2::from(slate)).unwrap(), + body: serde_json::to_string(&SlateV3::from(slate)).unwrap(), }) } @@ -392,7 +392,7 @@ impl LocalWalletClient { sender_id: self.id.clone(), dest: dest.to_owned(), method: "send_tx_slate".to_owned(), - body: serde_json::to_string(&SlateV2::from(slate)).unwrap(), + body: serde_json::to_string(&SlateV3::from(slate)).unwrap(), }; { let p = self.proxy_tx.lock(); @@ -403,7 +403,7 @@ impl LocalWalletClient { let r = self.rx.lock(); let m = r.recv().unwrap(); trace!("Received send_tx_slate response: {:?}", m.clone()); - let slate: SlateV2 = serde_json::from_str(&m.body).context( + let slate: SlateV3 = serde_json::from_str(&m.body).context( libwallet::ErrorKind::ClientCallback("Parsing send_tx_slate response".to_owned()), )?; Ok(Slate::from(slate)) diff --git a/libwallet/Cargo.toml b/libwallet/Cargo.toml index 1e91d1e6..8bb1f98e 100644 --- a/libwallet/Cargo.toml +++ b/libwallet/Cargo.toml @@ -24,6 +24,7 @@ chrono = { version = "0.4.4", features = ["serde"] } lazy_static = "1" strum = "0.15" strum_macros = "0.15" +ed25519-dalek = "1.0.0-pre.1" grin_wallet_util = { path = "../util", version = "3.0.0-alpha.1" } grin_wallet_config = { path = "../config", version = "3.0.0-alpha.1" } diff --git a/libwallet/src/slate.rs b/libwallet/src/slate.rs index 8c684bef..e84e2bfd 100644 --- a/libwallet/src/slate.rs +++ b/libwallet/src/slate.rs @@ -30,6 +30,8 @@ use crate::grin_util::secp::key::{PublicKey, SecretKey}; use crate::grin_util::secp::pedersen::Commitment; use crate::grin_util::secp::Signature; use crate::grin_util::{self, secp, RwLock}; +use crate::slate_versions::ser as dalek_ser; +use ed25519_dalek::PublicKey as DalekPublicKey; use failure::ResultExt; use rand::rngs::mock::StepRng; use rand::thread_rng; @@ -39,13 +41,23 @@ use std::fmt; use std::sync::Arc; use uuid::Uuid; -use crate::slate_versions::v2::{ - CoinbaseV2, InputV2, OutputV2, ParticipantDataV2, SlateV2, TransactionBodyV2, TransactionV2, - TxKernelV2, VersionCompatInfoV2, +use crate::slate_versions::v3::{ + CoinbaseV3, InputV3, OutputV3, ParticipantDataV3, PaymentInfoV3, SlateV3, TransactionBodyV3, + TransactionV3, TxKernelV3, VersionCompatInfoV3, }; use crate::slate_versions::{CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION}; use crate::types::CbData; +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PaymentInfo { + #[serde(with = "dalek_ser::dalek_pubkey_serde")] + pub sender_address: DalekPublicKey, + #[serde(with = "dalek_ser::option_dalek_pubkey_serde")] + pub receiver_address: Option, + #[serde(with = "secp_ser::option_sig_serde")] + pub receiver_signature: Option, +} + /// Public data for each participant in the slate #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ParticipantData { @@ -174,9 +186,20 @@ pub struct Slate { /// Participant data, each participant in the transaction will /// insert their public data here. For now, 0 is sender and 1 /// is receiver, though this will change for multi-party + #[serde(with = "secp_ser::string_or_u64")] + pub ttl_cutoff_height: u64, + /// Participant data, each participant in the transaction will + /// insert their public data here. For now, 0 is sender and 1 + /// is receiver, though this will change for multi-party pub participant_data: Vec, + /// Payment Proof + #[serde(default = "default_payment_none")] + pub payment_proof: Option, } +fn default_payment_none() -> Option { + None +} /// Versioning and compatibility info about this slate #[derive(Serialize, Deserialize, Debug, Clone)] pub struct VersionCompatInfo { @@ -206,18 +229,18 @@ impl Slate { /// Recieve a slate, upgrade it to the latest version internally pub fn deserialize_upgrade(slate_json: &str) -> Result { let version = Slate::parse_slate_version(slate_json)?; - let v2: SlateV2 = match version { - 2 => serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?, + let v3: SlateV3 = match version { + 3 => serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?, // left as a reminder /*0 => { let v0: SlateV0 = serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?; let v1 = SlateV1::from(v0); - SlateV2::from(v1) + SlateV3::from(v1) }*/ _ => return Err(ErrorKind::SlateVersion(version).into()), }; - Ok(v2.into()) + Ok(v3.into()) } /// Create a new slate @@ -230,12 +253,14 @@ impl Slate { fee: 0, height: 0, lock_height: 0, + ttl_cutoff_height: 0, participant_data: vec![], version_info: VersionCompatInfo { version: CURRENT_SLATE_VERSION, orig_version: CURRENT_SLATE_VERSION, block_header_version: GRIN_BLOCK_HEADER_VERSION, }, + payment_proof: None, } } @@ -698,9 +723,9 @@ impl Serialize for Slate { { use serde::ser::Error; - let v2 = SlateV2::from(self); + let v3 = SlateV3::from(self); match self.version_info.orig_version { - 2 => v2.serialize(serializer), + 3 => v3.serialize(serializer), // left as a reminder /*0 => { let v1 = SlateV1::from(v2); @@ -733,11 +758,11 @@ impl SlateVersionProbe { } // Coinbase data to versioned. -impl From for CoinbaseV2 { - fn from(cb: CbData) -> CoinbaseV2 { - CoinbaseV2 { - output: OutputV2::from(&cb.output), - kernel: TxKernelV2::from(&cb.kernel), +impl From for CoinbaseV3 { + fn from(cb: CbData) -> CoinbaseV3 { + CoinbaseV3 { + output: OutputV3::from(&cb.output), + kernel: TxKernelV3::from(&cb.kernel), key_id: cb.key_id, } } @@ -746,8 +771,8 @@ impl From for CoinbaseV2 { // Current slate version to versioned conversions // Slate to versioned -impl From for SlateV2 { - fn from(slate: Slate) -> SlateV2 { +impl From for SlateV3 { + fn from(slate: Slate) -> SlateV3 { let Slate { num_participants, id, @@ -756,13 +781,19 @@ impl From for SlateV2 { fee, height, lock_height, + ttl_cutoff_height, participant_data, version_info, + payment_proof, } = slate; - let participant_data = map_vec!(participant_data, |data| ParticipantDataV2::from(data)); - let version_info = VersionCompatInfoV2::from(&version_info); - let tx = TransactionV2::from(tx); - SlateV2 { + let participant_data = map_vec!(participant_data, |data| ParticipantDataV3::from(data)); + let version_info = VersionCompatInfoV3::from(&version_info); + let payment_proof = match payment_proof { + Some(p) => Some(PaymentInfoV3::from(&p)), + None => None, + }; + let tx = TransactionV3::from(tx); + SlateV3 { num_participants, id, tx, @@ -770,14 +801,16 @@ impl From for SlateV2 { fee, height, lock_height, + ttl_cutoff_height, participant_data, version_info, + payment_proof, } } } -impl From<&Slate> for SlateV2 { - fn from(slate: &Slate) -> SlateV2 { +impl From<&Slate> for SlateV3 { + fn from(slate: &Slate) -> SlateV3 { let Slate { num_participants, id, @@ -786,19 +819,26 @@ impl From<&Slate> for SlateV2 { fee, height, lock_height, + ttl_cutoff_height, participant_data, version_info, + payment_proof, } = slate; let num_participants = *num_participants; let id = *id; - let tx = TransactionV2::from(tx); + let tx = TransactionV3::from(tx); let amount = *amount; let fee = *fee; let height = *height; let lock_height = *lock_height; - let participant_data = map_vec!(participant_data, |data| ParticipantDataV2::from(data)); - let version_info = VersionCompatInfoV2::from(version_info); - SlateV2 { + let ttl_cutoff_height = *ttl_cutoff_height; + let participant_data = map_vec!(participant_data, |data| ParticipantDataV3::from(data)); + let version_info = VersionCompatInfoV3::from(version_info); + let payment_proof = match payment_proof { + Some(p) => Some(PaymentInfoV3::from(p)), + None => None, + }; + SlateV3 { num_participants, id, tx, @@ -806,14 +846,16 @@ impl From<&Slate> for SlateV2 { fee, height, lock_height, + ttl_cutoff_height, participant_data, version_info, + payment_proof, } } } -impl From<&ParticipantData> for ParticipantDataV2 { - fn from(data: &ParticipantData) -> ParticipantDataV2 { +impl From<&ParticipantData> for ParticipantDataV3 { + fn from(data: &ParticipantData) -> ParticipantDataV3 { let ParticipantData { id, public_blind_excess, @@ -828,7 +870,7 @@ impl From<&ParticipantData> for ParticipantDataV2 { let part_sig = *part_sig; let message: Option = message.as_ref().map(|t| String::from(&**t)); let message_sig = *message_sig; - ParticipantDataV2 { + ParticipantDataV3 { id, public_blind_excess, public_nonce, @@ -839,8 +881,8 @@ impl From<&ParticipantData> for ParticipantDataV2 { } } -impl From<&VersionCompatInfo> for VersionCompatInfoV2 { - fn from(data: &VersionCompatInfo) -> VersionCompatInfoV2 { +impl From<&VersionCompatInfo> for VersionCompatInfoV3 { + fn from(data: &VersionCompatInfo) -> VersionCompatInfoV3 { let VersionCompatInfo { version, orig_version, @@ -849,7 +891,7 @@ impl From<&VersionCompatInfo> for VersionCompatInfoV2 { let version = *version; let orig_version = *orig_version; let block_header_version = *block_header_version; - VersionCompatInfoV2 { + VersionCompatInfoV3 { version, orig_version, block_header_version, @@ -857,35 +899,53 @@ impl From<&VersionCompatInfo> for VersionCompatInfoV2 { } } -impl From for TransactionV2 { - fn from(tx: Transaction) -> TransactionV2 { - let Transaction { offset, body } = tx; - let body = TransactionBodyV2::from(&body); - TransactionV2 { offset, body } +impl From<&PaymentInfo> for PaymentInfoV3 { + fn from(data: &PaymentInfo) -> PaymentInfoV3 { + let PaymentInfo { + sender_address, + receiver_address, + receiver_signature, + } = data; + let sender_address = *sender_address; + let receiver_address = *receiver_address; + let receiver_signature = *receiver_signature; + PaymentInfoV3 { + sender_address, + receiver_address, + receiver_signature, + } } } -impl From<&Transaction> for TransactionV2 { - fn from(tx: &Transaction) -> TransactionV2 { +impl From for TransactionV3 { + fn from(tx: Transaction) -> TransactionV3 { + let Transaction { offset, body } = tx; + let body = TransactionBodyV3::from(&body); + TransactionV3 { offset, body } + } +} + +impl From<&Transaction> for TransactionV3 { + fn from(tx: &Transaction) -> TransactionV3 { let Transaction { offset, body } = tx; let offset = offset.clone(); - let body = TransactionBodyV2::from(body); - TransactionV2 { offset, body } + let body = TransactionBodyV3::from(body); + TransactionV3 { offset, body } } } -impl From<&TransactionBody> for TransactionBodyV2 { - fn from(body: &TransactionBody) -> TransactionBodyV2 { +impl From<&TransactionBody> for TransactionBodyV3 { + fn from(body: &TransactionBody) -> TransactionBodyV3 { let TransactionBody { inputs, outputs, kernels, } = body; - let inputs = map_vec!(inputs, |inp| InputV2::from(inp)); - let outputs = map_vec!(outputs, |out| OutputV2::from(out)); - let kernels = map_vec!(kernels, |kern| TxKernelV2::from(kern)); - TransactionBodyV2 { + let inputs = map_vec!(inputs, |inp| InputV3::from(inp)); + let outputs = map_vec!(outputs, |out| OutputV3::from(out)); + let kernels = map_vec!(kernels, |kern| TxKernelV3::from(kern)); + TransactionBodyV3 { inputs, outputs, kernels, @@ -893,21 +953,21 @@ impl From<&TransactionBody> for TransactionBodyV2 { } } -impl From<&Input> for InputV2 { - fn from(input: &Input) -> InputV2 { +impl From<&Input> for InputV3 { + fn from(input: &Input) -> InputV3 { let Input { features, commit } = *input; - InputV2 { features, commit } + InputV3 { features, commit } } } -impl From<&Output> for OutputV2 { - fn from(output: &Output) -> OutputV2 { +impl From<&Output> for OutputV3 { + fn from(output: &Output) -> OutputV3 { let Output { features, commit, proof, } = *output; - OutputV2 { + OutputV3 { features, commit, proof, @@ -915,8 +975,8 @@ impl From<&Output> for OutputV2 { } } -impl From<&TxKernel> for TxKernelV2 { - fn from(kernel: &TxKernel) -> TxKernelV2 { +impl From<&TxKernel> for TxKernelV3 { + fn from(kernel: &TxKernel) -> TxKernelV3 { let (features, fee, lock_height) = match kernel.features { KernelFeatures::Plain { fee } => (CompatKernelFeatures::Plain, fee, 0), KernelFeatures::Coinbase => (CompatKernelFeatures::Coinbase, 0, 0), @@ -924,7 +984,7 @@ impl From<&TxKernel> for TxKernelV2 { (CompatKernelFeatures::HeightLocked, fee, lock_height) } }; - TxKernelV2 { + TxKernelV3 { features, fee, lock_height, @@ -935,9 +995,9 @@ impl From<&TxKernel> for TxKernelV2 { } // Versioned to current slate -impl From for Slate { - fn from(slate: SlateV2) -> Slate { - let SlateV2 { +impl From for Slate { + fn from(slate: SlateV3) -> Slate { + let SlateV3 { num_participants, id, tx, @@ -945,11 +1005,17 @@ impl From for Slate { fee, height, lock_height, + ttl_cutoff_height, participant_data, version_info, + payment_proof, } = slate; let participant_data = map_vec!(participant_data, |data| ParticipantData::from(data)); let version_info = VersionCompatInfo::from(&version_info); + let payment_proof = match payment_proof { + Some(p) => Some(PaymentInfo::from(&p)), + None => None, + }; let tx = Transaction::from(tx); Slate { num_participants, @@ -959,15 +1025,17 @@ impl From for Slate { fee, height, lock_height, + ttl_cutoff_height, participant_data, version_info, + payment_proof, } } } -impl From<&ParticipantDataV2> for ParticipantData { - fn from(data: &ParticipantDataV2) -> ParticipantData { - let ParticipantDataV2 { +impl From<&ParticipantDataV3> for ParticipantData { + fn from(data: &ParticipantDataV3) -> ParticipantData { + let ParticipantDataV3 { id, public_blind_excess, public_nonce, @@ -992,9 +1060,9 @@ impl From<&ParticipantDataV2> for ParticipantData { } } -impl From<&VersionCompatInfoV2> for VersionCompatInfo { - fn from(data: &VersionCompatInfoV2) -> VersionCompatInfo { - let VersionCompatInfoV2 { +impl From<&VersionCompatInfoV3> for VersionCompatInfo { + fn from(data: &VersionCompatInfoV3) -> VersionCompatInfo { + let VersionCompatInfoV3 { version, orig_version, block_header_version, @@ -1010,17 +1078,35 @@ impl From<&VersionCompatInfoV2> for VersionCompatInfo { } } -impl From for Transaction { - fn from(tx: TransactionV2) -> Transaction { - let TransactionV2 { offset, body } = tx; +impl From<&PaymentInfoV3> for PaymentInfo { + fn from(data: &PaymentInfoV3) -> PaymentInfo { + let PaymentInfoV3 { + sender_address, + receiver_address, + receiver_signature, + } = data; + let sender_address = *sender_address; + let receiver_address = *receiver_address; + let receiver_signature = *receiver_signature; + PaymentInfo { + sender_address, + receiver_address, + receiver_signature, + } + } +} + +impl From for Transaction { + fn from(tx: TransactionV3) -> Transaction { + let TransactionV3 { offset, body } = tx; let body = TransactionBody::from(&body); Transaction { offset, body } } } -impl From<&TransactionBodyV2> for TransactionBody { - fn from(body: &TransactionBodyV2) -> TransactionBody { - let TransactionBodyV2 { +impl From<&TransactionBodyV3> for TransactionBody { + fn from(body: &TransactionBodyV3) -> TransactionBody { + let TransactionBodyV3 { inputs, outputs, kernels, @@ -1037,16 +1123,16 @@ impl From<&TransactionBodyV2> for TransactionBody { } } -impl From<&InputV2> for Input { - fn from(input: &InputV2) -> Input { - let InputV2 { features, commit } = *input; +impl From<&InputV3> for Input { + fn from(input: &InputV3) -> Input { + let InputV3 { features, commit } = *input; Input { features, commit } } } -impl From<&OutputV2> for Output { - fn from(output: &OutputV2) -> Output { - let OutputV2 { +impl From<&OutputV3> for Output { + fn from(output: &OutputV3) -> Output { + let OutputV3 { features, commit, proof, @@ -1059,8 +1145,8 @@ impl From<&OutputV2> for Output { } } -impl From<&TxKernelV2> for TxKernel { - fn from(kernel: &TxKernelV2) -> TxKernel { +impl From<&TxKernelV3> for TxKernel { + fn from(kernel: &TxKernelV3) -> TxKernel { let (fee, lock_height) = (kernel.fee, kernel.lock_height); let features = match kernel.features { CompatKernelFeatures::Plain => KernelFeatures::Plain { fee }, diff --git a/libwallet/src/slate_versions/mod.rs b/libwallet/src/slate_versions/mod.rs index a5db155a..5f3def25 100644 --- a/libwallet/src/slate_versions/mod.rs +++ b/libwallet/src/slate_versions/mod.rs @@ -18,14 +18,16 @@ //! remains for future needs use crate::slate::Slate; -use crate::slate_versions::v2::{CoinbaseV2, SlateV2}; +use crate::slate_versions::v3::{CoinbaseV3, SlateV3}; use crate::types::CbData; +pub mod ser; + #[allow(missing_docs)] -pub mod v2; +pub mod v3; /// The most recent version of the slate -pub const CURRENT_SLATE_VERSION: u16 = 2; +pub const CURRENT_SLATE_VERSION: u16 = 3; /// The grin block header this slate is intended to be compatible with pub const GRIN_BLOCK_HEADER_VERSION: u16 = 2; @@ -33,8 +35,8 @@ pub const GRIN_BLOCK_HEADER_VERSION: u16 = 2; /// Existing versions of the slate #[derive(EnumIter, Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)] pub enum SlateVersion { - /// V2 (most current) - V2, + /// V3 (most current) + V3, } #[derive(Debug, Serialize, Deserialize)] @@ -42,26 +44,26 @@ pub enum SlateVersion { /// Versions are ordered newest to oldest so serde attempts to /// deserialize newer versions first, then falls back to older versions. pub enum VersionedSlate { - /// Current (Grin 1.1.0 - 2.x (current)) - V2(SlateV2), + /// Current (3.0.0 Onwards ) + V3(SlateV3), } impl VersionedSlate { /// Return slate version pub fn version(&self) -> SlateVersion { match *self { - VersionedSlate::V2(_) => SlateVersion::V2, + VersionedSlate::V3(_) => SlateVersion::V3, } } /// convert this slate type to a specified older version pub fn into_version(slate: Slate, version: SlateVersion) -> VersionedSlate { match version { - SlateVersion::V2 => VersionedSlate::V2(slate.into()), + SlateVersion::V3 => VersionedSlate::V3(slate.into()), // Left here as a reminder of what needs to be inserted on // the release of a new slate /*SlateVersion::V0 => { - let s = SlateV2::from(slate); + let s = SlateV3::from(slate); let s = SlateV1::from(s); let s = SlateV0::from(s); VersionedSlate::V0(s) @@ -73,8 +75,8 @@ impl VersionedSlate { impl From for Slate { fn from(slate: VersionedSlate) -> Slate { match slate { - VersionedSlate::V2(s) => { - let s = SlateV2::from(s); + VersionedSlate::V3(s) => { + let s = SlateV3::from(s); Slate::from(s) } // Again, left in as a reminder /*VersionedSlate::V0(s) => { @@ -93,14 +95,14 @@ impl From for Slate { /// deserialize newer versions first, then falls back to older versions. pub enum VersionedCoinbase { /// Current supported coinbase version. - V2(CoinbaseV2), + V3(CoinbaseV3), } impl VersionedCoinbase { /// convert this coinbase data to a specific versioned representation for the json api. pub fn into_version(cb: CbData, version: SlateVersion) -> VersionedCoinbase { match version { - SlateVersion::V2 => VersionedCoinbase::V2(cb.into()), + SlateVersion::V3 => VersionedCoinbase::V3(cb.into()), } } } diff --git a/libwallet/src/slate_versions/ser.rs b/libwallet/src/slate_versions/ser.rs new file mode 100644 index 00000000..7b54cddb --- /dev/null +++ b/libwallet/src/slate_versions/ser.rs @@ -0,0 +1,132 @@ +// Copyright 2019 The Grin Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Sane serialization & deserialization of cryptographic structs into hex + +/// Serializes an ed25519 PublicKey to and from hex +pub mod dalek_pubkey_serde { + use crate::grin_util::{from_hex, to_hex}; + use ed25519_dalek::PublicKey as DalekPublicKey; + use serde::{Deserialize, Deserializer, Serializer}; + + /// + pub fn serialize(key: &DalekPublicKey, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&to_hex(key.to_bytes().to_vec())) + } + + /// + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + String::deserialize(deserializer) + .and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string()))) + .and_then(|bytes: Vec| { + DalekPublicKey::from_bytes(&bytes).map_err(|err| Error::custom(err.to_string())) + }) + } +} + +/// Serializes an Option to and from hex +pub mod option_dalek_pubkey_serde { + use ed25519_dalek::PublicKey as DalekPublicKey; + use serde::de::Error; + use serde::{Deserialize, Deserializer, Serializer}; + + use crate::grin_util::{from_hex, to_hex}; + + /// + pub fn serialize(key: &Option, serializer: S) -> Result + where + S: Serializer, + { + match key { + Some(key) => serializer.serialize_str(&to_hex(key.to_bytes().to_vec())), + None => serializer.serialize_none(), + } + } + + /// + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + Option::::deserialize(deserializer).and_then(|res| match res { + Some(string) => from_hex(string.to_string()) + .map_err(|err| Error::custom(err.to_string())) + .and_then(|bytes: Vec| { + let mut b = [0u8; 32]; + b.copy_from_slice(&bytes[0..32]); + DalekPublicKey::from_bytes(&b) + .map(|val| Some(val)) + .map_err(|err| Error::custom(err.to_string())) + }), + None => Ok(None), + }) + } +} +// Test serialization methods of components that are being used +#[cfg(test)] +mod test { + use super::*; + use rand::rngs::mock::StepRng; + + use crate::grin_util::{secp, static_secp_instance}; + use ed25519_dalek::PublicKey as DalekPublicKey; + use ed25519_dalek::SecretKey as DalekSecretKey; + use serde::Deserialize; + + use serde_json; + + #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] + struct SerTest { + #[serde(with = "dalek_pubkey_serde")] + pub pub_key: DalekPublicKey, + #[serde(with = "option_dalek_pubkey_serde")] + pub pub_key_opt: Option, + } + + impl SerTest { + pub fn random() -> SerTest { + let secp_inst = static_secp_instance(); + let secp = secp_inst.lock(); + let mut test_rng = StepRng::new(1234567890u64, 1); + let sec_key = secp::key::SecretKey::new(&secp, &mut test_rng); + let d_skey = DalekSecretKey::from_bytes(&sec_key.0).unwrap(); + let d_pub_key: DalekPublicKey = (&d_skey).into(); + SerTest { + pub_key: d_pub_key.clone(), + pub_key_opt: Some(d_pub_key), + } + } + } + + #[test] + fn ser_dalek_primitives() { + for _ in 0..10 { + let s = SerTest::random(); + println!("Before Serialization: {:?}", s); + let serialized = serde_json::to_string_pretty(&s).unwrap(); + println!("JSON: {}", serialized); + let deserialized: SerTest = serde_json::from_str(&serialized).unwrap(); + println!("After Serialization: {:?}", deserialized); + println!(); + assert_eq!(s, deserialized); + } + } +} diff --git a/libwallet/src/slate_versions/v2.rs b/libwallet/src/slate_versions/v3.rs similarity index 78% rename from libwallet/src/slate_versions/v2.rs rename to libwallet/src/slate_versions/v3.rs index 12ace67f..b158162b 100644 --- a/libwallet/src/slate_versions/v2.rs +++ b/libwallet/src/slate_versions/v3.rs @@ -12,28 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Contains V2 of the slate (grin-wallet 1.1.0) -//! Changes from V1: -//! * ParticipantData struct fields serialized as hex strings instead of arrays: -//! * public_blind_excess -//! * public_nonce -//! * part_sig -//! * message_sig -//! * Transaction fields serialized as hex strings instead of arrays: -//! * offset -//! * Input field serialized as hex strings instead of arrays: -//! commit -//! * Output fields serialized as hex strings instead of arrays: -//! commit -//! proof -//! * TxKernel fields serialized as hex strings instead of arrays: -//! commit -//! signature -//! * version field removed -//! * VersionCompatInfo struct created with fields and added to beginning of struct -//! version: u16 -//! orig_version: u16, -//! block_header_version: u16, +//! Contains V3 of the slate (grin-wallet 3.0.0) +//! Changes from V2: +//! * Addition of payment_proof (PaymentInfo struct) +//! * Addition of a u64 ttl_cutoff_height field use crate::grin_core::core::transaction::OutputFeatures; use crate::grin_core::libtx::secp_ser; @@ -43,19 +25,21 @@ use crate::grin_util::secp::key::PublicKey; use crate::grin_util::secp::pedersen::{Commitment, RangeProof}; use crate::grin_util::secp::Signature; use crate::slate::CompatKernelFeatures; +use crate::slate_versions::ser as dalek_ser; +use ed25519_dalek::PublicKey as DalekPublicKey; use uuid::Uuid; #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SlateV2 { +pub struct SlateV3 { /// Versioning info - pub version_info: VersionCompatInfoV2, + pub version_info: VersionCompatInfoV3, /// The number of participants intended to take part in this transaction pub num_participants: usize, /// Unique transaction ID, selected by sender pub id: Uuid, /// The core transaction data: /// inputs, outputs, kernels, kernel offset - pub tx: TransactionV2, + pub tx: TransactionV3, /// base amount (excluding fee) #[serde(with = "secp_ser::string_or_u64")] pub amount: u64, @@ -68,14 +52,26 @@ pub struct SlateV2 { /// Lock height #[serde(with = "secp_ser::string_or_u64")] pub lock_height: u64, + /// TTL, the block height at which wallets + /// should refuse to process the transaction and unlock all + /// associated outputs + #[serde(with = "secp_ser::string_or_u64")] + pub ttl_cutoff_height: u64, /// Participant data, each participant in the transaction will /// insert their public data here. For now, 0 is sender and 1 /// is receiver, though this will change for multi-party - pub participant_data: Vec, + pub participant_data: Vec, + /// Payment Proof + #[serde(default = "default_payment_none")] + pub payment_proof: Option, +} + +fn default_payment_none() -> Option { + None } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct VersionCompatInfoV2 { +pub struct VersionCompatInfoV3 { /// The current version of the slate format pub version: u16, /// Original version this slate was converted from @@ -85,7 +81,7 @@ pub struct VersionCompatInfoV2 { } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct ParticipantDataV2 { +pub struct ParticipantDataV3 { /// Id of participant in the transaction. (For now, 0=sender, 1=rec) #[serde(with = "secp_ser::string_or_u64")] pub id: u64, @@ -105,9 +101,19 @@ pub struct ParticipantDataV2 { pub message_sig: Option, } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PaymentInfoV3 { + #[serde(with = "dalek_ser::dalek_pubkey_serde")] + pub sender_address: DalekPublicKey, + #[serde(with = "dalek_ser::option_dalek_pubkey_serde")] + pub receiver_address: Option, + #[serde(with = "secp_ser::option_sig_serde")] + pub receiver_signature: Option, +} + /// A transaction #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct TransactionV2 { +pub struct TransactionV3 { /// The kernel "offset" k2 /// excess is k1G after splitting the key k = k1 + k2 #[serde( @@ -116,21 +122,21 @@ pub struct TransactionV2 { )] pub offset: BlindingFactor, /// The transaction body - inputs/outputs/kernels - pub body: TransactionBodyV2, + pub body: TransactionBodyV3, } /// TransactionBody is a common abstraction for transaction and block #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct TransactionBodyV2 { +pub struct TransactionBodyV3 { /// List of inputs spent by the transaction. - pub inputs: Vec, + pub inputs: Vec, /// List of outputs the transaction produces. - pub outputs: Vec, + pub outputs: Vec, /// List of kernels that make up this transaction (usually a single kernel). - pub kernels: Vec, + pub kernels: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct InputV2 { +pub struct InputV3 { /// The features of the output being spent. /// We will check maturity for coinbase output. pub features: OutputFeatures, @@ -143,7 +149,7 @@ pub struct InputV2 { } #[derive(Debug, Copy, Clone, Serialize, Deserialize)] -pub struct OutputV2 { +pub struct OutputV3 { /// Options for an output's structure or use pub features: OutputFeatures, /// The homomorphic commitment representing the output amount @@ -161,7 +167,7 @@ pub struct OutputV2 { } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct TxKernelV2 { +pub struct TxKernelV3 { /// Options for a kernel's structure or use pub features: CompatKernelFeatures, /// Fee originally included in the transaction this proof is for. @@ -187,11 +193,11 @@ pub struct TxKernelV2 { /// A mining node requests new coinbase via the foreign api every time a new candidate block is built. #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CoinbaseV2 { +pub struct CoinbaseV3 { /// Output - pub output: OutputV2, + pub output: OutputV3, /// Kernel - pub kernel: TxKernelV2, + pub kernel: TxKernelV3, /// Key Id pub key_id: Option, } diff --git a/tests/owner_v3_lifecycle.rs b/tests/owner_v3_lifecycle.rs index f1733a88..f0a52d46 100644 --- a/tests/owner_v3_lifecycle.rs +++ b/tests/owner_v3_lifecycle.rs @@ -364,7 +364,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { "id": 1, "method": "finalize_invoice_tx", "params": { - "slate": VersionedSlate::into_version(slate, SlateVersion::V2), + "slate": VersionedSlate::into_version(slate, SlateVersion::V3), } }); let res =