Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3.x.x - v4.0.0 wallet compatibility fixes #398

Merged
5 changes: 5 additions & 0 deletions api/src/foreign_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ pub trait ForeignRpc {
}
]
},
null,
null
]
}
Expand Down Expand Up @@ -180,6 +181,8 @@ pub trait ForeignRpc {
&self,
slate: VersionedSlate,
dest_acct_name: Option<String>,
//TODO: Remove post-HF3
message: Option<String>,
) -> Result<VersionedSlate, ErrorKind>;

/**
Expand Down Expand Up @@ -295,6 +298,8 @@ where
&self,
in_slate: VersionedSlate,
dest_acct_name: Option<String>,
//TODO: Remove post HF3
_message: Option<String>,
) -> Result<VersionedSlate, ErrorKind> {
let version = in_slate.version();
let slate_from = Slate::from(in_slate);
Expand Down
78 changes: 76 additions & 2 deletions controller/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ use crate::config::{TorConfig, WalletConfig, WALLET_CONFIG_FILE_NAME};
use crate::core::{core, global};
use crate::error::{Error, ErrorKind};
use crate::impls::{create_sender, KeybaseAllChannels, SlateGetter as _, SlateReceiver as _};
use crate::impls::{PathToSlate, SlatePutter};
use crate::impls::{HttpSlateSender, PathToSlate, SlatePutter};
use crate::keychain;
use crate::libwallet::{
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, WalletLCProvider,
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, SlateVersion,
WalletLCProvider,
};
use crate::util::secp::key::SecretKey;
use crate::util::{Mutex, ZeroingString};
Expand Down Expand Up @@ -277,6 +278,8 @@ pub struct SendArgs {
pub target_slate_version: Option<u16>,
pub payment_proof_address: Option<OnionV3Address>,
pub ttl_blocks: Option<u64>,
//TODO: Remove HF3
pub output_v4_slate: bool,
}

pub fn send<L, C, K>(
Expand All @@ -292,6 +295,60 @@ where
K: keychain::Keychain + 'static,
{
let wallet_inst = owner_api.wallet_inst.clone();
// Check other version, and if it only supports 3 set the target slate
// version to 3 to avoid removing the transaction object
// TODO: This block is temporary, for the period between the release of v4.0.0 and HF3,
// after which this should be removable
let mut args = args;
{
let invalid = || {
ErrorKind::GenericError(format!(
"Invalid wallet comm type and destination. method: {}, dest: {}",
args.method, args.dest
))
};
let trailing = match args.dest.ends_with('/') {
true => "",
false => "/",
};
let url_str = format!("{}{}v2/foreign", args.dest, trailing);
match args.method.as_ref() {
"http" => {
let v_sender = HttpSlateSender::new(&args.dest).map_err(|_| invalid())?;
let other_version = v_sender.check_other_version(&url_str)?;
if other_version == SlateVersion::V3 {
args.target_slate_version = Some(3);
}
}
"tor" => {
let v_sender = HttpSlateSender::with_socks_proxy(
&args.dest,
&tor_config.as_ref().unwrap().socks_proxy_addr,
&tor_config.as_ref().unwrap().send_config_dir,
)
.map_err(|_| invalid())?;
let other_version = v_sender.check_other_version(&url_str)?;
if other_version == SlateVersion::V3 {
args.target_slate_version = Some(3);
}
}
"file" => {
// For files spit out a V3 Slate if we're before HF3,
// Or V4 slate otherwise
let cur_height = {
libwallet::wallet_lock!(wallet_inst, w);
w.w2n_client().get_chain_tip()?.0
};
// TODO: Floonet HF4
if cur_height < 786240 && !args.output_v4_slate {
args.target_slate_version = Some(3);
}
}
_ => {}
}
}
// end block to delete post HF3

controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
if args.estimate_selection_strategies {
let strategies = vec!["smallest", "all"]
Expand Down Expand Up @@ -503,6 +560,9 @@ pub struct IssueInvoiceArgs {
pub issue_args: IssueInvoiceTxArgs,
/// whether to output as bin
pub bin: bool,
// TODO: Remove HF3
/// whether to output a V4 slate
pub output_v4_slate: bool,
}

pub fn issue_invoice_tx<L, C, K>(
Expand All @@ -515,6 +575,20 @@ where
C: NodeClient + 'static,
K: keychain::Keychain + 'static,
{
//TODO: Remove block HF3
let args = {
let mut a = args;
let wallet_inst = owner_api.wallet_inst.clone();
let cur_height = {
libwallet::wallet_lock!(wallet_inst, w);
w.w2n_client().get_chain_tip()?.0
};
// TODO: Floonet HF4
if cur_height < 786240 && !a.output_v4_slate && !a.bin {
a.issue_args.target_slate_version = Some(3);
}
a
};
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let slate = api.issue_invoice_tx(m, args.issue_args)?;
PathToSlate((&args.dest).into()).put_tx(&slate, args.bin)?;
Expand Down
64 changes: 51 additions & 13 deletions impls/src/adapters/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ use std::fs::File;
use std::io::{Read, Write};

use crate::client_utils::byte_ser;
use crate::libwallet::{Error, ErrorKind, Slate, SlateVersion, VersionedBinSlate, VersionedSlate};
use crate::libwallet::slate_versions::v3::SlateV3;
use crate::libwallet::slate_versions::v4::SlateV4;
use crate::libwallet::{
Error, ErrorKind, Slate, SlateState, SlateVersion, VersionedBinSlate, VersionedSlate,
};
use crate::{SlateGetter, SlatePutter};
use std::convert::TryFrom;
use std::path::PathBuf;
Expand All @@ -29,20 +33,54 @@ impl SlatePutter for PathToSlate {
fn put_tx(&self, slate: &Slate, as_bin: bool) -> Result<(), Error> {
let mut pub_tx = File::create(&self.0)?;
// TODO:
// * Will need to set particpant id to 1 manually if this is invoice
// * Set slate height manually
// * Reconcile unknown slate states from V3
let _r: crate::adapters::Reminder;
let out_slate = {
// TODO: This will need to be filled with any incompatibilities in the V4 Slate
if false {
warn!("Transaction contains features that require grin-wallet 4.0.0 or later");
warn!("Please ensure the other party is running grin-wallet v4.0.0 or later before sending");
VersionedSlate::into_version(slate.clone(), SlateVersion::V4)?
// TODO: Remove post HF3
if slate.version_info.version == 2 || slate.version_info.version == 3 {
// if the slate we read in in V3 or 2 (holdover from 3.0.0), output a slate V3,
// which can be read by v3.x wallets
let v4_slate = SlateV4::from(slate.clone());
let mut v3_slate = SlateV3::try_from(&v4_slate)?;
// Fill in V3 participant IDs according to state
if slate.state == SlateState::Invoice1 {
for mut e in v3_slate.participant_data.iter_mut() {
if Some(e.public_blind_excess.clone()) == slate.participant_id {
e.id = 1;
} else {
e.id = 0;
}
}
}
if slate.state == SlateState::Invoice2 {
for mut e in v3_slate.participant_data.iter_mut() {
if Some(e.public_blind_excess.clone()) == slate.participant_id {
e.id = 0;
} else {
e.id = 1;
}
}
}
if slate.state == SlateState::Standard1 {
for mut e in v3_slate.participant_data.iter_mut() {
if Some(e.public_blind_excess.clone()) == slate.participant_id {
e.id = 0;
} else {
e.id = 1;
}
}
}
if slate.state == SlateState::Standard2 {
for mut e in v3_slate.participant_data.iter_mut() {
if Some(e.public_blind_excess.clone()) == slate.participant_id {
e.id = 1;
} else {
e.id = 0;
}
}
}
v3_slate.version_info.version = 3;
VersionedSlate::V3(v3_slate)
} else {
let mut s = slate.clone();
s.version_info.version = 4;
VersionedSlate::into_version(s, SlateVersion::V4)?
VersionedSlate::into_version(slate.clone(), SlateVersion::V4)?
}
};
if as_bin {
Expand Down
17 changes: 11 additions & 6 deletions impls/src/adapters/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl HttpSlateSender {
}

/// Check version of the listening wallet
fn check_other_version(&self, url: &str) -> Result<SlateVersion, Error> {
pub fn check_other_version(&self, url: &str) -> Result<SlateVersion, Error> {
let req = json!({
"jsonrpc": "2.0",
"method": "check_version",
Expand Down Expand Up @@ -180,16 +180,15 @@ impl SlateSender for HttpSlateSender {
SlateVersion::V4 => VersionedSlate::into_version(slate.clone(), SlateVersion::V4)?,
SlateVersion::V3 => {
let mut slate = slate.clone();
let _r: crate::adapters::Reminder;
//TODO: Fill out with Slate V4 incompatibilities
// * Will need to set particpant id to 1 manually if this is invoice
// * Set slate height manually
// * Reconcile unknown slate states from V3
if false {
return Err(ErrorKind::ClientCallback("feature x requested, but other wallet does not support feature x. Please urge other user to upgrade, or re-send tx without feature x".into()).into());
}
slate.version_info.version = 4;
VersionedSlate::into_version(slate, SlateVersion::V4)?
slate.version_info.version = 3;
VersionedSlate::into_version(slate, SlateVersion::V3)?
}
};
// Note: not using easy-jsonrpc as don't want the dependencies in this crate
Expand All @@ -206,7 +205,10 @@ impl SlateSender for HttpSlateSender {
trace!("Sending receive_tx request: {}", req);

let res: String = self.post(&url_str, None, req).map_err(|e| {
let report = format!("Posting transaction slate (is recipient listening?): {}", e);
let report = format!(
"Sending transaction slate to other wallet (is recipient listening?): {}",
e
);
error!("{}", report);
ErrorKind::ClientCallback(report)
})?;
Expand All @@ -225,7 +227,10 @@ impl SlateSender for HttpSlateSender {
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)?;
.map_err(|e| {
error!("Error deserializing response slate: {}", e);
ErrorKind::SlateDeser
})?;

Ok(slate)
}
Expand Down
7 changes: 0 additions & 7 deletions impls/src/adapters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ use crate::libwallet::{Error, ErrorKind, Slate};
use crate::tor::config::complete_tor_address;
use crate::util::ZeroingString;

/// Little SlateV4 reminder warning helper
#[deprecated(
since = "3.0.0",
note = "Remember to handle SlateV4 incompatibilities here"
)]
pub struct Reminder;

/// Sends transactions to a corresponding SlateReceiver
pub trait SlateSender {
/// Send a transaction slate to another listening wallet and return result
Expand Down
22 changes: 20 additions & 2 deletions libwallet/src/api_impl/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ where
args.ttl_blocks,
)?;

if let Some(v) = args.target_slate_version {
slate.version_info.version = v;
};

// if we just want to estimate, don't save a context, just send the results
// back
if let Some(true) = args.estimate_only {
Expand Down Expand Up @@ -380,6 +384,9 @@ where

context.offset = Some(slate.tx_or_err()?.offset.clone());

//TODO: Remove after HF3
slate.offset = slate.tx_or_err()?.offset.clone();

// Save the aggsig context in our DB for when we
// recieve the transaction back
{
Expand All @@ -388,7 +395,9 @@ where
batch.commit()?;
}

slate.compact()?;
if slate.is_compact() {
slate.compact()?;
}

Ok(slate)
}
Expand Down Expand Up @@ -428,8 +437,15 @@ where
use_test_rng,
)?;

if let Some(v) = args.target_slate_version {
slate.version_info.version = v;
};

context.offset = Some(slate.tx_or_err()?.offset.clone());

//TODO: Remove after HF3
slate.offset = slate.tx_or_err()?.offset.clone();

// Save the aggsig context in our DB for when we
// recieve the transaction back
{
Expand All @@ -438,7 +454,9 @@ where
batch.commit()?;
}

slate.compact()?;
if slate.is_compact() {
slate.compact()?;
}

Ok(slate)
}
Expand Down
1 change: 1 addition & 0 deletions libwallet/src/internal/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ where
slate.fill_round_2(&wallet.keychain(keychain_mask)?, &sec_key, &sec_nonce)?;

// Final transaction can be built by anyone at this stage
trace!("Slate to finalize is: {}", slate);
slate.finalize(&wallet.keychain(keychain_mask)?)?;
Ok(())
}
Expand Down
Loading