mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 07:11:36 +02:00
Merge 2.0.0 branch into master (#164)
* create 2.0.0 branch * V0/V1 Slate Removal + Grin Header Version Bump (#140) * Remove V0 and V1 Slates from Wallet * rustfmt * V1 API + V2 wallet to wallet impl (#144) * remove v1 API * rustfmt * convert http adapter to use V2 api * rustfmt * V2 API conversion Pt2 - Check version (#146) * call check_version on wallet before http send * rustfmt * Support new Bulletproof rewind scheme (#122) * Restore with LegacyProofBuilder * Switch to ProofBuilder at HF block * Switch proof builder for coinbase outputs at hard fork * Use valid_header_version to switch proof builder * Fix compilation errors * Use legacy proof builder for AutomatedTesting chain type * Add macro to avoid duplicate code * Read version info from server, react accordingly (#154) * read and parse version, bump hf * rustfmt * add foreign api middleware check * rustfmt * add middleware checks * rustfmt * add check for incoming pre-hf slates * api tests * Add double rewind period (#155) * Add double rewind period * Simplify restore * Fix comment * bump imported version for beta release * version bump for next (potential) release * Provide more specific error when other wallet is outdated (#162) * add appropriate error message when other wallet is out of date * rustfmt * missing cargo.lock
This commit is contained in:
Generated
+350
-339
File diff suppressed because it is too large
Load Diff
+8
-7
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "grin_wallet"
|
||||
version = "1.1.1-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||
license = "Apache-2.0"
|
||||
@@ -28,14 +28,15 @@ failure_derive = "0.1"
|
||||
prettytable-rs = "0.7"
|
||||
log = "0.4"
|
||||
linefeed = "0.5"
|
||||
semver = "0.9"
|
||||
|
||||
grin_wallet_api = { path = "./api", version = "1.1.1-beta.1" }
|
||||
grin_wallet_impls = { path = "./impls", version = "1.1.1-beta.1" }
|
||||
grin_wallet_libwallet = { path = "./libwallet", version = "1.1.1-beta.1" }
|
||||
grin_wallet_controller = { path = "./controller", version = "1.1.1-beta.1" }
|
||||
grin_wallet_config = { path = "./config", version = "1.1.1-beta.1" }
|
||||
grin_wallet_api = { path = "./api", version = "2.0.0-beta.2" }
|
||||
grin_wallet_impls = { path = "./impls", version = "2.0.0-beta.2" }
|
||||
grin_wallet_libwallet = { path = "./libwallet", version = "2.0.0-beta.2" }
|
||||
grin_wallet_controller = { path = "./controller", version = "2.0.0-beta.2" }
|
||||
grin_wallet_config = { path = "./config", version = "2.0.0-beta.2" }
|
||||
|
||||
grin_wallet_util = { path = "./util", version = "1.1.1-beta.1" }
|
||||
grin_wallet_util = { path = "./util", version = "2.0.0-beta.2" }
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.3"
|
||||
|
||||
+5
-6
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "grin_wallet_api"
|
||||
version = "1.1.1-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||
description = "Grin Wallet API"
|
||||
license = "Apache-2.0"
|
||||
@@ -18,11 +18,10 @@ serde_json = "1"
|
||||
easy-jsonrpc = "0.5.1"
|
||||
chrono = { version = "0.4.4", features = ["serde"] }
|
||||
|
||||
grin_wallet_libwallet = { path = "../libwallet", version = "1.1.1-beta.1" }
|
||||
grin_wallet_config = { path = "../config", version = "1.1.1-beta.1" }
|
||||
grin_wallet_impls = { path = "../impls", version = "1.1.1-beta.1" }
|
||||
|
||||
grin_wallet_util = { path = "../util", version = "1.1.1-beta.1" }
|
||||
grin_wallet_libwallet = { path = "../libwallet", version = "2.0.0-beta.2" }
|
||||
grin_wallet_config = { path = "../config", version = "2.0.0-beta.2" }
|
||||
grin_wallet_impls = { path = "../impls", version = "2.0.0-beta.2" }
|
||||
grin_wallet_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1"
|
||||
|
||||
+72
-8
@@ -16,11 +16,31 @@
|
||||
|
||||
use crate::keychain::Keychain;
|
||||
use crate::libwallet::api_impl::foreign;
|
||||
use crate::libwallet::{BlockFees, CbData, Error, NodeClient, Slate, VersionInfo, WalletBackend};
|
||||
use crate::libwallet::{
|
||||
BlockFees, CbData, Error, NodeClient, NodeVersionInfo, Slate, VersionInfo, WalletBackend,
|
||||
};
|
||||
use crate::util::Mutex;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// ForeignAPI Middleware Check callback
|
||||
pub type ForeignCheckMiddleware =
|
||||
fn(ForeignCheckMiddlewareFn, Option<NodeVersionInfo>, Option<&Slate>) -> Result<(), Error>;
|
||||
|
||||
/// Middleware Identifiers for each function
|
||||
pub enum ForeignCheckMiddlewareFn {
|
||||
/// check_version
|
||||
CheckVersion,
|
||||
/// build_coinbase
|
||||
BuildCoinbase,
|
||||
/// verify_slate_messages
|
||||
VerifySlateMessages,
|
||||
/// receive_tx
|
||||
ReceiveTx,
|
||||
/// finalize_invoice_tx
|
||||
FinalizeInvoiceTx,
|
||||
}
|
||||
|
||||
/// Main interface into all wallet API functions.
|
||||
/// Wallet APIs are split into two seperate blocks of functionality
|
||||
/// called the ['Owner'](struct.Owner.html) and ['Foreign'](struct.Foreign.html) APIs
|
||||
@@ -46,8 +66,12 @@ where
|
||||
pub wallet: Arc<Mutex<W>>,
|
||||
/// Flag to normalize some output during testing. Can mostly be ignored.
|
||||
pub doctest_mode: bool,
|
||||
/// phantom
|
||||
phantom: PhantomData<K>,
|
||||
/// phantom
|
||||
phantom_c: PhantomData<C>,
|
||||
/// foreign check middleware
|
||||
middleware: Option<ForeignCheckMiddleware>,
|
||||
}
|
||||
|
||||
impl<'a, W: ?Sized, C, K> Foreign<W, C, K>
|
||||
@@ -67,6 +91,8 @@ where
|
||||
/// # Arguments
|
||||
/// * `wallet_in` - A reference-counted mutex containing an implementation of the
|
||||
/// [`WalletBackend`](../grin_wallet_libwallet/types/trait.WalletBackend.html) trait.
|
||||
/// * middleware - Option middleware which containts the NodeVersionInfo and can call
|
||||
/// a predefined function with the slate to check if the operation should continue
|
||||
///
|
||||
/// # Returns
|
||||
/// * An instance of the ForeignApi holding a reference to the provided wallet
|
||||
@@ -109,17 +135,18 @@ where
|
||||
/// LMDBBackend::new(wallet_config.clone(), "", node_client).unwrap()
|
||||
/// ));
|
||||
///
|
||||
/// let api_owner = Foreign::new(wallet.clone());
|
||||
/// let api_foreign = Foreign::new(wallet.clone(), None);
|
||||
/// // .. perform wallet operations
|
||||
///
|
||||
/// ```
|
||||
|
||||
pub fn new(wallet_in: Arc<Mutex<W>>) -> Self {
|
||||
pub fn new(wallet_in: Arc<Mutex<W>>, middleware: Option<ForeignCheckMiddleware>) -> Self {
|
||||
Foreign {
|
||||
wallet: wallet_in,
|
||||
doctest_mode: false,
|
||||
phantom: PhantomData,
|
||||
phantom_c: PhantomData,
|
||||
middleware,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,13 +160,21 @@ where
|
||||
/// ```
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone());
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
///
|
||||
/// let version_info = api_foreign.check_version();
|
||||
/// // check and proceed accordingly
|
||||
/// ```
|
||||
|
||||
pub fn check_version(&self) -> Result<VersionInfo, Error> {
|
||||
if let Some(m) = self.middleware.as_ref() {
|
||||
let mut w = self.wallet.lock();
|
||||
m(
|
||||
ForeignCheckMiddlewareFn::CheckVersion,
|
||||
w.w2n_client().get_version_info(),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
Ok(foreign::check_version())
|
||||
}
|
||||
|
||||
@@ -176,7 +211,7 @@ where
|
||||
/// ```
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone());
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
///
|
||||
/// let block_fees = BlockFees {
|
||||
/// fees: 800000,
|
||||
@@ -195,6 +230,13 @@ where
|
||||
|
||||
pub fn build_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
if let Some(m) = self.middleware.as_ref() {
|
||||
m(
|
||||
ForeignCheckMiddlewareFn::BuildCoinbase,
|
||||
w.w2n_client().get_version_info(),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
w.open_with_credentials()?;
|
||||
let res = foreign::build_coinbase(&mut *w, block_fees, self.doctest_mode);
|
||||
w.close()?;
|
||||
@@ -222,7 +264,7 @@ where
|
||||
/// ```
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone());
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
///
|
||||
/// # let slate = Slate::blank(2);
|
||||
/// // Receive a slate via some means
|
||||
@@ -240,6 +282,14 @@ where
|
||||
/// ```
|
||||
|
||||
pub fn verify_slate_messages(&self, slate: &Slate) -> Result<(), Error> {
|
||||
if let Some(m) = self.middleware.as_ref() {
|
||||
let mut w = self.wallet.lock();
|
||||
m(
|
||||
ForeignCheckMiddlewareFn::VerifySlateMessages,
|
||||
w.w2n_client().get_version_info(),
|
||||
Some(slate),
|
||||
)?;
|
||||
}
|
||||
foreign::verify_slate_messages(slate)
|
||||
}
|
||||
|
||||
@@ -286,7 +336,7 @@ where
|
||||
/// ```
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone());
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
/// # let slate = Slate::blank(2);
|
||||
///
|
||||
/// // . . .
|
||||
@@ -306,6 +356,13 @@ where
|
||||
message: Option<String>,
|
||||
) -> Result<Slate, Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
if let Some(m) = self.middleware.as_ref() {
|
||||
m(
|
||||
ForeignCheckMiddlewareFn::ReceiveTx,
|
||||
w.w2n_client().get_version_info(),
|
||||
Some(slate),
|
||||
)?;
|
||||
}
|
||||
w.open_with_credentials()?;
|
||||
let res = foreign::receive_tx(&mut *w, slate, dest_acct_name, message, self.doctest_mode);
|
||||
w.close()?;
|
||||
@@ -340,7 +397,7 @@ where
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_owner = Owner::new(wallet.clone());
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone());
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
///
|
||||
/// // . . .
|
||||
/// // Issue the invoice tx via the owner API
|
||||
@@ -361,6 +418,13 @@ where
|
||||
|
||||
pub fn finalize_invoice_tx(&self, slate: &Slate) -> Result<Slate, Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
if let Some(m) = self.middleware.as_ref() {
|
||||
m(
|
||||
ForeignCheckMiddlewareFn::FinalizeInvoiceTx,
|
||||
w.w2n_client().get_version_info(),
|
||||
Some(slate),
|
||||
)?;
|
||||
}
|
||||
w.open_with_credentials()?;
|
||||
let res = foreign::finalize_invoice_tx(&mut *w, slate);
|
||||
w.close()?;
|
||||
|
||||
+22
-14
@@ -16,10 +16,10 @@
|
||||
|
||||
use crate::keychain::Keychain;
|
||||
use crate::libwallet::{
|
||||
BlockFees, CbData, ErrorKind, InitTxArgs, IssueInvoiceTxArgs, NodeClient, Slate, VersionInfo,
|
||||
VersionedSlate, WalletBackend,
|
||||
self, BlockFees, CbData, ErrorKind, InitTxArgs, IssueInvoiceTxArgs, NodeClient,
|
||||
NodeVersionInfo, Slate, VersionInfo, VersionedSlate, WalletBackend,
|
||||
};
|
||||
use crate::Foreign;
|
||||
use crate::{Foreign, ForeignCheckMiddlewareFn};
|
||||
use easy_jsonrpc;
|
||||
|
||||
/// Public definition used to generate Foreign jsonrpc api.
|
||||
@@ -52,8 +52,6 @@ pub trait ForeignRpc {
|
||||
"Ok": {
|
||||
"foreign_api_version": 2,
|
||||
"supported_slate_versions": [
|
||||
"V0",
|
||||
"V1",
|
||||
"V2"
|
||||
]
|
||||
}
|
||||
@@ -104,7 +102,7 @@ pub trait ForeignRpc {
|
||||
"output": {
|
||||
"commit": "08fe198e525a5937d0c5d01fa354394d2679be6df5d42064a0f7550c332fce3d9d",
|
||||
"features": "Coinbase",
|
||||
"proof": "9166dc13a374a50d99f16ddfb228ce6010ea22d1676de755c34123402b5a8e68871b37d716c14e07be14ceb0771cca62a302358aa82922fa87f1387cff3a4507027f04f3fcf54ed16bd97e40a06c6f969139188daca366bb78ccbc7ff0203de62e30077f8b4a8b314901666205d24ca93d54581aa082e37c370e178dea267ff11fa4669756a31c026348255108c4de4b7abe3636ebdd67f25387c9c2868d16fab9209ebee6d19c6395eaf313da67f164d8e997ed97de9478ddb24c34d8a0dcedc24c5d0a9d1c9f15de3264323fc768271d7981b1e2ae1e59675537115fdcd1ea7d60a7bd276865698d1c1598b7c22a1a6e212db4d0a0ba98706a746f63f2d8460a9d28b4e8a7d2ad1f531b32046e2285a034c2d49f7896026fa186f9665766ae158435157f94bd31b8ebf5c0637a9d72036348c1d1fb70659b6ca5e64427a9eb51569074311e970316fd370373149067a0781cd49cc450e80e14a84f9818ae8caf6c02877f15ab11397d60309249658e5a03f49354dce3873118be6f43ca436aa81165ca44d624fd6f504b8d186bca2ef7e3c5ff2b85db86b29ddd0fb58173960caf2b437c8190511685303ab0eb1b5a757e1509529063a145f5242350edb8e1a1807f505866fdb5689fd39d4595cf5084d30a1ba2af882969bf64aecad342926b16930a3d93781dcebc839b7bf5762146e0016c502aad33d24c9e708c810505bd9c6648bd8303ddbbe5c5cf82eb420784223182e1b59286249e38458c885f089e9211b3aafe7c6f85097878679775287423ebca7557cd3be9e44bb454c6b1914b9012e100d601d7a2ecb0c2a07b5e6f0c293b671e45a425d97169eb793834a40a0a64277e68b2809ca4556eed7d130c2ea973021fda08a01c771111b1cc12b647029fe19f1018486a0ef82bbe5ca7ff484c71d52f3238766d771eaf4204793809dc27"
|
||||
"proof": "9d8488fcb43c9c0f683b9ce62f3c8e047b71f2b4cd94b99a3c9a36aef3bb8361ee17b4489eb5f6d6507250532911acb76f18664604c2ca4215347a5d5d8e417d00ca2d59ec29371286986428b0ec1177fc2e416339ea8542eff8186550ad0d65ffac35d761c38819601d331fd427576e2fff823bbc3faa04f49f5332bd4de46cd4f83d0fd46cdb1dfb87069e95974e4a45e0235db71f5efe5cec83bbb30e152ac50a010ef4e57e33aabbeb894b9114f90bb5c3bb03b009014e358aa3914b1a208eb9d8806fbb679c256d4c1a47b0fce3f1235d58192cb7f615bd7c5dab48486db8962c2a594e69ff70029784a810b4eb76b0516805f3417308cda8acb38b9a3ea061568f0c97f5b46a3beff556dc7ebb58c774f08be472b4b6f603e5f8309c2d1f8d6f52667cb86816b330eca5374148aa898f5bbaf3f23a3ebcdc359ee1e14d73a65596c0ddf51f123234969ac8b557ba9dc53255dd6f5c0d3dd2c035a6d1a1185102612fdca474d018b9f9e81acfa3965d42769f5a303bbaabb78d17e0c026b8be0039c55ad1378c8316101b5206359f89fd1ee239115dde458749a040997be43c039055594cab76f602a0a1ee4f5322f3ab1157342404239adbf8b6786544cd67d9891c2689530e65f2a4b8e52d8551b92ffefb812ffa4a472a10701884151d1fb77d8cdc0b1868cb31b564e98e4c035e0eaa26203b882552c7b69deb0d8ec67cf28d5ec044554f8a91a6cae87eb377d6d906bba6ec94dda24ebfd372727f68334af798b11256d88e17cef7c4fed092128215f992e712ed128db2a9da2f5e8fadea9395bddd294a524dce47f818794c56b03e1253bf0fb9cb8beebc5742e4acf19c24824aa1d41996e839906e24be120a0bdf6800da599ec9ec3d1c4c11571c9f143eadbb554fa3c8c9777994a3f3421d454e4ec54c11b97eea3e4e6ede2d97a2bc"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +172,7 @@ pub trait ForeignRpc {
|
||||
"version_info": {
|
||||
"orig_version": 2,
|
||||
"version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -212,7 +210,7 @@ pub trait ForeignRpc {
|
||||
"version_info": {
|
||||
"version": 2,
|
||||
"orig_version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
},
|
||||
"num_participants": 2,
|
||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||
@@ -323,7 +321,7 @@ pub trait ForeignRpc {
|
||||
{
|
||||
"commit": "084ee97defa8c37124d4c69baa753e2532535faa81f79ea5e0489db25297d5beb8",
|
||||
"features": "Plain",
|
||||
"proof": "bffb26e7df4bf753f4d8e810c67fb5106b1746c1870f5cb96585537eb8e2f66b372ed05fd35ae18c6e8515cd9f2aaae85d5a7655361c6a8573e20fbdfdda6e0a0b25817fc0db23dc25297382af379659d846bd8044f807c467722708d3a3797b84fceb09eb29f11c77b79c7c93c578d06d95b58d845930531e5cac6346d1373ee1c5db69c14d0aa1a9c22e187dc346156c468540ad166a04902d3faf357ed31a50775d274913ccc9ba976ca3977e18f383b20f0cd02a0866b7b44847bfbba35c099f5eba9c9747cad961033321925f3e0ad43e357aaecc50989bbbcb5b44ead58fe359c59903530c58bf1c9a6f9fb120a3492e835fabc01bb8b31b52b15ace4785a08c3ea9a82bd15c41c744544286b114b1be733fa6237300cf2dc99e8af6f8557bd9a083ba59cc1a500bdfba228b53785a7fdbf576f7dce035769058bc7644041ec5731485e5641eac5c75a6eb57e4abc287b0be8eab77c7e8a5122ee8d49f02f103a3af6fe38b8fcecd1aa9bb342b3e110f4003ee6c771ed93401ca3438dcf0d751a36dbb7a7a45d32709525686f3d2e5f542c747c9c745fe50cd789a0aa55419934afff363044d3c3f5f7669ebb9f2245b449bfdc4e09dfb1661552485107afbd9a2b571a0647b1fc330089a65e4b5df07f58f1a9c11c3da51d56cd854f227c5111d25ca8c4bec4bb0fbcb4a23fc3288418423dd0649d731b6a6c08851954ea920046ce67a4114d35c3876c25361e7a99474aa04354a4ed0555f9bef527d902fbb0d1d5c2b42f5eea5ced359005121167f9908729939dba610cdabca41f714e144ab148faec77f4d70566287671e6786459bd7d16787a24e12f2328b9faab1c7ac80a916d2f83f12a7351a2bedff610d33dfb2df7d8e57b68fb4a5dcc0d8e4fa807b2077877aa96ba7bc22e627a4f6a308d3abc091f56d518258f073cc1b70ef81"
|
||||
"proof": "007df7dddd1efca757b2070740cc604628390eb59e151f96ff2eaa5361f5435fd1aa6ea3febc97fcfe1b3248d040c82de36180392976ba2d1147c2fb021c87ad044f1f9763934d9d3f4431417762eed03c53ce17aedb7824565c1f48fccec9c4abc0d28bd32b02ce9bee40bf6a60cf7c9c203cc24e4b779f901e12c987573698cf7f04e3aace26e71262138605424800adf3295d09f7f45dddf1855c785e98d45eae3cd111d18552e733895458df15e71a13838d789a4cb369f4ddb8aa9c503b080fd88a147245df0522d4136d36a183bd941e6cf94dffc78438b12194d4df7114d1e27a7a2f014920a321223ecbebb2b9642a22f8ed4e74883125f3e757b2f118853ffab1b68f15c1a2d021e583ff3fd1ea28720a81325b3cc2327ba9fb2fd9b2644adb7f3c7b2e319b2536a34f67e6f09346f24da6bcae1b241f8590493476dfe35b183e54f105eb219b601e0e53965409701dc1fd9562c42ad977505ea7bf264f01770569a4a358a70fb0b2c65969fac3b23954f0ca0adace0703243f1dab626509a8656e7a981709c3ac1d51694bafa55aad45c101937cbf3e45d6708c07be71419769a10a4f64f2b7d53a54eac73cdbd3279f91c5f8991a4b17621c36195a9391364fa221e8a8dee21ebc3a6eb9cd2940a3676e7ef3cdd46319bdc11f748785e49ff41bec2c3243255d83c6895bc0c893e6a772d7440a68321246b177709d3bd82d0dc2f5bca40c878e859b6f82319a386e0b7fcbc8010a25178b08418389ba7c6a77f99ac7f4ae5c686ab6574fcd0116f8573bccda3edfdff36c9c92ce2fb8bfb0ce2fe5c6b2498c6eb16fc2d40de9ddcba199a7e93d648abf39d6b248e196de7127e6b812e3080497f2a82afa69a471ab511e753e5b17a1c39c6728a065898af6674608d92a625e96e2f0258fe2eb06a27d0586d889d61f97faaa3facf58cda"
|
||||
},
|
||||
{
|
||||
"commit": "0812276cc788e6870612296d926cba9f0e7b9810670710b5a6e6f1ba006d395774",
|
||||
@@ -337,7 +335,7 @@ pub trait ForeignRpc {
|
||||
"version_info": {
|
||||
"orig_version": 2,
|
||||
"version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -370,7 +368,7 @@ pub trait ForeignRpc {
|
||||
"version_info": {
|
||||
"version": 2,
|
||||
"orig_version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
},
|
||||
"num_participants": 2,
|
||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||
@@ -505,7 +503,7 @@ pub trait ForeignRpc {
|
||||
"version_info": {
|
||||
"orig_version": 2,
|
||||
"version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -559,6 +557,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn test_check_middleware(
|
||||
_name: ForeignCheckMiddlewareFn,
|
||||
_node_version_info: Option<NodeVersionInfo>,
|
||||
_slate: Option<&Slate>,
|
||||
) -> Result<(), libwallet::Error> {
|
||||
// TODO: Implement checks
|
||||
// return Err(ErrorKind::GenericError("Test Rejection".into()))?
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// helper to set up a real environment to run integrated doctests
|
||||
pub fn run_doctest_foreign(
|
||||
request: serde_json::Value,
|
||||
@@ -677,8 +685,8 @@ pub fn run_doctest_foreign(
|
||||
}
|
||||
|
||||
let mut api_foreign = match init_invoice_tx {
|
||||
false => Foreign::new(wallet1.clone()),
|
||||
true => Foreign::new(wallet2.clone()),
|
||||
false => Foreign::new(wallet1.clone(), Some(test_check_middleware)),
|
||||
true => Foreign::new(wallet2.clone(), Some(test_check_middleware)),
|
||||
};
|
||||
api_foreign.doctest_mode = true;
|
||||
let foreign_api = &api_foreign as &dyn ForeignRpc;
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ mod foreign;
|
||||
mod foreign_rpc;
|
||||
mod owner;
|
||||
mod owner_rpc;
|
||||
pub use crate::foreign::Foreign;
|
||||
pub use crate::foreign::{Foreign, ForeignCheckMiddleware, ForeignCheckMiddlewareFn};
|
||||
pub use crate::foreign_rpc::ForeignRpc;
|
||||
pub use crate::owner::Owner;
|
||||
pub use crate::owner_rpc::OwnerRpc;
|
||||
|
||||
+11
-11
@@ -382,7 +382,7 @@ pub trait OwnerRpc {
|
||||
{
|
||||
"commit": "094be57c91787fc2033d5d97fae099f1a6ddb37ea48370f1a138f09524c767fdd3",
|
||||
"features": "Plain",
|
||||
"proof": "2a42e9e902b70ce44e1fccb14de87ee0a97100bddf12c6bead1b9c5f4eb60300f29c13094fa12ffeee238fb4532b18f6b61cf51b23c1c7e1ad2e41560dc27edc0a2b9e647a0b3e4e806fced5b65e61d0f1f5197d3e2285c632d359e27b6b9206b2caffea4f67e0c7a2812e7a22c134b98cf89bd43d9f28b8bec25cce037a0ac5b1ae8f667e54e1250813a5263004486b4465ad4e641ab2b535736ea26535a11013564f08f483b7dab1c2bcc3ee38eadf2f7850eff7e3459a4bbabf9f0cf6c50d0c0a4120565cd4a2ce3e354c11721cd695760a24c70e0d5a0dfc3c5dcd51dfad6de2c237a682f36dc0b271f21bb3655e5333016aaa42c2efa1446e5f3c0a79ec417c4d30f77556951cb0f05dbfafb82d9f95951a9ea241fda2a6388f73ace036b98acce079f0e4feebccc96290a86dcc89118a901210b245f2d114cf94396e4dbb461e82aa26a0581389707957968c7cdc466213bb1cd417db207ef40c05842ab67a01a9b96eb1430ebc26e795bb491258d326d5174ad549401059e41782121e506744af8af9d8e493644a87d613600888541cbbe538c625883f3eb4aa3102c5cfcc25de8e97af8927619ce6a731b3b8462d51d993066b935b0648d2344ad72e4fd70f347fbd81041042e5ea31cc7b2e3156a920b80ecba487b950ca32ca95fae85b759c936246ecf441a9fdd95e8fee932d6782cdec686064018c857efc47fb4b2a122600d5fdd79af2486f44df7e629184e1c573bc0a9b3feb40b190ef2861a1ab45e2ac2201b9cd42e495deea247269820ed32389a2810ad6c0f9a296d2a2d9c54089fed50b7f5ecfcd33ab9954360e1d7f5598c32128cfcf2a1d8bf14616818da8a5343bfa88f0eedf392e9d4ab1ace1b60324129cd4852c2e27813a9cf71a6ae6229a4fcecc1a756b3e664c5f50af333082616815a3bec8fc0b75b8e4e767d719"
|
||||
"proof": "1319630b26d02363861ebdb15514086dc8b0772b4bb63ef9b828704e0ac348efada6747dd7a29848138d630c7b403e573c9cde04be5d25f2d344db4b010d6b890dd6c54cc0911c0cadc7a8a225b2ec3f2dcac88189a17aa62257e969eef9de9172009d8e864e413f1953998b28531e580d3ea495a512d320e8d4ff50e7495a6c283c6e544d16364d34272805893526f1e3b6fd176ef4adc5671b165cf28efcfb8d25c0dfcd018a2c5e65beeb9201f3983194e5a521c0844d05c700654dfaed1b9b39dae08cc9afab9cb891256bc0237ad2ce78da8b44586580f52dd346dcafde5e471917f16e4c4b51e966e1946f13e31771503c85bb0f1b41d1c7fcc953e70af55400638a35e7f5610f9f4c5b881a35060a693deaf46e1839c54a8f7d2c626b05acd3450b72ae8f2e0f8721bcbbd8562141d3fef851c6ac3c8069fa6389389bc4fcba5e4fb49709a3b63a59ba96a82827dfbd6f16de849ef95f3114593d207aff6e030152929fa220b0c3b54ca419cfcbffb7a0106dd3154e858878c7d8f38cadcc376c502bdc50292b494484936d0846fc3fac10910962bca4ddcca5c80b458fd7df15e9a6c2f39b516425a2190a97c9d0e2e2f105ee29905f36e3a648a135ebf387d0bb2a6b61d95b215319d6dc9ee8b4b2798810fb6e01c007041b288c2b39e805c9af86c88dd4a380b6a346b4a0e67bba6aaac5acc70088ac3297486b90cfe371d9464552747a2f7680f42d5629fb09bed835382d842234712c0574c5b4f256c226e77602429983e4def71541cff80ccf4cd3b761685c91463c8e1c7bf828699c688509282b85e752424df3da670b3cfacdea2f66cfb804fecdf8b7eb056e8917fdae78d83c011964e3d5a0748873f817d0abf4b04c20452733eac35c318b96e100a5ace0f54085bd24f968b8fc5b276e0d7b134f01db50b3d2771cdcf1423d44"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -462,7 +462,7 @@ pub trait OwnerRpc {
|
||||
{
|
||||
"commit": "09cf47204446c326e361a1a92f34b174deff732daaedb80d7339fbe3db5ca2f6ba",
|
||||
"features": "Plain",
|
||||
"proof": "8f511614315626b5f39224482351d766f5a8ef136262befc050d839be8479b0a13470cd88f4436346d213d83847a4055c6e0ac63681556470349a1aab47034a3015eb64d8163955998e2dd4165dd24386b1e279974b05deb5d46ba2bc321f7000c0784f8f10690605ffe717119d045e02b141ed12d8fc6d20930483a8af889ef533495eb442fcff36d98ebc104f13fc645c28431b3296e4a11f7c991ff97f9abbc2f8886762d7f29fdacb31d52c6850e6ccf5386117d89e8ea4ca3071c56c218dd5d3bcd65f6c06ed9f51f848507ca1d594f41796d1cf99f68a5c3f0c5dd9873602284cff31269b102fcc6c68607565faaf0adb04ed4ff3ea5d41f3b5235ac6cb90e4046c808c9c48c27172c891b20085c56a99913ef47fd8b3dc4920cef50534b9319a7cefe0df10a0206a634ac837e11da92df83ff58b1a14de81313400988aa48b946fcbe1b81f0e79e13f7c6c639b1c10983b424bda08d0ce593a20f1f47e0aa01473e7144f116b76d9ebc60599053d8f1542d60747793d99064e51fce8f8866390325d48d6e8e3bbdbc1822c864303451525c6cb4c6902f105a70134186fb32110d8192fc2528a9483fc8a4001f4bdeab1dd7b3d1ccb9ae2e746a78013ef74043f0b2436f0ca49627af1768b7c791c669bd331fd18c16ef88ad0a29861db70f2f76f3e74fde5accb91b73573e31333333223693d6fbc786e740c085e4fc6e7bde0a3f54e9703f816c54f012d3b1f41ec4d253d9337af61e7f1f1383bd929421ac346e3d2771dfee0b60503b33938e7c83eb37af3b6bf66041a3519a2b4cb557b34e3b9afcf95524f9a011425a34d32e7b6e9f255291094930acae26e8f7a1e4e6bc405d0f88e919f354f3ba85356a34f1aba5f7da1fad88e2692f4129cc1fb80a2122b2d996c6ccf7f08d8248e511d92af9ce49039de728848a2dc74101f4e94a"
|
||||
"proof": "b368448efb3bfae95e7f18381883d64cbc9f01390e9c677d5d9f3523df43754dd174811768b7ffcafbfb284ae7413bdf56640ecb06918a5c38a5dae6cb33baff099c7cca6b052e07f915faecedee50a11ceaf41a7809bd33b51e22306ddf42620f7118133a418802f6e98222a8f3683cf3d5a5314155d0bf5f2e8be68e81ebe049ece23b0135d7b878c1ecebbf03de69fb8cbaf5f9611a430ae3083f71e0a74db8899b0083123a9e1924db8d340fdcc0bba4816afc613a0c6622fa89a84f31982cd4298a3b4c4de9d5f67800f48c6b37b4b49fb527290ec92f1551f4570abe42ac6ac42b05e3579b33533b784061ccbd2507af419079c3ea846f1af1aa2bfb04837166c60eab8207fed9000d3c2f5166e655e9220051223b90fb5751becc8a18cf10fb43cbc1cdeb8d0f11f5d0eb9dffdd4480abd69a49737f526b41b78f3c00bd7ef10f6ad3d8704f9ac6e79196c57b315a37265ca561fa333733e9c9275a2a4dc703b509b3ff11e6d983dd43a06566c82832ae0da9c8e9759038c6c86b30a05dd5cacc42c10fad496dee8cf63127233ae0bd27c766aed7448ebd7afbaa35c5491795fca7441b5373c4912e99ffbded6c7082d67f0b688f5af662be375f76699a69fcccb9c1c1841056fb4b6ec3f1c4dc40f032675fc2c87bab58e3375dac567533c4d0e3f1521e561029e231f3675368bde5817d177bd9c20b8cd7eb3b94260b0794f207bb33b9b8157518dbac8d725352b27ffa0e2aaa95d04592a87a6ee68deebaf1c51183704bea8ddd4298616fa353bc411936eafa1b31cc667a41a13a2d1a91db48464ea26c39ee1f68e67cbdd652165b040b43df2c80beda6af53dfbe0aa3aeb06c1887f9be83ed19b4b7094ba35700dad3ea4090594e662ae2a1c276b969751ab6d5d49a2c727d7ee2c80ffdc3d1ba040a20269b9bfc45930f467dbb43f64"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -535,7 +535,7 @@ pub trait OwnerRpc {
|
||||
"version_info": {
|
||||
"orig_version": 2,
|
||||
"version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -610,7 +610,7 @@ pub trait OwnerRpc {
|
||||
{
|
||||
"commit": "094be57c91787fc2033d5d97fae099f1a6ddb37ea48370f1a138f09524c767fdd3",
|
||||
"features": "Plain",
|
||||
"proof": "2a42e9e902b70ce44e1fccb14de87ee0a97100bddf12c6bead1b9c5f4eb60300f29c13094fa12ffeee238fb4532b18f6b61cf51b23c1c7e1ad2e41560dc27edc0a2b9e647a0b3e4e806fced5b65e61d0f1f5197d3e2285c632d359e27b6b9206b2caffea4f67e0c7a2812e7a22c134b98cf89bd43d9f28b8bec25cce037a0ac5b1ae8f667e54e1250813a5263004486b4465ad4e641ab2b535736ea26535a11013564f08f483b7dab1c2bcc3ee38eadf2f7850eff7e3459a4bbabf9f0cf6c50d0c0a4120565cd4a2ce3e354c11721cd695760a24c70e0d5a0dfc3c5dcd51dfad6de2c237a682f36dc0b271f21bb3655e5333016aaa42c2efa1446e5f3c0a79ec417c4d30f77556951cb0f05dbfafb82d9f95951a9ea241fda2a6388f73ace036b98acce079f0e4feebccc96290a86dcc89118a901210b245f2d114cf94396e4dbb461e82aa26a0581389707957968c7cdc466213bb1cd417db207ef40c05842ab67a01a9b96eb1430ebc26e795bb491258d326d5174ad549401059e41782121e506744af8af9d8e493644a87d613600888541cbbe538c625883f3eb4aa3102c5cfcc25de8e97af8927619ce6a731b3b8462d51d993066b935b0648d2344ad72e4fd70f347fbd81041042e5ea31cc7b2e3156a920b80ecba487b950ca32ca95fae85b759c936246ecf441a9fdd95e8fee932d6782cdec686064018c857efc47fb4b2a122600d5fdd79af2486f44df7e629184e1c573bc0a9b3feb40b190ef2861a1ab45e2ac2201b9cd42e495deea247269820ed32389a2810ad6c0f9a296d2a2d9c54089fed50b7f5ecfcd33ab9954360e1d7f5598c32128cfcf2a1d8bf14616818da8a5343bfa88f0eedf392e9d4ab1ace1b60324129cd4852c2e27813a9cf71a6ae6229a4fcecc1a756b3e664c5f50af333082616815a3bec8fc0b75b8e4e767d719"
|
||||
"proof": "1319630b26d02363861ebdb15514086dc8b0772b4bb63ef9b828704e0ac348efada6747dd7a29848138d630c7b403e573c9cde04be5d25f2d344db4b010d6b890dd6c54cc0911c0cadc7a8a225b2ec3f2dcac88189a17aa62257e969eef9de9172009d8e864e413f1953998b28531e580d3ea495a512d320e8d4ff50e7495a6c283c6e544d16364d34272805893526f1e3b6fd176ef4adc5671b165cf28efcfb8d25c0dfcd018a2c5e65beeb9201f3983194e5a521c0844d05c700654dfaed1b9b39dae08cc9afab9cb891256bc0237ad2ce78da8b44586580f52dd346dcafde5e471917f16e4c4b51e966e1946f13e31771503c85bb0f1b41d1c7fcc953e70af55400638a35e7f5610f9f4c5b881a35060a693deaf46e1839c54a8f7d2c626b05acd3450b72ae8f2e0f8721bcbbd8562141d3fef851c6ac3c8069fa6389389bc4fcba5e4fb49709a3b63a59ba96a82827dfbd6f16de849ef95f3114593d207aff6e030152929fa220b0c3b54ca419cfcbffb7a0106dd3154e858878c7d8f38cadcc376c502bdc50292b494484936d0846fc3fac10910962bca4ddcca5c80b458fd7df15e9a6c2f39b516425a2190a97c9d0e2e2f105ee29905f36e3a648a135ebf387d0bb2a6b61d95b215319d6dc9ee8b4b2798810fb6e01c007041b288c2b39e805c9af86c88dd4a380b6a346b4a0e67bba6aaac5acc70088ac3297486b90cfe371d9464552747a2f7680f42d5629fb09bed835382d842234712c0574c5b4f256c226e77602429983e4def71541cff80ccf4cd3b761685c91463c8e1c7bf828699c688509282b85e752424df3da670b3cfacdea2f66cfb804fecdf8b7eb056e8917fdae78d83c011964e3d5a0748873f817d0abf4b04c20452733eac35c318b96e100a5ace0f54085bd24f968b8fc5b276e0d7b134f01db50b3d2771cdcf1423d44"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -619,7 +619,7 @@ pub trait OwnerRpc {
|
||||
"version_info": {
|
||||
"orig_version": 2,
|
||||
"version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -688,7 +688,7 @@ pub trait OwnerRpc {
|
||||
"version_info": {
|
||||
"orig_version": 2,
|
||||
"version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
}
|
||||
},
|
||||
0
|
||||
@@ -726,7 +726,7 @@ pub trait OwnerRpc {
|
||||
"version_info": {
|
||||
"version": 2,
|
||||
"orig_version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
},
|
||||
"num_participants": 2,
|
||||
"id": "0436430c-2b02-624c-2032-570501212b00",
|
||||
@@ -862,7 +862,7 @@ pub trait OwnerRpc {
|
||||
"version_info": {
|
||||
"orig_version": 2,
|
||||
"version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1045,12 +1045,12 @@ pub trait OwnerRpc {
|
||||
{
|
||||
"commit": "099b48cfb1f80a2347dc89818449e68e76a3c6817a532a8e9ef2b4a5ccf4363850",
|
||||
"features": "Plain",
|
||||
"proof": "7ebcd2ed9bf5fb29854033ba3d0e720613bdf7dfacc586d2f6084c1cde0a2b72e955d4ce625916701dc7c347132f40d0f102a34e801d745ee54b49b765d08aae0bb801c60403e57cafade3b4b174e795b633ab9e402b5b1b6e1243fd10bbcf9368a75cb6a6c375c7bdf02da9e03b7f210df45d942e6fba2729cd512a372e6ed91a1b5c9c22831febea843e3f85adcf198f39ac9f7b73b70c60bfb474aa69878ea8d1d32fef30166b59caacaec3fd024de29a90f1587e08d2c36b3d5c560cabf658e212e0a40a4129b3e5c35557058def5551f4eb395759597ba808b3c34eac3bfb9716e4480d7931c5789c538463ec75be0eb807c894047fda6cbcd22682d3c6d3823cb330f090a2099e3510a3706b57d46c95224394d7f1c0a20d99cc314b8f1d9d02668e2e435f62e1194de0be6a1f50f72ed777ed51c8819f527a94918d1aa8df6461e98ed4c2b18210de50fbcf8c3df210bfe326d41f1dc0ad748cb0320ae28401c85ab4f7dcb99d88a052e95dc85b76d22b36cabd60e06ab84bb7e4ddfdab9c9730c8a986583237ed1ecbb323ee8e79b8cadca4b438b7c09531670b471dda6a2eb3e747916c88ce7d9d8e1b7f61660eeb9e5a13c60e4dfe89d1177d81d6f6570fda85158e646a15f1e8b9e977494dc19a339aab2e0e478670d80092d6ba37646e60714ef64eb4a3d37fe15f8f38b59114af34b235489eed3f69b7781c5fe496eb43ffe245c14bd740f745844a38cf0d904347aaa2b64f51add18822dac009d8b63fa3e4c9b1fa72187f9a4acba1ab315daa1b04c9a41f3be846ac420b37990e6c947a16cc9d5c0671b292bf77d7d8b8974d2ad3afae95ba7772c37432840f53a007f31e0195f3abdf100c4477723cc6c6d5da14894a73dfac342833731036487488fdade7b9d556c06f26173b6b67598d3769447ce2828d71dd45ac5af436c6b0"
|
||||
"proof": "29701ceae262cac77b79b868c883a292e61e6de8192b868edcd1300b0973d91396b156ace6bd673402a303de10ddd8a5e6b7f17ba6557a574a672bd04cc273ab04ed8e2ca80bac483345c0ec843f521814ce1301ec9adc38956a12b4d948acce71295a4f52bcdeb8a1c9f2d6b2da5d731262a5e9c0276ef904df9ef8d48001420cd59f75a2f1ae5c7a1c7c6b9f140e7613e52ef9e249f29f9340b7efb80699e460164324616f98fd4cde3db52497c919e95222fffeacb7e65deca7e368a80ce713c19de7da5369726228ee336f5bd494538c12ccbffeb1b9bfd5fc8906d1c64245b516f103fa96d9c56975837652c1e0fa5803d7ccf1147d8f927e36da717f7ad79471dbe192f5f50f87a79fc3fe030dba569b634b92d2cf307993cce545633af263897cd7e6ebf4dcafb176d07358bdc38d03e45a49dfa9c8c6517cd68d167ffbf6c3b4de0e2dd21909cbad4c467b84e5700be473a39ac59c669d7c155c4bcab9b8026eea3431c779cd277e4922d2b9742e1f6678cbe869ec3b5b7ef4132ddb6cdd06cf27dbeb28be72b949fa897610e48e3a0d789fd2eea75abc97b3dc7e00e5c8b3d24e40c6f24112adb72352b89a2bef0599345338e9e76202a3c46efa6370952b2aca41aadbae0ea32531acafcdab6dd066d769ebf50cf4f3c0a59d2d5fa79600a207b9417c623f76ad05e8cccfcd4038f9448bc40f127ca7c0d372e46074e334fe49f5a956ec0056f4da601e6af80eb1a6c4951054869e665b296d8c14f344ca2dc5fdd5df4a3652536365a1615ad9b422165c77bf8fe65a835c8e0c41e070014eb66ef8c525204e990b3a3d663c1e42221b496895c37a2f0c1bf05e91235409c3fe3d89a9a79d6c78609ab18a463311911f71fa37bb73b15fcd38143d1404fd2ce81004dc7ff89cf1115dcc0c35ce1c1bf9941586fb959770f2618ccb7118a7"
|
||||
},
|
||||
{
|
||||
"commit": "0812276cc788e6870612296d926cba9f0e7b9810670710b5a6e6f1ba006d395774",
|
||||
"features": "Plain",
|
||||
"proof": "dcff6175390c602bfa92c2ffd1a9b2d84dcc9ea941f6f317bdd0f875244ef23e696fd17c71df79760ce5ce1a96aab1d15dd057358dc835e972febeb86d50ccec0dad7cfe0246d742eb753cf7b88c045d15bc7123f8cf7155647ccf663fca92a83c9a65d0ed756ea7ebffd2cac90c380a102ed9caaa355d175ed0bf58d3ac2f5e909d6c447dfc6b605e04925c2b17c33ebd1908c965a5541ea5d2ed45a0958e6402f89d7a56df1992e036d836e74017e73ccad5cb3a82b8e139e309792a31b15f3ffd72ed033253428c156c2b9799458a25c1da65b719780a22de7fe7f437ae2fccd22cf7ea357ab5aa66a5ef7d71fb0dc64aa0b5761f68278062bb39bb296c787e4cabc5e2a2933a416ce1c9a9696160386449c437e9120f7bb26e5b0e74d1f2e7d5bcd7aafb2a92b87d1548f1f911fb06af7bd6cc13cee29f7c9cb79021aed18186272af0e9d189ec107c81a8a3aeb4782b0d950e4881aa51b776bb6844b25bce97035b48a9bdb2aea3608687bcdd479d4fa998b5a839ff88558e4a29dff0ed13b55900abb5d439b70793d902ae9ad34587b18c919f6b875c91d14deeb1c373f5e76570d59a6549758f655f1128a54f162dfe8868e1587028e26ad91e528c5ae7ee9335fa58fb59022b5de29d80f0764a9917390d46db899acc6a5b416e25ecc9dccb7153646addcc81cadb5f0078febc7e05d7735aba494f39ef05697bbcc9b47b2ccc79595d75fc13c80678b5e237edce58d731f34c05b1ddcaa649acf2d865bbbc3ceda10508bcdd29d0496744644bf1c3516f6687dfeef5649c7dff90627d642739a59d91a8d1d0c4dc55d74a949e1074427664b467992c9e0f7d3af9d6ea79513e8946ddc0d356bac49878e64e6a95b0a30214214faf2ce317fa622ff3266b32a816e10a18e6d789a5da1f23e67b4f970a68a7bcd9e18825ee274b0483896a40"
|
||||
"proof": "284b9f9199411c6bbf7227eae15cc9fa7ed30534af3ecff85b0d016da329cae1f1edf79f01426434cb90afcc2f0a1fb296e5c51a91b5e57a1f0230fda4f8c5950e7986fa379b99d64b6039a86cc7e35e040ba192b781043959851268ca9874a918805ea958c84f7fee8d3ab4262f032f5a3f840ebcdd273b29be810114e6e86a959d8e4c080572e3ef249edd6ad68503ec3bc4486548520ea2775a41aea67aac99945fce9e7a7769d71f893ad7f0d0108692f6b6852312cae6f9857063055bda59dce521927c70040b8026a41b6517cae0a1c947ca244984a5c0adf7c6483b0939346c48f61cac37d501f46a1c5878b67cee0d0723f4eeadc9f5d71ed5e9f33b4294b58d3ebeefeaa13f20357599be549ce18e6e2eb1d50e1235ccc40ec9184c68a623741a7238ce69aa3a1d25156b3b7eb38fdd6fbe5473979feee3317df279c60d48a289826aa4c76dbce24d526890d4e6e2f83e80f674a1248fc1dc037d982009012ae1133f5e158ae6cdadb18c8d53e4a8ae5595c758782c67aa0c20f146d52085cf45a35794cec45702830f8952a69744718fbe6fe0d3da66e348dd3473a0aced7080fbf5494c3e7e141916f3b135b33277f998fcd9acfbca8709814866e9838a5dcda4c29422cf157293e6fc2ccc2d25423517843bd8e21c61ced72312c0b48814c312021b0d31598d2389b0b329baa1169922a4c34173dd5f540545be5066a0f291f1a870e1aaff94c19f0a855254882a17984baeda08e8ead53d1563e9ee4bc36742789cef4f3ab158054d7ddfe2a2b37b5a8a30be84ff7df9a7d758a9b76751a3622057721a3ec5b873582d0c91cd1febbc153662739854ea15c9903023c193c6b5768b55484108f897cdc47d13a9088b32558e57f12f5807668649c99a17b51905127340e8b49c42775f1b3cab072dfad33d33cc1e4ba5964d728ed0a905"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1121,7 +1121,7 @@ pub trait OwnerRpc {
|
||||
"version_info": {
|
||||
"orig_version": 2,
|
||||
"version": 2,
|
||||
"block_header_version": 1
|
||||
"block_header_version": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! core::libtx specific tests
|
||||
use grin_wallet_api::foreign_rpc_client;
|
||||
//use grin_wallet_api::foreign_rpc_client;
|
||||
use grin_wallet_api::run_doctest_foreign;
|
||||
use grin_wallet_libwallet::{Slate, SlateVersion, VersionedSlate};
|
||||
//use grin_wallet_libwallet::VersionedSlate;
|
||||
use serde_json;
|
||||
use serde_json::Value;
|
||||
use tempfile::tempdir;
|
||||
@@ -22,8 +22,8 @@ use tempfile::tempdir;
|
||||
//use grin_wallet_libwallet::slate_versions::v2::SlateV2;
|
||||
|
||||
// test all slate conversions
|
||||
#[test]
|
||||
fn receive_versioned_slate() {
|
||||
//#[test]
|
||||
fn _receive_versioned_slate() {
|
||||
// as in doctests, except exercising versioning functionality
|
||||
// by accepting and responding with a V1 slate
|
||||
|
||||
@@ -65,6 +65,9 @@ fn receive_versioned_slate() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Re-introduce on a new slate version
|
||||
|
||||
/*
|
||||
/// call ForeignRpc::receive_tx on vs and return the result
|
||||
fn receive_tx(vs: VersionedSlate) -> VersionedSlate {
|
||||
let dir = tempdir().map_err(|e| format!("{:#?}", e)).unwrap();
|
||||
@@ -128,4 +131,4 @@ fn version_unchanged() {
|
||||
VersionedSlate::V2(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "grin_wallet_config"
|
||||
version = "1.1.1-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||
description = "Configuration for grin wallet , a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||
license = "Apache-2.0"
|
||||
@@ -16,7 +16,7 @@ serde_derive = "1"
|
||||
toml = "0.4"
|
||||
dirs = "1.0.3"
|
||||
|
||||
grin_wallet_util = { path = "../util", version = "1.1.1-beta.1" }
|
||||
grin_wallet_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.5.1"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "grin_wallet_controller"
|
||||
version = "1.1.1-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||
description = "Controllers for grin wallet instantiation"
|
||||
license = "Apache-2.0"
|
||||
@@ -32,9 +32,9 @@ chrono = { version = "0.4.4", features = ["serde"] }
|
||||
easy-jsonrpc = "0.5.1"
|
||||
lazy_static = "1"
|
||||
|
||||
grin_wallet_util = { path = "../util", version = "1.1.1-beta.1" }
|
||||
grin_wallet_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||
|
||||
grin_wallet_api = { path = "../api", version = "1.1.1-beta.1" }
|
||||
grin_wallet_impls = { path = "../impls", version = "1.1.1-beta.1" }
|
||||
grin_wallet_libwallet = { path = "../libwallet", version = "1.1.1-beta.1" }
|
||||
grin_wallet_config = { path = "../config", version = "1.1.1-beta.1" }
|
||||
grin_wallet_api = { path = "../api", version = "2.0.0-beta.2" }
|
||||
grin_wallet_impls = { path = "../impls", version = "2.0.0-beta.2" }
|
||||
grin_wallet_libwallet = { path = "../libwallet", version = "2.0.0-beta.2" }
|
||||
grin_wallet_config = { path = "../config", version = "2.0.0-beta.2" }
|
||||
|
||||
+41
-630
@@ -14,15 +14,11 @@
|
||||
|
||||
//! Controller for wallet.. instantiates and handles listeners (or single-run
|
||||
//! invocations) as needed.
|
||||
//! Still experimental
|
||||
use crate::api::{self, ApiServer, BasicAuthMiddleware, ResponseFuture, Router, TLSConfig};
|
||||
use crate::core::core;
|
||||
use crate::core::core::Transaction;
|
||||
use crate::impls::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
|
||||
use crate::keychain::Keychain;
|
||||
use crate::libwallet::{
|
||||
CbData, Error, ErrorKind, InitTxArgs, NodeClient, OutputCommitMapping, SendTXArgs, Slate,
|
||||
TxLogEntry, WalletBackend, WalletInfo,
|
||||
Error, ErrorKind, NodeClient, NodeVersionInfo, Slate, WalletBackend, CURRENT_SLATE_VERSION,
|
||||
GRIN_BLOCK_HEADER_VERSION,
|
||||
};
|
||||
use crate::util::to_base64;
|
||||
use crate::util::Mutex;
|
||||
@@ -33,14 +29,11 @@ use hyper::header::HeaderValue;
|
||||
use hyper::{Body, Request, Response, StatusCode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use url::form_urlencoded;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::apiwallet::{Foreign, ForeignRpc, Owner, OwnerRpc};
|
||||
use crate::apiwallet::{Foreign, ForeignCheckMiddlewareFn, ForeignRpc, Owner, OwnerRpc};
|
||||
use easy_jsonrpc;
|
||||
use easy_jsonrpc::{Handler, MaybeReply};
|
||||
|
||||
@@ -49,6 +42,36 @@ lazy_static! {
|
||||
HeaderValue::from_str("Basic realm=GrinOwnerAPI").unwrap();
|
||||
}
|
||||
|
||||
fn check_middleware(
|
||||
name: ForeignCheckMiddlewareFn,
|
||||
node_version_info: Option<NodeVersionInfo>,
|
||||
slate: Option<&Slate>,
|
||||
) -> Result<(), Error> {
|
||||
match name {
|
||||
// allow coinbases to be built regardless
|
||||
ForeignCheckMiddlewareFn::BuildCoinbase => Ok(()),
|
||||
_ => {
|
||||
let mut bhv = 1;
|
||||
if let Some(n) = node_version_info {
|
||||
bhv = n.block_header_version;
|
||||
}
|
||||
if let Some(s) = slate {
|
||||
if s.version_info.version < CURRENT_SLATE_VERSION
|
||||
|| (bhv == 1 && s.version_info.block_header_version != 1)
|
||||
|| (bhv > 1 && s.version_info.block_header_version < GRIN_BLOCK_HEADER_VERSION)
|
||||
{
|
||||
Err(ErrorKind::Compatibility(
|
||||
"Incoming Slate is not compatible with this wallet. \
|
||||
Please upgrade the node or use a different one."
|
||||
.into(),
|
||||
))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Instantiate wallet Owner API for a single-use (command line) call
|
||||
/// Return a function containing a loaded API context to call
|
||||
pub fn owner_single_use<F, T: ?Sized, C, K>(wallet: Arc<Mutex<T>>, f: F) -> Result<(), Error>
|
||||
@@ -71,7 +94,7 @@ where
|
||||
C: NodeClient,
|
||||
K: Keychain,
|
||||
{
|
||||
f(&mut Foreign::new(wallet.clone()))?;
|
||||
f(&mut Foreign::new(wallet.clone(), Some(check_middleware)))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -86,11 +109,9 @@ pub fn owner_listener<T: ?Sized, C, K>(
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||
OwnerAPIHandler<T, C, K>: api::Handler,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
let api_handler = OwnerAPIHandler::new(wallet.clone());
|
||||
let api_handler_v2 = OwnerAPIHandlerV2::new(wallet.clone());
|
||||
|
||||
let mut router = Router::new();
|
||||
@@ -104,10 +125,6 @@ where
|
||||
router.add_middleware(basic_auth_middleware);
|
||||
}
|
||||
|
||||
router
|
||||
.add_route("/v1/wallet/owner/**", Arc::new(api_handler))
|
||||
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
|
||||
|
||||
router
|
||||
.add_route("/v2/owner", Arc::new(api_handler_v2))
|
||||
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
|
||||
@@ -115,11 +132,6 @@ where
|
||||
// If so configured, add the foreign API to the same port
|
||||
if owner_api_include_foreign.unwrap_or(false) {
|
||||
info!("Starting HTTP Foreign API on Owner server at {}.", addr);
|
||||
let foreign_api_handler = ForeignAPIHandler::new(wallet.clone());
|
||||
router
|
||||
.add_route("/v1/wallet/foreign/**", Arc::new(foreign_api_handler))
|
||||
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
|
||||
|
||||
let foreign_api_handler_v2 = ForeignAPIHandlerV2::new(wallet.clone());
|
||||
router
|
||||
.add_route("/v2/foreign", Arc::new(foreign_api_handler_v2))
|
||||
@@ -151,13 +163,9 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
let api_handler = ForeignAPIHandler::new(wallet.clone());
|
||||
let api_handler_v2 = ForeignAPIHandlerV2::new(wallet);
|
||||
|
||||
let mut router = Router::new();
|
||||
router
|
||||
.add_route("/v1/wallet/foreign/**", Arc::new(api_handler))
|
||||
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
|
||||
|
||||
router
|
||||
.add_route("/v2/foreign", Arc::new(api_handler_v2))
|
||||
@@ -180,475 +188,6 @@ where
|
||||
|
||||
type WalletResponseFuture = Box<dyn Future<Item = Response<Body>, Error = Error> + Send>;
|
||||
|
||||
/// API Handler/Wrapper for owner functions
|
||||
pub struct OwnerAPIHandler<T: ?Sized, C, K>
|
||||
where
|
||||
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
/// Wallet instance
|
||||
pub wallet: Arc<Mutex<T>>,
|
||||
phantom: PhantomData<K>,
|
||||
phantom_c: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized, C, K> OwnerAPIHandler<T, C, K>
|
||||
where
|
||||
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
/// Create a new owner API handler for GET methods
|
||||
pub fn new(wallet: Arc<Mutex<T>>) -> OwnerAPIHandler<T, C, K> {
|
||||
OwnerAPIHandler {
|
||||
wallet,
|
||||
phantom: PhantomData,
|
||||
phantom_c: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn retrieve_outputs(
|
||||
&self,
|
||||
req: &Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Result<(bool, Vec<OutputCommitMapping>), Error> {
|
||||
let mut update_from_node = false;
|
||||
let mut id = None;
|
||||
let mut show_spent = false;
|
||||
let params = parse_params(req);
|
||||
|
||||
if let Some(_) = params.get("refresh") {
|
||||
update_from_node = true;
|
||||
}
|
||||
if let Some(_) = params.get("show_spent") {
|
||||
show_spent = true;
|
||||
}
|
||||
if let Some(ids) = params.get("tx_id") {
|
||||
if let Some(x) = ids.first() {
|
||||
id = Some(x.parse().unwrap());
|
||||
}
|
||||
}
|
||||
api.retrieve_outputs(show_spent, update_from_node, id)
|
||||
}
|
||||
|
||||
pub fn retrieve_txs(
|
||||
&self,
|
||||
req: &Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Result<(bool, Vec<TxLogEntry>), Error> {
|
||||
let mut tx_id = None;
|
||||
let mut tx_slate_id = None;
|
||||
let mut update_from_node = false;
|
||||
|
||||
let params = parse_params(req);
|
||||
|
||||
if let Some(_) = params.get("refresh") {
|
||||
update_from_node = true;
|
||||
}
|
||||
if let Some(ids) = params.get("id") {
|
||||
if let Some(x) = ids.first() {
|
||||
tx_id = Some(x.parse().unwrap());
|
||||
}
|
||||
}
|
||||
if let Some(tx_slate_ids) = params.get("tx_id") {
|
||||
if let Some(x) = tx_slate_ids.first() {
|
||||
tx_slate_id = Some(x.parse().unwrap());
|
||||
}
|
||||
}
|
||||
api.retrieve_txs(update_from_node, tx_id, tx_slate_id)
|
||||
}
|
||||
|
||||
pub fn retrieve_stored_tx(
|
||||
&self,
|
||||
req: &Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Result<(bool, Option<Transaction>), Error> {
|
||||
let params = parse_params(req);
|
||||
if let Some(id_string) = params.get("id") {
|
||||
match id_string[0].parse() {
|
||||
Ok(id) => match api.retrieve_txs(true, Some(id), None) {
|
||||
Ok((_, txs)) => {
|
||||
let stored_tx = api.get_stored_tx(&txs[0])?;
|
||||
Ok((txs[0].confirmed, stored_tx))
|
||||
}
|
||||
Err(e) => {
|
||||
error!("retrieve_stored_tx: failed with error: {}", e);
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("retrieve_stored_tx: could not parse id: {}", e);
|
||||
Err(ErrorKind::TransactionDumpError(
|
||||
"retrieve_stored_tx: cannot dump transaction. Could not parse id in request.",
|
||||
).into())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(ErrorKind::TransactionDumpError(
|
||||
"retrieve_stored_tx: Cannot retrieve transaction. Missing id param in request.",
|
||||
)
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn retrieve_summary_info(
|
||||
&self,
|
||||
req: &Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Result<(bool, WalletInfo), Error> {
|
||||
let mut minimum_confirmations = 1; // TODO - default needed here
|
||||
let params = parse_params(req);
|
||||
let update_from_node = params.get("refresh").is_some();
|
||||
|
||||
if let Some(confs) = params.get("minimum_confirmations") {
|
||||
if let Some(x) = confs.first() {
|
||||
minimum_confirmations = x.parse().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
api.retrieve_summary_info(update_from_node, minimum_confirmations)
|
||||
}
|
||||
|
||||
pub fn node_height(
|
||||
&self,
|
||||
_req: &Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Result<(u64, bool), Error> {
|
||||
let res = api.node_height()?;
|
||||
Ok((res.height, res.updated_from_node))
|
||||
}
|
||||
|
||||
fn handle_get_request(&self, req: &Request<Body>) -> Result<Response<Body>, Error> {
|
||||
let api = Owner::new(self.wallet.clone());
|
||||
|
||||
Ok(
|
||||
match req
|
||||
.uri()
|
||||
.path()
|
||||
.trim_end_matches("/")
|
||||
.rsplit("/")
|
||||
.next()
|
||||
.unwrap()
|
||||
{
|
||||
"retrieve_outputs" => json_response(&self.retrieve_outputs(req, api)?),
|
||||
"retrieve_summary_info" => json_response(&self.retrieve_summary_info(req, api)?),
|
||||
"node_height" => json_response(&self.node_height(req, api)?),
|
||||
"retrieve_txs" => json_response(&self.retrieve_txs(req, api)?),
|
||||
"retrieve_stored_tx" => json_response(&self.retrieve_stored_tx(req, api)?),
|
||||
_ => response(StatusCode::BAD_REQUEST, ""),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn issue_send_tx(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Box<dyn Future<Item = Slate, Error = Error> + Send> {
|
||||
Box::new(parse_body(req).and_then(move |args: SendTXArgs| {
|
||||
let init_args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
amount: args.amount,
|
||||
minimum_confirmations: args.minimum_confirmations,
|
||||
max_outputs: args.max_outputs as u32,
|
||||
num_change_outputs: args.num_change_outputs as u32,
|
||||
selection_strategy_is_use_all: args.selection_strategy_is_use_all,
|
||||
message: args.message.clone(),
|
||||
target_slate_version: args.target_slate_version,
|
||||
send_args: None,
|
||||
..Default::default()
|
||||
};
|
||||
let result = api.init_send_tx(init_args);
|
||||
let mut slate = match result {
|
||||
Ok(s) => {
|
||||
info!(
|
||||
"Tx created: {} grin to {} (strategy '{}')",
|
||||
core::amount_to_hr_string(args.amount, false),
|
||||
&args.dest,
|
||||
args.selection_strategy_is_use_all,
|
||||
);
|
||||
s
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Tx not created: {}", e);
|
||||
match e.kind() {
|
||||
// user errors, don't backtrace
|
||||
ErrorKind::NotEnoughFunds { .. } => {}
|
||||
ErrorKind::Fee { .. } => {}
|
||||
_ => {
|
||||
// otherwise give full dump
|
||||
error!("Backtrace: {}", e.backtrace().unwrap());
|
||||
}
|
||||
};
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
match args.method.as_ref() {
|
||||
"http" => slate = HTTPWalletCommAdapter::new().send_tx_sync(&args.dest, &slate)?,
|
||||
"file" => {
|
||||
FileWalletCommAdapter::new().send_tx_async(&args.dest, &slate)?;
|
||||
}
|
||||
"keybase" => {
|
||||
//TODO: in case of keybase, the response might take 60s and leave the service hanging
|
||||
slate = KeybaseWalletCommAdapter::new().send_tx_sync(&args.dest, &slate)?;
|
||||
}
|
||||
_ => {
|
||||
error!("unsupported payment method: {}", args.method);
|
||||
return Err(ErrorKind::ClientCallback(
|
||||
"unsupported payment method".to_owned(),
|
||||
))?;
|
||||
}
|
||||
}
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
if args.method != "file" {
|
||||
slate = api.finalize_tx(&slate)?;
|
||||
}
|
||||
Ok(slate)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn finalize_tx(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Box<dyn Future<Item = Slate, Error = Error> + Send> {
|
||||
Box::new(
|
||||
parse_body(req).and_then(move |slate| match api.finalize_tx(&slate) {
|
||||
Ok(s) => ok(s.clone()),
|
||||
Err(e) => {
|
||||
error!("finalize_tx: failed with error: {}", e);
|
||||
err(e)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn cancel_tx(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Box<dyn Future<Item = (), Error = Error> + Send> {
|
||||
let params = parse_params(&req);
|
||||
if let Some(id_string) = params.get("id") {
|
||||
Box::new(match id_string[0].parse() {
|
||||
Ok(id) => match api.cancel_tx(Some(id), None) {
|
||||
Ok(_) => ok(()),
|
||||
Err(e) => {
|
||||
error!("cancel_tx: failed with error: {}", e);
|
||||
err(e)
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("cancel_tx: could not parse id: {}", e);
|
||||
err(ErrorKind::TransactionCancellationError(
|
||||
"cancel_tx: cannot cancel transaction. Could not parse id in request.",
|
||||
)
|
||||
.into())
|
||||
}
|
||||
})
|
||||
} else if let Some(tx_id_string) = params.get("tx_id") {
|
||||
Box::new(match tx_id_string[0].parse() {
|
||||
Ok(tx_id) => match api.cancel_tx(None, Some(tx_id)) {
|
||||
Ok(_) => ok(()),
|
||||
Err(e) => {
|
||||
error!("cancel_tx: failed with error: {}", e);
|
||||
err(e)
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("cancel_tx: could not parse tx_id: {}", e);
|
||||
err(ErrorKind::TransactionCancellationError(
|
||||
"cancel_tx: cannot cancel transaction. Could not parse tx_id in request.",
|
||||
)
|
||||
.into())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Box::new(err(ErrorKind::TransactionCancellationError(
|
||||
"cancel_tx: Cannot cancel transaction. Missing id or tx_id param in request.",
|
||||
)
|
||||
.into()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post_tx(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Box<dyn Future<Item = (), Error = Error> + Send> {
|
||||
let params = match req.uri().query() {
|
||||
Some(query_string) => form_urlencoded::parse(query_string.as_bytes())
|
||||
.into_owned()
|
||||
.fold(HashMap::new(), |mut hm, (k, v)| {
|
||||
hm.entry(k).or_insert(vec![]).push(v);
|
||||
hm
|
||||
}),
|
||||
None => HashMap::new(),
|
||||
};
|
||||
let fluff = params.get("fluff").is_some();
|
||||
Box::new(parse_body(req).and_then(
|
||||
move |slate: Slate| match api.post_tx(&slate.tx, fluff) {
|
||||
Ok(_) => ok(()),
|
||||
Err(e) => {
|
||||
error!("post_tx: failed with error: {}", e);
|
||||
err(e)
|
||||
}
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn repost(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
api: Owner<T, C, K>,
|
||||
) -> Box<dyn Future<Item = (), Error = Error> + Send> {
|
||||
let params = parse_params(&req);
|
||||
let mut id_int: Option<u32> = None;
|
||||
let mut tx_uuid: Option<Uuid> = None;
|
||||
|
||||
if let Some(id_string) = params.get("id") {
|
||||
match id_string[0].parse() {
|
||||
Ok(id) => id_int = Some(id),
|
||||
Err(e) => {
|
||||
error!("repost: could not parse id: {}", e);
|
||||
return Box::new(err(ErrorKind::GenericError(
|
||||
"repost: cannot repost transaction. Could not parse id in request."
|
||||
.to_owned(),
|
||||
)
|
||||
.into()));
|
||||
}
|
||||
}
|
||||
} else if let Some(tx_id_string) = params.get("tx_id") {
|
||||
match tx_id_string[0].parse() {
|
||||
Ok(tx_id) => tx_uuid = Some(tx_id),
|
||||
Err(e) => {
|
||||
error!("repost: could not parse tx_id: {}", e);
|
||||
return Box::new(err(ErrorKind::GenericError(
|
||||
"repost: cannot repost transaction. Could not parse tx_id in request."
|
||||
.to_owned(),
|
||||
)
|
||||
.into()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Box::new(err(ErrorKind::GenericError(
|
||||
"repost: Cannot repost transaction. Missing id or tx_id param in request."
|
||||
.to_owned(),
|
||||
)
|
||||
.into()));
|
||||
}
|
||||
|
||||
let res = api.retrieve_txs(true, id_int, tx_uuid);
|
||||
if let Err(e) = res {
|
||||
return Box::new(err(ErrorKind::GenericError(format!(
|
||||
"repost: cannot repost transaction. retrieve_txs failed, err: {:?}",
|
||||
e
|
||||
))
|
||||
.into()));
|
||||
}
|
||||
let (_, txs) = res.unwrap();
|
||||
let res = api.get_stored_tx(&txs[0]);
|
||||
if let Err(e) = res {
|
||||
return Box::new(err(ErrorKind::GenericError(format!(
|
||||
"repost: cannot repost transaction. get_stored_tx failed, err: {:?}",
|
||||
e
|
||||
))
|
||||
.into()));
|
||||
}
|
||||
let stored_tx = res.unwrap();
|
||||
if stored_tx.is_none() {
|
||||
error!(
|
||||
"Transaction with id {:?}/{:?} does not have transaction data. Not reposting.",
|
||||
id_int, tx_uuid,
|
||||
);
|
||||
return Box::new(err(ErrorKind::GenericError(
|
||||
"repost: Cannot repost transaction. Missing id or tx_id param in request."
|
||||
.to_owned(),
|
||||
)
|
||||
.into()));
|
||||
}
|
||||
|
||||
let fluff = params.get("fluff").is_some();
|
||||
Box::new(match api.post_tx(&stored_tx.unwrap(), fluff) {
|
||||
Ok(_) => ok(()),
|
||||
Err(e) => {
|
||||
error!("repost: failed with error: {}", e);
|
||||
err(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_post_request(&self, req: Request<Body>) -> WalletResponseFuture {
|
||||
let api = Owner::new(self.wallet.clone());
|
||||
match req
|
||||
.uri()
|
||||
.path()
|
||||
.trim_end_matches("/")
|
||||
.rsplit("/")
|
||||
.next()
|
||||
.unwrap()
|
||||
{
|
||||
"issue_send_tx" => Box::new(
|
||||
self.issue_send_tx(req, api)
|
||||
.and_then(|slate| ok(json_response_pretty(&slate))),
|
||||
),
|
||||
"finalize_tx" => Box::new(
|
||||
self.finalize_tx(req, api)
|
||||
.and_then(|slate| ok(json_response_pretty(&slate))),
|
||||
),
|
||||
"cancel_tx" => Box::new(
|
||||
self.cancel_tx(req, api)
|
||||
.and_then(|_| ok(response(StatusCode::OK, "{}"))),
|
||||
),
|
||||
"post_tx" => Box::new(
|
||||
self.post_tx(req, api)
|
||||
.and_then(|_| ok(response(StatusCode::OK, "{}"))),
|
||||
),
|
||||
"repost" => Box::new(
|
||||
self.repost(req, api)
|
||||
.and_then(|_| ok(response(StatusCode::OK, ""))),
|
||||
),
|
||||
_ => Box::new(err(ErrorKind::GenericError(
|
||||
"Unknown error handling post request".to_owned(),
|
||||
)
|
||||
.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, C, K> api::Handler for OwnerAPIHandler<T, C, K>
|
||||
where
|
||||
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
fn get(&self, req: Request<Body>) -> ResponseFuture {
|
||||
match self.handle_get_request(&req) {
|
||||
Ok(r) => Box::new(ok(r)),
|
||||
Err(e) => {
|
||||
error!("Request Error: {:?}", e);
|
||||
Box::new(ok(create_error_response(e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn post(&self, req: Request<Body>) -> ResponseFuture {
|
||||
Box::new(
|
||||
self.handle_post_request(req)
|
||||
.and_then(|r| ok(r))
|
||||
.or_else(|e| {
|
||||
error!("Request Error: {:?}", e);
|
||||
ok(create_error_response(e))
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn options(&self, _req: Request<Body>) -> ResponseFuture {
|
||||
Box::new(ok(create_ok_response("{}")))
|
||||
}
|
||||
}
|
||||
|
||||
/// V2 API Handler/Wrapper for owner functions
|
||||
pub struct OwnerAPIHandlerV2<T: ?Sized, C, K>
|
||||
where
|
||||
@@ -726,107 +265,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// API Handler/Wrapper for foreign functions
|
||||
pub struct ForeignAPIHandler<T: ?Sized, C, K>
|
||||
where
|
||||
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
/// Wallet instance
|
||||
pub wallet: Arc<Mutex<T>>,
|
||||
phantom: PhantomData<K>,
|
||||
phantom_c: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized, C, K> ForeignAPIHandler<T, C, K>
|
||||
where
|
||||
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
/// create a new api handler
|
||||
pub fn new(wallet: Arc<Mutex<T>>) -> ForeignAPIHandler<T, C, K> {
|
||||
ForeignAPIHandler {
|
||||
wallet,
|
||||
phantom: PhantomData,
|
||||
phantom_c: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_coinbase(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
api: Foreign<T, C, K>,
|
||||
) -> Box<dyn Future<Item = CbData, Error = Error> + Send> {
|
||||
Box::new(parse_body(req).and_then(move |block_fees| api.build_coinbase(&block_fees)))
|
||||
}
|
||||
|
||||
fn receive_tx(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
api: Foreign<T, C, K>,
|
||||
) -> Box<dyn Future<Item = Slate, Error = Error> + Send> {
|
||||
Box::new(parse_body(req).and_then(
|
||||
//TODO: No way to insert a message from the params
|
||||
move |slate_str: String| {
|
||||
let slate: Slate = Slate::deserialize_upgrade(&slate_str).unwrap();
|
||||
if let Err(e) = api.verify_slate_messages(&slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
err(e)
|
||||
} else {
|
||||
match api.receive_tx(&slate, None, None) {
|
||||
Ok(s) => ok(s),
|
||||
Err(e) => {
|
||||
error!("receive_tx: failed with error: {}", e);
|
||||
err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn handle_request(&self, req: Request<Body>) -> WalletResponseFuture {
|
||||
let api = Foreign::new(self.wallet.clone());
|
||||
match req
|
||||
.uri()
|
||||
.path()
|
||||
.trim_end_matches("/")
|
||||
.rsplit("/")
|
||||
.next()
|
||||
.unwrap()
|
||||
{
|
||||
"build_coinbase" => Box::new(
|
||||
self.build_coinbase(req, api)
|
||||
.and_then(|res| ok(json_response(&res))),
|
||||
),
|
||||
"receive_tx" => Box::new(
|
||||
self.receive_tx(req, api)
|
||||
.and_then(|res| ok(json_response(&res))),
|
||||
),
|
||||
_ => Box::new(ok(response(StatusCode::BAD_REQUEST, "unknown action"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized, C, K> api::Handler for ForeignAPIHandler<T, C, K>
|
||||
where
|
||||
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||
C: NodeClient + Send + Sync + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
fn post(&self, req: Request<Body>) -> ResponseFuture {
|
||||
Box::new(self.handle_request(req).and_then(|r| ok(r)).or_else(|e| {
|
||||
error!("Request Error: {:?}", e);
|
||||
ok(create_error_response(e))
|
||||
}))
|
||||
}
|
||||
|
||||
fn options(&self, _req: Request<Body>) -> ResponseFuture {
|
||||
Box::new(ok(create_ok_response("{}")))
|
||||
}
|
||||
}
|
||||
|
||||
/// V2 API Handler/Wrapper for foreign functions
|
||||
pub struct ForeignAPIHandlerV2<T: ?Sized, C, K>
|
||||
where
|
||||
@@ -874,7 +312,7 @@ where
|
||||
}
|
||||
|
||||
fn handle_post_request(&self, req: Request<Body>) -> WalletResponseFuture {
|
||||
let api = Foreign::new(self.wallet.clone());
|
||||
let api = Foreign::new(self.wallet.clone(), Some(check_middleware));
|
||||
Box::new(
|
||||
self.call_api(req, api)
|
||||
.and_then(|resp| ok(json_response_pretty(&resp))),
|
||||
@@ -903,9 +341,10 @@ where
|
||||
Box::new(ok(create_ok_response("{}")))
|
||||
}
|
||||
}
|
||||
|
||||
// Utility to serialize a struct into JSON and produce a sensible Response
|
||||
// out of it.
|
||||
fn json_response<T>(s: &T) -> Response<Body>
|
||||
fn _json_response<T>(s: &T) -> Response<Body>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
@@ -973,18 +412,6 @@ fn response<T: Into<Body>>(status: StatusCode, text: T) -> Response<Body> {
|
||||
builder.body(text.into()).unwrap()
|
||||
}
|
||||
|
||||
fn parse_params(req: &Request<Body>) -> HashMap<String, Vec<String>> {
|
||||
match req.uri().query() {
|
||||
Some(query_string) => form_urlencoded::parse(query_string.as_bytes())
|
||||
.into_owned()
|
||||
.fold(HashMap::new(), |mut hm, (k, v)| {
|
||||
hm.entry(k).or_insert(vec![]).push(v);
|
||||
hm
|
||||
}),
|
||||
None => HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_body<T>(req: Request<Body>) -> Box<dyn Future<Item = T, Error = Error> + Send>
|
||||
where
|
||||
for<'de> T: Deserialize<'de> + Send + 'static,
|
||||
@@ -993,26 +420,10 @@ where
|
||||
req.into_body()
|
||||
.concat2()
|
||||
.map_err(|_| ErrorKind::GenericError("Failed to read request".to_owned()).into())
|
||||
.and_then(|body| {
|
||||
match serde_json::from_reader(&body.to_vec()[..]) {
|
||||
Ok(obj) => ok(obj),
|
||||
Err(_) => {
|
||||
// try to parse as string instead, for backwards compatibility
|
||||
let replaced_str = String::from_utf8(body.to_vec().clone())
|
||||
.unwrap()
|
||||
.replace("\"", "\\\"");
|
||||
let mut str_vec = replaced_str.as_bytes().to_vec();
|
||||
str_vec.push(0x22);
|
||||
str_vec.insert(0, 0x22);
|
||||
match serde_json::from_reader(&str_vec[..]) {
|
||||
Ok(obj) => ok(obj),
|
||||
Err(e) => err(ErrorKind::GenericError(format!(
|
||||
"Invalid request body: {}",
|
||||
e
|
||||
))
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
.and_then(|body| match serde_json::from_reader(&body.to_vec()[..]) {
|
||||
Ok(obj) => ok(obj),
|
||||
Err(e) => {
|
||||
err(ErrorKind::GenericError(format!("Invalid request body: {}", e)).into())
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "grin_wallet_impls"
|
||||
version = "1.1.1-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||
description = "Concrete types derived from libwallet traits"
|
||||
license = "Apache-2.0"
|
||||
@@ -26,7 +26,7 @@ tokio-retry = "0.1"
|
||||
uuid = { version = "0.7", features = ["serde", "v4"] }
|
||||
chrono = { version = "0.4.4", features = ["serde"] }
|
||||
|
||||
grin_wallet_util = { path = "../util", version = "1.1.1-beta.1" }
|
||||
grin_wallet_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||
|
||||
grin_wallet_libwallet = { path = "../libwallet", version = "1.1.1-beta.1" }
|
||||
grin_wallet_config = { path = "../config", version = "1.1.1-beta.1" }
|
||||
grin_wallet_libwallet = { path = "../libwallet", version = "2.0.0-beta.2" }
|
||||
grin_wallet_config = { path = "../config", version = "2.0.0-beta.2" }
|
||||
|
||||
@@ -12,14 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//TODO: Update to V2 API when after Hard fork
|
||||
|
||||
/// HTTP Wallet 'plugin' implementation
|
||||
use crate::api;
|
||||
use crate::libwallet::{Error, ErrorKind, Slate};
|
||||
use crate::WalletCommAdapter;
|
||||
use config::WalletConfig;
|
||||
use serde::Serialize;
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -30,6 +29,63 @@ impl HTTPWalletCommAdapter {
|
||||
pub fn new() -> Box<dyn WalletCommAdapter> {
|
||||
Box::new(HTTPWalletCommAdapter {})
|
||||
}
|
||||
|
||||
/// Check version of the other wallet
|
||||
fn check_other_version(&self, url: &str) -> Result<(), Error> {
|
||||
let req = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "check_version",
|
||||
"id": 1,
|
||||
"params": []
|
||||
});
|
||||
|
||||
let res: String = post(url, None, &req).map_err(|e| {
|
||||
let mut report = format!("Performing version check (is recipient listening?): {}", e);
|
||||
let err_string = format!("{}", e);
|
||||
if err_string.contains("404") {
|
||||
// Report that the other version of the wallet is out of date
|
||||
report = format!(
|
||||
"Other wallet is incompatible and requires an upgrade. \
|
||||
Please urge the other wallet owner to upgrade and try the transaction again."
|
||||
);
|
||||
}
|
||||
error!("{}", report);
|
||||
ErrorKind::ClientCallback(report)
|
||||
})?;
|
||||
|
||||
let res: Value = serde_json::from_str(&res).unwrap();
|
||||
trace!("Response: {}", res);
|
||||
if res["error"] != json!(null) {
|
||||
let report = format!(
|
||||
"Posting transaction slate: Error: {}, Message: {}",
|
||||
res["error"]["code"], res["error"]["message"]
|
||||
);
|
||||
error!("{}", report);
|
||||
return Err(ErrorKind::ClientCallback(report).into());
|
||||
}
|
||||
|
||||
let resp_value = res["result"]["Ok"].clone();
|
||||
trace!("resp_value: {}", resp_value.clone());
|
||||
let foreign_api_version: u16 =
|
||||
serde_json::from_value(resp_value["foreign_api_version"].clone()).unwrap();
|
||||
let supported_slate_versions: Vec<String> =
|
||||
serde_json::from_value(resp_value["supported_slate_versions"].clone()).unwrap();
|
||||
|
||||
// trivial tests for now, but will be expanded later
|
||||
if foreign_api_version < 2 {
|
||||
let report = format!("Other wallet reports unrecognized API format.");
|
||||
error!("{}", report);
|
||||
return Err(ErrorKind::ClientCallback(report).into());
|
||||
}
|
||||
|
||||
if !supported_slate_versions.contains(&"V2".to_owned()) {
|
||||
let report = format!("Unable to negotiate slate format with other wallet.");
|
||||
error!("{}", report);
|
||||
return Err(ErrorKind::ClientCallback(report).into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletCommAdapter for HTTPWalletCommAdapter {
|
||||
@@ -46,14 +102,45 @@ impl WalletCommAdapter for HTTPWalletCommAdapter {
|
||||
error!("{}", err_str,);
|
||||
Err(ErrorKind::Uri)?
|
||||
}
|
||||
let url = format!("{}/v1/wallet/foreign/receive_tx", dest);
|
||||
let url = format!("{}/v2/foreign", dest);
|
||||
debug!("Posting transaction slate to {}", url);
|
||||
let res: String = post(url.as_str(), None, &slate).map_err(|e| {
|
||||
|
||||
self.check_other_version(&url)?;
|
||||
|
||||
// Note: not using easy-jsonrpc as don't want the dependencies in this crate
|
||||
let req = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "receive_tx",
|
||||
"id": 1,
|
||||
"params": [
|
||||
slate,
|
||||
null,
|
||||
null
|
||||
]
|
||||
});
|
||||
trace!("Sending receive_tx request: {}", req);
|
||||
|
||||
let res: String = post(url.as_str(), None, &req).map_err(|e| {
|
||||
let report = format!("Posting transaction slate (is recipient listening?): {}", e);
|
||||
error!("{}", report);
|
||||
ErrorKind::ClientCallback(report)
|
||||
})?;
|
||||
let slate = Slate::deserialize_upgrade(&res).map_err(|_| ErrorKind::SlateDeser)?;
|
||||
|
||||
let res: Value = serde_json::from_str(&res).unwrap();
|
||||
trace!("Response: {}", res);
|
||||
if res["error"] != json!(null) {
|
||||
let report = format!(
|
||||
"Posting transaction slate: Error: {}, Message: {}",
|
||||
res["error"]["code"], res["error"]["message"]
|
||||
);
|
||||
error!("{}", report);
|
||||
return Err(ErrorKind::ClientCallback(report).into());
|
||||
}
|
||||
|
||||
let slate_value = res["result"]["Ok"].clone();
|
||||
trace!("slate_value: {}", slate_value);
|
||||
let slate = Slate::deserialize_upgrade(&serde_json::to_string(&slate_value).unwrap())
|
||||
.map_err(|_| ErrorKind::SlateDeser)?;
|
||||
|
||||
Ok(slate)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ use uuid::Uuid;
|
||||
|
||||
use crate::blake2::blake2b::Blake2b;
|
||||
|
||||
use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain};
|
||||
use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain, SwitchCommitmentType};
|
||||
use crate::store::{self, option_to_not_found, to_key, to_key_u64};
|
||||
|
||||
use crate::core::core::Transaction;
|
||||
@@ -68,7 +68,7 @@ fn private_ctx_xor_keys<K>(
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let root_key = keychain.derive_key(0, &K::root_key_id())?;
|
||||
let root_key = keychain.derive_key(0, &K::root_key_id(), &SwitchCommitmentType::Regular)?;
|
||||
|
||||
// derive XOR values for storing secret values in DB
|
||||
// h(root_key|slate_id|"blind")
|
||||
@@ -203,7 +203,10 @@ where
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(util::to_hex(
|
||||
self.keychain().commit(amount, &id)?.0.to_vec(),
|
||||
self.keychain()
|
||||
.commit(amount, &id, &SwitchCommitmentType::Regular)?
|
||||
.0
|
||||
.to_vec(), // TODO: proper support for different switch commitment schemes
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
use futures::{stream, Stream};
|
||||
|
||||
use crate::libwallet::{NodeClient, TxWrapper};
|
||||
use crate::libwallet::{NodeClient, NodeVersionInfo, TxWrapper};
|
||||
use std::collections::HashMap;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
@@ -30,6 +30,7 @@ use crate::util::secp::pedersen;
|
||||
pub struct HTTPNodeClient {
|
||||
node_url: String,
|
||||
node_api_secret: Option<String>,
|
||||
node_version_info: Option<NodeVersionInfo>,
|
||||
}
|
||||
|
||||
impl HTTPNodeClient {
|
||||
@@ -38,6 +39,7 @@ impl HTTPNodeClient {
|
||||
HTTPNodeClient {
|
||||
node_url: node_url.to_owned(),
|
||||
node_api_secret: node_api_secret,
|
||||
node_version_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,14 +65,43 @@ impl NodeClient for HTTPNodeClient {
|
||||
self.node_api_secret = node_api_secret;
|
||||
}
|
||||
|
||||
fn get_version_info(&mut self) -> Option<NodeVersionInfo> {
|
||||
if let Some(v) = self.node_version_info.as_ref() {
|
||||
return Some(v.clone());
|
||||
}
|
||||
let url = format!("{}/v1/version", self.node_url());
|
||||
let mut retval =
|
||||
match api::client::get::<NodeVersionInfo>(url.as_str(), self.node_api_secret()) {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
// If node isn't available, allow offline functions
|
||||
// unfortunately have to parse string due to error structure
|
||||
let err_string = format!("{}", e);
|
||||
if err_string.contains("404") {
|
||||
return Some(NodeVersionInfo {
|
||||
node_version: "1.0.0".into(),
|
||||
block_header_version: 1,
|
||||
verified: Some(false),
|
||||
});
|
||||
} else {
|
||||
error!("Unable to contact Node to get version info: {}", e);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
retval.verified = Some(true);
|
||||
self.node_version_info = Some(retval.clone());
|
||||
Some(retval)
|
||||
}
|
||||
|
||||
/// Posts a transaction to a grin node
|
||||
fn post_tx(&self, tx: &TxWrapper, fluff: bool) -> Result<(), libwallet::Error> {
|
||||
let url;
|
||||
let dest = self.node_url();
|
||||
if fluff {
|
||||
url = format!("{}/v1/pool/push?fluff", dest);
|
||||
url = format!("{}/v1/pool/push_tx?fluff", dest);
|
||||
} else {
|
||||
url = format!("{}/v1/pool/push", dest);
|
||||
url = format!("{}/v1/pool/push_tx", dest);
|
||||
}
|
||||
let res = api::client::post_no_ret(url.as_str(), self.node_api_secret(), tx);
|
||||
if let Err(e) = res {
|
||||
|
||||
@@ -26,7 +26,7 @@ use crate::core::global::{set_mining_mode, ChainTypes};
|
||||
use crate::core::{pow, ser};
|
||||
use crate::keychain::Keychain;
|
||||
use crate::libwallet::api_impl::foreign;
|
||||
use crate::libwallet::{NodeClient, Slate, TxWrapper, WalletInst};
|
||||
use crate::libwallet::{NodeClient, NodeVersionInfo, Slate, TxWrapper, WalletInst};
|
||||
use crate::util;
|
||||
use crate::util::secp::pedersen;
|
||||
use crate::util::secp::pedersen::Commitment;
|
||||
@@ -402,6 +402,9 @@ impl NodeClient for LocalWalletClient {
|
||||
}
|
||||
fn set_node_url(&mut self, _node_url: &str) {}
|
||||
fn set_node_api_secret(&mut self, _node_api_secret: Option<String>) {}
|
||||
fn get_version_info(&mut self) -> Option<NodeVersionInfo> {
|
||||
None
|
||||
}
|
||||
/// Posts a transaction to a grin node
|
||||
/// In this case it will create a new block with award rewarded to
|
||||
fn post_tx(&self, tx: &TxWrapper, _fluff: bool) -> Result<(), libwallet::Error> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "grin_wallet_libwallet"
|
||||
version = "1.1.1-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||
license = "Apache-2.0"
|
||||
@@ -25,7 +25,7 @@ lazy_static = "1"
|
||||
strum = "0.15"
|
||||
strum_macros = "0.15"
|
||||
|
||||
grin_wallet_util = { path = "../util", version = "1.1.1-beta.1" }
|
||||
grin_wallet_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
grin_wallet_config = { path = "../config", version = "1.1.1-beta.1" }
|
||||
grin_wallet_config = { path = "../config", version = "2.0.0-beta.2" }
|
||||
|
||||
@@ -193,6 +193,10 @@ pub enum ErrorKind {
|
||||
#[fail(display = "Unknown Slate Version: {}", _0)]
|
||||
SlateVersion(u16),
|
||||
|
||||
/// Compatibility error between incoming slate versions and what's expected
|
||||
#[fail(display = "Compatibility Error: {}", _0)]
|
||||
Compatibility(String),
|
||||
|
||||
/// Other
|
||||
#[fail(display = "Generic error: {}", _0)]
|
||||
GenericError(String),
|
||||
|
||||
@@ -13,14 +13,17 @@
|
||||
// limitations under the License.
|
||||
//! Functions to restore a wallet's outputs from just the master seed
|
||||
|
||||
use crate::grin_core::consensus::{valid_header_version, WEEK_HEIGHT};
|
||||
use crate::grin_core::core::HeaderVersion;
|
||||
use crate::grin_core::global;
|
||||
use crate::grin_core::libtx::proof;
|
||||
use crate::grin_keychain::{ExtKeychain, Identifier, Keychain};
|
||||
use crate::grin_util::secp::{key::SecretKey, pedersen};
|
||||
use crate::grin_keychain::{ExtKeychain, Identifier, Keychain, SwitchCommitmentType};
|
||||
use crate::grin_util::secp::pedersen;
|
||||
use crate::internal::{keys, updater};
|
||||
use crate::types::*;
|
||||
use crate::{Error, OutputCommitMapping};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
|
||||
/// Utility struct for return values from below
|
||||
#[derive(Clone)]
|
||||
@@ -41,8 +44,6 @@ struct OutputResult {
|
||||
pub lock_height: u64,
|
||||
///
|
||||
pub is_coinbase: bool,
|
||||
///
|
||||
pub blinding: SecretKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -73,15 +74,38 @@ where
|
||||
outputs.len(),
|
||||
);
|
||||
|
||||
let keychain = wallet.keychain();
|
||||
let legacy_builder = proof::LegacyProofBuilder::new(keychain);
|
||||
let builder = proof::ProofBuilder::new(keychain);
|
||||
let legacy_version = HeaderVersion(1);
|
||||
|
||||
for output in outputs.iter() {
|
||||
let (commit, proof, is_coinbase, height, mmr_index) = output;
|
||||
// attempt to unwind message from the RP and get a value
|
||||
// will fail if it's not ours
|
||||
let info = proof::rewind(wallet.keychain(), *commit, None, *proof)?;
|
||||
let info = {
|
||||
// Before HF+2wk, try legacy rewind first
|
||||
let info_legacy =
|
||||
if valid_header_version(height.saturating_sub(2 * WEEK_HEIGHT), legacy_version) {
|
||||
proof::rewind(keychain.secp(), &legacy_builder, *commit, None, *proof)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if !info.success {
|
||||
continue;
|
||||
}
|
||||
// If legacy didn't work, try new rewind
|
||||
if info_legacy.is_none() {
|
||||
proof::rewind(keychain.secp(), &builder, *commit, None, *proof)?
|
||||
} else {
|
||||
info_legacy
|
||||
}
|
||||
};
|
||||
|
||||
let (amount, key_id, switch) = match info {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let lock_height = if *is_coinbase {
|
||||
*height + global::coinbase_maturity()
|
||||
@@ -89,24 +113,23 @@ where
|
||||
*height
|
||||
};
|
||||
|
||||
// TODO: Output paths are always going to be length 3 for now, but easy enough to grind
|
||||
// through to find the right path if required later
|
||||
let key_id = Identifier::from_serialized_path(3u8, &info.message.as_bytes());
|
||||
|
||||
info!(
|
||||
"Output found: {:?}, amount: {:?}, key_id: {:?}, mmr_index: {},",
|
||||
commit, info.value, key_id, mmr_index,
|
||||
commit, amount, key_id, mmr_index,
|
||||
);
|
||||
|
||||
if switch != SwitchCommitmentType::Regular {
|
||||
warn!("Unexpected switch commitment type {:?}", switch);
|
||||
}
|
||||
|
||||
wallet_outputs.push(OutputResult {
|
||||
commit: *commit,
|
||||
key_id: key_id.clone(),
|
||||
n_child: key_id.to_path().last_path_index(),
|
||||
value: info.value,
|
||||
value: amount,
|
||||
height: *height,
|
||||
lock_height: lock_height,
|
||||
is_coinbase: *is_coinbase,
|
||||
blinding: info.blinding,
|
||||
mmr_index: *mmr_index,
|
||||
});
|
||||
}
|
||||
@@ -402,6 +425,7 @@ where
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
warn!("Starting restore.");
|
||||
|
||||
let result_vec = collect_chain_outputs(wallet)?;
|
||||
@@ -450,5 +474,11 @@ where
|
||||
debug!("Next child for account {} is {}", path, max_child_index + 1);
|
||||
batch.commit()?;
|
||||
}
|
||||
|
||||
let mut sec = now.elapsed().as_secs();
|
||||
let min = sec / 60;
|
||||
sec %= 60;
|
||||
info!("Restored wallet in {}m{}s", min, sec);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::grin_core::core::amount_to_hr_string;
|
||||
use crate::grin_core::libtx::{build, tx_fee};
|
||||
use crate::grin_core::libtx::{
|
||||
build,
|
||||
proof::{ProofBuild, ProofBuilder},
|
||||
tx_fee,
|
||||
};
|
||||
use crate::grin_keychain::{Identifier, Keychain};
|
||||
use crate::internal::keys;
|
||||
use crate::slate::Slate;
|
||||
@@ -54,15 +58,14 @@ where
|
||||
selection_strategy_is_use_all,
|
||||
&parent_key_id,
|
||||
)?;
|
||||
let keychain = wallet.keychain();
|
||||
let blinding = slate.add_transaction_elements(keychain, &ProofBuilder::new(keychain), elems)?;
|
||||
|
||||
slate.fee = fee;
|
||||
|
||||
let keychain = wallet.keychain().clone();
|
||||
let blinding = slate.add_transaction_elements(&keychain, elems)?;
|
||||
|
||||
// Create our own private context
|
||||
let mut context = Context::new(
|
||||
wallet.keychain().secp(),
|
||||
keychain.secp(),
|
||||
blinding.secret_key(&keychain.secp()).unwrap(),
|
||||
&parent_key_id,
|
||||
use_test_nonce,
|
||||
@@ -182,15 +185,17 @@ where
|
||||
{
|
||||
// Create a potential output for this transaction
|
||||
let key_id = keys::next_available_key(wallet).unwrap();
|
||||
|
||||
let keychain = wallet.keychain().clone();
|
||||
let key_id_inner = key_id.clone();
|
||||
let amount = slate.amount;
|
||||
let height = slate.height;
|
||||
|
||||
let slate_id = slate.id.clone();
|
||||
let blinding =
|
||||
slate.add_transaction_elements(&keychain, vec![build::output(amount, key_id.clone())])?;
|
||||
let blinding = slate.add_transaction_elements(
|
||||
&keychain,
|
||||
&ProofBuilder::new(&keychain),
|
||||
vec![build::output(amount, key_id.clone())],
|
||||
)?;
|
||||
|
||||
// Add blinding sum to our context
|
||||
let mut context = Context::new(
|
||||
@@ -235,7 +240,7 @@ where
|
||||
/// Builds a transaction to send to someone from the HD seed associated with the
|
||||
/// wallet and the amount to send. Handles reading through the wallet data file,
|
||||
/// selecting outputs to spend and building the change.
|
||||
pub fn select_send_tx<T: ?Sized, C, K>(
|
||||
pub fn select_send_tx<T: ?Sized, C, K, B>(
|
||||
wallet: &mut T,
|
||||
amount: u64,
|
||||
current_height: u64,
|
||||
@@ -247,7 +252,7 @@ pub fn select_send_tx<T: ?Sized, C, K>(
|
||||
parent_key_id: &Identifier,
|
||||
) -> Result<
|
||||
(
|
||||
Vec<Box<build::Append<K>>>,
|
||||
Vec<Box<build::Append<K, B>>>,
|
||||
Vec<OutputData>,
|
||||
Vec<(u64, Identifier, Option<u64>)>, // change amounts and derivations
|
||||
u64, // fee
|
||||
@@ -258,6 +263,7 @@ where
|
||||
T: WalletBackend<C, K>,
|
||||
C: NodeClient,
|
||||
K: Keychain,
|
||||
B: ProofBuild,
|
||||
{
|
||||
let (coins, _total, amount, fee) = select_coins_and_fee(
|
||||
wallet,
|
||||
@@ -387,7 +393,7 @@ where
|
||||
}
|
||||
|
||||
/// Selects inputs and change for a transaction
|
||||
pub fn inputs_and_change<T: ?Sized, C, K>(
|
||||
pub fn inputs_and_change<T: ?Sized, C, K, B>(
|
||||
coins: &Vec<OutputData>,
|
||||
wallet: &mut T,
|
||||
amount: u64,
|
||||
@@ -395,7 +401,7 @@ pub fn inputs_and_change<T: ?Sized, C, K>(
|
||||
num_change_outputs: usize,
|
||||
) -> Result<
|
||||
(
|
||||
Vec<Box<build::Append<K>>>,
|
||||
Vec<Box<build::Append<K, B>>>,
|
||||
Vec<(u64, Identifier, Option<u64>)>,
|
||||
),
|
||||
Error,
|
||||
@@ -404,6 +410,7 @@ where
|
||||
T: WalletBackend<C, K>,
|
||||
C: NodeClient,
|
||||
K: Keychain,
|
||||
B: ProofBuild,
|
||||
{
|
||||
let mut parts = vec![];
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::grin_core::consensus::valid_header_version;
|
||||
use crate::grin_core::core::HeaderVersion;
|
||||
use crate::grin_keychain::{Identifier, Keychain};
|
||||
use crate::grin_util::Mutex;
|
||||
use crate::internal::{selection, updater};
|
||||
@@ -54,6 +56,10 @@ where
|
||||
slate.amount = amount;
|
||||
slate.height = current_height;
|
||||
|
||||
if valid_header_version(current_height, HeaderVersion(1)) {
|
||||
slate.version_info.block_header_version = 1;
|
||||
}
|
||||
|
||||
// Set the lock_height explicitly to 0 here.
|
||||
// This will generate a Plain kernel (rather than a HeightLocked kernel).
|
||||
slate.lock_height = 0;
|
||||
@@ -330,7 +336,7 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::grin_core::libtx::build;
|
||||
use crate::grin_core::libtx::{build, ProofBuilder};
|
||||
use crate::grin_keychain::{ExtKeychain, ExtKeychainPath, Keychain};
|
||||
|
||||
#[test]
|
||||
@@ -338,10 +344,21 @@ mod test {
|
||||
// based on the public key and amount begin spent
|
||||
fn output_commitment_equals_input_commitment_on_spend() {
|
||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||
let builder = ProofBuilder::new(&keychain);
|
||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||
|
||||
let tx1 = build::transaction(vec![build::output(105, key_id1.clone())], &keychain).unwrap();
|
||||
let tx2 = build::transaction(vec![build::input(105, key_id1.clone())], &keychain).unwrap();
|
||||
let tx1 = build::transaction(
|
||||
vec![build::output(105, key_id1.clone())],
|
||||
&keychain,
|
||||
&builder,
|
||||
)
|
||||
.unwrap();
|
||||
let tx2 = build::transaction(
|
||||
vec![build::input(105, key_id1.clone())],
|
||||
&keychain,
|
||||
&builder,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(tx1.outputs()[0].features, tx2.inputs()[0].features);
|
||||
assert_eq!(tx1.outputs()[0].commitment(), tx2.inputs()[0].commitment());
|
||||
|
||||
@@ -22,8 +22,9 @@ use crate::error::Error;
|
||||
use crate::grin_core::consensus::reward;
|
||||
use crate::grin_core::core::{Output, TxKernel};
|
||||
use crate::grin_core::global;
|
||||
use crate::grin_core::libtx::proof::ProofBuilder;
|
||||
use crate::grin_core::libtx::reward;
|
||||
use crate::grin_keychain::{Identifier, Keychain};
|
||||
use crate::grin_keychain::{Identifier, Keychain, SwitchCommitmentType};
|
||||
use crate::grin_util as util;
|
||||
use crate::grin_util::secp::pedersen;
|
||||
use crate::internal::keys;
|
||||
@@ -74,7 +75,9 @@ where
|
||||
.map(|output| {
|
||||
let commit = match output.commit.clone() {
|
||||
Some(c) => pedersen::Commitment::from_vec(util::from_hex(c).unwrap()),
|
||||
None => keychain.commit(output.value, &output.key_id).unwrap(),
|
||||
None => keychain
|
||||
.commit(output.value, &output.key_id, &SwitchCommitmentType::Regular)
|
||||
.unwrap(), // TODO: proper support for different switch commitment schemes
|
||||
};
|
||||
OutputCommitMapping { output, commit }
|
||||
})
|
||||
@@ -186,7 +189,9 @@ where
|
||||
for out in unspents {
|
||||
let commit = match out.commit.clone() {
|
||||
Some(c) => pedersen::Commitment::from_vec(util::from_hex(c).unwrap()),
|
||||
None => keychain.commit(out.value, &out.key_id).unwrap(),
|
||||
None => keychain
|
||||
.commit(out.value, &out.key_id, &SwitchCommitmentType::Regular)
|
||||
.unwrap(), // TODO: proper support for different switch commitment schemes
|
||||
};
|
||||
wallet_outputs.insert(commit, (out.key_id.clone(), out.mmr_index));
|
||||
}
|
||||
@@ -505,6 +510,13 @@ where
|
||||
|
||||
debug!("receive_coinbase: {:?}", block_fees);
|
||||
|
||||
let (out, kern) = reward::output(wallet.keychain(), &key_id, block_fees.fees, test_mode)?;
|
||||
let keychain = wallet.keychain();
|
||||
let (out, kern) = reward::output(
|
||||
keychain,
|
||||
&ProofBuilder::new(keychain),
|
||||
&key_id,
|
||||
block_fees.fees,
|
||||
test_mode,
|
||||
)?;
|
||||
Ok((out, kern, block_fees))
|
||||
}
|
||||
|
||||
@@ -52,13 +52,16 @@ mod types;
|
||||
|
||||
pub use crate::error::{Error, ErrorKind};
|
||||
pub use crate::slate::{ParticipantData, ParticipantMessageData, Slate};
|
||||
pub use crate::slate_versions::{SlateVersion, VersionedSlate};
|
||||
pub use crate::slate_versions::{
|
||||
SlateVersion, VersionedSlate, CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION,
|
||||
};
|
||||
pub use api_impl::types::{
|
||||
BlockFees, CbData, InitTxArgs, InitTxSendArgs, IssueInvoiceTxArgs, NodeHeightResult,
|
||||
OutputCommitMapping, SendTXArgs, VersionInfo,
|
||||
};
|
||||
pub use internal::restore::{check_repair, restore};
|
||||
pub use types::{
|
||||
AcctPathMapping, BlockIdentifier, Context, NodeClient, OutputData, OutputStatus, TxLogEntry,
|
||||
TxLogEntryType, TxWrapper, WalletBackend, WalletInfo, WalletInst, WalletOutputBatch,
|
||||
AcctPathMapping, BlockIdentifier, Context, NodeClient, NodeVersionInfo, OutputData,
|
||||
OutputStatus, TxLogEntry, TxLogEntryType, TxWrapper, WalletBackend, WalletInfo, WalletInst,
|
||||
WalletOutputBatch,
|
||||
};
|
||||
|
||||
+13
-21
@@ -24,7 +24,7 @@ use crate::grin_core::core::transaction::{
|
||||
Weighting,
|
||||
};
|
||||
use crate::grin_core::core::verifier_cache::LruVerifierCache;
|
||||
use crate::grin_core::libtx::{aggsig, build, secp_ser, tx_fee};
|
||||
use crate::grin_core::libtx::{aggsig, build, proof::ProofBuild, secp_ser, tx_fee};
|
||||
use crate::grin_core::map_vec;
|
||||
use crate::grin_keychain::{BlindSum, BlindingFactor, Keychain};
|
||||
use crate::grin_util::secp::key::{PublicKey, SecretKey};
|
||||
@@ -39,8 +39,6 @@ use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::slate_versions::v0::SlateV0;
|
||||
use crate::slate_versions::v1::SlateV1;
|
||||
use crate::slate_versions::v2::{
|
||||
InputV2, OutputV2, ParticipantDataV2, SlateV2, TransactionBodyV2, TransactionV2, TxKernelV2,
|
||||
VersionCompatInfoV2,
|
||||
@@ -207,20 +205,15 @@ impl Slate {
|
||||
/// 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 {
|
||||
let v2: SlateV2 = 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 => {
|
||||
// left as a reminder
|
||||
/*0 => {
|
||||
let v0: SlateV0 =
|
||||
serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?;
|
||||
let v1 = SlateV1::from(v0);
|
||||
SlateV2::from(v1)
|
||||
}
|
||||
}*/
|
||||
_ => return Err(ErrorKind::SlateVersion(version).into()),
|
||||
};
|
||||
Ok(v2.into())
|
||||
@@ -247,19 +240,21 @@ impl Slate {
|
||||
|
||||
/// Adds selected inputs and outputs to the slate's transaction
|
||||
/// Returns blinding factor
|
||||
pub fn add_transaction_elements<K>(
|
||||
pub fn add_transaction_elements<K, B>(
|
||||
&mut self,
|
||||
keychain: &K,
|
||||
mut elems: Vec<Box<build::Append<K>>>,
|
||||
builder: &B,
|
||||
mut elems: Vec<Box<build::Append<K, B>>>,
|
||||
) -> Result<BlindingFactor, Error>
|
||||
where
|
||||
K: Keychain,
|
||||
B: ProofBuild,
|
||||
{
|
||||
// Append to the exiting transaction
|
||||
if self.tx.kernels().len() != 0 {
|
||||
elems.insert(0, build::initial_tx(self.tx.clone()));
|
||||
}
|
||||
let (tx, blind) = build::partial_transaction(elems, keychain)?;
|
||||
let (tx, blind) = build::partial_transaction(elems, keychain, builder)?;
|
||||
self.tx = tx;
|
||||
Ok(blind)
|
||||
}
|
||||
@@ -681,15 +676,12 @@ impl Serialize for Slate {
|
||||
let v2 = SlateV2::from(self);
|
||||
match self.version_info.orig_version {
|
||||
2 => v2.serialize(serializer),
|
||||
1 => {
|
||||
let v1 = SlateV1::from(v2);
|
||||
v1.serialize(serializer)
|
||||
}
|
||||
0 => {
|
||||
// left as a reminder
|
||||
/*0 => {
|
||||
let v1 = SlateV1::from(v2);
|
||||
let v0 = SlateV0::from(v1);
|
||||
v0.serialize(serializer)
|
||||
}
|
||||
}*/
|
||||
v => Err(S::Error::custom(format!("Unknown slate version {}", v))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,15 +14,12 @@
|
||||
|
||||
//! This module contains old slate versions and conversions to the newest slate version
|
||||
//! Used for serialization and deserialization of slates in a backwards compatible way.
|
||||
//! Versions earlier than V2 are removed for the 2.0.0 release, but versioning code
|
||||
//! remains for future needs
|
||||
|
||||
use crate::slate::Slate;
|
||||
use crate::slate_versions::v0::SlateV0;
|
||||
use crate::slate_versions::v1::SlateV1;
|
||||
use crate::slate_versions::v2::SlateV2;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub mod v0;
|
||||
#[allow(missing_docs)]
|
||||
pub mod v1;
|
||||
#[allow(missing_docs)]
|
||||
pub mod v2;
|
||||
|
||||
@@ -30,15 +27,11 @@ pub mod v2;
|
||||
pub const CURRENT_SLATE_VERSION: u16 = 2;
|
||||
|
||||
/// The grin block header this slate is intended to be compatible with
|
||||
pub const GRIN_BLOCK_HEADER_VERSION: u16 = 1;
|
||||
pub const GRIN_BLOCK_HEADER_VERSION: u16 = 2;
|
||||
|
||||
/// Existing versions of the slate
|
||||
#[derive(EnumIter, Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||
pub enum SlateVersion {
|
||||
/// V0
|
||||
V0,
|
||||
/// V1
|
||||
V1,
|
||||
/// V2 (most current)
|
||||
V2,
|
||||
}
|
||||
@@ -48,12 +41,8 @@ pub enum SlateVersion {
|
||||
/// Versions are ordered newest to oldest so serde attempts to
|
||||
/// deserialize newer versions first, then falls back to older versions.
|
||||
pub enum VersionedSlate {
|
||||
/// Current
|
||||
/// Current (Grin 1.1.0 - 2.x (current))
|
||||
V2(SlateV2),
|
||||
/// V1 - Grin 1.0.1 - 1.0.3)
|
||||
V1(SlateV1),
|
||||
/// V0 - Grin 1.0.0
|
||||
V0(SlateV0),
|
||||
}
|
||||
|
||||
impl VersionedSlate {
|
||||
@@ -61,8 +50,6 @@ impl VersionedSlate {
|
||||
pub fn version(&self) -> SlateVersion {
|
||||
match *self {
|
||||
VersionedSlate::V2(_) => SlateVersion::V2,
|
||||
VersionedSlate::V1(_) => SlateVersion::V1,
|
||||
VersionedSlate::V0(_) => SlateVersion::V0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,17 +57,14 @@ impl VersionedSlate {
|
||||
pub fn into_version(slate: Slate, version: SlateVersion) -> VersionedSlate {
|
||||
match version {
|
||||
SlateVersion::V2 => VersionedSlate::V2(slate.into()),
|
||||
SlateVersion::V1 => {
|
||||
let s = SlateV2::from(slate);
|
||||
let s = SlateV1::from(s);
|
||||
VersionedSlate::V1(s)
|
||||
}
|
||||
SlateVersion::V0 => {
|
||||
// Left here as a reminder of what needs to be inserted on
|
||||
// the release of a new slate
|
||||
/*SlateVersion::V0 => {
|
||||
let s = SlateV2::from(slate);
|
||||
let s = SlateV1::from(s);
|
||||
let s = SlateV0::from(s);
|
||||
VersionedSlate::V0(s)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,18 +75,13 @@ impl From<VersionedSlate> for Slate {
|
||||
VersionedSlate::V2(s) => {
|
||||
let s = SlateV2::from(s);
|
||||
Slate::from(s)
|
||||
}
|
||||
VersionedSlate::V1(s) => {
|
||||
let s = SlateV1::from(s);
|
||||
let s = SlateV2::from(s);
|
||||
Slate::from(s)
|
||||
}
|
||||
VersionedSlate::V0(s) => {
|
||||
let s = SlateV0::from(s);
|
||||
let s = SlateV1::from(s);
|
||||
let s = SlateV2::from(s);
|
||||
Slate::from(s)
|
||||
}
|
||||
} // Again, left in as a reminder
|
||||
/*VersionedSlate::V0(s) => {
|
||||
let s = SlateV0::from(s);
|
||||
let s = SlateV1::from(s);
|
||||
let s = SlateV2::from(s);
|
||||
Slate::from(s)
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
// 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 V0 of the slate (grin 1.0.0)
|
||||
//! And methods to downgrade v1 to v0
|
||||
use crate::grin_core::core::transaction::{KernelFeatures, OutputFeatures};
|
||||
use crate::grin_keychain::BlindingFactor;
|
||||
use crate::grin_util::secp;
|
||||
use crate::grin_util::secp::key::PublicKey;
|
||||
use crate::grin_util::secp::pedersen::{Commitment, RangeProof};
|
||||
use crate::grin_util::secp::Signature;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct SlateV0 {
|
||||
/// The number of participants intended to take part in this transaction
|
||||
pub num_participants: usize,
|
||||
/// Unique transaction ID, selected by sender
|
||||
pub id: Uuid,
|
||||
/// The core transaction data:
|
||||
/// inputs, outputs, kernels, kernel offset
|
||||
pub tx: TransactionV0,
|
||||
/// 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<ParticipantDataV0>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ParticipantDataV0 {
|
||||
/// 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 TransactionV0 {
|
||||
/// 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: TransactionBodyV0,
|
||||
}
|
||||
|
||||
/// TransactionBody is a common abstraction for transaction and block
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct TransactionBodyV0 {
|
||||
/// List of inputs spent by the transaction.
|
||||
pub inputs: Vec<InputV0>,
|
||||
/// List of outputs the transaction produces.
|
||||
pub outputs: Vec<OutputV0>,
|
||||
/// List of kernels that make up this transaction (usually a single kernel).
|
||||
pub kernels: Vec<TxKernelV0>,
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct InputV0 {
|
||||
/// 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 OutputV0 {
|
||||
/// 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 TxKernelV0 {
|
||||
/// 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,
|
||||
}
|
||||
@@ -1,382 +0,0 @@
|
||||
// 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::grin_core::core::transaction::{KernelFeatures, OutputFeatures};
|
||||
use crate::grin_core::map_vec;
|
||||
use crate::grin_keychain::BlindingFactor;
|
||||
use crate::grin_util::secp;
|
||||
use crate::grin_util::secp::key::PublicKey;
|
||||
use crate::grin_util::secp::pedersen::{Commitment, RangeProof};
|
||||
use crate::grin_util::secp::Signature;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::slate_versions::v0::{
|
||||
InputV0, OutputV0, ParticipantDataV0, SlateV0, TransactionBodyV0, TransactionV0, TxKernelV0,
|
||||
};
|
||||
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
use crate::grin_core::core::transaction::{KernelFeatures, OutputFeatures};
|
||||
use crate::grin_core::libtx::secp_ser;
|
||||
use crate::grin_core::map_vec;
|
||||
use crate::grin_keychain::BlindingFactor;
|
||||
use crate::grin_util::secp;
|
||||
use crate::grin_util::secp::key::PublicKey;
|
||||
@@ -45,10 +44,6 @@ use crate::grin_util::secp::pedersen::{Commitment, RangeProof};
|
||||
use crate::grin_util::secp::Signature;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::slate_versions::v1::{
|
||||
InputV1, OutputV1, ParticipantDataV1, SlateV1, TransactionBodyV1, TransactionV1, TxKernelV1,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct SlateV2 {
|
||||
/// Versioning info
|
||||
@@ -188,271 +183,3 @@ pub struct TxKernelV2 {
|
||||
#[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 orig_version = orig_version as u16;
|
||||
let block_header_version = 1;
|
||||
let participant_data = map_vec!(participant_data, |data| ParticipantDataV2::from(data));
|
||||
let version_info = VersionCompatInfoV2 {
|
||||
version,
|
||||
orig_version,
|
||||
block_header_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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +221,10 @@ pub trait NodeClient: Sync + Send + Clone {
|
||||
/// Posts a transaction to a grin node
|
||||
fn post_tx(&self, tx: &TxWrapper, fluff: bool) -> Result<(), Error>;
|
||||
|
||||
/// Returns the api version string and block header version as reported
|
||||
/// by the node. Result can be cached for later use
|
||||
fn get_version_info(&mut self) -> Option<NodeVersionInfo>;
|
||||
|
||||
/// retrieves the current tip from the specified grin node
|
||||
fn get_chain_height(&self) -> Result<u64, Error>;
|
||||
|
||||
@@ -250,6 +254,17 @@ pub trait NodeClient: Sync + Send + Clone {
|
||||
>;
|
||||
}
|
||||
|
||||
/// Node version info
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct NodeVersionInfo {
|
||||
/// Semver version string
|
||||
pub node_version: String,
|
||||
/// block header verson
|
||||
pub block_header_version: u16,
|
||||
/// Whether this version info was successfully verified from a node
|
||||
pub verified: Option<bool>,
|
||||
}
|
||||
|
||||
/// Information about an output that's being tracked by the wallet. Must be
|
||||
/// enough to reconstruct the commitment associated with the ouput when the
|
||||
/// root private key is known.
|
||||
|
||||
@@ -16,7 +16,7 @@ use grin_wallet_libwallet::Context;
|
||||
use grin_wallet_util::grin_core::core::transaction;
|
||||
use grin_wallet_util::grin_core::libtx::{aggsig, proof};
|
||||
use grin_wallet_util::grin_keychain::{
|
||||
BlindSum, BlindingFactor, ExtKeychain, ExtKeychainPath, Keychain,
|
||||
BlindSum, BlindingFactor, ExtKeychain, ExtKeychainPath, Keychain, SwitchCommitmentType,
|
||||
};
|
||||
use grin_wallet_util::grin_util::secp;
|
||||
use grin_wallet_util::grin_util::secp::key::{PublicKey, SecretKey};
|
||||
@@ -29,6 +29,7 @@ fn kernel_sig_msg() -> secp::Message {
|
||||
#[test]
|
||||
fn aggsig_sender_receiver_interaction() {
|
||||
let parent = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||
let switch = &SwitchCommitmentType::Regular;
|
||||
let sender_keychain = ExtKeychain::from_random_seed(true).unwrap();
|
||||
let receiver_keychain = ExtKeychain::from_random_seed(true).unwrap();
|
||||
|
||||
@@ -36,8 +37,8 @@ fn aggsig_sender_receiver_interaction() {
|
||||
// Normally this would happen during transaction building.
|
||||
let kernel_excess = {
|
||||
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
let skey1 = sender_keychain.derive_key(0, &id1).unwrap();
|
||||
let skey2 = receiver_keychain.derive_key(0, &id1).unwrap();
|
||||
let skey1 = sender_keychain.derive_key(0, &id1, switch).unwrap();
|
||||
let skey2 = receiver_keychain.derive_key(0, &id1, switch).unwrap();
|
||||
|
||||
let keychain = ExtKeychain::from_random_seed(true).unwrap();
|
||||
let blinding_factor = keychain
|
||||
@@ -60,7 +61,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||
let (sender_pub_excess, _sender_pub_nonce) = {
|
||||
let keychain = sender_keychain.clone();
|
||||
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
let skey = keychain.derive_key(0, &id1).unwrap();
|
||||
let skey = keychain.derive_key(0, &id1, switch).unwrap();
|
||||
|
||||
// dealing with an input here so we need to negate the blinding_factor
|
||||
// rather than use it as is
|
||||
@@ -83,7 +84,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
|
||||
// let blind = blind_sum.secret_key(&keychain.secp())?;
|
||||
let blind = keychain.derive_key(0, &key_id).unwrap();
|
||||
let blind = keychain.derive_key(0, &key_id, switch).unwrap();
|
||||
|
||||
rx_cx = Context::new(&keychain.secp(), blind, &parent, false, 1);
|
||||
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
||||
@@ -234,6 +235,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||
#[test]
|
||||
fn aggsig_sender_receiver_interaction_offset() {
|
||||
let parent = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||
let switch = &SwitchCommitmentType::Regular;
|
||||
let sender_keychain = ExtKeychain::from_random_seed(true).unwrap();
|
||||
let receiver_keychain = ExtKeychain::from_random_seed(true).unwrap();
|
||||
|
||||
@@ -246,8 +248,8 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||
// Normally this would happen during transaction building.
|
||||
let kernel_excess = {
|
||||
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
let skey1 = sender_keychain.derive_key(0, &id1).unwrap();
|
||||
let skey2 = receiver_keychain.derive_key(0, &id1).unwrap();
|
||||
let skey1 = sender_keychain.derive_key(0, &id1, switch).unwrap();
|
||||
let skey2 = receiver_keychain.derive_key(0, &id1, switch).unwrap();
|
||||
|
||||
let keychain = ExtKeychain::from_random_seed(true).unwrap();
|
||||
let blinding_factor = keychain
|
||||
@@ -257,7 +259,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||
.add_blinding_factor(BlindingFactor::from_secret_key(skey2))
|
||||
// subtract the kernel offset here like as would when
|
||||
// verifying a kernel signature
|
||||
.sub_blinding_factor(BlindingFactor::from_secret_key(kernel_offset)),
|
||||
.sub_blinding_factor(BlindingFactor::from_secret_key(kernel_offset.clone())),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -273,7 +275,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||
let (sender_pub_excess, _sender_pub_nonce) = {
|
||||
let keychain = sender_keychain.clone();
|
||||
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
let skey = keychain.derive_key(0, &id1).unwrap();
|
||||
let skey = keychain.derive_key(0, &id1, switch).unwrap();
|
||||
|
||||
// dealing with an input here so we need to negate the blinding_factor
|
||||
// rather than use it as is
|
||||
@@ -300,7 +302,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||
let keychain = receiver_keychain.clone();
|
||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
|
||||
let blind = keychain.derive_key(0, &key_id).unwrap();
|
||||
let blind = keychain.derive_key(0, &key_id, switch).unwrap();
|
||||
|
||||
rx_cx = Context::new(&keychain.secp(), blind, &parent, false, 1);
|
||||
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
||||
@@ -450,52 +452,71 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||
#[test]
|
||||
fn test_rewind_range_proof() {
|
||||
let keychain = ExtKeychain::from_random_seed(true).unwrap();
|
||||
let builder = proof::ProofBuilder::new(&keychain);
|
||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||
let commit = keychain.commit(5, &key_id).unwrap();
|
||||
let switch = &SwitchCommitmentType::Regular;
|
||||
let commit = keychain.commit(5, &key_id, switch).unwrap();
|
||||
let extra_data = [99u8; 64];
|
||||
|
||||
let proof = proof::create(
|
||||
&keychain,
|
||||
&builder,
|
||||
5,
|
||||
&key_id,
|
||||
switch,
|
||||
commit,
|
||||
Some(extra_data.to_vec().clone()),
|
||||
)
|
||||
.unwrap();
|
||||
let proof_info =
|
||||
proof::rewind(&keychain, commit, Some(extra_data.to_vec().clone()), proof).unwrap();
|
||||
|
||||
assert_eq!(proof_info.success, true);
|
||||
assert_eq!(proof_info.value, 5);
|
||||
assert_eq!(proof_info.message.as_bytes(), key_id.serialize_path());
|
||||
|
||||
// cannot rewind with a different commit
|
||||
let commit2 = keychain.commit(5, &key_id2).unwrap();
|
||||
let proof_info =
|
||||
proof::rewind(&keychain, commit2, Some(extra_data.to_vec().clone()), proof).unwrap();
|
||||
assert_eq!(proof_info.success, false);
|
||||
assert_eq!(proof_info.value, 0);
|
||||
assert_eq!(proof_info.message, secp::pedersen::ProofMessage::empty());
|
||||
|
||||
// cannot rewind with a commitment to a different value
|
||||
let commit3 = keychain.commit(4, &key_id).unwrap();
|
||||
let proof_info =
|
||||
proof::rewind(&keychain, commit3, Some(extra_data.to_vec().clone()), proof).unwrap();
|
||||
assert_eq!(proof_info.success, false);
|
||||
assert_eq!(proof_info.value, 0);
|
||||
|
||||
// cannot rewind with wrong extra committed data
|
||||
let commit3 = keychain.commit(4, &key_id).unwrap();
|
||||
let wrong_extra_data = [98u8; 64];
|
||||
let _should_err = proof::rewind(
|
||||
&keychain,
|
||||
commit3,
|
||||
Some(wrong_extra_data.to_vec().clone()),
|
||||
let proof_info = proof::rewind(
|
||||
keychain.secp(),
|
||||
&builder,
|
||||
commit,
|
||||
Some(extra_data.to_vec().clone()),
|
||||
proof,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(proof_info.success, false);
|
||||
assert_eq!(proof_info.value, 0);
|
||||
assert!(proof_info.is_some());
|
||||
let (r_amount, r_key_id, r_switch) = proof_info.unwrap();
|
||||
assert_eq!(r_amount, 5);
|
||||
assert_eq!(r_key_id, key_id);
|
||||
assert_eq!(&r_switch, switch);
|
||||
|
||||
// cannot rewind with a different commit
|
||||
let commit2 = keychain.commit(5, &key_id2, switch).unwrap();
|
||||
let proof_info = proof::rewind(
|
||||
keychain.secp(),
|
||||
&builder,
|
||||
commit2,
|
||||
Some(extra_data.to_vec().clone()),
|
||||
proof,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(proof_info.is_none());
|
||||
|
||||
// cannot rewind with a commitment to a different value
|
||||
let commit3 = keychain.commit(4, &key_id, switch).unwrap();
|
||||
let proof_info = proof::rewind(
|
||||
keychain.secp(),
|
||||
&builder,
|
||||
commit3,
|
||||
Some(extra_data.to_vec().clone()),
|
||||
proof,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(proof_info.is_none());
|
||||
|
||||
// cannot rewind with wrong extra committed data
|
||||
let wrong_extra_data = [98u8; 64];
|
||||
let proof_info = proof::rewind(
|
||||
keychain.secp(),
|
||||
&builder,
|
||||
commit,
|
||||
Some(wrong_extra_data.to_vec().clone()),
|
||||
proof,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(proof_info.is_none());
|
||||
}
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! core::libtx specific tests
|
||||
use grin_wallet_libwallet::Slate;
|
||||
//use grin_wallet_libwallet::Slate;
|
||||
|
||||
// test all slate conversions
|
||||
/* TODO: Turn back on upon release of new slate version
|
||||
#[test]
|
||||
fn slate_conversions() {
|
||||
// Test V0 to V2
|
||||
@@ -92,3 +93,4 @@ fn slate_conversions() {
|
||||
assert_eq!(v.unwrap(), 0);
|
||||
println!("v2 -> v0: {}", s);
|
||||
}
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+19
-19
@@ -18,10 +18,13 @@ use clap::ArgMatches;
|
||||
use grin_wallet_config::WalletConfig;
|
||||
use grin_wallet_impls::{HTTPNodeClient, WalletSeed, SEED_FILE};
|
||||
use grin_wallet_libwallet::NodeClient;
|
||||
use semver::Version;
|
||||
use std::path::PathBuf;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
const MIN_COMPAT_NODE_VERSION: &str = "2.0.0-beta.1";
|
||||
|
||||
pub fn _init_wallet_seed(wallet_config: WalletConfig, password: &str) {
|
||||
if let Err(_) = WalletSeed::from_file(&wallet_config, password) {
|
||||
WalletSeed::init_file(&wallet_config, 32, None, password)
|
||||
@@ -44,32 +47,29 @@ pub fn wallet_command(wallet_args: &ArgMatches<'_>, config: GlobalWalletConfig)
|
||||
// just get defaults from the global config
|
||||
let wallet_config = config.members.unwrap().wallet;
|
||||
|
||||
// TODO: Very temporary code to obsolete grin wallet for the first hard fork
|
||||
// All tx operations call get_chain_height as a first order of business,
|
||||
// so this is the most non-intrusive place to put this
|
||||
// Check the node version info, and exit with report if we're not compatible
|
||||
let mut node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
|
||||
let global_wallet_args = wallet_args::parse_global_args(&wallet_config, &wallet_args)
|
||||
.expect("Can't read configuration file");
|
||||
node_client.set_node_api_secret(global_wallet_args.node_api_secret.clone());
|
||||
|
||||
match node_client.clone().chain_height() {
|
||||
Ok(h) => {
|
||||
if h >= 262080 {
|
||||
let err_str = "This version of grin-wallet is obsolete as of block 252080. Please download v2.0.0 from https://github.com/mimblewimble/grin-wallet/releases";
|
||||
error!("{}", err_str);
|
||||
println!();
|
||||
println!("***************");
|
||||
println!("{}", err_str);
|
||||
println!("***************");
|
||||
println!("(You can still view your balances by disconnecting from the grin node, however you will not be able to transact until you upgrade)");
|
||||
println!();
|
||||
return 1;
|
||||
}
|
||||
// This will also cache the node version info for calls to foreign API check middleware
|
||||
if let Some(v) = node_client.clone().get_version_info() {
|
||||
// Isn't going to happen just yet (as of 2.0.0) but keep this here for
|
||||
// the future. the nodeclient's get_version_info will return 1.0 if
|
||||
// it gets a 404 for the version function
|
||||
if Version::parse(&v.node_version) < Version::parse(MIN_COMPAT_NODE_VERSION) {
|
||||
let version = if v.node_version == "1.0.0" {
|
||||
"1.0.x series"
|
||||
} else {
|
||||
&v.node_version
|
||||
};
|
||||
println!("Specified Grin Node (version {}) is outdated and incompatible with this wallet version", version);
|
||||
println!("Please update the node or use a different one");
|
||||
return 1;
|
||||
}
|
||||
// just continue if can't connect to node, as user won't be able to do
|
||||
// anything meaninful anyhow
|
||||
Err(_) => {}
|
||||
}
|
||||
// ... if node isn't available, allow offline functions
|
||||
|
||||
let res = wallet_args::wallet_command(wallet_args, wallet_config, node_client);
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ pub fn parse_send_args(args: &ArgMatches) -> Result<command::SendArgs, ParseErro
|
||||
let v = parse_required(args, "slate_version")?;
|
||||
Some(parse_u64(v, "slate_version")? as u16)
|
||||
}
|
||||
false => Some(0),
|
||||
false => None,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: grin-wallet
|
||||
version: "1.1.1-beta.1"
|
||||
version: "2.0.0-beta.2"
|
||||
about: Reference Grin Wallet
|
||||
author: The Grin Team
|
||||
|
||||
|
||||
+25
-25
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "grin_wallet_util"
|
||||
version = "1.1.1-beta.1"
|
||||
version = "2.0.0-beta.2"
|
||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||
description = "Util, for generic utilities and to re-export grin crates"
|
||||
license = "Apache-2.0"
|
||||
@@ -17,36 +17,36 @@ toml = "0.4"
|
||||
dirs = "1.0.3"
|
||||
|
||||
# For Release
|
||||
#grin_core = "1.1.0"
|
||||
#grin_keychain = "1.1.0"
|
||||
#grin_chain = "1.1.0"
|
||||
#grin_util = "1.1.0"
|
||||
#grin_api = "1.1.0"
|
||||
#grin_store = "1.1.0"
|
||||
#grin_core = "2.0.0"
|
||||
#grin_keychain = "2.0.0"
|
||||
#grin_chain = "2.0.0"
|
||||
#grin_util = "2.0.0"
|
||||
#grin_api = "2.0.0"
|
||||
#grin_store = "2.0.0"
|
||||
|
||||
# For beta release
|
||||
# grin_core = { git = "https://github.com/mimblewimble/grin", tag = "v1.1.0-beta.2" }
|
||||
# grin_keychain = { git = "https://github.com/mimblewimble/grin", tag = "v1.1.0-beta.2" }
|
||||
# grin_chain = { git = "https://github.com/mimblewimble/grin", tag = "v1.1.0-beta.2" }
|
||||
# grin_util = { git = "https://github.com/mimblewimble/grin", tag = "v1.1.0-beta.2" }
|
||||
# grin_api = { git = "https://github.com/mimblewimble/grin", tag = "v1.1.0-beta.2" }
|
||||
# grin_store = { git = "https://github.com/mimblewimble/grin", tag = "v1.1.0-beta.2" }
|
||||
grin_core = { git = "https://github.com/mimblewimble/grin", tag = "2.0.0-beta.2" }
|
||||
grin_keychain = { git = "https://github.com/mimblewimble/grin", tag = "2.0.0-beta.2" }
|
||||
grin_chain = { git = "https://github.com/mimblewimble/grin", tag = "2.0.0-beta.2" }
|
||||
grin_util = { git = "https://github.com/mimblewimble/grin", tag = "2.0.0-beta.2" }
|
||||
grin_api = { git = "https://github.com/mimblewimble/grin", tag = "2.0.0-beta.2" }
|
||||
grin_store = { git = "https://github.com/mimblewimble/grin", tag = "2.0.0-beta.2" }
|
||||
|
||||
# For bleeding edge
|
||||
grin_core = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_keychain = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_chain = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_api = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_store = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
# grin_core = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
# grin_keychain = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
# grin_chain = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
# grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
# grin_api = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
# grin_store = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
|
||||
# For local testing
|
||||
#grin_core = { path = "../../grin/core", version= "1.1.0-beta.2"}
|
||||
#grin_keychain = { path = "../../grin/keychain", version= "1.1.0-beta.2"}
|
||||
#grin_chain = { path = "../../grin/chain", version= "1.1.0-beta.2"}
|
||||
#grin_util = { path = "../../grin/util", version= "1.1.0-beta.2"}
|
||||
#grin_api = { path = "../../grin/api", version= "1.1.0-beta.2"}
|
||||
#grin_store = { path = "../../grin/store", version= "1.1.0-beta.2"}
|
||||
#grin_core = { path = "../../grin/core", version= "2.0.0-beta.2"}
|
||||
#grin_keychain = { path = "../../grin/keychain", version= "2.0.0-beta.2"}
|
||||
#grin_chain = { path = "../../grin/chain", version= "2.0.0-beta.2"}
|
||||
#grin_util = { path = "../../grin/util", version= "2.0.0-beta.2"}
|
||||
#grin_api = { path = "../../grin/api", version= "2.0.0-beta.2"}
|
||||
#grin_store = { path = "../../grin/store", version= "2.0.0-beta.2"}
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.5.1"
|
||||
|
||||
Reference in New Issue
Block a user