Update transactions via kernel where necessary (#220)

* add test for no change output scenario

* rustfmt

* add kernel lookup functionality to transaction retrievals

* rustfmt

* updates and fixes for no-change invoice workflow, test implementations

* rustfmt
This commit is contained in:
Yeastplume
2019-09-24 09:56:10 +01:00
committed by GitHub
parent 26ad378686
commit 07758f55d3
14 changed files with 424 additions and 28 deletions
+1
View File
@@ -15,6 +15,7 @@ failure = "0.1"
failure_derive = "0.1"
futures = "0.1"
rand = "0.5"
semver = "0.9"
serde = "1"
serde_derive = "1"
serde_json = "1"
+53 -1
View File
@@ -17,14 +17,17 @@
use futures::{stream, Stream};
use crate::api::LocatedTxKernel;
use crate::core::core::TxKernel;
use crate::libwallet::{NodeClient, NodeVersionInfo, TxWrapper};
use semver::Version;
use std::collections::HashMap;
use tokio::runtime::Runtime;
use crate::api;
use crate::libwallet;
use crate::util;
use crate::util::secp::pedersen;
use crate::util::{self, to_hex};
#[derive(Clone)]
pub struct HTTPNodeClient {
@@ -127,6 +130,55 @@ impl NodeClient for HTTPNodeClient {
}
}
/// Get kernel implementation
fn get_kernel(
&mut self,
excess: &pedersen::Commitment,
min_height: Option<u64>,
max_height: Option<u64>,
) -> Result<Option<(TxKernel, u64, u64)>, libwallet::Error> {
let version = self
.get_version_info()
.ok_or(libwallet::ErrorKind::ClientCallback(
"Unable to get version".into(),
))?;
let version = Version::parse(&version.node_version)
.map_err(|_| libwallet::ErrorKind::ClientCallback("Unable to parse version".into()))?;
if version <= Version::new(2, 0, 0) {
return Err(libwallet::ErrorKind::ClientCallback(
"Kernel lookup not supported by node, please upgrade it".into(),
)
.into());
}
let mut query = String::new();
if let Some(h) = min_height {
query += &format!("min_height={}", h);
}
if let Some(h) = max_height {
if query.len() > 0 {
query += "&";
}
query += &format!("max_height={}", h);
}
if query.len() > 0 {
query.insert_str(0, "?");
}
let url = format!(
"{}/v1/chain/kernels/{}{}",
self.node_url(),
to_hex(excess.0.to_vec()),
query
);
let res: Option<LocatedTxKernel> = api::client::get(url.as_str(), self.node_api_secret())
.map_err(|e| {
libwallet::ErrorKind::ClientCallback(format!("Kernel lookup: {}", e))
})?;
Ok(res.map(|k| (k.tx_kernel, k.height, k.mmr_index)))
}
/// Retrieve outputs from node
fn get_outputs_from_node(
&self,
+17
View File
@@ -52,6 +52,23 @@ fn get_output_local(chain: &chain::Chain, commit: &pedersen::Commitment) -> Opti
None
}
/// Get a kernel from the chain locally
fn get_kernel_local(
chain: Arc<chain::Chain>,
excess: &pedersen::Commitment,
min_height: Option<u64>,
max_height: Option<u64>,
) -> Option<api::LocatedTxKernel> {
chain
.get_kernel_height(&excess, min_height, max_height)
.unwrap()
.map(|(tx_kernel, height, mmr_index)| api::LocatedTxKernel {
tx_kernel,
height,
mmr_index,
})
}
/// get output listing traversing pmmr from local
fn get_outputs_by_pmmr_index_local(
chain: Arc<chain::Chain>,
+64 -2
View File
@@ -16,11 +16,11 @@
//! so that wallet API can be fully exercised
//! Operates directly on a chain instance
use crate::api;
use crate::api::{self, LocatedTxKernel};
use crate::chain::types::NoopAdapter;
use crate::chain::Chain;
use crate::core::core::verifier_cache::LruVerifierCache;
use crate::core::core::Transaction;
use crate::core::core::{Transaction, TxKernel};
use crate::core::global::{set_mining_mode, ChainTypes};
use crate::core::{pow, ser};
use crate::keychain::Keychain;
@@ -151,6 +151,7 @@ where
"get_outputs_by_pmmr_index" => self.get_outputs_by_pmmr_index(m)?,
"send_tx_slate" => self.send_tx_slate(m)?,
"post_tx" => self.post_tx(m)?,
"get_kernel" => self.get_kernel(m)?,
_ => panic!("Unknown Wallet Proxy Message"),
};
@@ -299,6 +300,26 @@ where
body: serde_json::to_string(&ol).unwrap(),
})
}
/// get kernel
fn get_kernel(
&mut self,
m: WalletProxyMessage,
) -> Result<WalletProxyMessage, libwallet::Error> {
let split = m.body.split(",").collect::<Vec<&str>>();
let excess = split[0].parse::<String>().unwrap();
let min = split[1].parse::<u64>().unwrap();
let max = split[2].parse::<u64>().unwrap();
let commit_bytes = util::from_hex(excess).unwrap();
let commit = pedersen::Commitment::from_vec(commit_bytes);
let k = super::get_kernel_local(self.chain.clone(), &commit, Some(min), Some(max));
Ok(WalletProxyMessage {
sender_id: "node".to_owned(),
dest: m.sender_id,
method: m.method,
body: serde_json::to_string(&k).unwrap(),
})
}
}
#[derive(Clone)]
@@ -450,6 +471,47 @@ impl NodeClient for LocalWalletClient {
Ok(api_outputs)
}
fn get_kernel(
&mut self,
excess: &pedersen::Commitment,
min_height: Option<u64>,
max_height: Option<u64>,
) -> Result<Option<(TxKernel, u64, u64)>, libwallet::Error> {
let mut query = format!("{},", util::to_hex(excess.0.to_vec()));
if let Some(h) = min_height {
query += &format!("{},", h);
} else {
query += "0,"
}
if let Some(h) = max_height {
query += &format!("{}", h);
} else {
query += "0"
}
let m = WalletProxyMessage {
sender_id: self.id.clone(),
dest: self.node_url().to_owned(),
method: "get_kernel".to_owned(),
body: query,
};
{
let p = self.proxy_tx.lock();
p.send(m).context(libwallet::ErrorKind::ClientCallback(
"Get outputs from node by PMMR index send".to_owned(),
))?;
}
let r = self.rx.lock();
let m = r.recv().unwrap();
let res: Option<LocatedTxKernel> = serde_json::from_str(&m.body).context(
libwallet::ErrorKind::ClientCallback("Get transaction kernels send".to_owned()),
)?;
match res {
Some(k) => Ok(Some((k.tx_kernel, k.height, k.mmr_index))),
None => Ok(None),
}
}
fn get_outputs_by_pmmr_index(
&self,
start_height: u64,