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

Store completed transactions in files instead of DB #2148

Merged
merged 6 commits into from
Dec 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/bin/cmd/wallet_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ mod wallet_tests {
Ok(())
})?;

// Try using the self-send method
// Try using the self-send method, splitting up outputs for the fun of it
let arg_vec = vec![
"grin",
"wallet",
Expand All @@ -423,6 +423,8 @@ mod wallet_tests {
"mining",
"-g",
"Self love",
"-o",
"75",
"-s",
"smallest",
"10",
Expand Down
2 changes: 1 addition & 1 deletion wallet/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ pub fn repost(
) -> Result<(), Error> {
controller::owner_single_use(wallet.clone(), |api| {
let (_, txs) = api.retrieve_txs(true, Some(args.id), None)?;
let stored_tx = txs[0].get_stored_tx();
let stored_tx = api.get_stored_tx(&txs[0])?;
if stored_tx.is_none() {
error!(
"Transaction with id {} does not have transaction data. Not reposting.",
Expand Down
5 changes: 4 additions & 1 deletion wallet/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,10 @@ where
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)) => Ok((txs[0].confirmed, txs[0].get_stored_tx())),
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)
Expand Down
2 changes: 1 addition & 1 deletion wallet/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ pub fn txs(
)
};
let tx_data = match t.tx_hex {
Some(_) => format!("Exists"),
Some(t) => format!("{}", t),
None => "None".to_owned(),
};
if dark_background_color_scheme {
Expand Down
22 changes: 16 additions & 6 deletions wallet/src/libwallet/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,13 @@ where
num_change_outputs: usize,
selection_strategy_is_use_all: bool,
message: Option<String>,
) -> Result<(Slate, impl FnOnce(&mut W, &str) -> Result<(), Error>), Error> {
) -> Result<
(
Slate,
impl FnOnce(&mut W, &Transaction) -> Result<(), Error>,
),
Error,
> {
let mut w = self.wallet.lock();
w.open_with_credentials()?;
let parent_key_id = match src_acct_name {
Expand Down Expand Up @@ -653,12 +659,11 @@ where
pub fn tx_lock_outputs(
&mut self,
slate: &Slate,
lock_fn: impl FnOnce(&mut W, &str) -> Result<(), Error>,
lock_fn: impl FnOnce(&mut W, &Transaction) -> Result<(), Error>,
) -> Result<(), Error> {
let mut w = self.wallet.lock();
w.open_with_credentials()?;
let tx_hex = util::to_hex(ser::ser_vec(&slate.tx).unwrap());
lock_fn(&mut *w, &tx_hex)?;
lock_fn(&mut *w, &slate.tx)?;
Ok(())
}

Expand All @@ -668,11 +673,10 @@ where
/// propagation.
pub fn finalize_tx(&mut self, slate: &mut Slate) -> Result<(), Error> {
let mut w = self.wallet.lock();
let parent_key_id = w.parent_key_id();
w.open_with_credentials()?;
let context = w.get_private_context(slate.id.as_bytes())?;
tx::complete_tx(&mut *w, slate, &context)?;
tx::update_tx_hex(&mut *w, &parent_key_id, slate)?;
tx::update_stored_tx(&mut *w, slate)?;
{
let mut batch = w.batch()?;
batch.delete_private_context(slate.id.as_bytes())?;
Expand Down Expand Up @@ -706,6 +710,12 @@ where
Ok(())
}

/// Retrieves a stored transaction from a TxLogEntry
pub fn get_stored_tx(&self, entry: &TxLogEntry) -> Result<Option<Transaction>, Error> {
let w = self.wallet.lock();
w.get_stored_tx(entry)
}

/// Posts a transaction to the chain
pub fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), Error> {
let tx_hex = util::to_hex(ser::ser_vec(tx).unwrap());
Expand Down
78 changes: 42 additions & 36 deletions wallet/src/libwallet/internal/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

//! Selection of inputs for building transactions

use crate::core::core::Transaction;
use crate::core::libtx::{build, slate::Slate, tx_fee};
use crate::keychain::{Identifier, Keychain};
use crate::libwallet::error::{Error, ErrorKind};
Expand All @@ -40,7 +41,7 @@ pub fn build_send_tx_slate<T: ?Sized, C, K>(
(
Slate,
Context,
impl FnOnce(&mut T, &str) -> Result<(), Error>,
impl FnOnce(&mut T, &Transaction) -> Result<(), Error>,
),
Error,
>
Expand Down Expand Up @@ -94,42 +95,47 @@ where

// Return a closure to acquire wallet lock and lock the coins being spent
// so we avoid accidental double spend attempt.
let update_sender_wallet_fn = move |wallet: &mut T, tx_hex: &str| {
let mut batch = wallet.batch()?;
let log_id = batch.next_tx_log_id(&parent_key_id)?;
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id);
t.tx_slate_id = Some(slate_id);
t.fee = Some(fee);
t.tx_hex = Some(tx_hex.to_owned());
let mut amount_debited = 0;
t.num_inputs = lock_inputs.len();
for id in lock_inputs {
let mut coin = batch.get(&id).unwrap();
coin.tx_log_entry = Some(log_id);
amount_debited = amount_debited + coin.value;
batch.lock_output(&mut coin)?;
}
let update_sender_wallet_fn = move |wallet: &mut T, tx: &Transaction| {
let tx_entry = {
let mut batch = wallet.batch()?;
let log_id = batch.next_tx_log_id(&parent_key_id)?;
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id);
t.tx_slate_id = Some(slate_id);
let filename = format!("{}.grintx", slate_id);
t.tx_hex = Some(filename);
t.fee = Some(fee);
let mut amount_debited = 0;
t.num_inputs = lock_inputs.len();
for id in lock_inputs {
let mut coin = batch.get(&id).unwrap();
coin.tx_log_entry = Some(log_id);
amount_debited = amount_debited + coin.value;
batch.lock_output(&mut coin)?;
}

t.amount_debited = amount_debited;

// write the output representing our change
for (change_amount, id) in &change_amounts_derivations {
t.num_outputs += 1;
t.amount_credited += change_amount;
batch.save(OutputData {
root_key_id: parent_key_id.clone(),
key_id: id.clone(),
n_child: id.to_path().last_path_index(),
value: change_amount.clone(),
status: OutputStatus::Unconfirmed,
height: current_height,
lock_height: 0,
is_coinbase: false,
tx_log_entry: Some(log_id),
})?;
}
batch.save_tx_log_entry(t, &parent_key_id)?;
batch.commit()?;
t.amount_debited = amount_debited;

// write the output representing our change
for (change_amount, id) in &change_amounts_derivations {
t.num_outputs += 1;
t.amount_credited += change_amount;
batch.save(OutputData {
root_key_id: parent_key_id.clone(),
key_id: id.clone(),
n_child: id.to_path().last_path_index(),
value: change_amount.clone(),
status: OutputStatus::Unconfirmed,
height: current_height,
lock_height: 0,
is_coinbase: false,
tx_log_entry: Some(log_id),
})?;
}
batch.save_tx_log_entry(t.clone(), &parent_key_id)?;
batch.commit()?;
t
};
wallet.store_tx(&format!("{}", tx_entry.tx_slate_id.unwrap()), tx)?;
Ok(())
};

Expand Down
22 changes: 6 additions & 16 deletions wallet/src/libwallet/internal/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@

//! Transaction building functions

use crate::util;
use uuid::Uuid;

use crate::core::core::Transaction;
use crate::core::libtx::slate::Slate;
use crate::core::ser;
use crate::keychain::{Identifier, Keychain};
use crate::libwallet::internal::{selection, updater};
use crate::libwallet::types::{Context, NodeClient, TxLogEntryType, WalletBackend};
Expand Down Expand Up @@ -74,7 +73,7 @@ pub fn create_send_tx<T: ?Sized, C, K>(
(
Slate,
Context,
impl FnOnce(&mut T, &str) -> Result<(), Error>,
impl FnOnce(&mut T, &Transaction) -> Result<(), Error>,
),
Error,
>
Expand Down Expand Up @@ -200,19 +199,13 @@ where
Ok((tx.confirmed, tx.tx_hex))
}

/// Update the stored hex transaction (this update needs to happen when the TX is finalised)
pub fn update_tx_hex<T: ?Sized, C, K>(
wallet: &mut T,
_parent_key_id: &Identifier,
slate: &Slate,
) -> Result<(), Error>
/// Update the stored transaction (this update needs to happen when the TX is finalised)
pub fn update_stored_tx<T: ?Sized, C, K>(wallet: &mut T, slate: &Slate) -> Result<(), Error>
where
T: WalletBackend<C, K>,
C: NodeClient,
K: Keychain,
{
let tx_hex = util::to_hex(ser::ser_vec(&slate.tx).unwrap());
// This will ignore the parent key, so no need to specify account on the
// finalize command
let tx_vec = updater::retrieve_txs(wallet, None, Some(slate.id), None)?;
let mut tx = None;
Expand All @@ -223,14 +216,11 @@ where
break;
}
}
let mut tx = match tx {
let tx = match tx {
Some(t) => t,
None => return Err(ErrorKind::TransactionDoesntExist(slate.id.to_string()))?,
};
tx.tx_hex = Some(tx_hex);
let batch = wallet.batch()?;
batch.save_tx_log_entry(tx.clone(), &tx.parent_key_id)?;
batch.commit()?;
wallet.store_tx(&format!("{}", tx.tx_slate_id.unwrap()), &slate.tx)?;
Ok(())
}

Expand Down
21 changes: 8 additions & 13 deletions wallet/src/libwallet/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use crate::core::libtx::aggsig;
use crate::core::ser;
use crate::keychain::{Identifier, Keychain};
use crate::libwallet::error::{Error, ErrorKind};
use crate::util;
use crate::util::secp::key::{PublicKey, SecretKey};
use crate::util::secp::{self, pedersen, Secp256k1};
use chrono::prelude::*;
Expand Down Expand Up @@ -102,6 +101,12 @@ where
/// Gets an account path for a given label
fn get_acct_path(&self, label: String) -> Result<Option<AcctPathMapping>, Error>;

/// Stores a transaction
fn store_tx(&self, uuid: &str, tx: &Transaction) -> Result<(), Error>;

/// Retrieves a stored transaction from a TxLogEntry
fn get_stored_tx(&self, entry: &TxLogEntry) -> Result<Option<Transaction>, Error>;

/// Create a new write batch to update or remove output data
fn batch<'a>(&'a mut self) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error>;

Expand Down Expand Up @@ -156,7 +161,7 @@ where
fn tx_log_iter(&self) -> Box<dyn Iterator<Item = TxLogEntry>>;

/// save a tx log entry
fn save_tx_log_entry(&self, t: TxLogEntry, parent_id: &Identifier) -> Result<(), Error>;
fn save_tx_log_entry(&mut self, t: TxLogEntry, parent_id: &Identifier) -> Result<(), Error>;

/// save an account label -> path mapping
fn save_acct_path(&mut self, mapping: AcctPathMapping) -> Result<(), Error>;
Expand Down Expand Up @@ -595,6 +600,7 @@ pub struct TxLogEntry {
pub amount_debited: u64,
/// Fee
pub fee: Option<u64>,
// TODO: rename this to 'stored_tx_file' or something for mainnet
/// The transaction json itself, stored for reference or resending
pub tx_hex: Option<String>,
}
Expand Down Expand Up @@ -636,17 +642,6 @@ impl TxLogEntry {
pub fn update_confirmation_ts(&mut self) {
self.confirmation_ts = Some(Utc::now());
}

/// Retrieve the stored transaction, if any
pub fn get_stored_tx(&self) -> Option<Transaction> {
match self.tx_hex.as_ref() {
None => None,
Some(t) => {
let tx_bin = util::from_hex(t.clone()).unwrap();
Some(ser::deserialize::<Transaction>(&mut &tx_bin[..]).unwrap())
}
}
}
}

/// Map of named accounts to BIP32 paths
Expand Down
Loading