mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-01-20 19:11:09 +03:00
Late locking (experimental) (#530)
* Late locking (experimental) * Error on fee change * Improve comments * Fix typo in comment * Add late locking flag to CLI command
This commit is contained in:
parent
c0e68ec3ea
commit
a83f92dfd3
14 changed files with 433 additions and 193 deletions
|
@ -163,17 +163,17 @@ pub trait ForeignRpc {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"off": "a4052c9200000001a6052c9200000002ed564fab50b75fc5ea32ce052fc9bebf",
|
"off": "a4f88ac429dee1d453ae33ed9f944417a52c7310477936e484fd83f0f22db483",
|
||||||
"proof": {
|
"proof": {
|
||||||
"raddr": "32cdd63928854f8b2628b1dce4626ddcdf35d56cb7cfdf7d64cca5822b78d4d3",
|
"raddr": "32cdd63928854f8b2628b1dce4626ddcdf35d56cb7cfdf7d64cca5822b78d4d3",
|
||||||
"rsig": "feb98c299e8328ea6b73b06e756eb3094180c3cc5ba01ed82dce75a5bfbe14f3ea235d9d9c2cee3e72cd162d9e5b5b77fcb8e34ad6a40551924bb010c9afdc0f",
|
"rsig": "02357a13b304ba8e22f4896d5664b72ad6d1b824e88782e2b716686ea14ec47281ef5ee14c03ead84c3260f5b0c1529ad3ddae57f28f6b8b1b66532bfcb2ee0f",
|
||||||
"saddr": "32cdd63928854f8b2628b1dce4626ddcdf35d56cb7cfdf7d64cca5822b78d4d3"
|
"saddr": "32cdd63928854f8b2628b1dce4626ddcdf35d56cb7cfdf7d64cca5822b78d4d3"
|
||||||
},
|
},
|
||||||
"sigs": [
|
"sigs": [
|
||||||
{
|
{
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b54735cb9ed2f59fb457144f7b1c8226d08b54cbdd0eb7e6492950751b0bb54f9",
|
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841babbc82d2e200efe3a3b70cdfbed5b4e1d2a87641d0c4f6a3d7e73b80facb8507",
|
||||||
"xs": "03b0d73a044f1f9ae06cf96ef91593f121864b66bf7f7e7ac481b0ce61e39847fe"
|
"xs": "02e3c128e436510500616fef3f9a22b15ca015f407c8c5cf96c9059163c873828f"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sta": "S2",
|
"sta": "S2",
|
||||||
|
@ -209,13 +209,13 @@ pub trait ForeignRpc {
|
||||||
"ver": "4:2",
|
"ver": "4:2",
|
||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"sta": "I2",
|
"sta": "I2",
|
||||||
"off": "750dbf4fd43b7f4cfd68d2698a522f3ff6e6a00ad9895b33f1ec46493b837b49",
|
"off": "dbd68b83e4d6f9ebaebf179fdde3efd4309734124937bcb5f5a7df49120eca7f",
|
||||||
"fee": "7000000",
|
"fee": "7000000",
|
||||||
"sigs": [
|
"sigs": [
|
||||||
{
|
{
|
||||||
"xs": "030152d2d72e2dba7c6086ad49a219d9ff0dfe0fd993dcaea22e058c210033ce93",
|
"xs": "0384a71f13c434e79b70f9a0649e34887f1c6caf3021636cfced448a146ca23c7a",
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841bdad934daa17db7e477c4eed90afed40d1117896df8c4f5861b6309a949878074"
|
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b6485299a0be2e4306663dcc78f1bc9d029c7be30e423558fe3f4fcfc9ad79a8e"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"coms": [
|
"coms": [
|
||||||
|
@ -262,17 +262,17 @@ pub trait ForeignRpc {
|
||||||
],
|
],
|
||||||
"fee": "7000000",
|
"fee": "7000000",
|
||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"off": "750dbf4fd43b7f4cfd68d2698a522f3ff6e6a00ad9895b33f1ec46493b837b49",
|
"off": "4940f497462b7140383738c1665fa3989e6fff5d9f411a33aa04438f75d6de2c",
|
||||||
"sigs": [
|
"sigs": [
|
||||||
{
|
{
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841bdad934daa17db7e477c4eed90afed40d1117896df8c4f5861b6309a949878074",
|
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b6485299a0be2e4306663dcc78f1bc9d029c7be30e423558fe3f4fcfc9ad79a8e",
|
||||||
"xs": "030152d2d72e2dba7c6086ad49a219d9ff0dfe0fd993dcaea22e058c210033ce93"
|
"xs": "0384a71f13c434e79b70f9a0649e34887f1c6caf3021636cfced448a146ca23c7a"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b35fdfe55271f2ae73d75f58c70d1efb69b3384c7bc507d57e99e56de77e20874",
|
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b32617ea149fa6faf220f4212530517809e9ed2193f5e558b1de9d339414fda91",
|
||||||
"xs": "033bbe2a419ea2e9d6810a8d66552e709d1783ca50759a44dbaf63fc79c0164c4c"
|
"xs": "02e89cce4499ac1e9bb498dab9e3fab93cc40cd3d26c04a0292e00f4bf272499ec"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sta": "I3",
|
"sta": "I3",
|
||||||
|
|
|
@ -395,7 +395,6 @@ pub trait OwnerRpc {
|
||||||
"amt": "6000000000",
|
"amt": "6000000000",
|
||||||
"fee": "8000000",
|
"fee": "8000000",
|
||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"off": "d202964900000000d302964900000000d402964900000000d502964900000000",
|
|
||||||
"proof": {
|
"proof": {
|
||||||
"raddr": "32cdd63928854f8b2628b1dce4626ddcdf35d56cb7cfdf7d64cca5822b78d4d3",
|
"raddr": "32cdd63928854f8b2628b1dce4626ddcdf35d56cb7cfdf7d64cca5822b78d4d3",
|
||||||
"saddr": "32cdd63928854f8b2628b1dce4626ddcdf35d56cb7cfdf7d64cca5822b78d4d3"
|
"saddr": "32cdd63928854f8b2628b1dce4626ddcdf35d56cb7cfdf7d64cca5822b78d4d3"
|
||||||
|
@ -403,7 +402,7 @@ pub trait OwnerRpc {
|
||||||
"sigs": [
|
"sigs": [
|
||||||
{
|
{
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"xs": "023878ce845727f3a4ec76ca3f3db4b38a2d05d636b8c3632108b857fed63c96de"
|
"xs": "02e89cce4499ac1e9bb498dab9e3fab93cc40cd3d26c04a0292e00f4bf272499ec"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sta": "S1",
|
"sta": "S1",
|
||||||
|
@ -447,11 +446,10 @@ pub trait OwnerRpc {
|
||||||
"Ok": {
|
"Ok": {
|
||||||
"amt": "6000000000",
|
"amt": "6000000000",
|
||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"off": "d202964900000000d302964900000000d402964900000000d502964900000000",
|
|
||||||
"sigs": [
|
"sigs": [
|
||||||
{
|
{
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"xs": "028e95921cc0d5be5922362265d352c9bdabe51a9e1502a3f0d4a10387f1893f40"
|
"xs": "02e89cce4499ac1e9bb498dab9e3fab93cc40cd3d26c04a0292e00f4bf272499ec"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sta": "I1",
|
"sta": "I1",
|
||||||
|
@ -529,12 +527,12 @@ pub trait OwnerRpc {
|
||||||
],
|
],
|
||||||
"fee": "8000000",
|
"fee": "8000000",
|
||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"off": "9b6e26e78b49c7136ce70334dd83acb89c78f6c54cfab64ba62e598837241d36",
|
"off": "bca108f36955448dacfc0464d75d010641f9e1a81709c27bc4404eea895c4f91",
|
||||||
"sigs": [
|
"sigs": [
|
||||||
{
|
{
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841bf1804f6fe8e55f5556bbd807fefbcd72b30d90cf708f8c56447acc63228274e6",
|
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b20b8e09af72b6b7212c1bf6a4c17d56ce0048e05bb5309c1394a3d763a102a7e",
|
||||||
"xs": "023878ce845727f3a4ec76ca3f3db4b38a2d05d636b8c3632108b857fed63c96de"
|
"xs": "02e3c128e436510500616fef3f9a22b15ca015f407c8c5cf96c9059163c873828f"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sta": "I2",
|
"sta": "I2",
|
||||||
|
@ -616,12 +614,12 @@ pub trait OwnerRpc {
|
||||||
"ver": "4:2",
|
"ver": "4:2",
|
||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"sta": "S2",
|
"sta": "S2",
|
||||||
"off": "a4052c9200000001a6052c9200000002ed564fab50b75fc5ea32ce052fc9bebf",
|
"off": "696a69136154775485782121887bb3c32487a8320551fdb9702ec2d333fe54ee",
|
||||||
"sigs": [
|
"sigs": [
|
||||||
{
|
{
|
||||||
"xs": "033bbe2a419ea2e9d6810a8d66552e709d1783ca50759a44dbaf63fc79c0164c4c",
|
"xs": "0384a71f13c434e79b70f9a0649e34887f1c6caf3021636cfced448a146ca23c7a",
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b35fdfe55271f2ae73d75f58c70d1efb69b3384c7bc507d57e99e56de77e20874"
|
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b6485299a0be2e4306663dcc78f1bc9d029c7be30e423558fe3f4fcfc9ad79a8e"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"coms": [
|
"coms": [
|
||||||
|
@ -661,17 +659,17 @@ pub trait OwnerRpc {
|
||||||
],
|
],
|
||||||
"fee": "7000000",
|
"fee": "7000000",
|
||||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||||
"off": "750dbf4fd43b7f4cfd68d2698a522f3ff6e6a00ad9895b33f1ec46493b837b49",
|
"off": "4940f497462b7140383738c1665fa3989e6fff5d9f411a33aa04438f75d6de2c",
|
||||||
"sigs": [
|
"sigs": [
|
||||||
{
|
{
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b35fdfe55271f2ae73d75f58c70d1efb69b3384c7bc507d57e99e56de77e20874",
|
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b6485299a0be2e4306663dcc78f1bc9d029c7be30e423558fe3f4fcfc9ad79a8e",
|
||||||
"xs": "033bbe2a419ea2e9d6810a8d66552e709d1783ca50759a44dbaf63fc79c0164c4c"
|
"xs": "0384a71f13c434e79b70f9a0649e34887f1c6caf3021636cfced448a146ca23c7a"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
"nonce": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841bdad934daa17db7e477c4eed90afed40d1117896df8c4f5861b6309a949878074",
|
"part": "8f07ddd5e9f5179cff19486034181ed76505baaad53e5d994064127b56c5841b32617ea149fa6faf220f4212530517809e9ed2193f5e558b1de9d339414fda91",
|
||||||
"xs": "030152d2d72e2dba7c6086ad49a219d9ff0dfe0fd993dcaea22e058c210033ce93"
|
"xs": "02e89cce4499ac1e9bb498dab9e3fab93cc40cd3d26c04a0292e00f4bf272499ec"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sta": "S3",
|
"sta": "S3",
|
||||||
|
@ -1626,11 +1624,11 @@ pub trait OwnerRpc {
|
||||||
"result": {
|
"result": {
|
||||||
"Ok": {
|
"Ok": {
|
||||||
"amount": "60000000000",
|
"amount": "60000000000",
|
||||||
"excess": "091f151170bfac881479bfb56c7012c52cd4ce4198ad661586374dd499925922fb",
|
"excess": "09eac5f5872fa5e08e0c29fd900f1b8f77ff3ad1d0d1c46aeb202cbf92363fe0af",
|
||||||
"recipient_address": "tgrin10qlk22rxjap2ny8qltc2tl996kenxr3hhwuu6hrzs6tdq08yaqgqq6t83r",
|
"recipient_address": "tgrin10qlk22rxjap2ny8qltc2tl996kenxr3hhwuu6hrzs6tdq08yaqgqq6t83r",
|
||||||
"recipient_sig": "b9b1885a3f33297df32e1aa4db23220bd305da8ed92ff6873faf3ab2c116fea25e9d0e34bd4f567f022b88a37400821ffbcaec71c9a8c3a327c4626611886d0d",
|
"recipient_sig": "02868f2d2b983981f8f98043701687a8531ed2de564ea3df48e9e7e0229ccbe8359efe506896df2efbe3528e977252c50e4a41ca3cc9896e7c5a30bbb1d33604",
|
||||||
"sender_address": "tgrin1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfs9gm2lp",
|
"sender_address": "tgrin1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfs9gm2lp",
|
||||||
"sender_sig": "611b92331e395c3d29871ac35b1fce78ec595e28ccbe8cc55452da40775e8e46d35a2e84eaffd986935da3275e34d46a8d777d02dabcf4339704c2a621da9700"
|
"sender_sig": "c511764f3f61ed3d1cbca9514df8bc6811fad5662b1cb0e0587b9c9e49db9f33183cce71af6cb24b507fabf525a2bc405c6e84e63a60334edff0b451ae5e6102"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1659,11 +1657,11 @@ pub trait OwnerRpc {
|
||||||
"token": "d202964900000000d302964900000000d402964900000000d502964900000000",
|
"token": "d202964900000000d302964900000000d402964900000000d502964900000000",
|
||||||
"proof": {
|
"proof": {
|
||||||
"amount": "60000000000",
|
"amount": "60000000000",
|
||||||
"excess": "091f151170bfac881479bfb56c7012c52cd4ce4198ad661586374dd499925922fb",
|
"excess": "09eac5f5872fa5e08e0c29fd900f1b8f77ff3ad1d0d1c46aeb202cbf92363fe0af",
|
||||||
"recipient_address": "slatepack10qlk22rxjap2ny8qltc2tl996kenxr3hhwuu6hrzs6tdq08yaqgqnlumr7",
|
"recipient_address": "slatepack10qlk22rxjap2ny8qltc2tl996kenxr3hhwuu6hrzs6tdq08yaqgqnlumr7",
|
||||||
"recipient_sig": "b9b1885a3f33297df32e1aa4db23220bd305da8ed92ff6873faf3ab2c116fea25e9d0e34bd4f567f022b88a37400821ffbcaec71c9a8c3a327c4626611886d0d",
|
"recipient_sig": "02868f2d2b983981f8f98043701687a8531ed2de564ea3df48e9e7e0229ccbe8359efe506896df2efbe3528e977252c50e4a41ca3cc9896e7c5a30bbb1d33604",
|
||||||
"sender_address": "slatepack1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfskdvkdu",
|
"sender_address": "slatepack1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfskdvkdu",
|
||||||
"sender_sig": "611b92331e395c3d29871ac35b1fce78ec595e28ccbe8cc55452da40775e8e46d35a2e84eaffd986935da3275e34d46a8d777d02dabcf4339704c2a621da9700"
|
"sender_sig": "c511764f3f61ed3d1cbca9514df8bc6811fad5662b1cb0e0587b9c9e49db9f33183cce71af6cb24b507fabf525a2bc405c6e84e63a60334edff0b451ae5e6102"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"id": 1
|
"id": 1
|
||||||
|
|
|
@ -249,6 +249,7 @@ pub struct SendArgs {
|
||||||
pub minimum_confirmations: u64,
|
pub minimum_confirmations: u64,
|
||||||
pub selection_strategy: String,
|
pub selection_strategy: String,
|
||||||
pub estimate_selection_strategies: bool,
|
pub estimate_selection_strategies: bool,
|
||||||
|
pub late_lock: bool,
|
||||||
pub dest: String,
|
pub dest: String,
|
||||||
pub change_outputs: usize,
|
pub change_outputs: usize,
|
||||||
pub fluff: bool,
|
pub fluff: bool,
|
||||||
|
@ -307,6 +308,7 @@ where
|
||||||
payment_proof_recipient_address: args.payment_proof_address.clone(),
|
payment_proof_recipient_address: args.payment_proof_address.clone(),
|
||||||
ttl_blocks: args.ttl_blocks,
|
ttl_blocks: args.ttl_blocks,
|
||||||
send_args: None,
|
send_args: None,
|
||||||
|
late_lock: Some(args.late_lock),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let result = api.init_send_tx(m, init_args);
|
let result = api.init_send_tx(m, init_args);
|
||||||
|
|
163
controller/tests/late_lock.rs
Normal file
163
controller/tests/late_lock.rs
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
// Copyright 2020 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.
|
||||||
|
|
||||||
|
//! Tests and experimentations with late locking
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
extern crate grin_wallet_controller as wallet;
|
||||||
|
extern crate grin_wallet_impls as impls;
|
||||||
|
extern crate grin_wallet_libwallet as libwallet;
|
||||||
|
|
||||||
|
use self::libwallet::{InitTxArgs, Slate};
|
||||||
|
use impls::test_framework::{self, LocalWalletClient};
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod common;
|
||||||
|
use common::{clean_output_dir, create_wallet_proxy, setup};
|
||||||
|
|
||||||
|
/// self send impl
|
||||||
|
fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||||
|
// Create a new proxy to simulate server and wallet responses
|
||||||
|
let mut wallet_proxy = create_wallet_proxy(test_dir);
|
||||||
|
let chain = wallet_proxy.chain.clone();
|
||||||
|
let stopper = wallet_proxy.running.clone();
|
||||||
|
|
||||||
|
// Create a new wallet test client, and set its queues to communicate with the
|
||||||
|
// proxy
|
||||||
|
create_wallet_and_add!(
|
||||||
|
client1,
|
||||||
|
wallet1,
|
||||||
|
mask1_i,
|
||||||
|
test_dir,
|
||||||
|
"wallet1",
|
||||||
|
None,
|
||||||
|
&mut wallet_proxy,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
let mask1 = (&mask1_i).as_ref();
|
||||||
|
create_wallet_and_add!(
|
||||||
|
client2,
|
||||||
|
wallet2,
|
||||||
|
mask2_i,
|
||||||
|
test_dir,
|
||||||
|
"wallet2",
|
||||||
|
None,
|
||||||
|
&mut wallet_proxy,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
let mask2 = (&mask2_i).as_ref();
|
||||||
|
|
||||||
|
// Set the wallet proxy listener running
|
||||||
|
thread::spawn(move || {
|
||||||
|
if let Err(e) = wallet_proxy.run() {
|
||||||
|
error!("Wallet Proxy error: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// add some accounts
|
||||||
|
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||||
|
api.create_account_path(m, "mining")?;
|
||||||
|
api.create_account_path(m, "listener")?;
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// add some accounts
|
||||||
|
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||||
|
api.create_account_path(m, "account1")?;
|
||||||
|
api.create_account_path(m, "account2")?;
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Get some mining done
|
||||||
|
{
|
||||||
|
wallet_inst!(wallet1, w);
|
||||||
|
w.set_parent_key_id_by_name("mining")?;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
wallet_inst!(wallet2, w);
|
||||||
|
w.set_parent_key_id_by_name("account1")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bh = 10u64;
|
||||||
|
let _ =
|
||||||
|
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||||
|
|
||||||
|
let mut slate = Slate::blank(2, false);
|
||||||
|
let amount = 60_000_000_000;
|
||||||
|
|
||||||
|
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
|
||||||
|
let args = InitTxArgs {
|
||||||
|
src_acct_name: Some("mining".to_owned()),
|
||||||
|
amount,
|
||||||
|
minimum_confirmations: 2,
|
||||||
|
max_outputs: 500,
|
||||||
|
num_change_outputs: 1,
|
||||||
|
selection_strategy_is_use_all: false,
|
||||||
|
late_lock: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||||
|
println!("S1 SLATE: {}", slate_i);
|
||||||
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
|
println!("S2 SLATE: {}", slate);
|
||||||
|
|
||||||
|
// Note we don't call `tx_lock_outputs` on the sender side here,
|
||||||
|
// as the outputs will only be locked during finalization
|
||||||
|
|
||||||
|
slate = sender_api.finalize_tx(m, &slate)?;
|
||||||
|
println!("S3 SLATE: {}", slate);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||||
|
|
||||||
|
// update/test contents of both accounts
|
||||||
|
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||||
|
let (wallet1_refreshed, wallet_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||||
|
assert!(wallet1_refreshed);
|
||||||
|
print!(
|
||||||
|
"Wallet 1 amount: {}",
|
||||||
|
wallet_info.amount_currently_spendable
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||||
|
let (wallet2_refreshed, wallet_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||||
|
assert!(wallet2_refreshed);
|
||||||
|
println!(
|
||||||
|
"Wallet 2 amount: {}",
|
||||||
|
wallet_info.amount_currently_spendable
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// let logging finish
|
||||||
|
stopper.store(false, Ordering::Relaxed);
|
||||||
|
thread::sleep(Duration::from_millis(200));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn late_lock() {
|
||||||
|
let test_dir = "test_output/late_lock";
|
||||||
|
setup(test_dir);
|
||||||
|
if let Err(e) = late_lock_test_impl(test_dir) {
|
||||||
|
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||||
|
}
|
||||||
|
clean_output_dir(test_dir);
|
||||||
|
}
|
|
@ -105,6 +105,9 @@ where
|
||||||
use_test_rng,
|
use_test_rng,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Add our contribution to the offset
|
||||||
|
ret_slate.adjust_offset(&keychain, &context)?;
|
||||||
|
|
||||||
let excess = ret_slate.calc_excess(keychain.secp())?;
|
let excess = ret_slate.calc_excess(keychain.secp())?;
|
||||||
|
|
||||||
if let Some(ref mut p) = ret_slate.payment_proof {
|
if let Some(ref mut p) = ret_slate.payment_proof {
|
||||||
|
@ -143,6 +146,9 @@ where
|
||||||
if sl.state == SlateState::Invoice2 {
|
if sl.state == SlateState::Invoice2 {
|
||||||
check_ttl(w, &sl)?;
|
check_ttl(w, &sl)?;
|
||||||
|
|
||||||
|
// Add our contribution to the offset
|
||||||
|
sl.adjust_offset(&w.keychain(keychain_mask)?, &context)?;
|
||||||
|
|
||||||
let mut temp_ctx = context.clone();
|
let mut temp_ctx = context.clone();
|
||||||
temp_ctx.sec_key = context.initial_sec_key.clone();
|
temp_ctx.sec_key = context.initial_sec_key.clone();
|
||||||
temp_ctx.sec_nonce = context.initial_sec_nonce.clone();
|
temp_ctx.sec_nonce = context.initial_sec_nonce.clone();
|
||||||
|
|
|
@ -457,9 +457,9 @@ where
|
||||||
C: NodeClient + 'a,
|
C: NodeClient + 'a,
|
||||||
K: Keychain + 'a,
|
K: Keychain + 'a,
|
||||||
{
|
{
|
||||||
let parent_key_id = match args.src_acct_name {
|
let parent_key_id = match &args.src_acct_name {
|
||||||
Some(d) => {
|
Some(d) => {
|
||||||
let pm = w.get_acct_path(d)?;
|
let pm = w.get_acct_path(d.clone())?;
|
||||||
match pm {
|
match pm {
|
||||||
Some(p) => p.path,
|
Some(p) => p.path,
|
||||||
None => w.parent_key_id(),
|
None => w.parent_key_id(),
|
||||||
|
@ -500,19 +500,31 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
let height = w.w2n_client().get_chain_tip()?.0;
|
let height = w.w2n_client().get_chain_tip()?.0;
|
||||||
let mut context = tx::add_inputs_to_slate(
|
let mut context = if args.late_lock.unwrap_or(false) {
|
||||||
&mut *w,
|
tx::create_late_lock_context(
|
||||||
keychain_mask,
|
&mut *w,
|
||||||
&mut slate,
|
keychain_mask,
|
||||||
height,
|
&mut slate,
|
||||||
args.minimum_confirmations,
|
height,
|
||||||
args.max_outputs as usize,
|
&args,
|
||||||
args.num_change_outputs as usize,
|
&parent_key_id,
|
||||||
args.selection_strategy_is_use_all,
|
use_test_rng,
|
||||||
&parent_key_id,
|
)?
|
||||||
true,
|
} else {
|
||||||
use_test_rng,
|
tx::add_inputs_to_slate(
|
||||||
)?;
|
&mut *w,
|
||||||
|
keychain_mask,
|
||||||
|
&mut slate,
|
||||||
|
height,
|
||||||
|
args.minimum_confirmations,
|
||||||
|
args.max_outputs as usize,
|
||||||
|
args.num_change_outputs as usize,
|
||||||
|
args.selection_strategy_is_use_all,
|
||||||
|
&parent_key_id,
|
||||||
|
true,
|
||||||
|
use_test_rng,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
// Payment Proof, add addresses to slate and save address
|
// Payment Proof, add addresses to slate and save address
|
||||||
// TODO: Note we only use single derivation path for now,
|
// TODO: Note we only use single derivation path for now,
|
||||||
|
@ -667,6 +679,19 @@ where
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let keychain = w.keychain(keychain_mask)?;
|
let keychain = w.keychain(keychain_mask)?;
|
||||||
|
|
||||||
|
// Add our contribution to the offset
|
||||||
|
if context_res.is_ok() {
|
||||||
|
// Self sending: don't correct for inputs and outputs
|
||||||
|
// here, as we will do it during finalization.
|
||||||
|
let mut tmp_context = context.clone();
|
||||||
|
tmp_context.input_ids.clear();
|
||||||
|
tmp_context.output_ids.clear();
|
||||||
|
ret_slate.adjust_offset(&keychain, &tmp_context)?;
|
||||||
|
} else {
|
||||||
|
ret_slate.adjust_offset(&keychain, &context)?;
|
||||||
|
}
|
||||||
|
|
||||||
// needs to be stored as we're removing sig data for return trip. this needs to be present
|
// needs to be stored as we're removing sig data for return trip. this needs to be present
|
||||||
// when locking transaction context and updating tx log with excess later
|
// when locking transaction context and updating tx log with excess later
|
||||||
context.calculated_excess = Some(ret_slate.calc_excess(keychain.secp())?);
|
context.calculated_excess = Some(ret_slate.calc_excess(keychain.secp())?);
|
||||||
|
@ -685,7 +710,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tx::sub_inputs_from_offset(&mut *w, keychain_mask, &context, &mut ret_slate)?;
|
|
||||||
selection::repopulate_tx(&mut *w, keychain_mask, &mut ret_slate, &context, false)?;
|
selection::repopulate_tx(&mut *w, keychain_mask, &mut ret_slate, &context, false)?;
|
||||||
|
|
||||||
// Save the aggsig context in our DB for when we
|
// Save the aggsig context in our DB for when we
|
||||||
|
@ -754,16 +778,51 @@ where
|
||||||
{
|
{
|
||||||
let mut sl = slate.clone();
|
let mut sl = slate.clone();
|
||||||
check_ttl(w, &sl)?;
|
check_ttl(w, &sl)?;
|
||||||
let context = w.get_private_context(keychain_mask, sl.id.as_bytes())?;
|
let mut context = w.get_private_context(keychain_mask, sl.id.as_bytes())?;
|
||||||
|
let keychain = w.keychain(keychain_mask)?;
|
||||||
let parent_key_id = w.parent_key_id();
|
let parent_key_id = w.parent_key_id();
|
||||||
|
|
||||||
// since we're now actually inserting our inputs, pick an offset and adjust
|
if let Some(args) = context.late_lock_args.take() {
|
||||||
// our contribution to the excess by offset amount
|
// Transaction was late locked, select inputs+change now
|
||||||
// TODO: Post HF3, this should allow for inputs to be picked at this stage
|
// and insert into original context
|
||||||
// as opposed to locking them prior to this stage, as the excess to this point
|
|
||||||
// will just be the change output
|
let current_height = w.w2n_client().get_chain_tip()?.0;
|
||||||
|
let mut temp_sl =
|
||||||
|
tx::new_tx_slate(&mut *w, context.amount, false, 2, false, args.ttl_blocks)?;
|
||||||
|
let temp_context = selection::build_send_tx(
|
||||||
|
w,
|
||||||
|
&keychain,
|
||||||
|
keychain_mask,
|
||||||
|
&mut temp_sl,
|
||||||
|
current_height,
|
||||||
|
args.minimum_confirmations,
|
||||||
|
args.max_outputs as usize,
|
||||||
|
args.num_change_outputs as usize,
|
||||||
|
args.selection_strategy_is_use_all,
|
||||||
|
Some(context.fee),
|
||||||
|
parent_key_id.clone(),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Add inputs and outputs to original context
|
||||||
|
context.input_ids = temp_context.input_ids;
|
||||||
|
context.output_ids = temp_context.output_ids;
|
||||||
|
|
||||||
|
// Store the updated context
|
||||||
|
{
|
||||||
|
let mut batch = w.batch(keychain_mask)?;
|
||||||
|
batch.save_private_context(sl.id.as_bytes(), &context)?;
|
||||||
|
batch.commit()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now do the actual locking
|
||||||
|
tx_lock_outputs(w, keychain_mask, &sl)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add our contribution to the offset
|
||||||
|
sl.adjust_offset(&keychain, &context)?;
|
||||||
|
|
||||||
tx::sub_inputs_from_offset(&mut *w, keychain_mask, &context, &mut sl)?;
|
|
||||||
selection::repopulate_tx(&mut *w, keychain_mask, &mut sl, &context, true)?;
|
selection::repopulate_tx(&mut *w, keychain_mask, &mut sl, &context, true)?;
|
||||||
|
|
||||||
tx::complete_tx(&mut *w, keychain_mask, &mut sl, &context)?;
|
tx::complete_tx(&mut *w, keychain_mask, &mut sl, &context)?;
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::SlatepackAddress;
|
||||||
use ed25519_dalek::Signature as DalekSignature;
|
use ed25519_dalek::Signature as DalekSignature;
|
||||||
|
|
||||||
/// V2 Init / Send TX API Args
|
/// V2 Init / Send TX API Args
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct InitTxArgs {
|
pub struct InitTxArgs {
|
||||||
/// The human readable account name from which to draw outputs
|
/// The human readable account name from which to draw outputs
|
||||||
/// for the transaction, overriding whatever the active account is as set via the
|
/// for the transaction, overriding whatever the active account is as set via the
|
||||||
|
@ -71,6 +71,10 @@ pub struct InitTxArgs {
|
||||||
/// 'true', the amount field in the slate will contain the total amount locked, not the provided
|
/// 'true', the amount field in the slate will contain the total amount locked, not the provided
|
||||||
/// transaction amount
|
/// transaction amount
|
||||||
pub estimate_only: Option<bool>,
|
pub estimate_only: Option<bool>,
|
||||||
|
/// EXPERIMENTAL: if flagged, create the transaction as late-locked, i.e. don't select actual
|
||||||
|
/// inputs until just before finalization
|
||||||
|
#[serde(default)]
|
||||||
|
pub late_lock: Option<bool>,
|
||||||
/// Sender arguments. If present, the underlying function will also attempt to send the
|
/// Sender arguments. If present, the underlying function will also attempt to send the
|
||||||
/// transaction to a destination and optionally finalize the result
|
/// transaction to a destination and optionally finalize the result
|
||||||
pub send_args: Option<InitTxSendArgs>,
|
pub send_args: Option<InitTxSendArgs>,
|
||||||
|
@ -78,7 +82,7 @@ pub struct InitTxArgs {
|
||||||
|
|
||||||
/// Send TX API Args, for convenience functionality that inits the transaction and sends
|
/// Send TX API Args, for convenience functionality that inits the transaction and sends
|
||||||
/// in one go
|
/// in one go
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct InitTxSendArgs {
|
pub struct InitTxSendArgs {
|
||||||
/// The destination, contents will depend on the particular method
|
/// The destination, contents will depend on the particular method
|
||||||
pub dest: String,
|
pub dest: String,
|
||||||
|
@ -103,6 +107,7 @@ impl Default for InitTxArgs {
|
||||||
ttl_blocks: None,
|
ttl_blocks: None,
|
||||||
estimate_only: Some(false),
|
estimate_only: Some(false),
|
||||||
payment_proof_recipient_address: None,
|
payment_proof_recipient_address: None,
|
||||||
|
late_lock: Some(false),
|
||||||
send_args: None,
|
send_args: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,10 @@ pub fn build_send_tx<'a, T: ?Sized, C, K>(
|
||||||
max_outputs: usize,
|
max_outputs: usize,
|
||||||
change_outputs: usize,
|
change_outputs: usize,
|
||||||
selection_strategy_is_use_all: bool,
|
selection_strategy_is_use_all: bool,
|
||||||
|
fixed_fee: Option<u64>,
|
||||||
parent_key_id: Identifier,
|
parent_key_id: Identifier,
|
||||||
use_test_nonce: bool,
|
use_test_nonce: bool,
|
||||||
|
is_initiator: bool,
|
||||||
) -> Result<Context, Error>
|
) -> Result<Context, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<'a, C, K>,
|
T: WalletBackend<'a, C, K>,
|
||||||
|
@ -67,17 +69,20 @@ where
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
if fixed_fee.map(|f| fee != f).unwrap_or(false) {
|
||||||
|
return Err(ErrorKind::Fee("The initially selected fee is not sufficient".into()).into());
|
||||||
|
}
|
||||||
|
|
||||||
// Update the fee on the slate so we account for this when building the tx.
|
// Update the fee on the slate so we account for this when building the tx.
|
||||||
slate.fee = fee;
|
slate.fee = fee;
|
||||||
|
slate.add_transaction_elements(keychain, &ProofBuilder::new(keychain), elems)?;
|
||||||
let blinding = slate.add_transaction_elements(keychain, &ProofBuilder::new(keychain), elems)?;
|
|
||||||
|
|
||||||
// Create our own private context
|
// Create our own private context
|
||||||
let mut context = Context::new(
|
let mut context = Context::new(
|
||||||
keychain.secp(),
|
keychain.secp(),
|
||||||
blinding.secret_key(&keychain.secp()).unwrap(),
|
|
||||||
&parent_key_id,
|
&parent_key_id,
|
||||||
use_test_nonce,
|
use_test_nonce,
|
||||||
|
is_initiator,
|
||||||
);
|
);
|
||||||
|
|
||||||
context.fee = fee;
|
context.fee = fee;
|
||||||
|
@ -237,6 +242,7 @@ pub fn build_recipient_output<'a, T: ?Sized, C, K>(
|
||||||
current_height: u64,
|
current_height: u64,
|
||||||
parent_key_id: Identifier,
|
parent_key_id: Identifier,
|
||||||
use_test_rng: bool,
|
use_test_rng: bool,
|
||||||
|
is_initiator: bool,
|
||||||
) -> Result<(Identifier, Context, TxLogEntry), Error>
|
) -> Result<(Identifier, Context, TxLogEntry), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<'a, C, K>,
|
T: WalletBackend<'a, C, K>,
|
||||||
|
@ -251,21 +257,14 @@ where
|
||||||
let height = current_height;
|
let height = current_height;
|
||||||
|
|
||||||
let slate_id = slate.id;
|
let slate_id = slate.id;
|
||||||
let blinding = slate.add_transaction_elements(
|
slate.add_transaction_elements(
|
||||||
&keychain,
|
&keychain,
|
||||||
&ProofBuilder::new(&keychain),
|
&ProofBuilder::new(&keychain),
|
||||||
vec![build::output(amount, key_id.clone())],
|
vec![build::output(amount, key_id.clone())],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Add blinding sum to our context
|
// Add blinding sum to our context
|
||||||
let mut context = Context::new(
|
let mut context = Context::new(keychain.secp(), &parent_key_id, use_test_rng, is_initiator);
|
||||||
keychain.secp(),
|
|
||||||
blinding
|
|
||||||
.secret_key(wallet.keychain(keychain_mask)?.secp())
|
|
||||||
.unwrap(),
|
|
||||||
&parent_key_id,
|
|
||||||
use_test_rng,
|
|
||||||
);
|
|
||||||
|
|
||||||
context.add_output(&key_id, &None, amount);
|
context.add_output(&key_id, &None, amount);
|
||||||
context.amount = amount;
|
context.amount = amount;
|
||||||
|
@ -398,9 +397,6 @@ where
|
||||||
// recipient should double check the fee calculation and not blindly trust the
|
// recipient should double check the fee calculation and not blindly trust the
|
||||||
// sender
|
// sender
|
||||||
|
|
||||||
// TODO - Is it safe to spend without a change output? (1 input -> 1 output)
|
|
||||||
// TODO - Does this not potentially reveal the senders private key?
|
|
||||||
//
|
|
||||||
// First attempt to spend without change
|
// First attempt to spend without change
|
||||||
let mut fee = tx_fee(coins.len(), 1, 1, None);
|
let mut fee = tx_fee(coins.len(), 1, 1, None);
|
||||||
let mut total: u64 = coins.iter().map(|c| c.value).sum();
|
let mut total: u64 = coins.iter().map(|c| c.value).sum();
|
||||||
|
@ -665,7 +661,7 @@ where
|
||||||
let keychain = wallet.keychain(keychain_mask)?;
|
let keychain = wallet.keychain(keychain_mask)?;
|
||||||
|
|
||||||
// restore my signature data
|
// restore my signature data
|
||||||
slate.add_participant_info(&keychain, &context.sec_key, &context.sec_nonce, None)?;
|
slate.add_participant_info(&keychain, &context, None)?;
|
||||||
|
|
||||||
let mut parts = vec![];
|
let mut parts = vec![];
|
||||||
for (id, _, value) in &context.get_inputs() {
|
for (id, _, value) in &context.get_inputs() {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::grin_core::consensus::valid_header_version;
|
use crate::grin_core::consensus::valid_header_version;
|
||||||
use crate::grin_core::core::HeaderVersion;
|
use crate::grin_core::core::HeaderVersion;
|
||||||
use crate::grin_keychain::{BlindSum, BlindingFactor, Identifier, Keychain, SwitchCommitmentType};
|
use crate::grin_keychain::{Identifier, Keychain};
|
||||||
use crate::grin_util::secp::key::SecretKey;
|
use crate::grin_util::secp::key::SecretKey;
|
||||||
use crate::grin_util::secp::pedersen;
|
use crate::grin_util::secp::pedersen;
|
||||||
use crate::grin_util::Mutex;
|
use crate::grin_util::Mutex;
|
||||||
|
@ -28,6 +28,7 @@ use crate::internal::{selection, updater};
|
||||||
use crate::slate::Slate;
|
use crate::slate::Slate;
|
||||||
use crate::types::{Context, NodeClient, StoredProofInfo, TxLogEntryType, WalletBackend};
|
use crate::types::{Context, NodeClient, StoredProofInfo, TxLogEntryType, WalletBackend};
|
||||||
use crate::util::OnionV3Address;
|
use crate::util::OnionV3Address;
|
||||||
|
use crate::InitTxArgs;
|
||||||
use crate::{address, Error, ErrorKind};
|
use crate::{address, Error, ErrorKind};
|
||||||
use ed25519_dalek::Keypair as DalekKeypair;
|
use ed25519_dalek::Keypair as DalekKeypair;
|
||||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||||
|
@ -175,19 +176,16 @@ where
|
||||||
max_outputs,
|
max_outputs,
|
||||||
num_change_outputs,
|
num_change_outputs,
|
||||||
selection_strategy_is_use_all,
|
selection_strategy_is_use_all,
|
||||||
|
None,
|
||||||
parent_key_id.clone(),
|
parent_key_id.clone(),
|
||||||
use_test_rng,
|
use_test_rng,
|
||||||
|
is_initiator,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Generate a kernel offset and subtract from our context's secret key. Store
|
// Generate a kernel offset and subtract from our context's secret key. Store
|
||||||
// the offset in the slate's transaction kernel, and adds our public key
|
// the offset in the slate's transaction kernel, and adds our public key
|
||||||
// information to the slate
|
// information to the slate
|
||||||
slate.fill_round_1(
|
slate.fill_round_1(&wallet.keychain(keychain_mask)?, &mut context)?;
|
||||||
&wallet.keychain(keychain_mask)?,
|
|
||||||
&mut context.sec_key,
|
|
||||||
&context.sec_nonce,
|
|
||||||
use_test_rng,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
context.initial_sec_key = context.sec_key.clone();
|
context.initial_sec_key = context.sec_key.clone();
|
||||||
|
|
||||||
|
@ -227,15 +225,11 @@ where
|
||||||
current_height,
|
current_height,
|
||||||
parent_key_id.clone(),
|
parent_key_id.clone(),
|
||||||
use_test_rng,
|
use_test_rng,
|
||||||
|
is_initiator,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// fill public keys
|
// fill public keys
|
||||||
slate.fill_round_1(
|
slate.fill_round_1(&keychain, &mut context)?;
|
||||||
&keychain,
|
|
||||||
&mut context.sec_key,
|
|
||||||
&context.sec_nonce,
|
|
||||||
use_test_rng,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
context.initial_sec_key = context.sec_key.clone();
|
context.initial_sec_key = context.sec_key.clone();
|
||||||
|
|
||||||
|
@ -252,6 +246,53 @@ where
|
||||||
Ok(context)
|
Ok(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create context, without adding inputs to slate
|
||||||
|
pub fn create_late_lock_context<'a, T: ?Sized, C, K>(
|
||||||
|
wallet: &mut T,
|
||||||
|
keychain_mask: Option<&SecretKey>,
|
||||||
|
slate: &mut Slate,
|
||||||
|
current_height: u64,
|
||||||
|
init_tx_args: &InitTxArgs,
|
||||||
|
parent_key_id: &Identifier,
|
||||||
|
use_test_rng: bool,
|
||||||
|
) -> Result<Context, Error>
|
||||||
|
where
|
||||||
|
T: WalletBackend<'a, C, K>,
|
||||||
|
C: NodeClient + 'a,
|
||||||
|
K: Keychain + 'a,
|
||||||
|
{
|
||||||
|
// sender should always refresh outputs
|
||||||
|
updater::refresh_outputs(wallet, keychain_mask, parent_key_id, false)?;
|
||||||
|
|
||||||
|
// we're just going to run a selection to get the potential fee,
|
||||||
|
// but this won't be locked
|
||||||
|
let (_coins, _total, _amount, fee) = selection::select_coins_and_fee(
|
||||||
|
wallet,
|
||||||
|
init_tx_args.amount,
|
||||||
|
current_height,
|
||||||
|
init_tx_args.minimum_confirmations,
|
||||||
|
init_tx_args.max_outputs as usize,
|
||||||
|
init_tx_args.num_change_outputs as usize,
|
||||||
|
init_tx_args.selection_strategy_is_use_all,
|
||||||
|
&parent_key_id,
|
||||||
|
)?;
|
||||||
|
slate.fee = fee;
|
||||||
|
|
||||||
|
let keychain = wallet.keychain(keychain_mask)?;
|
||||||
|
|
||||||
|
// Create our own private context
|
||||||
|
let mut context = Context::new(keychain.secp(), &parent_key_id, use_test_rng, true);
|
||||||
|
context.fee = slate.fee;
|
||||||
|
context.amount = slate.amount;
|
||||||
|
context.late_lock_args = Some(init_tx_args.clone());
|
||||||
|
|
||||||
|
// Generate a blinding factor for the tx and add
|
||||||
|
// public key info to the slate
|
||||||
|
slate.fill_round_1(&wallet.keychain(keychain_mask)?, &mut context)?;
|
||||||
|
|
||||||
|
Ok(context)
|
||||||
|
}
|
||||||
|
|
||||||
/// Complete a transaction
|
/// Complete a transaction
|
||||||
pub fn complete_tx<'a, T: ?Sized, C, K>(
|
pub fn complete_tx<'a, T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
|
@ -396,47 +437,6 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the transaction's offset by subtracting the inputs
|
|
||||||
/// stored in the context
|
|
||||||
pub fn sub_inputs_from_offset<'a, T: ?Sized, C, K>(
|
|
||||||
wallet: &mut T,
|
|
||||||
keychain_mask: Option<&SecretKey>,
|
|
||||||
context: &Context,
|
|
||||||
slate: &mut Slate,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
T: WalletBackend<'a, C, K>,
|
|
||||||
C: NodeClient + 'a,
|
|
||||||
K: Keychain + 'a,
|
|
||||||
{
|
|
||||||
let k = wallet.keychain(keychain_mask)?;
|
|
||||||
// Offset has been created and adjusted
|
|
||||||
// Now subtract sum total of all my inputs from the offset
|
|
||||||
let new_offset = k.blind_sum(
|
|
||||||
&context
|
|
||||||
.get_inputs()
|
|
||||||
.iter()
|
|
||||||
.map(
|
|
||||||
|i| match k.derive_key(i.2, &i.0, SwitchCommitmentType::Regular) {
|
|
||||||
Ok(k) => BlindingFactor::from_secret_key(k),
|
|
||||||
Err(e) => {
|
|
||||||
error!("Error deriving key for offset: {}", e);
|
|
||||||
BlindingFactor::zero()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.fold(
|
|
||||||
BlindSum::new().add_blinding_factor(slate.offset.clone()),
|
|
||||||
|acc, x| acc.sub_blinding_factor(x.clone()),
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
slate.offset = new_offset.clone();
|
|
||||||
slate.tx_or_err_mut()?.offset = new_offset;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn payment_proof_message(
|
pub fn payment_proof_message(
|
||||||
amount: u64,
|
amount: u64,
|
||||||
kernel_commitment: &pedersen::Commitment,
|
kernel_commitment: &pedersen::Commitment,
|
||||||
|
|
|
@ -24,15 +24,13 @@ use crate::grin_core::core::transaction::{
|
||||||
use crate::grin_core::core::verifier_cache::LruVerifierCache;
|
use crate::grin_core::core::verifier_cache::LruVerifierCache;
|
||||||
use crate::grin_core::libtx::{aggsig, build, proof::ProofBuild, tx_fee};
|
use crate::grin_core::libtx::{aggsig, build, proof::ProofBuild, tx_fee};
|
||||||
use crate::grin_core::map_vec;
|
use crate::grin_core::map_vec;
|
||||||
use crate::grin_keychain::{BlindSum, BlindingFactor, Keychain};
|
use crate::grin_keychain::{BlindSum, BlindingFactor, Keychain, SwitchCommitmentType};
|
||||||
use crate::grin_util::secp::key::{PublicKey, SecretKey};
|
use crate::grin_util::secp::key::{PublicKey, SecretKey};
|
||||||
use crate::grin_util::secp::pedersen::Commitment;
|
use crate::grin_util::secp::pedersen::Commitment;
|
||||||
use crate::grin_util::secp::Signature;
|
use crate::grin_util::secp::Signature;
|
||||||
use crate::grin_util::{secp, static_secp_instance, RwLock};
|
use crate::grin_util::{secp, static_secp_instance, RwLock};
|
||||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||||
use ed25519_dalek::Signature as DalekSignature;
|
use ed25519_dalek::Signature as DalekSignature;
|
||||||
use rand::rngs::mock::StepRng;
|
|
||||||
use rand::thread_rng;
|
|
||||||
use serde::ser::{Serialize, Serializer};
|
use serde::ser::{Serialize, Serializer};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -45,6 +43,7 @@ use crate::slate_versions::v4::{
|
||||||
};
|
};
|
||||||
use crate::slate_versions::VersionedSlate;
|
use crate::slate_versions::VersionedSlate;
|
||||||
use crate::slate_versions::{CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION};
|
use crate::slate_versions::{CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION};
|
||||||
|
use crate::Context;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PaymentInfo {
|
pub struct PaymentInfo {
|
||||||
|
@ -337,20 +336,11 @@ impl Slate {
|
||||||
|
|
||||||
/// Completes callers part of round 1, adding public key info
|
/// Completes callers part of round 1, adding public key info
|
||||||
/// to the slate
|
/// to the slate
|
||||||
pub fn fill_round_1<K>(
|
pub fn fill_round_1<K>(&mut self, keychain: &K, context: &mut Context) -> Result<(), Error>
|
||||||
&mut self,
|
|
||||||
keychain: &K,
|
|
||||||
sec_key: &mut SecretKey,
|
|
||||||
sec_nonce: &SecretKey,
|
|
||||||
use_test_rng: bool,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// Always choose my part of the offset, and subtract from my excess
|
self.add_participant_info(keychain, context, None)
|
||||||
self.generate_offset(keychain, sec_key, use_test_rng)?;
|
|
||||||
self.add_participant_info(keychain, &sec_key, &sec_nonce, None)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build kernel features based on variant and associated data.
|
// Build kernel features based on variant and associated data.
|
||||||
|
@ -455,7 +445,7 @@ impl Slate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the sum of public blinding factors
|
/// Return the sum of public blinding factors
|
||||||
fn pub_blind_sum(&self, secp: &secp::Secp256k1) -> Result<PublicKey, Error> {
|
pub fn pub_blind_sum(&self, secp: &secp::Secp256k1) -> Result<PublicKey, Error> {
|
||||||
let pub_blinds: Vec<&PublicKey> = self
|
let pub_blinds: Vec<&PublicKey> = self
|
||||||
.participant_data
|
.participant_data
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -488,16 +478,15 @@ impl Slate {
|
||||||
pub fn add_participant_info<K>(
|
pub fn add_participant_info<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
keychain: &K,
|
keychain: &K,
|
||||||
sec_key: &SecretKey,
|
context: &Context,
|
||||||
sec_nonce: &SecretKey,
|
|
||||||
part_sig: Option<Signature>,
|
part_sig: Option<Signature>,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// Add our public key and nonce to the slate
|
// Add our public key and nonce to the slate
|
||||||
let pub_key = PublicKey::from_secret_key(keychain.secp(), &sec_key)?;
|
let pub_key = PublicKey::from_secret_key(keychain.secp(), &context.sec_key)?;
|
||||||
let pub_nonce = PublicKey::from_secret_key(keychain.secp(), &sec_nonce)?;
|
let pub_nonce = PublicKey::from_secret_key(keychain.secp(), &context.sec_nonce)?;
|
||||||
let mut part_sig = part_sig;
|
let mut part_sig = part_sig;
|
||||||
|
|
||||||
// Remove if already here and replace
|
// Remove if already here and replace
|
||||||
|
@ -524,46 +513,32 @@ impl Slate {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Somebody involved needs to generate an offset with their private key
|
/// Add our contribution to the offset based on the excess, inputs and outputs
|
||||||
/// For now, we'll have the transaction initiator be responsible for it
|
pub fn adjust_offset<K: Keychain>(
|
||||||
/// Return offset private key for the participant to use later in the
|
|
||||||
/// transaction
|
|
||||||
pub fn generate_offset<K>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
keychain: &K,
|
keychain: &K,
|
||||||
sec_key: &mut SecretKey,
|
context: &Context,
|
||||||
use_test_rng: bool,
|
) -> Result<(), Error> {
|
||||||
) -> Result<(), Error>
|
let mut sum = BlindSum::new()
|
||||||
where
|
.add_blinding_factor(self.offset.clone())
|
||||||
K: Keychain,
|
.sub_blinding_factor(BlindingFactor::from_secret_key(
|
||||||
{
|
context.initial_sec_key.clone(),
|
||||||
// Generate a random kernel offset here
|
));
|
||||||
// and subtract it from the blind_sum so we create
|
for (id, _, amount) in &context.input_ids {
|
||||||
// the aggsig context with the "split" key
|
sum = sum.sub_blinding_factor(BlindingFactor::from_secret_key(keychain.derive_key(
|
||||||
let my_offset = match use_test_rng {
|
*amount,
|
||||||
false => {
|
id,
|
||||||
BlindingFactor::from_secret_key(SecretKey::new(&keychain.secp(), &mut thread_rng()))
|
SwitchCommitmentType::Regular,
|
||||||
}
|
)?));
|
||||||
true => {
|
}
|
||||||
// allow for consistent test results
|
for (id, _, amount) in &context.output_ids {
|
||||||
let mut test_rng = StepRng::new(1_234_567_890_u64, 1);
|
sum = sum.add_blinding_factor(BlindingFactor::from_secret_key(keychain.derive_key(
|
||||||
BlindingFactor::from_secret_key(SecretKey::new(&keychain.secp(), &mut test_rng))
|
*amount,
|
||||||
}
|
id,
|
||||||
};
|
SwitchCommitmentType::Regular,
|
||||||
|
)?));
|
||||||
let total_offset = keychain.blind_sum(
|
}
|
||||||
&BlindSum::new()
|
self.offset = keychain.blind_sum(&sum)?;
|
||||||
.add_blinding_factor(self.offset.clone())
|
|
||||||
.add_blinding_factor(my_offset.clone()),
|
|
||||||
)?;
|
|
||||||
self.offset = total_offset;
|
|
||||||
|
|
||||||
let adjusted_offset = keychain.blind_sum(
|
|
||||||
&BlindSum::new()
|
|
||||||
.add_blinding_factor(BlindingFactor::from_secret_key(sec_key.clone()))
|
|
||||||
.sub_blinding_factor(my_offset),
|
|
||||||
)?;
|
|
||||||
*sec_key = adjusted_offset.secret_key(&keychain.secp())?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,13 @@ use crate::grin_util::secp::key::{PublicKey, SecretKey};
|
||||||
use crate::grin_util::secp::{self, pedersen, Secp256k1};
|
use crate::grin_util::secp::{self, pedersen, Secp256k1};
|
||||||
use crate::grin_util::{ToHex, ZeroingString};
|
use crate::grin_util::{ToHex, ZeroingString};
|
||||||
use crate::slate_versions::ser as dalek_ser;
|
use crate::slate_versions::ser as dalek_ser;
|
||||||
|
use crate::InitTxArgs;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||||
use ed25519_dalek::Signature as DalekSignature;
|
use ed25519_dalek::Signature as DalekSignature;
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
|
use rand::rngs::mock::StepRng;
|
||||||
|
use rand::thread_rng;
|
||||||
use serde;
|
use serde;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -554,6 +557,9 @@ pub struct Context {
|
||||||
pub fee: u64,
|
pub fee: u64,
|
||||||
/// Payment proof sender address derivation path, if needed
|
/// Payment proof sender address derivation path, if needed
|
||||||
pub payment_proof_derivation_index: Option<u32>,
|
pub payment_proof_derivation_index: Option<u32>,
|
||||||
|
/// If late-locking, store my tranasction creation prefs
|
||||||
|
/// for later
|
||||||
|
pub late_lock_args: Option<InitTxArgs>,
|
||||||
/// for invoice I2 Only, store the tx excess so we can
|
/// for invoice I2 Only, store the tx excess so we can
|
||||||
/// remove it from the slate on return
|
/// remove it from the slate on return
|
||||||
pub calculated_excess: Option<pedersen::Commitment>,
|
pub calculated_excess: Option<pedersen::Commitment>,
|
||||||
|
@ -562,26 +568,49 @@ pub struct Context {
|
||||||
impl Context {
|
impl Context {
|
||||||
/// Create a new context with defaults
|
/// Create a new context with defaults
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
secp: &secp::Secp256k1,
|
||||||
|
parent_key_id: &Identifier,
|
||||||
|
use_test_rng: bool,
|
||||||
|
is_initiator: bool,
|
||||||
|
) -> Self {
|
||||||
|
let sec_key = match use_test_rng {
|
||||||
|
false => SecretKey::new(secp, &mut thread_rng()),
|
||||||
|
true => {
|
||||||
|
// allow for consistent test results
|
||||||
|
let mut test_rng = if is_initiator {
|
||||||
|
StepRng::new(1_234_567_890_u64, 1)
|
||||||
|
} else {
|
||||||
|
StepRng::new(1_234_567_891_u64, 1)
|
||||||
|
};
|
||||||
|
SecretKey::new(secp, &mut test_rng)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Self::with_excess(secp, sec_key, parent_key_id, use_test_rng)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new context with a specific excess
|
||||||
|
pub fn with_excess(
|
||||||
secp: &secp::Secp256k1,
|
secp: &secp::Secp256k1,
|
||||||
sec_key: SecretKey,
|
sec_key: SecretKey,
|
||||||
parent_key_id: &Identifier,
|
parent_key_id: &Identifier,
|
||||||
use_test_rng: bool,
|
use_test_rng: bool,
|
||||||
) -> Context {
|
) -> Self {
|
||||||
let sec_nonce = match use_test_rng {
|
let sec_nonce = match use_test_rng {
|
||||||
false => aggsig::create_secnonce(secp).unwrap(),
|
false => aggsig::create_secnonce(secp).unwrap(),
|
||||||
true => SecretKey::from_slice(secp, &[1; 32]).unwrap(),
|
true => SecretKey::from_slice(secp, &[1; 32]).unwrap(),
|
||||||
};
|
};
|
||||||
Context {
|
Self {
|
||||||
parent_key_id: parent_key_id.clone(),
|
parent_key_id: parent_key_id.clone(),
|
||||||
sec_key: sec_key.clone(),
|
sec_key: sec_key.clone(),
|
||||||
sec_nonce: sec_nonce.clone(),
|
sec_nonce: sec_nonce.clone(),
|
||||||
initial_sec_key: sec_key.clone(),
|
initial_sec_key: sec_key,
|
||||||
initial_sec_nonce: sec_nonce.clone(),
|
initial_sec_nonce: sec_nonce,
|
||||||
input_ids: vec![],
|
input_ids: vec![],
|
||||||
output_ids: vec![],
|
output_ids: vec![],
|
||||||
amount: 0,
|
amount: 0,
|
||||||
fee: 0,
|
fee: 0,
|
||||||
payment_proof_derivation_index: None,
|
payment_proof_derivation_index: None,
|
||||||
|
late_lock_args: None,
|
||||||
calculated_excess: None,
|
calculated_excess: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||||
|
|
||||||
let blind = blinding_factor.secret_key(&keychain.secp()).unwrap();
|
let blind = blinding_factor.secret_key(&keychain.secp()).unwrap();
|
||||||
|
|
||||||
s_cx = Context::new(&keychain.secp(), blind, &parent, false);
|
s_cx = Context::with_excess(&keychain.secp(), blind, &parent, false);
|
||||||
s_cx.get_public_keys(&keychain.secp())
|
s_cx.get_public_keys(&keychain.secp())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||||
// let blind = blind_sum.secret_key(&keychain.secp())?;
|
// let blind = blind_sum.secret_key(&keychain.secp())?;
|
||||||
let blind = keychain.derive_key(0, &key_id, switch).unwrap();
|
let blind = keychain.derive_key(0, &key_id, switch).unwrap();
|
||||||
|
|
||||||
rx_cx = Context::new(&keychain.secp(), blind, &parent, false);
|
rx_cx = Context::with_excess(&keychain.secp(), blind, &parent, false);
|
||||||
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
||||||
rx_cx.add_output(&key_id, &None, 0);
|
rx_cx.add_output(&key_id, &None, 0);
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||||
|
|
||||||
let blind = blinding_factor.secret_key(&keychain.secp()).unwrap();
|
let blind = blinding_factor.secret_key(&keychain.secp()).unwrap();
|
||||||
|
|
||||||
s_cx = Context::new(&keychain.secp(), blind, &parent, false);
|
s_cx = Context::with_excess(&keychain.secp(), blind, &parent, false);
|
||||||
s_cx.get_public_keys(&keychain.secp())
|
s_cx.get_public_keys(&keychain.secp())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||||
|
|
||||||
let blind = keychain.derive_key(0, &key_id, switch).unwrap();
|
let blind = keychain.derive_key(0, &key_id, switch).unwrap();
|
||||||
|
|
||||||
rx_cx = Context::new(&keychain.secp(), blind, &parent, false);
|
rx_cx = Context::with_excess(&keychain.secp(), blind, &parent, false);
|
||||||
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
||||||
rx_cx.add_output(&key_id, &None, 0);
|
rx_cx.add_output(&key_id, &None, 0);
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,10 @@ subcommands:
|
||||||
help: Estimates all possible Coin/Output selection strategies.
|
help: Estimates all possible Coin/Output selection strategies.
|
||||||
short: e
|
short: e
|
||||||
long: estimate-selection
|
long: estimate-selection
|
||||||
|
- late_lock:
|
||||||
|
help: EXPERIMENTAL - Do not lock the coins immediately, instead only lock them during finalization.
|
||||||
|
short: l
|
||||||
|
long: late-lock
|
||||||
- change_outputs:
|
- change_outputs:
|
||||||
help: Number of change outputs to generate (mainly for testing)
|
help: Number of change outputs to generate (mainly for testing)
|
||||||
short: o
|
short: o
|
||||||
|
|
|
@ -479,6 +479,8 @@ pub fn parse_send_args(args: &ArgMatches) -> Result<command::SendArgs, ParseErro
|
||||||
// estimate_selection_strategies
|
// estimate_selection_strategies
|
||||||
let estimate_selection_strategies = args.is_present("estimate_selection_strategies");
|
let estimate_selection_strategies = args.is_present("estimate_selection_strategies");
|
||||||
|
|
||||||
|
let late_lock = args.is_present("late_lock");
|
||||||
|
|
||||||
// dest
|
// dest
|
||||||
let dest = match args.value_of("dest") {
|
let dest = match args.value_of("dest") {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
|
@ -533,6 +535,7 @@ pub fn parse_send_args(args: &ArgMatches) -> Result<command::SendArgs, ParseErro
|
||||||
minimum_confirmations: min_c,
|
minimum_confirmations: min_c,
|
||||||
selection_strategy: selection_strategy.to_owned(),
|
selection_strategy: selection_strategy.to_owned(),
|
||||||
estimate_selection_strategies,
|
estimate_selection_strategies,
|
||||||
|
late_lock,
|
||||||
dest: dest.to_owned(),
|
dest: dest.to_owned(),
|
||||||
change_outputs: change_outputs,
|
change_outputs: change_outputs,
|
||||||
fluff: fluff,
|
fluff: fluff,
|
||||||
|
|
Loading…
Reference in a new issue