mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-01-20 19:11:09 +03:00
Slate version conversions (#13)
* add slate upgrading/downgrading * add slate versions * slate versioning compilation and tests * transaction slate responses downgrade themselves to the version of the caller * add command line arg for target slate version output * v2 versioning comment info * doctest fixes
This commit is contained in:
parent
be99ef8335
commit
02655afca8
30 changed files with 3234 additions and 353 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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<String>,
|
||||
target_slate_version: Option<u16>,
|
||||
) -> Result<(Slate, OutputLockFn<W, C, K>), 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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<VersionedSlate> 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<ParticipantData>,
|
||||
/// 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<u16, Error> {
|
||||
// keep attempting to deser, working through known versions until we have
|
||||
// enough to get the version out
|
||||
let res : Result<SlateV2, serde_json::Error> = serde_json::from_str(slate_json);
|
||||
if let Ok(s) = res {
|
||||
return Ok(s.version_info.version);
|
||||
}
|
||||
let res : Result<SlateV1, serde_json::Error> = serde_json::from_str(slate_json);
|
||||
if let Ok(s) = res {
|
||||
return Ok(s.version as u16);
|
||||
}
|
||||
let res : Result<SlateV0, serde_json::Error> = 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<Slate, Error> {
|
||||
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<u16>) -> Result<String, Error> {
|
||||
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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<SlateV0> 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<String> = 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<TransactionV0> 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<Slate> 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<String> = 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<Transaction> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
391
libwallet/src/slate_versions/v1.rs
Normal file
391
libwallet/src/slate_versions/v1.rs
Normal file
|
@ -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<ParticipantDataV1>,
|
||||
/// 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<Signature>,
|
||||
/// A message for other participants
|
||||
pub message: Option<String>,
|
||||
/// Signature, created with private key corresponding to 'public_blind_excess'
|
||||
pub message_sig: Option<Signature>,
|
||||
}
|
||||
|
||||
/// 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<InputV1>,
|
||||
/// List of outputs the transaction produces.
|
||||
pub outputs: Vec<OutputV1>,
|
||||
/// List of kernels that make up this transaction (usually a single kernel).
|
||||
pub kernels: Vec<TxKernelV1>,
|
||||
}
|
||||
#[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<SlateV1> 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<String> = 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<TransactionV1> 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<SlateV0> 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<String> = 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<TransactionV0> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
460
libwallet/src/slate_versions/v2.rs
Normal file
460
libwallet/src/slate_versions/v2.rs
Normal file
|
@ -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<ParticipantDataV2>,
|
||||
}
|
||||
|
||||
#[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<Signature>,
|
||||
/// A message for other participants
|
||||
pub message: Option<String>,
|
||||
/// Signature, created with private key corresponding to 'public_blind_excess'
|
||||
#[serde(with = "secp_ser::option_sig_serde")]
|
||||
pub message_sig: Option<Signature>,
|
||||
}
|
||||
|
||||
/// 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<InputV2>,
|
||||
/// List of outputs the transaction produces.
|
||||
pub outputs: Vec<OutputV2>,
|
||||
/// List of kernels that make up this transaction (usually a single kernel).
|
||||
pub kernels: Vec<TxKernelV2>,
|
||||
}
|
||||
#[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<SlateV2> 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<String> = 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<TransactionV2> 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<SlateV1> 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<String> = 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<TransactionV1> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -720,4 +720,6 @@ pub struct SendTXArgs {
|
|||
pub selection_strategy_is_use_all: bool,
|
||||
/// Optional message, that will be signed
|
||||
pub message: Option<String>,
|
||||
/// Optional slate version to target when sending
|
||||
pub target_slate_version: Option<u16>,
|
||||
}
|
||||
|
|
69
libwallet/tests/slate_versioning.rs
Normal file
69
libwallet/tests/slate_versioning.rs
Normal file
|
@ -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());
|
||||
|
||||
}
|
1027
libwallet/tests/slates/v0.slate
Normal file
1027
libwallet/tests/slates/v0.slate
Normal file
File diff suppressed because it is too large
Load diff
1028
libwallet/tests/slates/v1.slate
Normal file
1028
libwallet/tests/slates/v1.slate
Normal file
File diff suppressed because it is too large
Load diff
54
libwallet/tests/slates/v2.slate
Normal file
54
libwallet/tests/slates/v2.slate
Normal file
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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(
|
||||
|
|
|
@ -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<VersionedSlate, _> = api::client::post(url.as_str(), None, &slate);
|
||||
let slate = slate.serialize_to_version(Some(slate.version_info.orig_version))?;
|
||||
let res: Result<String, _> = 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)?),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Slate> {
|
|||
while start.elapsed().as_secs() < nseconds {
|
||||
let unread = read_from_channel(channel, SLATE_SIGNED);
|
||||
for msg in unread.unwrap().iter() {
|
||||
let blob = from_str::<VersionedSlate>(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<Slate> {
|
|||
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::<VersionedSlate>(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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -206,6 +206,7 @@ pub struct SendArgs {
|
|||
pub change_outputs: usize,
|
||||
pub fluff: bool,
|
||||
pub max_outputs: usize,
|
||||
pub target_slate_version: Option<u16>,
|
||||
}
|
||||
|
||||
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) => {
|
||||
|
|
|
@ -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<Body>,
|
||||
api: APIForeign<T, C, K>,
|
||||
) -> Box<dyn Future<Item = VersionedSlate, Error = Error> + Send> {
|
||||
) -> Box<dyn Future<Item = String, Error = Error> + 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)
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -393,6 +393,17 @@ pub fn parse_send_args(args: &ArgMatches) -> Result<command::SendArgs, ParseErro
|
|||
// max_outputs
|
||||
let max_outputs = 500;
|
||||
|
||||
// target slate version to create/send
|
||||
let target_slate_version = {
|
||||
match args.is_present("target_slate_version") {
|
||||
true => {
|
||||
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<command::SendArgs, ParseErro
|
|||
change_outputs: change_outputs,
|
||||
fluff: fluff,
|
||||
max_outputs: max_outputs,
|
||||
target_slate_version: target_slate_version,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -132,6 +132,11 @@ subcommands:
|
|||
short: t
|
||||
long: stored_tx
|
||||
takes_value: true
|
||||
- slate_version:
|
||||
help: Target slate version to output/send to receiver
|
||||
short: v
|
||||
long: slate_version
|
||||
takes_value: true
|
||||
- receive:
|
||||
about: Processes a transaction file to accept a transfer from a sender
|
||||
args:
|
||||
|
|
Loading…
Reference in a new issue