mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-01-21 03:21:08 +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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
|
@ -462,7 +462,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.27 (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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "grin_api"
|
name = "grin_api"
|
||||||
version = "1.1.0"
|
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 = [
|
dependencies = [
|
||||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -607,7 +607,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_chain"
|
name = "grin_chain"
|
||||||
version = "1.1.0"
|
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 = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -630,7 +630,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_core"
|
name = "grin_core"
|
||||||
version = "1.1.0"
|
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 = [
|
dependencies = [
|
||||||
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -656,7 +656,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_keychain"
|
name = "grin_keychain"
|
||||||
version = "1.1.0"
|
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 = [
|
dependencies = [
|
||||||
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -699,7 +699,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_p2p"
|
name = "grin_p2p"
|
||||||
version = "1.1.0"
|
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 = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -719,7 +719,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_pool"
|
name = "grin_pool"
|
||||||
version = "1.1.0"
|
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 = [
|
dependencies = [
|
||||||
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -786,7 +786,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_store"
|
name = "grin_store"
|
||||||
version = "1.1.0"
|
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 = [
|
dependencies = [
|
||||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"croaring 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -806,7 +806,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_util"
|
name = "grin_util"
|
||||||
version = "1.1.0"
|
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 = [
|
dependencies = [
|
||||||
"backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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 = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.27 (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)",
|
"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]]
|
[[package]]
|
||||||
|
@ -2071,7 +2071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "0.15.27"
|
version = "0.15.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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 = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.27 (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)",
|
"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)",
|
"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 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 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 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 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 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"
|
"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",
|
"jsonrpc": "2.0",
|
||||||
"method": "finalize_tx",
|
"method": "finalize_tx",
|
||||||
"params": [{
|
"params": [{
|
||||||
|
"version_info": {
|
||||||
|
"version": 2,
|
||||||
|
"orig_version": 2,
|
||||||
|
"min_compat_version": 0
|
||||||
|
},
|
||||||
"amount": 0,
|
"amount": 0,
|
||||||
"fee": 0,
|
"fee": 0,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
|
@ -284,8 +289,7 @@ pub trait OwnerApi {
|
||||||
"outputs": []
|
"outputs": []
|
||||||
},
|
},
|
||||||
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
|
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
},
|
}
|
||||||
"version": 1
|
|
||||||
}],
|
}],
|
||||||
"id": 1
|
"id": 1
|
||||||
},
|
},
|
||||||
|
@ -416,6 +420,11 @@ pub trait OwnerApi {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "verify_slate_messages",
|
"method": "verify_slate_messages",
|
||||||
"params": [{
|
"params": [{
|
||||||
|
"version_info": {
|
||||||
|
"version": 2,
|
||||||
|
"orig_version": 2,
|
||||||
|
"min_compat_version": 0
|
||||||
|
},
|
||||||
"amount": 0,
|
"amount": 0,
|
||||||
"fee": 0,
|
"fee": 0,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
|
@ -430,8 +439,7 @@ pub trait OwnerApi {
|
||||||
"outputs": []
|
"outputs": []
|
||||||
},
|
},
|
||||||
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
|
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
},
|
}
|
||||||
"version": 1
|
|
||||||
}],
|
}],
|
||||||
"id": 1
|
"id": 1
|
||||||
},
|
},
|
||||||
|
@ -1103,6 +1111,7 @@ where
|
||||||
num_change_outputs: usize,
|
num_change_outputs: usize,
|
||||||
selection_strategy_is_use_all: bool,
|
selection_strategy_is_use_all: bool,
|
||||||
message: Option<String>,
|
message: Option<String>,
|
||||||
|
target_slate_version: Option<u16>,
|
||||||
) -> Result<(Slate, OutputLockFn<W, C, K>), Error> {
|
) -> Result<(Slate, OutputLockFn<W, C, K>), Error> {
|
||||||
let mut w = self.wallet.lock();
|
let mut w = self.wallet.lock();
|
||||||
w.open_with_credentials()?;
|
w.open_with_credentials()?;
|
||||||
|
@ -1148,6 +1157,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
w.close()?;
|
w.close()?;
|
||||||
|
// set target slate version
|
||||||
|
if let Some(v) = target_slate_version {
|
||||||
|
slate.version_info.orig_version = v;
|
||||||
|
}
|
||||||
Ok((slate, lock_fn))
|
Ok((slate, lock_fn))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1502,6 +1515,11 @@ pub trait ForeignApi {
|
||||||
"method": "verify_slate_messages",
|
"method": "verify_slate_messages",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
|
"version_info": {
|
||||||
|
"version": 2,
|
||||||
|
"orig_version": 2,
|
||||||
|
"min_compat_version": 0
|
||||||
|
},
|
||||||
"amount": 0,
|
"amount": 0,
|
||||||
"fee": 0,
|
"fee": 0,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
|
@ -1516,8 +1534,7 @@ pub trait ForeignApi {
|
||||||
"outputs": []
|
"outputs": []
|
||||||
},
|
},
|
||||||
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
|
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
},
|
}
|
||||||
"version": 1
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"id": 1
|
"id": 1
|
||||||
|
@ -1539,13 +1556,18 @@ pub trait ForeignApi {
|
||||||
|
|
||||||
# Json rpc example
|
# 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!(
|
# grin_apiwallet::doctest_helper_json_rpc_foreign_assert_response!(
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "receive_tx",
|
"method": "receive_tx",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
|
"version_info": {
|
||||||
|
"version": 2,
|
||||||
|
"orig_version": 2,
|
||||||
|
"min_compat_version": 0
|
||||||
|
},
|
||||||
"amount": 0,
|
"amount": 0,
|
||||||
"fee": 0,
|
"fee": 0,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
|
@ -1560,8 +1582,7 @@ pub trait ForeignApi {
|
||||||
"outputs": []
|
"outputs": []
|
||||||
},
|
},
|
||||||
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
|
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
},
|
}
|
||||||
"version": 1
|
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
|
|
|
@ -176,6 +176,18 @@ pub enum ErrorKind {
|
||||||
#[fail(display = "Committed Error")]
|
#[fail(display = "Committed Error")]
|
||||||
Committed(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
|
/// Other
|
||||||
#[fail(display = "Generic error: {}", _0)]
|
#[fail(display = "Generic error: {}", _0)]
|
||||||
GenericError(String),
|
GenericError(String),
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
use crate::blake2::blake2b::blake2b;
|
use crate::blake2::blake2b::blake2b;
|
||||||
use crate::error::{Error, ErrorKind};
|
use crate::error::{Error, ErrorKind};
|
||||||
use crate::keychain::{BlindSum, BlindingFactor, Keychain};
|
use crate::keychain::{BlindSum, BlindingFactor, Keychain};
|
||||||
use crate::slate_versions::v0::SlateV0;
|
|
||||||
use crate::util::secp;
|
use crate::util::secp;
|
||||||
use crate::util::secp::key::{PublicKey, SecretKey};
|
use crate::util::secp::key::{PublicKey, SecretKey};
|
||||||
use crate::util::secp::Signature;
|
use crate::util::secp::Signature;
|
||||||
|
@ -31,27 +30,14 @@ use grin_core::libtx::{aggsig, build, secp_ser, tx_fee};
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use uuid::Uuid;
|
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
|
const CURRENT_SLATE_VERSION: u16 = 2;
|
||||||
#[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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Public data for each participant in the slate
|
/// Public data for each participant in the slate
|
||||||
|
|
||||||
|
@ -126,6 +112,8 @@ impl ParticipantMessageData {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Slate {
|
pub struct Slate {
|
||||||
|
/// Versioning info
|
||||||
|
pub version_info: VersionCompatInfo,
|
||||||
/// The number of participants intended to take part in this transaction
|
/// The number of participants intended to take part in this transaction
|
||||||
pub num_participants: usize,
|
pub num_participants: usize,
|
||||||
/// Unique transaction ID, selected by sender
|
/// 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
|
/// insert their public data here. For now, 0 is sender and 1
|
||||||
/// is receiver, though this will change for multi-party
|
/// is receiver, though this will change for multi-party
|
||||||
pub participant_data: Vec<ParticipantData>,
|
pub participant_data: Vec<ParticipantData>,
|
||||||
/// Slate format version
|
|
||||||
#[serde(default = "no_version")]
|
|
||||||
pub version: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_version() -> u64 {
|
/// Versioning and compatibility info about this slate
|
||||||
0
|
#[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
|
/// Helper just to facilitate serialization
|
||||||
|
@ -162,6 +154,71 @@ pub struct ParticipantMessages {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Slate {
|
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
|
/// Create a new slate
|
||||||
pub fn blank(num_participants: usize) -> Slate {
|
pub fn blank(num_participants: usize) -> Slate {
|
||||||
Slate {
|
Slate {
|
||||||
|
@ -173,7 +230,11 @@ impl Slate {
|
||||||
height: 0,
|
height: 0,
|
||||||
lock_height: 0,
|
lock_height: 0,
|
||||||
participant_data: vec![],
|
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.
|
//! Used for serialization and deserialization of slates in a backwards compatible way.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub mod v0;
|
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
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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::{
|
use crate::core::core::transaction::{
|
||||||
Input, KernelFeatures, Output, OutputFeatures, Transaction, TransactionBody, TxKernel,
|
KernelFeatures, OutputFeatures,
|
||||||
};
|
};
|
||||||
use crate::keychain::BlindingFactor;
|
use crate::keychain::BlindingFactor;
|
||||||
use crate::slate::{ParticipantData, Slate};
|
|
||||||
use crate::util::secp;
|
use crate::util::secp;
|
||||||
use crate::util::secp::key::PublicKey;
|
use crate::util::secp::key::PublicKey;
|
||||||
use crate::util::secp::pedersen::{Commitment, RangeProof};
|
use crate::util::secp::pedersen::{Commitment, RangeProof};
|
||||||
use crate::util::secp::Signature;
|
use crate::util::secp::Signature;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct SlateV0 {
|
pub struct SlateV0 {
|
||||||
/// The number of participants intended to take part in this transaction
|
/// The number of participants intended to take part in this transaction
|
||||||
|
@ -119,252 +120,3 @@ pub struct TxKernelV0 {
|
||||||
/// the transaction fee.
|
/// the transaction fee.
|
||||||
pub excess_sig: secp::Signature,
|
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,
|
pub selection_strategy_is_use_all: bool,
|
||||||
/// Optional message, that will be signed
|
/// Optional message, that will be signed
|
||||||
pub message: Option<String>,
|
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::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
use crate::adapters::util::{deserialize_slate, serialize_slate};
|
|
||||||
use crate::libwallet::slate::Slate;
|
use crate::libwallet::slate::Slate;
|
||||||
use crate::libwallet::Error;
|
use crate::libwallet::Error;
|
||||||
use crate::{WalletCommAdapter, WalletConfig};
|
use crate::{WalletCommAdapter, WalletConfig};
|
||||||
|
@ -43,7 +42,7 @@ impl WalletCommAdapter for FileWalletCommAdapter {
|
||||||
|
|
||||||
fn send_tx_async(&self, dest: &str, slate: &Slate) -> Result<(), Error> {
|
fn send_tx_async(&self, dest: &str, slate: &Slate) -> Result<(), Error> {
|
||||||
let mut pub_tx = File::create(dest)?;
|
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.write_all(slate_string.as_bytes())?;
|
||||||
pub_tx.sync_all()?;
|
pub_tx.sync_all()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -53,7 +52,7 @@ impl WalletCommAdapter for FileWalletCommAdapter {
|
||||||
let mut pub_tx_f = File::open(params)?;
|
let mut pub_tx_f = File::open(params)?;
|
||||||
let mut content = String::new();
|
let mut content = String::new();
|
||||||
pub_tx_f.read_to_string(&mut content)?;
|
pub_tx_f.read_to_string(&mut content)?;
|
||||||
Ok(deserialize_slate(&content))
|
Ok(Slate::deserialize_upgrade(&content)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn listen(
|
fn listen(
|
||||||
|
|
|
@ -12,10 +12,9 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::adapters::util::get_versioned_slate;
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::controller;
|
use crate::controller;
|
||||||
use crate::libwallet::slate::{Slate, VersionedSlate};
|
use crate::libwallet::slate::Slate;
|
||||||
use crate::libwallet::{Error, ErrorKind};
|
use crate::libwallet::{Error, ErrorKind};
|
||||||
use crate::{instantiate_wallet, HTTPNodeClient, WalletCommAdapter, WalletConfig};
|
use crate::{instantiate_wallet, HTTPNodeClient, WalletCommAdapter, WalletConfig};
|
||||||
/// HTTP Wallet 'plugin' implementation
|
/// HTTP Wallet 'plugin' implementation
|
||||||
|
@ -48,15 +47,15 @@ impl WalletCommAdapter for HTTPWalletCommAdapter {
|
||||||
}
|
}
|
||||||
let url = format!("{}/v1/wallet/foreign/receive_tx", dest);
|
let url = format!("{}/v1/wallet/foreign/receive_tx", dest);
|
||||||
debug!("Posting transaction slate to {}", url);
|
debug!("Posting transaction slate to {}", url);
|
||||||
let slate = get_versioned_slate(slate);
|
let slate = slate.serialize_to_version(Some(slate.version_info.orig_version))?;
|
||||||
let res: Result<VersionedSlate, _> = api::client::post(url.as_str(), None, &slate);
|
let res: Result<String, _> = api::client::post(url.as_str(), None, &slate);
|
||||||
match res {
|
match res {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let report = format!("Posting transaction slate (is recipient listening?): {}", e);
|
let report = format!("Posting transaction slate (is recipient listening?): {}", e);
|
||||||
error!("{}", report);
|
error!("{}", report);
|
||||||
Err(ErrorKind::ClientCallback(report).into())
|
Err(ErrorKind::ClientCallback(report).into())
|
||||||
}
|
}
|
||||||
Ok(r) => Ok(r.into()),
|
Ok(r) => Ok(Slate::deserialize_upgrade(&r)?),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
// Keybase Wallet Plugin
|
// Keybase Wallet Plugin
|
||||||
|
|
||||||
use crate::controller;
|
use crate::controller;
|
||||||
use crate::libwallet::slate::{Slate, VersionedSlate};
|
use crate::libwallet::slate::Slate;
|
||||||
use crate::libwallet::slate_versions::v0::SlateV0;
|
|
||||||
use crate::libwallet::{Error, ErrorKind};
|
use crate::libwallet::{Error, ErrorKind};
|
||||||
use crate::{instantiate_wallet, HTTPNodeClient, WalletCommAdapter, WalletConfig};
|
use crate::{instantiate_wallet, HTTPNodeClient, WalletCommAdapter, WalletConfig};
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
|
@ -259,7 +258,7 @@ fn poll(nseconds: u64, channel: &str) -> Option<Slate> {
|
||||||
while start.elapsed().as_secs() < nseconds {
|
while start.elapsed().as_secs() < nseconds {
|
||||||
let unread = read_from_channel(channel, SLATE_SIGNED);
|
let unread = read_from_channel(channel, SLATE_SIGNED);
|
||||||
for msg in unread.unwrap().iter() {
|
for msg in unread.unwrap().iter() {
|
||||||
let blob = from_str::<VersionedSlate>(msg);
|
let blob = Slate::deserialize_upgrade(&msg);
|
||||||
match blob {
|
match blob {
|
||||||
Ok(slate) => {
|
Ok(slate) => {
|
||||||
let slate: Slate = slate.into();
|
let slate: Slate = slate.into();
|
||||||
|
@ -268,7 +267,7 @@ fn poll(nseconds: u64, channel: &str) -> Option<Slate> {
|
||||||
channel, slate.id,
|
channel, slate.id,
|
||||||
);
|
);
|
||||||
return Some(slate);
|
return Some(slate);
|
||||||
}
|
},
|
||||||
Err(_) => (),
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,7 +349,7 @@ impl WalletCommAdapter for KeybaseWalletCommAdapter {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (msg, channel) in &unread.unwrap() {
|
for (msg, channel) in &unread.unwrap() {
|
||||||
let blob = from_str::<VersionedSlate>(msg);
|
let blob = Slate::deserialize_upgrade(&msg);
|
||||||
match blob {
|
match blob {
|
||||||
Ok(message) => {
|
Ok(message) => {
|
||||||
let mut slate: Slate = message.clone().into();
|
let mut slate: Slate = message.clone().into();
|
||||||
|
@ -385,15 +384,9 @@ impl WalletCommAdapter for KeybaseWalletCommAdapter {
|
||||||
}) {
|
}) {
|
||||||
// Reply to the same channel with topic SLATE_SIGNED
|
// Reply to the same channel with topic SLATE_SIGNED
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let success = match message {
|
let slate = slate.serialize_to_version(Some(slate.version_info.orig_version))?;
|
||||||
// Send the same version of slate that was sent to us
|
// TODO: Send the same version of slate that was sent to us
|
||||||
VersionedSlate::V0(_) => {
|
let success = send(slate, channel, SLATE_SIGNED, TTL);
|
||||||
send(SlateV0::from(slate), channel, SLATE_SIGNED, TTL)
|
|
||||||
}
|
|
||||||
VersionedSlate::V1(_) => {
|
|
||||||
send(slate, channel, SLATE_SIGNED, TTL)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if success {
|
if success {
|
||||||
notify_on_receive(
|
notify_on_receive(
|
||||||
|
|
|
@ -16,7 +16,6 @@ mod file;
|
||||||
mod http;
|
mod http;
|
||||||
mod keybase;
|
mod keybase;
|
||||||
mod null;
|
mod null;
|
||||||
pub mod util;
|
|
||||||
|
|
||||||
pub use self::file::FileWalletCommAdapter;
|
pub use self::file::FileWalletCommAdapter;
|
||||||
pub use self::http::HTTPWalletCommAdapter;
|
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 change_outputs: usize,
|
||||||
pub fluff: bool,
|
pub fluff: bool,
|
||||||
pub max_outputs: usize,
|
pub max_outputs: usize,
|
||||||
|
pub target_slate_version: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(
|
pub fn send(
|
||||||
|
@ -241,6 +242,7 @@ pub fn send(
|
||||||
args.change_outputs,
|
args.change_outputs,
|
||||||
args.selection_strategy == "all",
|
args.selection_strategy == "all",
|
||||||
args.message.clone(),
|
args.message.clone(),
|
||||||
|
args.target_slate_version,
|
||||||
);
|
);
|
||||||
let (mut slate, lock_fn) = match result {
|
let (mut slate, lock_fn) = match result {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
|
|
|
@ -15,14 +15,13 @@
|
||||||
//! Controller for wallet.. instantiates and handles listeners (or single-run
|
//! Controller for wallet.. instantiates and handles listeners (or single-run
|
||||||
//! invocations) as needed.
|
//! invocations) as needed.
|
||||||
//! Still experimental
|
//! Still experimental
|
||||||
use crate::adapters::util::get_versioned_slate;
|
|
||||||
use crate::adapters::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
|
use crate::adapters::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
|
||||||
use crate::api::{ApiServer, BasicAuthMiddleware, Handler, ResponseFuture, Router, TLSConfig};
|
use crate::api::{ApiServer, BasicAuthMiddleware, Handler, ResponseFuture, Router, TLSConfig};
|
||||||
use crate::apiwallet::api::{APIForeign, APIOwner};
|
use crate::apiwallet::api::{APIForeign, APIOwner};
|
||||||
use crate::core::core;
|
use crate::core::core;
|
||||||
use crate::core::core::Transaction;
|
use crate::core::core::Transaction;
|
||||||
use crate::keychain::Keychain;
|
use crate::keychain::Keychain;
|
||||||
use crate::libwallet::slate::{Slate, VersionedSlate};
|
use crate::libwallet::slate::Slate;
|
||||||
use crate::libwallet::types::{
|
use crate::libwallet::types::{
|
||||||
CbData, NodeClient, OutputData, SendTXArgs, TxLogEntry, WalletBackend, WalletInfo,
|
CbData, NodeClient, OutputData, SendTXArgs, TxLogEntry, WalletBackend, WalletInfo,
|
||||||
};
|
};
|
||||||
|
@ -330,6 +329,7 @@ where
|
||||||
args.num_change_outputs,
|
args.num_change_outputs,
|
||||||
args.selection_strategy_is_use_all,
|
args.selection_strategy_is_use_all,
|
||||||
args.message,
|
args.message,
|
||||||
|
args.target_slate_version,
|
||||||
);
|
);
|
||||||
let (mut slate, lock_fn) = match result {
|
let (mut slate, lock_fn) = match result {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
|
@ -661,17 +661,17 @@ where
|
||||||
&self,
|
&self,
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
api: APIForeign<T, C, K>,
|
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(
|
Box::new(parse_body(req).and_then(
|
||||||
//TODO: No way to insert a message from the params
|
//TODO: No way to insert a message from the params
|
||||||
move |slate: VersionedSlate| {
|
move |slate_str: String| {
|
||||||
let mut slate: Slate = slate.into();
|
let mut slate: Slate = Slate::deserialize_upgrade(&slate_str).unwrap();
|
||||||
if let Err(e) = api.verify_slate_messages(&slate) {
|
if let Err(e) = api.verify_slate_messages(&slate) {
|
||||||
error!("Error validating participant messages: {}", e);
|
error!("Error validating participant messages: {}", e);
|
||||||
err(e)
|
err(e)
|
||||||
} else {
|
} else {
|
||||||
match api.receive_tx(&mut slate, None, None) {
|
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) => {
|
Err(e) => {
|
||||||
error!("receive_tx: failed with error: {}", e);
|
error!("receive_tx: failed with error: {}", e);
|
||||||
err(e)
|
err(e)
|
||||||
|
|
|
@ -202,6 +202,7 @@ where
|
||||||
1, // num change outputs
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
let mut slate = client.send_tx_slate_direct(dest, &slate_i)?;
|
let mut slate = client.send_tx_slate_direct(dest, &slate_i)?;
|
||||||
api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
||||||
api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None, // optional message
|
None, // optional message
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
// output tx file
|
// output tx file
|
||||||
let file_adapter = FileWalletCommAdapter::new();
|
let file_adapter = FileWalletCommAdapter::new();
|
||||||
|
|
|
@ -111,6 +111,7 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
1, // num change outputs
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
Some(message.to_owned()), // optional message
|
Some(message.to_owned()), // optional message
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
// output tx file
|
// output tx file
|
||||||
let file_adapter = FileWalletCommAdapter::new();
|
let file_adapter = FileWalletCommAdapter::new();
|
||||||
|
|
|
@ -109,6 +109,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
1, // num change outputs
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
// output tx file
|
// output tx file
|
||||||
let file_adapter = FileWalletCommAdapter::new();
|
let file_adapter = FileWalletCommAdapter::new();
|
||||||
|
@ -205,6 +206,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
1, // num change outputs
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet3", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet3", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
api.tx_lock_outputs(&slate, lock_fn)?;
|
api.tx_lock_outputs(&slate, lock_fn)?;
|
||||||
// Send directly to self
|
// Send directly to self
|
||||||
|
|
|
@ -104,6 +104,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
1, // num change outputs
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
1, // num change outputs
|
||||||
true, // select all outputs
|
true, // select all outputs
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
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
|
// max_outputs
|
||||||
let max_outputs = 500;
|
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 {
|
Ok(command::SendArgs {
|
||||||
amount: amount,
|
amount: amount,
|
||||||
message: message,
|
message: message,
|
||||||
|
@ -404,6 +415,7 @@ pub fn parse_send_args(args: &ArgMatches) -> Result<command::SendArgs, ParseErro
|
||||||
change_outputs: change_outputs,
|
change_outputs: change_outputs,
|
||||||
fluff: fluff,
|
fluff: fluff,
|
||||||
max_outputs: max_outputs,
|
max_outputs: max_outputs,
|
||||||
|
target_slate_version: target_slate_version,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,11 @@ subcommands:
|
||||||
short: t
|
short: t
|
||||||
long: stored_tx
|
long: stored_tx
|
||||||
takes_value: true
|
takes_value: true
|
||||||
|
- slate_version:
|
||||||
|
help: Target slate version to output/send to receiver
|
||||||
|
short: v
|
||||||
|
long: slate_version
|
||||||
|
takes_value: true
|
||||||
- receive:
|
- receive:
|
||||||
about: Processes a transaction file to accept a transfer from a sender
|
about: Processes a transaction file to accept a transfer from a sender
|
||||||
args:
|
args:
|
||||||
|
|
Loading…
Reference in a new issue