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:
Yeastplume
2019-06-27 10:41:05 +01:00
committed by GitHub
parent c7a00478aa
commit 64e8c48c35
37 changed files with 935 additions and 4061 deletions
Generated
+350 -339
View File
File diff suppressed because it is too large Load Diff
+8 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
}
]
+8 -5
View File
@@ -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
View File
@@ -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"
+6 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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" }
+92 -5
View File
@@ -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)
}
+6 -3
View File
@@ -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
)))
}
}
+34 -3
View File
@@ -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 {
+4 -1
View File
@@ -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> {
+3 -3
View File
@@ -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" }
+4
View File
@@ -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),
+45 -15
View File
@@ -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(())
}
+19 -12
View File
@@ -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![];
+20 -3
View File
@@ -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());
+16 -4
View File
@@ -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))
}
+6 -3
View File
@@ -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
View File
@@ -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))),
}
}
+16 -37
View File
@@ -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)
}*/
}
}
}
-119
View File
@@ -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,
}
-382
View File
@@ -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,
}
}
}
-273
View File
@@ -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,
}
}
}
+15
View File
@@ -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.
+63 -42
View File
@@ -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());
}
+3 -1
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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"