diff --git a/Cargo.lock b/Cargo.lock index 3e6508d3..9d82b600 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -418,7 +418,7 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -462,7 +462,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -553,7 +553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "grin_api" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#c3496b45dd2704b6d542dad3447e8649d25399e4" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -607,7 +607,7 @@ dependencies = [ [[package]] name = "grin_chain" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#c3496b45dd2704b6d542dad3447e8649d25399e4" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -630,7 +630,7 @@ dependencies = [ [[package]] name = "grin_core" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#c3496b45dd2704b6d542dad3447e8649d25399e4" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -656,7 +656,7 @@ dependencies = [ [[package]] name = "grin_keychain" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#c3496b45dd2704b6d542dad3447e8649d25399e4" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -699,7 +699,7 @@ dependencies = [ [[package]] name = "grin_p2p" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#c3496b45dd2704b6d542dad3447e8649d25399e4" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -719,7 +719,7 @@ dependencies = [ [[package]] name = "grin_pool" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#c3496b45dd2704b6d542dad3447e8649d25399e4" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -786,7 +786,7 @@ dependencies = [ [[package]] name = "grin_store" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#c3496b45dd2704b6d542dad3447e8649d25399e4" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "croaring 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -806,7 +806,7 @@ dependencies = [ [[package]] name = "grin_util" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#c3496b45dd2704b6d542dad3447e8649d25399e4" dependencies = [ "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1991,7 +1991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2071,7 +2071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.27" +version = "0.15.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2086,7 +2086,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2860,7 +2860,7 @@ dependencies = [ "checksum string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b639411d0b9c738748b5397d5ceba08e648f4f1992231aa859af1a017f31f60b" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum supercow 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "171758edb47aa306a78dfa4ab9aeb5167405bd4e3dc2b64e88f6a84bbe98bd63" -"checksum syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)" = "525bd55255f03c816e5d7f615587bd13030c7103354fadb104993dcee6a788ec" +"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" diff --git a/apiwallet/src/api.rs b/apiwallet/src/api.rs index 8f6307e9..d75c42cd 100644 --- a/apiwallet/src/api.rs +++ b/apiwallet/src/api.rs @@ -270,6 +270,11 @@ pub trait OwnerApi { "jsonrpc": "2.0", "method": "finalize_tx", "params": [{ + "version_info": { + "version": 2, + "orig_version": 2, + "min_compat_version": 0 + }, "amount": 0, "fee": 0, "height": 0, @@ -284,8 +289,7 @@ pub trait OwnerApi { "outputs": [] }, "offset": "0000000000000000000000000000000000000000000000000000000000000000" - }, - "version": 1 + } }], "id": 1 }, @@ -416,6 +420,11 @@ pub trait OwnerApi { "jsonrpc": "2.0", "method": "verify_slate_messages", "params": [{ + "version_info": { + "version": 2, + "orig_version": 2, + "min_compat_version": 0 + }, "amount": 0, "fee": 0, "height": 0, @@ -430,8 +439,7 @@ pub trait OwnerApi { "outputs": [] }, "offset": "0000000000000000000000000000000000000000000000000000000000000000" - }, - "version": 1 + } }], "id": 1 }, @@ -1103,6 +1111,7 @@ where num_change_outputs: usize, selection_strategy_is_use_all: bool, message: Option, + target_slate_version: Option, ) -> Result<(Slate, OutputLockFn), Error> { let mut w = self.wallet.lock(); w.open_with_credentials()?; @@ -1148,6 +1157,10 @@ where } w.close()?; + // set target slate version + if let Some(v) = target_slate_version { + slate.version_info.orig_version = v; + } Ok((slate, lock_fn)) } @@ -1502,6 +1515,11 @@ pub trait ForeignApi { "method": "verify_slate_messages", "params": [ { + "version_info": { + "version": 2, + "orig_version": 2, + "min_compat_version": 0 + }, "amount": 0, "fee": 0, "height": 0, @@ -1516,8 +1534,7 @@ pub trait ForeignApi { "outputs": [] }, "offset": "0000000000000000000000000000000000000000000000000000000000000000" - }, - "version": 1 + } } ], "id": 1 @@ -1539,13 +1556,18 @@ pub trait ForeignApi { # Json rpc example - ``` + ```ignore //TODO: No idea why this isn't expanding properly, check as we adjust the API # grin_apiwallet::doctest_helper_json_rpc_foreign_assert_response!( { "jsonrpc": "2.0", "method": "receive_tx", "params": [ { + "version_info": { + "version": 2, + "orig_version": 2, + "min_compat_version": 0 + }, "amount": 0, "fee": 0, "height": 0, @@ -1560,8 +1582,7 @@ pub trait ForeignApi { "outputs": [] }, "offset": "0000000000000000000000000000000000000000000000000000000000000000" - }, - "version": 1 + } }, null, null diff --git a/libwallet/src/error.rs b/libwallet/src/error.rs index b7855a1f..4e450a4e 100644 --- a/libwallet/src/error.rs +++ b/libwallet/src/error.rs @@ -176,6 +176,18 @@ pub enum ErrorKind { #[fail(display = "Committed Error")] Committed(committed::Error), + /// Can't parse slate version + #[fail(display = "Can't parse slate version")] + SlateVersionParse, + + /// Can't deserialize slate + #[fail(display = "Can't Deserialize slate")] + SlateDeser, + + /// Unknown slate version + #[fail(display = "Unknown Slate Version: {}", _0)] + SlateVersion(u16), + /// Other #[fail(display = "Generic error: {}", _0)] GenericError(String), diff --git a/libwallet/src/slate.rs b/libwallet/src/slate.rs index 23124853..289fc1ee 100644 --- a/libwallet/src/slate.rs +++ b/libwallet/src/slate.rs @@ -18,7 +18,6 @@ use crate::blake2::blake2b::blake2b; use crate::error::{Error, ErrorKind}; use crate::keychain::{BlindSum, BlindingFactor, Keychain}; -use crate::slate_versions::v0::SlateV0; use crate::util::secp; use crate::util::secp::key::{PublicKey, SecretKey}; use crate::util::secp::Signature; @@ -31,27 +30,14 @@ use grin_core::libtx::{aggsig, build, secp_ser, tx_fee}; use rand::thread_rng; use std::sync::Arc; use uuid::Uuid; +use failure::ResultExt; +use serde_json; -const CURRENT_SLATE_VERSION: u64 = 1; +use crate::slate_versions::v0::SlateV0; +use crate::slate_versions::v1::SlateV1; +use crate::slate_versions::v2::SlateV2; -/// A wrapper around slates the enables support for versioning -#[derive(Serialize, Deserialize, Clone)] -#[serde(untagged)] -pub enum VersionedSlate { - /// Pre versioning version - V0(SlateV0), - /// Version 1 with versioning and hex serialization - current - V1(Slate), -} - -impl From for Slate { - fn from(ver: VersionedSlate) -> Self { - match ver { - VersionedSlate::V0(slate_v0) => Slate::from(slate_v0), - VersionedSlate::V1(slate) => slate, - } - } -} +const CURRENT_SLATE_VERSION: u16 = 2; /// Public data for each participant in the slate @@ -126,6 +112,8 @@ impl ParticipantMessageData { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Slate { + /// Versioning info + pub version_info: VersionCompatInfo, /// The number of participants intended to take part in this transaction pub num_participants: usize, /// Unique transaction ID, selected by sender @@ -145,13 +133,17 @@ pub struct Slate { /// 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, - /// Slate format version - #[serde(default = "no_version")] - pub version: u64, } -fn no_version() -> u64 { - 0 +/// Versioning and compatibility info about this slate +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct VersionCompatInfo { + /// The current version of the slate format + pub version: u16, + /// Original version this slate was converted from + pub orig_version: u16, + /// Minimum version this slate is compatible with + pub min_compat_version: u16, } /// Helper just to facilitate serialization @@ -162,6 +154,71 @@ pub struct ParticipantMessages { } impl Slate { + // TODO: Reduce the number of changes that need to occur below for each new + // slate version + fn parse_slate_version(slate_json: &str) -> Result { + // keep attempting to deser, working through known versions until we have + // enough to get the version out + let res : Result = serde_json::from_str(slate_json); + if let Ok(s) = res { + return Ok(s.version_info.version); + } + let res : Result = serde_json::from_str(slate_json); + if let Ok(s) = res { + return Ok(s.version as u16); + } + let res : Result = serde_json::from_str(slate_json); + if let Ok(_) = res { + return Ok(0); + } + Err(ErrorKind::SlateVersionParse)? + } + + /// 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 = match version { + 2 => serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?, + 1 => { + let mut v1 : SlateV1 = serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?; + v1.orig_version = 1; + SlateV2::from(v1) + } + 0 => { + let v0 : SlateV0 = serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?; + let v1 = SlateV1::from(v0); + SlateV2::from(v1) + } + _ => return Err(ErrorKind::SlateVersion(version))?, + }; + let f = serde_json::to_string(&v2).context(ErrorKind::SlateDeser)?; + Ok(serde_json::from_str(&f).context(ErrorKind::SlateDeser)?) + } + + /// Downgrate slate to desired version + pub fn serialize_to_version(&self, version: Option) -> Result { + let version = match version { + Some(v) => v, + None => CURRENT_SLATE_VERSION, + }; + let ser_self = serde_json::to_string(&self).context(ErrorKind::SlateDeser)?; + match version { + 2 => Ok(ser_self.clone()), + 1 => { + let v2 : SlateV2 = serde_json::from_str(&ser_self).context(ErrorKind::SlateDeser)?; + let v1 = SlateV1::from(v2); + Ok(serde_json::to_string(&v1).context(ErrorKind::SlateDeser)?) + } + 0 => { + let v2 : SlateV2 = serde_json::from_str(&ser_self).context(ErrorKind::SlateDeser)?; + let v1 = SlateV1::from(v2); + let v0 = SlateV0::from(v1); + Ok(serde_json::to_string(&v0).context(ErrorKind::SlateDeser)?) + } + _ => Err(ErrorKind::SlateVersion(version))?, + } + } + /// Create a new slate pub fn blank(num_participants: usize) -> Slate { Slate { @@ -173,7 +230,11 @@ impl Slate { height: 0, lock_height: 0, participant_data: vec![], - version: CURRENT_SLATE_VERSION, + version_info: VersionCompatInfo { + version: CURRENT_SLATE_VERSION, + orig_version: CURRENT_SLATE_VERSION, + min_compat_version: 0, + }, } } diff --git a/libwallet/src/slate_versions/mod.rs b/libwallet/src/slate_versions/mod.rs index 03b4709f..5aaf1796 100644 --- a/libwallet/src/slate_versions/mod.rs +++ b/libwallet/src/slate_versions/mod.rs @@ -16,3 +16,7 @@ //! Used for serialization and deserialization of slates in a backwards compatible way. #[allow(missing_docs)] pub mod v0; +#[allow(missing_docs)] +pub mod v1; +#[allow(missing_docs)] +pub mod v2; diff --git a/libwallet/src/slate_versions/v0.rs b/libwallet/src/slate_versions/v0.rs index 7757085c..e622ef48 100644 --- a/libwallet/src/slate_versions/v0.rs +++ b/libwallet/src/slate_versions/v0.rs @@ -12,18 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Contains V0 of the slate +//! Contains V0 of the slate (grin 1.0.0) +//! And methods to downgrade v1 to v0 use crate::core::core::transaction::{ - Input, KernelFeatures, Output, OutputFeatures, Transaction, TransactionBody, TxKernel, + KernelFeatures, OutputFeatures, }; use crate::keychain::BlindingFactor; -use crate::slate::{ParticipantData, Slate}; use crate::util::secp; use crate::util::secp::key::PublicKey; use crate::util::secp::pedersen::{Commitment, RangeProof}; use crate::util::secp::Signature; use uuid::Uuid; + #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SlateV0 { /// The number of participants intended to take part in this transaction @@ -119,252 +120,3 @@ pub struct TxKernelV0 { /// the transaction fee. pub excess_sig: secp::Signature, } - -impl From for Slate { - fn from(slate: SlateV0) -> Slate { - let SlateV0 { - num_participants, - id, - tx, - amount, - fee, - height, - lock_height, - participant_data, - } = slate; - let tx = Transaction::from(tx); - let participant_data = map_vec!(participant_data, |data| ParticipantData::from(data)); - let version = 0; - Slate { - num_participants, - id, - tx, - amount, - fee, - height, - lock_height, - participant_data, - version, - } - } -} - -impl From<&ParticipantDataV0> for ParticipantData { - fn from(data: &ParticipantDataV0) -> ParticipantData { - let ParticipantDataV0 { - id, - public_blind_excess, - public_nonce, - part_sig, - message, - message_sig, - } = data; - let id = *id; - let public_blind_excess = *public_blind_excess; - let public_nonce = *public_nonce; - let part_sig = *part_sig; - let message: Option = message.as_ref().map(|t| String::from(&**t)); - let message_sig = *message_sig; - ParticipantData { - id, - public_blind_excess, - public_nonce, - part_sig, - message, - message_sig, - } - } -} - -impl From for Transaction { - fn from(tx: TransactionV0) -> Transaction { - let TransactionV0 { offset, body } = tx; - let body = TransactionBody::from(&body); - let transaction = Transaction::new(body.inputs, body.outputs, body.kernels); - transaction.with_offset(offset) - } -} - -impl From<&TransactionBodyV0> for TransactionBody { - fn from(body: &TransactionBodyV0) -> Self { - let TransactionBodyV0 { - inputs, - outputs, - kernels, - } = body; - - let inputs = map_vec!(inputs, |inp| Input::from(inp)); - let outputs = map_vec!(outputs, |out| Output::from(out)); - let kernels = map_vec!(kernels, |kern| TxKernel::from(kern)); - TransactionBody { - inputs, - outputs, - kernels, - } - } -} - -impl From<&InputV0> for Input { - fn from(input: &InputV0) -> Input { - let InputV0 { features, commit } = *input; - Input { features, commit } - } -} - -impl From<&OutputV0> for Output { - fn from(output: &OutputV0) -> Output { - let OutputV0 { - features, - commit, - proof, - } = *output; - Output { - features, - commit, - proof, - } - } -} - -impl From<&TxKernelV0> for TxKernel { - fn from(kernel: &TxKernelV0) -> TxKernel { - let TxKernelV0 { - features, - fee, - lock_height, - excess, - excess_sig, - } = *kernel; - TxKernel { - features, - fee, - lock_height, - excess, - excess_sig, - } - } -} - -impl From for SlateV0 { - fn from(slate: Slate) -> SlateV0 { - let Slate { - num_participants, - id, - tx, - amount, - fee, - height, - lock_height, - participant_data, - version: _, - } = slate; - let tx = TransactionV0::from(tx); - let participant_data = map_vec!(participant_data, |data| ParticipantDataV0::from(data)); - SlateV0 { - num_participants, - id, - tx, - amount, - fee, - height, - lock_height, - participant_data, - } - } -} - -impl From<&ParticipantData> for ParticipantDataV0 { - fn from(data: &ParticipantData) -> ParticipantDataV0 { - let ParticipantData { - id, - public_blind_excess, - public_nonce, - part_sig, - message, - message_sig, - } = data; - let id = *id; - let public_blind_excess = *public_blind_excess; - let public_nonce = *public_nonce; - let part_sig = *part_sig; - let message: Option = message.as_ref().map(|t| String::from(&**t)); - let message_sig = *message_sig; - ParticipantDataV0 { - id, - public_blind_excess, - public_nonce, - part_sig, - message, - message_sig, - } - } -} - -impl From for TransactionV0 { - fn from(tx: Transaction) -> TransactionV0 { - let offset = tx.offset; - let body: TransactionBody = tx.into(); - let body = TransactionBodyV0::from(&body); - TransactionV0 { offset, body } - } -} - -impl From<&TransactionBody> for TransactionBodyV0 { - fn from(body: &TransactionBody) -> Self { - let TransactionBody { - inputs, - outputs, - kernels, - } = body; - - let inputs = map_vec!(inputs, |inp| InputV0::from(inp)); - let outputs = map_vec!(outputs, |out| OutputV0::from(out)); - let kernels = map_vec!(kernels, |kern| TxKernelV0::from(kern)); - TransactionBodyV0 { - inputs, - outputs, - kernels, - } - } -} - -impl From<&Input> for InputV0 { - fn from(input: &Input) -> Self { - let Input { features, commit } = *input; - InputV0 { features, commit } - } -} - -impl From<&Output> for OutputV0 { - fn from(output: &Output) -> Self { - let Output { - features, - commit, - proof, - } = *output; - OutputV0 { - features, - commit, - proof, - } - } -} - -impl From<&TxKernel> for TxKernelV0 { - fn from(kernel: &TxKernel) -> Self { - let TxKernel { - features, - fee, - lock_height, - excess, - excess_sig, - } = *kernel; - TxKernelV0 { - features, - fee, - lock_height, - excess, - excess_sig, - } - } -} diff --git a/libwallet/src/slate_versions/v1.rs b/libwallet/src/slate_versions/v1.rs new file mode 100644 index 00000000..206d0e76 --- /dev/null +++ b/libwallet/src/slate_versions/v1.rs @@ -0,0 +1,391 @@ +// Copyright 2018 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. + + +//! Contains V1 of the slate (grin 1.0.1, 1.0.2) +//! Changes from V0: +//! * Addition of a version field to Slate struct + +use crate::core::core::transaction::{ + KernelFeatures, OutputFeatures, +}; +use crate::keychain::BlindingFactor; +use crate::util::secp; +use crate::util::secp::key::PublicKey; +use crate::util::secp::pedersen::{Commitment, RangeProof}; +use crate::util::secp::Signature; +use uuid::Uuid; + +use crate::slate_versions::v0::{SlateV0, TransactionV0, TransactionBodyV0, InputV0, OutputV0,TxKernelV0, ParticipantDataV0}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SlateV1 { + /// 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: TransactionV1, + /// base amount (excluding fee) + pub amount: u64, + /// fee amount + pub fee: u64, + /// Block height for the transaction + pub height: u64, + /// Lock height + pub lock_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, + /// Version + pub version: u64, + #[serde(skip)] + pub orig_version: u64, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ParticipantDataV1 { + /// Id of participant in the transaction. (For now, 0=sender, 1=rec) + pub id: u64, + /// Public key corresponding to private blinding factor + pub public_blind_excess: PublicKey, + /// Public key corresponding to private nonce + pub public_nonce: PublicKey, + /// Public partial signature + pub part_sig: Option, + /// A message for other participants + pub message: Option, + /// Signature, created with private key corresponding to 'public_blind_excess' + pub message_sig: Option, +} + +/// A transaction +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TransactionV1 { + /// The kernel "offset" k2 + /// excess is k1G after splitting the key k = k1 + k2 + pub offset: BlindingFactor, + /// The transaction body - inputs/outputs/kernels + pub body: TransactionBodyV1, +} + +/// TransactionBody is a common abstraction for transaction and block +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TransactionBodyV1 { + /// List of inputs spent by the transaction. + pub inputs: Vec, + /// List of outputs the transaction produces. + pub outputs: Vec, + /// List of kernels that make up this transaction (usually a single kernel). + pub kernels: Vec, +} +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct InputV1 { + /// The features of the output being spent. + /// We will check maturity for coinbase output. + pub features: OutputFeatures, + /// The commit referencing the output being spent. + pub commit: Commitment, +} + +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub struct OutputV1 { + /// Options for an output's structure or use + pub features: OutputFeatures, + /// The homomorphic commitment representing the output amount + pub commit: Commitment, + /// A proof that the commitment is in the right range + pub proof: RangeProof, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TxKernelV1 { + /// Options for a kernel's structure or use + pub features: KernelFeatures, + /// Fee originally included in the transaction this proof is for. + pub fee: u64, + /// This kernel is not valid earlier than lock_height blocks + /// The max lock_height of all *inputs* to this transaction + pub lock_height: u64, + /// Remainder of the sum of all transaction commitments. If the transaction + /// is well formed, amounts components should sum to zero and the excess + /// is hence a valid public key. + pub excess: Commitment, + /// The signature proving the excess is a valid public key, which signs + /// the transaction fee. + pub excess_sig: secp::Signature, +} + +// V1 to V0 Downgrade Conversion //////////////////////////////////// + +impl From for SlateV0 { + fn from(slate: SlateV1) -> SlateV0 { + let SlateV1 { + num_participants, + id, + tx, + amount, + fee, + height, + lock_height, + participant_data, + version: _, + orig_version: _, + } = slate; + let tx = TransactionV0::from(tx); + let participant_data = map_vec!(participant_data, |data| ParticipantDataV0::from(data)); + SlateV0 { + num_participants, + id, + tx, + amount, + fee, + height, + lock_height, + participant_data, + } + } +} + +impl From<&ParticipantDataV1> for ParticipantDataV0 { + fn from(data: &ParticipantDataV1) -> ParticipantDataV0 { + let ParticipantDataV1 { + id, + public_blind_excess, + public_nonce, + part_sig, + message, + message_sig, + } = data; + let id = *id; + let public_blind_excess = *public_blind_excess; + let public_nonce = *public_nonce; + let part_sig = *part_sig; + let message: Option = message.as_ref().map(|t| String::from(&**t)); + let message_sig = *message_sig; + ParticipantDataV0 { + id, + public_blind_excess, + public_nonce, + part_sig, + message, + message_sig, + } + } +} + +impl From for TransactionV0 { + fn from(tx: TransactionV1) -> TransactionV0 { + let TransactionV1 { offset, body } = tx; + let body = TransactionBodyV0::from(&body); + TransactionV0 { + offset, + body, + } + } +} + +impl From<&TransactionBodyV1> for TransactionBodyV0 { + fn from(body: &TransactionBodyV1) -> Self { + let TransactionBodyV1 { + inputs, + outputs, + kernels, + } = body; + + let inputs = map_vec!(inputs, |inp| InputV0::from(inp)); + let outputs = map_vec!(outputs, |out| OutputV0::from(out)); + let kernels = map_vec!(kernels, |kern| TxKernelV0::from(kern)); + TransactionBodyV0 { + inputs, + outputs, + kernels, + } + } +} + +impl From<&InputV1> for InputV0 { + fn from(input: &InputV1) -> InputV0 { + let InputV1 { features, commit } = *input; + InputV0 { features, commit } + } +} + +impl From<&OutputV1> for OutputV0 { + fn from(output: &OutputV1) -> OutputV0 { + let OutputV1 { + features, + commit, + proof, + } = *output; + OutputV0 { + features, + commit, + proof, + } + } +} + +impl From<&TxKernelV1> for TxKernelV0 { + fn from(kernel: &TxKernelV1) -> TxKernelV0 { + let TxKernelV1 { + features, + fee, + lock_height, + excess, + excess_sig, + } = *kernel; + TxKernelV0 { + features, + fee, + lock_height, + excess, + excess_sig, + } + } +} + +// V0 to V1 Upgrade Conversion //////////////////////////////////// + +impl From for SlateV1 { + fn from(slate: SlateV0) -> SlateV1 { + let SlateV0 { + num_participants, + id, + tx, + amount, + fee, + height, + lock_height, + participant_data, + } = slate; + let tx = TransactionV1::from(tx); + let participant_data = map_vec!(participant_data, |data| ParticipantDataV1::from(data)); + SlateV1 { + num_participants, + id, + tx, + amount, + fee, + height, + lock_height, + participant_data, + version: 1, + orig_version: 0, + } + } +} + +impl From<&ParticipantDataV0> for ParticipantDataV1 { + fn from(data: &ParticipantDataV0) -> ParticipantDataV1 { + let ParticipantDataV0 { + id, + public_blind_excess, + public_nonce, + part_sig, + message, + message_sig, + } = data; + let id = *id; + let public_blind_excess = *public_blind_excess; + let public_nonce = *public_nonce; + let part_sig = *part_sig; + let message: Option = message.as_ref().map(|t| String::from(&**t)); + let message_sig = *message_sig; + ParticipantDataV1 { + id, + public_blind_excess, + public_nonce, + part_sig, + message, + message_sig, + } + } +} + +impl From for TransactionV1 { + fn from(tx: TransactionV0) -> TransactionV1 { + let TransactionV0 { offset, body } = tx; + let body = TransactionBodyV1::from(&body); + TransactionV1 { + offset, + body, + } + } +} + +impl From<&TransactionBodyV0> for TransactionBodyV1 { + fn from(body: &TransactionBodyV0) -> Self { + let TransactionBodyV0 { + inputs, + outputs, + kernels, + } = body; + + let inputs = map_vec!(inputs, |inp| InputV1::from(inp)); + let outputs = map_vec!(outputs, |out| OutputV1::from(out)); + let kernels = map_vec!(kernels, |kern| TxKernelV1::from(kern)); + TransactionBodyV1 { + inputs, + outputs, + kernels, + } + } +} + +impl From<&InputV0> for InputV1 { + fn from(input: &InputV0) -> InputV1 { + let InputV0 { features, commit } = *input; + InputV1 { features, commit } + } +} + +impl From<&OutputV0> for OutputV1 { + fn from(output: &OutputV0) -> OutputV1 { + let OutputV0 { + features, + commit, + proof, + } = *output; + OutputV1 { + features, + commit, + proof, + } + } +} + +impl From<&TxKernelV0> for TxKernelV1 { + fn from(kernel: &TxKernelV0) -> TxKernelV1 { + let TxKernelV0 { + features, + fee, + lock_height, + excess, + excess_sig, + } = *kernel; + TxKernelV1 { + features, + fee, + lock_height, + excess, + excess_sig, + } + } +} + + + diff --git a/libwallet/src/slate_versions/v2.rs b/libwallet/src/slate_versions/v2.rs new file mode 100644 index 00000000..2750095b --- /dev/null +++ b/libwallet/src/slate_versions/v2.rs @@ -0,0 +1,460 @@ +// Copyright 2018 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. + + +//! 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_info field removed +//! * VersionCompatInfo struct created with fields and added to beginning of struct +//! version: u16 +//! orig_verion: u16, +//! min_compat_version: u16 + +use crate::core::core::transaction::{ + KernelFeatures, OutputFeatures, +}; + +use crate::keychain::BlindingFactor; +use crate::util::secp; +use crate::util::secp::key::PublicKey; +use crate::util::secp::pedersen::{Commitment, RangeProof}; +use crate::util::secp::Signature; +use crate::core::libtx::secp_ser; +use uuid::Uuid; + +use crate::slate_versions::v1::{SlateV1, TransactionV1, TransactionBodyV1, InputV1, OutputV1,TxKernelV1, ParticipantDataV1}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SlateV2 { + /// Versioning info + pub version_info: VersionCompatInfoV2, + /// 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, + /// base amount (excluding fee) + pub amount: u64, + /// fee amount + pub fee: u64, + /// Block height for the transaction + pub height: u64, + /// Lock height + pub lock_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, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct VersionCompatInfoV2 { + /// The current version of the slate format + pub version: u16, + /// Original version this slate was converted from + pub orig_version: u16, + /// Minimum version this slate is compatible with + pub min_compat_version: u16, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ParticipantDataV2 { + /// Id of participant in the transaction. (For now, 0=sender, 1=rec) + pub id: u64, + /// Public key corresponding to private blinding factor + #[serde(with = "secp_ser::pubkey_serde")] + pub public_blind_excess: PublicKey, + /// Public key corresponding to private nonce + #[serde(with = "secp_ser::pubkey_serde")] + pub public_nonce: PublicKey, + /// Public partial signature + #[serde(with = "secp_ser::option_sig_serde")] + pub part_sig: Option, + /// A message for other participants + pub message: Option, + /// Signature, created with private key corresponding to 'public_blind_excess' + #[serde(with = "secp_ser::option_sig_serde")] + pub message_sig: Option, +} + +/// A transaction +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TransactionV2 { + /// The kernel "offset" k2 + /// excess is k1G after splitting the key k = k1 + k2 + #[serde( + serialize_with = "secp_ser::as_hex", + deserialize_with = "secp_ser::blind_from_hex" + )] + pub offset: BlindingFactor, + /// The transaction body - inputs/outputs/kernels + pub body: TransactionBodyV2, +} + +/// TransactionBody is a common abstraction for transaction and block +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TransactionBodyV2 { + /// List of inputs spent by the transaction. + pub inputs: Vec, + /// List of outputs the transaction produces. + pub outputs: Vec, + /// List of kernels that make up this transaction (usually a single kernel). + pub kernels: Vec, +} +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct InputV2 { + /// The features of the output being spent. + /// We will check maturity for coinbase output. + pub features: OutputFeatures, + /// The commit referencing the output being spent. + #[serde( + serialize_with = "secp_ser::as_hex", + deserialize_with = "secp_ser::commitment_from_hex" + )] + pub commit: Commitment, +} + +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub struct OutputV2 { + /// Options for an output's structure or use + pub features: OutputFeatures, + /// The homomorphic commitment representing the output amount + #[serde( + serialize_with = "secp_ser::as_hex", + deserialize_with = "secp_ser::commitment_from_hex" + )] + pub commit: Commitment, + /// A proof that the commitment is in the right range + #[serde( + serialize_with = "secp_ser::as_hex", + deserialize_with = "secp_ser::rangeproof_from_hex" + )] + pub proof: RangeProof, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TxKernelV2 { + /// Options for a kernel's structure or use + pub features: KernelFeatures, + /// Fee originally included in the transaction this proof is for. + pub fee: u64, + /// This kernel is not valid earlier than lock_height blocks + /// The max lock_height of all *inputs* to this transaction + pub lock_height: u64, + /// Remainder of the sum of all transaction commitments. If the transaction + /// is well formed, amounts components should sum to zero and the excess + /// is hence a valid public key. + #[serde( + serialize_with = "secp_ser::as_hex", + deserialize_with = "secp_ser::commitment_from_hex" + )] + pub excess: Commitment, + /// The signature proving the excess is a valid public key, which signs + /// the transaction fee. + #[serde(with = "secp_ser::sig_serde")] + pub excess_sig: secp::Signature, +} + +// V2 to V1 Downgrade Conversion //////////////////////////////////// + +impl From for SlateV1 { + fn from(slate: SlateV2) -> SlateV1 { + let SlateV2 { + num_participants, + id, + tx, + amount, + fee, + height, + lock_height, + participant_data, + version_info, + } = slate; + let tx = TransactionV1::from(tx); + let version = 1; + let orig_version = version_info.orig_version as u64; + let participant_data = map_vec!(participant_data, |data| ParticipantDataV1::from(data)); + SlateV1 { + num_participants, + id, + tx, + amount, + fee, + height, + lock_height, + participant_data, + version, + orig_version, + } + } +} + +impl From<&ParticipantDataV2> for ParticipantDataV1 { + fn from(data: &ParticipantDataV2) -> ParticipantDataV1 { + let ParticipantDataV2 { + id, + public_blind_excess, + public_nonce, + part_sig, + message, + message_sig, + } = data; + let id = *id; + let public_blind_excess = *public_blind_excess; + let public_nonce = *public_nonce; + let part_sig = *part_sig; + let message: Option = message.as_ref().map(|t| String::from(&**t)); + let message_sig = *message_sig; + ParticipantDataV1 { + id, + public_blind_excess, + public_nonce, + part_sig, + message, + message_sig, + } + } +} + +impl From for TransactionV1 { + fn from(tx: TransactionV2) -> TransactionV1 { + let TransactionV2 { offset, body } = tx; + let body = TransactionBodyV1::from(&body); + /*let transaction = TransactionV2::new(body.inputs, body.outputs, body.kernels); + transaction.with_offset(offset)*/ + TransactionV1 { + offset, + body, + } + } +} + +impl From<&TransactionBodyV2> for TransactionBodyV1 { + fn from(body: &TransactionBodyV2) -> Self { + let TransactionBodyV2 { + inputs, + outputs, + kernels, + } = body; + + let inputs = map_vec!(inputs, |inp| InputV1::from(inp)); + let outputs = map_vec!(outputs, |out| OutputV1::from(out)); + let kernels = map_vec!(kernels, |kern| TxKernelV1::from(kern)); + TransactionBodyV1 { + inputs, + outputs, + kernels, + } + } +} + +impl From<&InputV2> for InputV1 { + fn from(input: &InputV2) -> InputV1 { + let InputV2 { features, commit } = *input; + InputV1 { features, commit } + } +} + +impl From<&OutputV2> for OutputV1 { + fn from(output: &OutputV2) -> OutputV1 { + let OutputV2 { + features, + commit, + proof, + } = *output; + OutputV1 { + features, + commit, + proof, + } + } +} + +impl From<&TxKernelV2> for TxKernelV1 { + fn from(kernel: &TxKernelV2) -> TxKernelV1 { + let TxKernelV2 { + features, + fee, + lock_height, + excess, + excess_sig, + } = *kernel; + TxKernelV1 { + features, + fee, + lock_height, + excess, + excess_sig, + } + } +} + +// V1 to V2 Upgrade Conversion //////////////////////////////////// + +impl From for SlateV2 { + fn from(slate: SlateV1) -> SlateV2 { + let SlateV1 { + num_participants, + id, + tx, + amount, + fee, + height, + lock_height, + participant_data, + version: _, + orig_version, + } = slate; + let tx = TransactionV2::from(tx); + let version = 2; + let min_compat_version = 0; + let orig_version = orig_version as u16; + let participant_data = map_vec!(participant_data, |data| ParticipantDataV2::from(data)); + let version_info = VersionCompatInfoV2 { + version, + orig_version, + min_compat_version, + }; + SlateV2 { + num_participants, + id, + tx, + amount, + fee, + height, + lock_height, + participant_data, + version_info, + } + } +} + +impl From<&ParticipantDataV1> for ParticipantDataV2 { + fn from(data: &ParticipantDataV1) -> ParticipantDataV2 { + let ParticipantDataV1 { + id, + public_blind_excess, + public_nonce, + part_sig, + message, + message_sig, + } = data; + let id = *id; + let public_blind_excess = *public_blind_excess; + let public_nonce = *public_nonce; + let part_sig = *part_sig; + let message: Option = message.as_ref().map(|t| String::from(&**t)); + let message_sig = *message_sig; + ParticipantDataV2 { + id, + public_blind_excess, + public_nonce, + part_sig, + message, + message_sig, + } + } +} + +impl From for TransactionV2 { + fn from(tx: TransactionV1) -> TransactionV2 { + let TransactionV1 { offset, body } = tx; + let body = TransactionBodyV2::from(&body); + /*let transaction = TransactionV2::new(body.inputs, body.outputs, body.kernels); + transaction.with_offset(offset)*/ + TransactionV2 { + offset, + body, + } + } +} + +impl From<&TransactionBodyV1> for TransactionBodyV2 { + fn from(body: &TransactionBodyV1) -> Self { + let TransactionBodyV1 { + 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 { + inputs, + outputs, + kernels, + } + } +} + +impl From<&InputV1> for InputV2 { + fn from(input: &InputV1) -> InputV2 { + let InputV1 { features, commit } = *input; + InputV2 { features, commit } + } +} + +impl From<&OutputV1> for OutputV2 { + fn from(output: &OutputV1) -> OutputV2 { + let OutputV1 { + features, + commit, + proof, + } = *output; + OutputV2 { + features, + commit, + proof, + } + } +} + +impl From<&TxKernelV1> for TxKernelV2 { + fn from(kernel: &TxKernelV1) -> TxKernelV2 { + let TxKernelV1 { + features, + fee, + lock_height, + excess, + excess_sig, + } = *kernel; + TxKernelV2 { + features, + fee, + lock_height, + excess, + excess_sig, + } + } +} + + diff --git a/libwallet/src/types.rs b/libwallet/src/types.rs index 7a7e8519..5c55e5f8 100644 --- a/libwallet/src/types.rs +++ b/libwallet/src/types.rs @@ -720,4 +720,6 @@ pub struct SendTXArgs { pub selection_strategy_is_use_all: bool, /// Optional message, that will be signed pub message: Option, + /// Optional slate version to target when sending + pub target_slate_version: Option, } diff --git a/libwallet/tests/slate_versioning.rs b/libwallet/tests/slate_versioning.rs new file mode 100644 index 00000000..2fd6873d --- /dev/null +++ b/libwallet/tests/slate_versioning.rs @@ -0,0 +1,69 @@ +// 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. + +//! core::libtx specific tests +use grin_libwallet::slate::Slate; + +// test all slate conversions +#[test] +fn slate_conversions() { + // Test V0 to V2 + let v0 = include_str!("slates/v0.slate"); + let res = Slate::deserialize_upgrade(&v0); + assert!(res.is_ok()); + // should serialize as latest + let res = res.unwrap(); + assert_eq!(res.version_info.orig_version, 0); + let s = res.serialize_to_version(Some(2)); + assert!(s.is_ok()); + println!("v0 -> v2: {}", s.unwrap()); + + // Test V1 to V2 + let v1 = include_str!("slates/v1.slate"); + let res = Slate::deserialize_upgrade(&v1); + assert!(res.is_ok()); + // should serialize as latest + let res = res.unwrap(); + assert_eq!(res.version_info.orig_version, 1); + let s = res.serialize_to_version(Some(2)); + assert!(s.is_ok()); + println!("v1 -> v2: {}", s.unwrap()); + + // V2 -> V2, check version + let v2 = include_str!("slates/v2.slate"); + let res = Slate::deserialize_upgrade(&v2); + assert!(res.is_ok()); + let res = res.unwrap().serialize_to_version(Some(2)); + let s = res.unwrap(); + let res = Slate::deserialize_upgrade(&s).unwrap(); + assert_eq!(res.version_info.orig_version, 2); + + // Downgrade to V1 + let v2 = include_str!("slates/v2.slate"); + let res = Slate::deserialize_upgrade(&v2); + assert!(res.is_ok()); + // downgrade + let s = res.unwrap().serialize_to_version(Some(1)); + assert!(s.is_ok()); + println!("v2 -> v1: {}", s.unwrap()); + + // Downgrade to V0 + let v2 = include_str!("slates/v2.slate"); + let res = Slate::deserialize_upgrade(&v2); + assert!(res.is_ok()); + // downgrade + let s = res.unwrap().serialize_to_version(Some(0)); + assert!(s.is_ok()); + println!("v2 -> v0: {}", s.unwrap()); + +} diff --git a/libwallet/tests/slates/v0.slate b/libwallet/tests/slates/v0.slate new file mode 100644 index 00000000..c1a19b7d --- /dev/null +++ b/libwallet/tests/slates/v0.slate @@ -0,0 +1,1027 @@ +{ + "num_participants": 2, + "id": "e0c69803-db50-40d9-a968-496e86660cd4", + "tx": { + "offset": [ + 168, + 83, + 175, + 235, + 241, + 93, + 140, + 17, + 31, + 101, + 64, + 89, + 148, + 9, + 69, + 180, + 120, + 44, + 56, + 102, + 3, + 151, + 37, + 119, + 7, + 181, + 62, + 191, + 219, + 64, + 58, + 82 + ], + "body": { + "inputs": [ + { + "features": "Plain", + "commit": [ + 9, + 211, + 4, + 174, + 214, + 48, + 15, + 129, + 36, + 235, + 139, + 45, + 70, + 204, + 30, + 10, + 123, + 122, + 155, + 144, + 66, + 185, + 203, + 53, + 224, + 32, + 221, + 149, + 82, + 223, + 156, + 105, + 124 + ] + }, + { + "features": "Plain", + "commit": [ + 9, + 211, + 204, + 145, + 93, + 195, + 23, + 72, + 93, + 200, + 187, + 245, + 236, + 70, + 105, + 164, + 11, + 185, + 211, + 48, + 12, + 150, + 223, + 51, + 132, + 209, + 22, + 221, + 173, + 73, + 141, + 13, + 177 + ] + } + ], + "outputs": [ + { + "features": "Plain", + "commit": [ + 8, + 211, + 69, + 62, + 181, + 206, + 53, + 161, + 182, + 187, + 194, + 167, + 169, + 175, + 227, + 36, + 131, + 119, + 76, + 1, + 31, + 153, + 117, + 244, + 35, + 147, + 70, + 143, + 165, + 205, + 67, + 73, + 167 + ], + "proof": [ + 219, + 32, + 104, + 52, + 192, + 34, + 238, + 193, + 243, + 70, + 166, + 123, + 87, + 25, + 65, + 241, + 182, + 134, + 122, + 228, + 189, + 129, + 137, + 202, + 6, + 75, + 105, + 11, + 50, + 54, + 126, + 69, + 74, + 74, + 90, + 221, + 81, + 118, + 28, + 71, + 43, + 14, + 9, + 148, + 206, + 127, + 0, + 87, + 139, + 192, + 106, + 231, + 185, + 175, + 223, + 140, + 226, + 17, + 133, + 70, + 119, + 25, + 118, + 217, + 0, + 70, + 66, + 20, + 211, + 184, + 49, + 254, + 116, + 169, + 72, + 118, + 152, + 10, + 146, + 131, + 21, + 175, + 181, + 194, + 175, + 1, + 143, + 93, + 89, + 94, + 86, + 253, + 116, + 6, + 88, + 176, + 196, + 242, + 212, + 244, + 99, + 228, + 1, + 203, + 236, + 39, + 4, + 179, + 16, + 5, + 205, + 141, + 125, + 135, + 69, + 130, + 144, + 163, + 102, + 140, + 194, + 232, + 44, + 43, + 8, + 103, + 217, + 145, + 7, + 37, + 68, + 249, + 232, + 200, + 5, + 5, + 108, + 151, + 255, + 102, + 204, + 5, + 44, + 242, + 169, + 102, + 103, + 104, + 208, + 214, + 138, + 205, + 198, + 234, + 31, + 200, + 15, + 185, + 181, + 230, + 225, + 147, + 102, + 199, + 180, + 154, + 218, + 56, + 179, + 104, + 192, + 195, + 227, + 247, + 57, + 119, + 223, + 0, + 63, + 12, + 103, + 68, + 115, + 123, + 49, + 176, + 88, + 199, + 212, + 226, + 118, + 110, + 151, + 238, + 4, + 20, + 126, + 240, + 75, + 226, + 41, + 6, + 240, + 135, + 132, + 34, + 5, + 129, + 60, + 125, + 129, + 117, + 152, + 198, + 137, + 200, + 64, + 8, + 125, + 53, + 204, + 156, + 233, + 169, + 143, + 82, + 230, + 140, + 102, + 189, + 222, + 5, + 33, + 172, + 248, + 20, + 115, + 126, + 253, + 7, + 38, + 84, + 114, + 143, + 65, + 142, + 100, + 148, + 167, + 235, + 127, + 166, + 48, + 94, + 199, + 213, + 114, + 171, + 185, + 29, + 59, + 250, + 191, + 114, + 21, + 231, + 126, + 12, + 156, + 243, + 55, + 105, + 87, + 47, + 249, + 168, + 103, + 26, + 36, + 224, + 160, + 67, + 2, + 230, + 172, + 92, + 238, + 153, + 40, + 236, + 17, + 215, + 201, + 134, + 30, + 209, + 135, + 24, + 20, + 42, + 21, + 99, + 150, + 121, + 85, + 228, + 40, + 228, + 19, + 76, + 109, + 222, + 136, + 189, + 190, + 161, + 18, + 72, + 174, + 153, + 215, + 132, + 165, + 101, + 146, + 160, + 101, + 18, + 41, + 72, + 178, + 194, + 251, + 139, + 226, + 92, + 17, + 147, + 69, + 185, + 250, + 125, + 178, + 239, + 189, + 252, + 248, + 70, + 233, + 186, + 71, + 239, + 255, + 61, + 0, + 36, + 189, + 185, + 152, + 233, + 59, + 202, + 190, + 26, + 0, + 34, + 43, + 163, + 107, + 136, + 236, + 79, + 124, + 42, + 33, + 81, + 191, + 0, + 178, + 37, + 246, + 161, + 75, + 77, + 230, + 102, + 88, + 218, + 236, + 170, + 33, + 152, + 19, + 245, + 26, + 146, + 57, + 238, + 201, + 97, + 198, + 113, + 49, + 6, + 182, + 76, + 79, + 31, + 248, + 81, + 229, + 71, + 149, + 34, + 14, + 227, + 205, + 197, + 149, + 49, + 240, + 172, + 192, + 80, + 225, + 124, + 132, + 139, + 33, + 185, + 22, + 181, + 113, + 178, + 246, + 176, + 147, + 252, + 206, + 192, + 70, + 88, + 125, + 10, + 23, + 24, + 200, + 43, + 215, + 167, + 142, + 34, + 34, + 63, + 225, + 72, + 77, + 236, + 132, + 24, + 32, + 19, + 153, + 80, + 220, + 232, + 76, + 151, + 101, + 155, + 14, + 172, + 27, + 250, + 95, + 206, + 133, + 213, + 96, + 47, + 72, + 13, + 113, + 77, + 202, + 177, + 69, + 156, + 79, + 41, + 226, + 116, + 107, + 204, + 180, + 73, + 77, + 128, + 9, + 53, + 221, + 198, + 48, + 245, + 50, + 87, + 100, + 159, + 21, + 68, + 112, + 32, + 3, + 165, + 131, + 213, + 84, + 34, + 233, + 87, + 25, + 47, + 174, + 191, + 252, + 184, + 216, + 131, + 236, + 107, + 178, + 19, + 44, + 134, + 36, + 157, + 107, + 80, + 237, + 174, + 132, + 243, + 192, + 104, + 66, + 178, + 113, + 66, + 103, + 36, + 156, + 141, + 245, + 142, + 46, + 220, + 58, + 202, + 105, + 223, + 246, + 110, + 227, + 47, + 181, + 217, + 61, + 185, + 21, + 109, + 243, + 115, + 171, + 81, + 223, + 44, + 9, + 71, + 66, + 81, + 123, + 70, + 255, + 149, + 41, + 140, + 174, + 195, + 70, + 65, + 81, + 234, + 145, + 200, + 168, + 254, + 116, + 187, + 96, + 255, + 185, + 76, + 124, + 151, + 74, + 166, + 203, + 46, + 71, + 221, + 30, + 224, + 95, + 71, + 30, + 45, + 47, + 11, + 85, + 94, + 254, + 23, + 48, + 39, + 105, + 19, + 151, + 96, + 188, + 17, + 12, + 151, + 148, + 83, + 247, + 191, + 171, + 67, + 179, + 243, + 203, + 164, + 217, + 76, + 138, + 94, + 235, + 88, + 38, + 75, + 181, + 193, + 109, + 230, + 172, + 187, + 201, + 197, + 108, + 176, + 105, + 231, + 225, + 172, + 31, + 120, + 56, + 208, + 166, + 66, + 64, + 23, + 184, + 213, + 99 + ] + } + ], + "kernels": [ + { + "features": "HeightLocked", + "fee": 7000000, + "lock_height": 70194, + "excess": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "excess_sig": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ] + } + }, + "amount": 84825921007, + "fee": 7000000, + "height": 70194, + "lock_height": 70194, + "participant_data": [ + { + "id": 0, + "public_blind_excess": [ + 3, + 145, + 248, + 252, + 116, + 187, + 95, + 244, + 222, + 55, + 51, + 82, + 231, + 222, + 224, + 8, + 96, + 212, + 251, + 120, + 237, + 122, + 153, + 118, + 85, + 133, + 175, + 152, + 13, + 138, + 49, + 198, + 21 + ], + "public_nonce": [ + 2, + 6, + 86, + 44, + 33, + 167, + 243, + 160, + 3, + 98, + 39, + 34, + 238, + 147, + 196, + 236, + 187, + 236, + 234, + 212, + 166, + 173, + 142, + 229, + 217, + 48, + 181, + 28, + 164, + 166, + 202, + 109, + 1 + ], + "part_sig": null, + "message": null, + "message_sig": null + } + ] +} diff --git a/libwallet/tests/slates/v1.slate b/libwallet/tests/slates/v1.slate new file mode 100644 index 00000000..6d530c5a --- /dev/null +++ b/libwallet/tests/slates/v1.slate @@ -0,0 +1,1028 @@ +{ + "num_participants": 2, + "id": "e0c69803-db50-40d9-a968-496e86660cd4", + "tx": { + "offset": [ + 168, + 83, + 175, + 235, + 241, + 93, + 140, + 17, + 31, + 101, + 64, + 89, + 148, + 9, + 69, + 180, + 120, + 44, + 56, + 102, + 3, + 151, + 37, + 119, + 7, + 181, + 62, + 191, + 219, + 64, + 58, + 82 + ], + "body": { + "inputs": [ + { + "features": "Plain", + "commit": [ + 9, + 211, + 4, + 174, + 214, + 48, + 15, + 129, + 36, + 235, + 139, + 45, + 70, + 204, + 30, + 10, + 123, + 122, + 155, + 144, + 66, + 185, + 203, + 53, + 224, + 32, + 221, + 149, + 82, + 223, + 156, + 105, + 124 + ] + }, + { + "features": "Plain", + "commit": [ + 9, + 211, + 204, + 145, + 93, + 195, + 23, + 72, + 93, + 200, + 187, + 245, + 236, + 70, + 105, + 164, + 11, + 185, + 211, + 48, + 12, + 150, + 223, + 51, + 132, + 209, + 22, + 221, + 173, + 73, + 141, + 13, + 177 + ] + } + ], + "outputs": [ + { + "features": "Plain", + "commit": [ + 8, + 211, + 69, + 62, + 181, + 206, + 53, + 161, + 182, + 187, + 194, + 167, + 169, + 175, + 227, + 36, + 131, + 119, + 76, + 1, + 31, + 153, + 117, + 244, + 35, + 147, + 70, + 143, + 165, + 205, + 67, + 73, + 167 + ], + "proof": [ + 219, + 32, + 104, + 52, + 192, + 34, + 238, + 193, + 243, + 70, + 166, + 123, + 87, + 25, + 65, + 241, + 182, + 134, + 122, + 228, + 189, + 129, + 137, + 202, + 6, + 75, + 105, + 11, + 50, + 54, + 126, + 69, + 74, + 74, + 90, + 221, + 81, + 118, + 28, + 71, + 43, + 14, + 9, + 148, + 206, + 127, + 0, + 87, + 139, + 192, + 106, + 231, + 185, + 175, + 223, + 140, + 226, + 17, + 133, + 70, + 119, + 25, + 118, + 217, + 0, + 70, + 66, + 20, + 211, + 184, + 49, + 254, + 116, + 169, + 72, + 118, + 152, + 10, + 146, + 131, + 21, + 175, + 181, + 194, + 175, + 1, + 143, + 93, + 89, + 94, + 86, + 253, + 116, + 6, + 88, + 176, + 196, + 242, + 212, + 244, + 99, + 228, + 1, + 203, + 236, + 39, + 4, + 179, + 16, + 5, + 205, + 141, + 125, + 135, + 69, + 130, + 144, + 163, + 102, + 140, + 194, + 232, + 44, + 43, + 8, + 103, + 217, + 145, + 7, + 37, + 68, + 249, + 232, + 200, + 5, + 5, + 108, + 151, + 255, + 102, + 204, + 5, + 44, + 242, + 169, + 102, + 103, + 104, + 208, + 214, + 138, + 205, + 198, + 234, + 31, + 200, + 15, + 185, + 181, + 230, + 225, + 147, + 102, + 199, + 180, + 154, + 218, + 56, + 179, + 104, + 192, + 195, + 227, + 247, + 57, + 119, + 223, + 0, + 63, + 12, + 103, + 68, + 115, + 123, + 49, + 176, + 88, + 199, + 212, + 226, + 118, + 110, + 151, + 238, + 4, + 20, + 126, + 240, + 75, + 226, + 41, + 6, + 240, + 135, + 132, + 34, + 5, + 129, + 60, + 125, + 129, + 117, + 152, + 198, + 137, + 200, + 64, + 8, + 125, + 53, + 204, + 156, + 233, + 169, + 143, + 82, + 230, + 140, + 102, + 189, + 222, + 5, + 33, + 172, + 248, + 20, + 115, + 126, + 253, + 7, + 38, + 84, + 114, + 143, + 65, + 142, + 100, + 148, + 167, + 235, + 127, + 166, + 48, + 94, + 199, + 213, + 114, + 171, + 185, + 29, + 59, + 250, + 191, + 114, + 21, + 231, + 126, + 12, + 156, + 243, + 55, + 105, + 87, + 47, + 249, + 168, + 103, + 26, + 36, + 224, + 160, + 67, + 2, + 230, + 172, + 92, + 238, + 153, + 40, + 236, + 17, + 215, + 201, + 134, + 30, + 209, + 135, + 24, + 20, + 42, + 21, + 99, + 150, + 121, + 85, + 228, + 40, + 228, + 19, + 76, + 109, + 222, + 136, + 189, + 190, + 161, + 18, + 72, + 174, + 153, + 215, + 132, + 165, + 101, + 146, + 160, + 101, + 18, + 41, + 72, + 178, + 194, + 251, + 139, + 226, + 92, + 17, + 147, + 69, + 185, + 250, + 125, + 178, + 239, + 189, + 252, + 248, + 70, + 233, + 186, + 71, + 239, + 255, + 61, + 0, + 36, + 189, + 185, + 152, + 233, + 59, + 202, + 190, + 26, + 0, + 34, + 43, + 163, + 107, + 136, + 236, + 79, + 124, + 42, + 33, + 81, + 191, + 0, + 178, + 37, + 246, + 161, + 75, + 77, + 230, + 102, + 88, + 218, + 236, + 170, + 33, + 152, + 19, + 245, + 26, + 146, + 57, + 238, + 201, + 97, + 198, + 113, + 49, + 6, + 182, + 76, + 79, + 31, + 248, + 81, + 229, + 71, + 149, + 34, + 14, + 227, + 205, + 197, + 149, + 49, + 240, + 172, + 192, + 80, + 225, + 124, + 132, + 139, + 33, + 185, + 22, + 181, + 113, + 178, + 246, + 176, + 147, + 252, + 206, + 192, + 70, + 88, + 125, + 10, + 23, + 24, + 200, + 43, + 215, + 167, + 142, + 34, + 34, + 63, + 225, + 72, + 77, + 236, + 132, + 24, + 32, + 19, + 153, + 80, + 220, + 232, + 76, + 151, + 101, + 155, + 14, + 172, + 27, + 250, + 95, + 206, + 133, + 213, + 96, + 47, + 72, + 13, + 113, + 77, + 202, + 177, + 69, + 156, + 79, + 41, + 226, + 116, + 107, + 204, + 180, + 73, + 77, + 128, + 9, + 53, + 221, + 198, + 48, + 245, + 50, + 87, + 100, + 159, + 21, + 68, + 112, + 32, + 3, + 165, + 131, + 213, + 84, + 34, + 233, + 87, + 25, + 47, + 174, + 191, + 252, + 184, + 216, + 131, + 236, + 107, + 178, + 19, + 44, + 134, + 36, + 157, + 107, + 80, + 237, + 174, + 132, + 243, + 192, + 104, + 66, + 178, + 113, + 66, + 103, + 36, + 156, + 141, + 245, + 142, + 46, + 220, + 58, + 202, + 105, + 223, + 246, + 110, + 227, + 47, + 181, + 217, + 61, + 185, + 21, + 109, + 243, + 115, + 171, + 81, + 223, + 44, + 9, + 71, + 66, + 81, + 123, + 70, + 255, + 149, + 41, + 140, + 174, + 195, + 70, + 65, + 81, + 234, + 145, + 200, + 168, + 254, + 116, + 187, + 96, + 255, + 185, + 76, + 124, + 151, + 74, + 166, + 203, + 46, + 71, + 221, + 30, + 224, + 95, + 71, + 30, + 45, + 47, + 11, + 85, + 94, + 254, + 23, + 48, + 39, + 105, + 19, + 151, + 96, + 188, + 17, + 12, + 151, + 148, + 83, + 247, + 191, + 171, + 67, + 179, + 243, + 203, + 164, + 217, + 76, + 138, + 94, + 235, + 88, + 38, + 75, + 181, + 193, + 109, + 230, + 172, + 187, + 201, + 197, + 108, + 176, + 105, + 231, + 225, + 172, + 31, + 120, + 56, + 208, + 166, + 66, + 64, + 23, + 184, + 213, + 99 + ] + } + ], + "kernels": [ + { + "features": "HeightLocked", + "fee": 7000000, + "lock_height": 70194, + "excess": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "excess_sig": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ] + } + }, + "amount": 84825921007, + "fee": 7000000, + "height": 70194, + "lock_height": 70194, + "participant_data": [ + { + "id": 0, + "public_blind_excess": [ + 3, + 145, + 248, + 252, + 116, + 187, + 95, + 244, + 222, + 55, + 51, + 82, + 231, + 222, + 224, + 8, + 96, + 212, + 251, + 120, + 237, + 122, + 153, + 118, + 85, + 133, + 175, + 152, + 13, + 138, + 49, + 198, + 21 + ], + "public_nonce": [ + 2, + 6, + 86, + 44, + 33, + 167, + 243, + 160, + 3, + 98, + 39, + 34, + 238, + 147, + 196, + 236, + 187, + 236, + 234, + 212, + 166, + 173, + 142, + 229, + 217, + 48, + 181, + 28, + 164, + 166, + 202, + 109, + 1 + ], + "part_sig": null, + "message": null, + "message_sig": null + } + ], + "version": 1 +} diff --git a/libwallet/tests/slates/v2.slate b/libwallet/tests/slates/v2.slate new file mode 100644 index 00000000..3258cbdb --- /dev/null +++ b/libwallet/tests/slates/v2.slate @@ -0,0 +1,54 @@ +{ + "version_info": { + "version": 2, + "orig_version": 2, + "min_compat_version": 0 + }, + "num_participants": 2, + "id": "e0c69803-db50-40d9-a968-496e86660cd4", + "tx": { + "offset": "a853afebf15d8c111f654059940945b4782c38660397257707b53ebfdb403a52", + "body": { + "inputs": [ + { + "features": "Plain", + "commit": "09d304aed6300f8124eb8b2d46cc1e0a7b7a9b9042b9cb35e020dd9552df9c697c" + }, + { + "features": "Plain", + "commit": "09d3cc915dc317485dc8bbf5ec4669a40bb9d3300c96df3384d116ddad498d0db1" + } + ], + "outputs": [ + { + "features": "Plain", + "commit": "08d3453eb5ce35a1b6bbc2a7a9afe32483774c011f9975f42393468fa5cd4349a7", + "proof": "db206834c022eec1f346a67b571941f1b6867ae4bd8189ca064b690b32367e454a4a5add51761c472b0e0994ce7f00578bc06ae7b9afdf8ce2118546771976d900464214d3b831fe74a94876980a928315afb5c2af018f5d595e56fd740658b0c4f2d4f463e401cbec2704b31005cd8d7d87458290a3668cc2e82c2b0867d991072544f9e8c805056c97ff66cc052cf2a9666768d0d68acdc6ea1fc80fb9b5e6e19366c7b49ada38b368c0c3e3f73977df003f0c6744737b31b058c7d4e2766e97ee04147ef04be22906f087842205813c7d817598c689c840087d35cc9ce9a98f52e68c66bdde0521acf814737efd072654728f418e6494a7eb7fa6305ec7d572abb91d3bfabf7215e77e0c9cf33769572ff9a8671a24e0a04302e6ac5cee9928ec11d7c9861ed18718142a1563967955e428e4134c6dde88bdbea11248ae99d784a56592a065122948b2c2fb8be25c119345b9fa7db2efbdfcf846e9ba47efff3d0024bdb998e93bcabe1a00222ba36b88ec4f7c2a2151bf00b225f6a14b4de66658daecaa219813f51a9239eec961c6713106b64c4f1ff851e54795220ee3cdc59531f0acc050e17c848b21b916b571b2f6b093fccec046587d0a1718c82bd7a78e22223fe1484dec841820139950dce84c97659b0eac1bfa5fce85d5602f480d714dcab1459c4f29e2746bccb4494d800935ddc630f53257649f1544702003a583d55422e957192faebffcb8d883ec6bb2132c86249d6b50edae84f3c06842b2714267249c8df58e2edc3aca69dff66ee32fb5d93db9156df373ab51df2c094742517b46ff95298caec3464151ea91c8a8fe74bb60ffb94c7c974aa6cb2e47dd1ee05f471e2d2f0b555efe17302769139760bc110c979453f7bfab43b3f3cba4d94c8a5eeb58264bb5c16de6acbbc9c56cb069e7e1ac1f7838d0a6424017b8d563" + } + ], + "kernels": [ + { + "features": "HeightLocked", + "fee": 7000000, + "lock_height": 70194, + "excess": "000000000000000000000000000000000000000000000000000000000000000000", + "excess_sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + }, + "amount": 84825921007, + "fee": 7000000, + "height": 70194, + "lock_height": 70194, + "participant_data": [ + { + "id": 0, + "public_blind_excess": "0391f8fc74bb5ff4de373352e7dee00860d4fb78ed7a99765585af980d8a31c615", + "public_nonce": "0206562c21a7f3a003622722ee93c4ecbbecead4a6ad8ee5d930b51ca4a6ca6d01", + "part_sig": null, + "message": null, + "message_sig": null + } + ] +} diff --git a/refwallet/src/adapters/file.rs b/refwallet/src/adapters/file.rs index 12fe459a..3dc62ca2 100644 --- a/refwallet/src/adapters/file.rs +++ b/refwallet/src/adapters/file.rs @@ -16,7 +16,6 @@ use std::fs::File; use std::io::{Read, Write}; -use crate::adapters::util::{deserialize_slate, serialize_slate}; use crate::libwallet::slate::Slate; use crate::libwallet::Error; use crate::{WalletCommAdapter, WalletConfig}; @@ -43,7 +42,7 @@ impl WalletCommAdapter for FileWalletCommAdapter { fn send_tx_async(&self, dest: &str, slate: &Slate) -> Result<(), Error> { let mut pub_tx = File::create(dest)?; - let slate_string = serialize_slate(slate); + let slate_string = slate.serialize_to_version(Some(slate.version_info.orig_version))?; pub_tx.write_all(slate_string.as_bytes())?; pub_tx.sync_all()?; Ok(()) @@ -53,7 +52,7 @@ impl WalletCommAdapter for FileWalletCommAdapter { let mut pub_tx_f = File::open(params)?; let mut content = String::new(); pub_tx_f.read_to_string(&mut content)?; - Ok(deserialize_slate(&content)) + Ok(Slate::deserialize_upgrade(&content)?) } fn listen( diff --git a/refwallet/src/adapters/http.rs b/refwallet/src/adapters/http.rs index c8988af7..ec6664d4 100644 --- a/refwallet/src/adapters/http.rs +++ b/refwallet/src/adapters/http.rs @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::adapters::util::get_versioned_slate; use crate::api; use crate::controller; -use crate::libwallet::slate::{Slate, VersionedSlate}; +use crate::libwallet::slate::Slate; use crate::libwallet::{Error, ErrorKind}; use crate::{instantiate_wallet, HTTPNodeClient, WalletCommAdapter, WalletConfig}; /// HTTP Wallet 'plugin' implementation @@ -48,15 +47,15 @@ impl WalletCommAdapter for HTTPWalletCommAdapter { } let url = format!("{}/v1/wallet/foreign/receive_tx", dest); debug!("Posting transaction slate to {}", url); - let slate = get_versioned_slate(slate); - let res: Result = api::client::post(url.as_str(), None, &slate); + let slate = slate.serialize_to_version(Some(slate.version_info.orig_version))?; + let res: Result = api::client::post(url.as_str(), None, &slate); match res { Err(e) => { let report = format!("Posting transaction slate (is recipient listening?): {}", e); error!("{}", report); Err(ErrorKind::ClientCallback(report).into()) } - Ok(r) => Ok(r.into()), + Ok(r) => Ok(Slate::deserialize_upgrade(&r)?), } } diff --git a/refwallet/src/adapters/keybase.rs b/refwallet/src/adapters/keybase.rs index f34e6350..06c8bcdf 100644 --- a/refwallet/src/adapters/keybase.rs +++ b/refwallet/src/adapters/keybase.rs @@ -15,8 +15,7 @@ // Keybase Wallet Plugin use crate::controller; -use crate::libwallet::slate::{Slate, VersionedSlate}; -use crate::libwallet::slate_versions::v0::SlateV0; +use crate::libwallet::slate::Slate; use crate::libwallet::{Error, ErrorKind}; use crate::{instantiate_wallet, HTTPNodeClient, WalletCommAdapter, WalletConfig}; use failure::ResultExt; @@ -259,7 +258,7 @@ fn poll(nseconds: u64, channel: &str) -> Option { while start.elapsed().as_secs() < nseconds { let unread = read_from_channel(channel, SLATE_SIGNED); for msg in unread.unwrap().iter() { - let blob = from_str::(msg); + let blob = Slate::deserialize_upgrade(&msg); match blob { Ok(slate) => { let slate: Slate = slate.into(); @@ -268,7 +267,7 @@ fn poll(nseconds: u64, channel: &str) -> Option { channel, slate.id, ); return Some(slate); - } + }, Err(_) => (), } } @@ -350,7 +349,7 @@ impl WalletCommAdapter for KeybaseWalletCommAdapter { break; } for (msg, channel) in &unread.unwrap() { - let blob = from_str::(msg); + let blob = Slate::deserialize_upgrade(&msg); match blob { Ok(message) => { let mut slate: Slate = message.clone().into(); @@ -385,15 +384,9 @@ impl WalletCommAdapter for KeybaseWalletCommAdapter { }) { // Reply to the same channel with topic SLATE_SIGNED Ok(_) => { - let success = match message { - // Send the same version of slate that was sent to us - VersionedSlate::V0(_) => { - send(SlateV0::from(slate), channel, SLATE_SIGNED, TTL) - } - VersionedSlate::V1(_) => { - send(slate, channel, SLATE_SIGNED, TTL) - } - }; + let slate = slate.serialize_to_version(Some(slate.version_info.orig_version))?; + // TODO: Send the same version of slate that was sent to us + let success = send(slate, channel, SLATE_SIGNED, TTL); if success { notify_on_receive( diff --git a/refwallet/src/adapters/mod.rs b/refwallet/src/adapters/mod.rs index d1c53eff..c42b0964 100644 --- a/refwallet/src/adapters/mod.rs +++ b/refwallet/src/adapters/mod.rs @@ -16,7 +16,6 @@ mod file; mod http; mod keybase; mod null; -pub mod util; pub use self::file::FileWalletCommAdapter; pub use self::http::HTTPWalletCommAdapter; diff --git a/refwallet/src/adapters/util.rs b/refwallet/src/adapters/util.rs deleted file mode 100644 index 86ac7f04..00000000 --- a/refwallet/src/adapters/util.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::libwallet::slate::{Slate, VersionedSlate}; -use crate::libwallet::slate_versions::v0::SlateV0; -use crate::libwallet::ErrorKind; -use serde_json as json; - -pub fn get_versioned_slate(slate: &Slate) -> VersionedSlate { - let slate = slate.clone(); - match slate.version { - 0 => VersionedSlate::V0(SlateV0::from(slate)), - _ => VersionedSlate::V1(slate), - } -} - -pub fn serialize_slate(slate: &Slate) -> String { - json::to_string(&get_versioned_slate(slate)).unwrap() -} - -pub fn deserialize_slate(raw_slate: &str) -> Slate { - let versioned_slate: VersionedSlate = json::from_str(&raw_slate) - .map_err(|err| ErrorKind::Format(err.to_string())) - .unwrap(); - versioned_slate.into() -} diff --git a/refwallet/src/command.rs b/refwallet/src/command.rs index 59d21b00..4b92d186 100644 --- a/refwallet/src/command.rs +++ b/refwallet/src/command.rs @@ -206,6 +206,7 @@ pub struct SendArgs { pub change_outputs: usize, pub fluff: bool, pub max_outputs: usize, + pub target_slate_version: Option, } pub fn send( @@ -241,6 +242,7 @@ pub fn send( args.change_outputs, args.selection_strategy == "all", args.message.clone(), + args.target_slate_version, ); let (mut slate, lock_fn) = match result { Ok(s) => { diff --git a/refwallet/src/controller.rs b/refwallet/src/controller.rs index e49fa731..b03067d0 100644 --- a/refwallet/src/controller.rs +++ b/refwallet/src/controller.rs @@ -15,14 +15,13 @@ //! Controller for wallet.. instantiates and handles listeners (or single-run //! invocations) as needed. //! Still experimental -use crate::adapters::util::get_versioned_slate; use crate::adapters::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter}; use crate::api::{ApiServer, BasicAuthMiddleware, Handler, ResponseFuture, Router, TLSConfig}; use crate::apiwallet::api::{APIForeign, APIOwner}; use crate::core::core; use crate::core::core::Transaction; use crate::keychain::Keychain; -use crate::libwallet::slate::{Slate, VersionedSlate}; +use crate::libwallet::slate::Slate; use crate::libwallet::types::{ CbData, NodeClient, OutputData, SendTXArgs, TxLogEntry, WalletBackend, WalletInfo, }; @@ -330,6 +329,7 @@ where args.num_change_outputs, args.selection_strategy_is_use_all, args.message, + args.target_slate_version, ); let (mut slate, lock_fn) = match result { Ok(s) => { @@ -661,17 +661,17 @@ where &self, req: Request, api: APIForeign, - ) -> Box + Send> { + ) -> Box + Send> { Box::new(parse_body(req).and_then( //TODO: No way to insert a message from the params - move |slate: VersionedSlate| { - let mut slate: Slate = slate.into(); + move |slate_str: String| { + let mut slate: Slate = Slate::deserialize_upgrade(&slate_str).unwrap(); if let Err(e) = api.verify_slate_messages(&slate) { error!("Error validating participant messages: {}", e); err(e) } else { match api.receive_tx(&mut slate, None, None) { - Ok(_) => ok(get_versioned_slate(&slate.clone())), + Ok(_) => ok(slate.serialize_to_version(Some(slate.version_info.orig_version)).unwrap()), Err(e) => { error!("receive_tx: failed with error: {}", e); err(e) diff --git a/refwallet/src/test_framework/mod.rs b/refwallet/src/test_framework/mod.rs index 48f788ab..5a71e987 100644 --- a/refwallet/src/test_framework/mod.rs +++ b/refwallet/src/test_framework/mod.rs @@ -202,6 +202,7 @@ where 1, // num change outputs true, // select all outputs None, + None, )?; let mut slate = client.send_tx_slate_direct(dest, &slate_i)?; api.tx_lock_outputs(&slate, lock_fn)?; diff --git a/refwallet/tests/accounts.rs b/refwallet/tests/accounts.rs index 3798afa6..0aff34c9 100644 --- a/refwallet/tests/accounts.rs +++ b/refwallet/tests/accounts.rs @@ -185,6 +185,7 @@ fn accounts_test_impl(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client1.send_tx_slate_direct("wallet2", &slate)?; api.tx_lock_outputs(&slate, lock_fn)?; diff --git a/refwallet/tests/check.rs b/refwallet/tests/check.rs index b43b5837..5cf39259 100644 --- a/refwallet/tests/check.rs +++ b/refwallet/tests/check.rs @@ -163,6 +163,7 @@ fn check_repair_impl(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, // optional message + None, )?; // output tx file let file_adapter = FileWalletCommAdapter::new(); diff --git a/refwallet/tests/file.rs b/refwallet/tests/file.rs index e90f8f41..47a8aee4 100644 --- a/refwallet/tests/file.rs +++ b/refwallet/tests/file.rs @@ -111,6 +111,7 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs Some(message.to_owned()), // optional message + None, )?; // output tx file let file_adapter = FileWalletCommAdapter::new(); diff --git a/refwallet/tests/repost.rs b/refwallet/tests/repost.rs index b40bed48..1557e3d6 100644 --- a/refwallet/tests/repost.rs +++ b/refwallet/tests/repost.rs @@ -109,6 +109,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; // output tx file let file_adapter = FileWalletCommAdapter::new(); @@ -205,6 +206,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; sender_api.tx_lock_outputs(&slate, lock_fn)?; diff --git a/refwallet/tests/restore.rs b/refwallet/tests/restore.rs index 63a60e37..25b25e2b 100644 --- a/refwallet/tests/restore.rs +++ b/refwallet/tests/restore.rs @@ -242,6 +242,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; sender_api.tx_lock_outputs(&slate, lock_fn)?; @@ -264,6 +265,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client1.send_tx_slate_direct("wallet3", &slate_i)?; sender_api.tx_lock_outputs(&slate, lock_fn)?; @@ -286,6 +288,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client3.send_tx_slate_direct("wallet2", &slate_i)?; sender_api.tx_lock_outputs(&slate, lock_fn)?; @@ -314,6 +317,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client3.send_tx_slate_direct("wallet2", &slate_i)?; sender_api.tx_lock_outputs(&slate, lock_fn)?; diff --git a/refwallet/tests/self_send.rs b/refwallet/tests/self_send.rs index 0ab1b686..237864cb 100644 --- a/refwallet/tests/self_send.rs +++ b/refwallet/tests/self_send.rs @@ -92,6 +92,7 @@ fn self_send_test_impl(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; api.tx_lock_outputs(&slate, lock_fn)?; // Send directly to self diff --git a/refwallet/tests/transaction.rs b/refwallet/tests/transaction.rs index 86d74ed6..a26b0d72 100644 --- a/refwallet/tests/transaction.rs +++ b/refwallet/tests/transaction.rs @@ -104,6 +104,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; sender_api.tx_lock_outputs(&slate, lock_fn)?; @@ -266,6 +267,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; sender_api.tx_lock_outputs(&slate, lock_fn)?; @@ -363,6 +365,7 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> { 1, // num change outputs true, // select all outputs None, + None, )?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; sender_api.tx_lock_outputs(&slate, lock_fn)?; diff --git a/src/bin/cmd/wallet_args.rs b/src/bin/cmd/wallet_args.rs index a6c7f0d4..9f9f1b4a 100644 --- a/src/bin/cmd/wallet_args.rs +++ b/src/bin/cmd/wallet_args.rs @@ -393,6 +393,17 @@ pub fn parse_send_args(args: &ArgMatches) -> Result { + let v = parse_required(args, "target_slate_version")?; + Some(parse_u64(v, "target_slate_version")? as u16) + }, + false => None, + } + }; + Ok(command::SendArgs { amount: amount, message: message, @@ -404,6 +415,7 @@ pub fn parse_send_args(args: &ArgMatches) -> Result