mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-08 12:21:09 +03:00
[WIP] Store completed transactions in files instead of DB (#2148)
Store completed transactions in files instead of DB
This commit is contained in:
parent
32a7c309e7
commit
8e678058f1
11 changed files with 141 additions and 80 deletions
|
@ -408,7 +408,7 @@ mod wallet_tests {
|
||||||
Ok(())
|
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![
|
let arg_vec = vec![
|
||||||
"grin",
|
"grin",
|
||||||
"wallet",
|
"wallet",
|
||||||
|
@ -423,6 +423,8 @@ mod wallet_tests {
|
||||||
"mining",
|
"mining",
|
||||||
"-g",
|
"-g",
|
||||||
"Self love",
|
"Self love",
|
||||||
|
"-o",
|
||||||
|
"75",
|
||||||
"-s",
|
"-s",
|
||||||
"smallest",
|
"smallest",
|
||||||
"10",
|
"10",
|
||||||
|
|
|
@ -409,7 +409,7 @@ pub fn repost(
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
controller::owner_single_use(wallet.clone(), |api| {
|
controller::owner_single_use(wallet.clone(), |api| {
|
||||||
let (_, txs) = api.retrieve_txs(true, Some(args.id), None)?;
|
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() {
|
if stored_tx.is_none() {
|
||||||
error!(
|
error!(
|
||||||
"Transaction with id {} does not have transaction data. Not reposting.",
|
"Transaction with id {} does not have transaction data. Not reposting.",
|
||||||
|
|
|
@ -231,7 +231,10 @@ where
|
||||||
if let Some(id_string) = params.get("id") {
|
if let Some(id_string) = params.get("id") {
|
||||||
match id_string[0].parse() {
|
match id_string[0].parse() {
|
||||||
Ok(id) => match api.retrieve_txs(true, Some(id), None) {
|
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) => {
|
Err(e) => {
|
||||||
error!("retrieve_stored_tx: failed with error: {}", e);
|
error!("retrieve_stored_tx: failed with error: {}", e);
|
||||||
Err(e)
|
Err(e)
|
||||||
|
|
|
@ -178,7 +178,7 @@ pub fn txs(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let tx_data = match t.tx_hex {
|
let tx_data = match t.tx_hex {
|
||||||
Some(_) => format!("Exists"),
|
Some(t) => format!("{}", t),
|
||||||
None => "None".to_owned(),
|
None => "None".to_owned(),
|
||||||
};
|
};
|
||||||
if dark_background_color_scheme {
|
if dark_background_color_scheme {
|
||||||
|
|
|
@ -612,7 +612,13 @@ where
|
||||||
num_change_outputs: usize,
|
num_change_outputs: usize,
|
||||||
selection_strategy_is_use_all: bool,
|
selection_strategy_is_use_all: bool,
|
||||||
message: Option<String>,
|
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();
|
let mut w = self.wallet.lock();
|
||||||
w.open_with_credentials()?;
|
w.open_with_credentials()?;
|
||||||
let parent_key_id = match src_acct_name {
|
let parent_key_id = match src_acct_name {
|
||||||
|
@ -653,12 +659,11 @@ where
|
||||||
pub fn tx_lock_outputs(
|
pub fn tx_lock_outputs(
|
||||||
&mut self,
|
&mut self,
|
||||||
slate: &Slate,
|
slate: &Slate,
|
||||||
lock_fn: impl FnOnce(&mut W, &str) -> Result<(), Error>,
|
lock_fn: impl FnOnce(&mut W, &Transaction) -> Result<(), Error>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut w = self.wallet.lock();
|
let mut w = self.wallet.lock();
|
||||||
w.open_with_credentials()?;
|
w.open_with_credentials()?;
|
||||||
let tx_hex = util::to_hex(ser::ser_vec(&slate.tx).unwrap());
|
lock_fn(&mut *w, &slate.tx)?;
|
||||||
lock_fn(&mut *w, &tx_hex)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,11 +673,10 @@ where
|
||||||
/// propagation.
|
/// propagation.
|
||||||
pub fn finalize_tx(&mut self, slate: &mut Slate) -> Result<(), Error> {
|
pub fn finalize_tx(&mut self, slate: &mut Slate) -> Result<(), Error> {
|
||||||
let mut w = self.wallet.lock();
|
let mut w = self.wallet.lock();
|
||||||
let parent_key_id = w.parent_key_id();
|
|
||||||
w.open_with_credentials()?;
|
w.open_with_credentials()?;
|
||||||
let context = w.get_private_context(slate.id.as_bytes())?;
|
let context = w.get_private_context(slate.id.as_bytes())?;
|
||||||
tx::complete_tx(&mut *w, slate, &context)?;
|
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()?;
|
let mut batch = w.batch()?;
|
||||||
batch.delete_private_context(slate.id.as_bytes())?;
|
batch.delete_private_context(slate.id.as_bytes())?;
|
||||||
|
@ -706,6 +710,12 @@ where
|
||||||
Ok(())
|
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
|
/// Posts a transaction to the chain
|
||||||
pub fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), Error> {
|
pub fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), Error> {
|
||||||
let tx_hex = util::to_hex(ser::ser_vec(tx).unwrap());
|
let tx_hex = util::to_hex(ser::ser_vec(tx).unwrap());
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
//! Selection of inputs for building transactions
|
//! Selection of inputs for building transactions
|
||||||
|
|
||||||
|
use crate::core::core::Transaction;
|
||||||
use crate::core::libtx::{build, slate::Slate, tx_fee};
|
use crate::core::libtx::{build, slate::Slate, tx_fee};
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::keychain::{Identifier, Keychain};
|
||||||
use crate::libwallet::error::{Error, ErrorKind};
|
use crate::libwallet::error::{Error, ErrorKind};
|
||||||
|
@ -40,7 +41,7 @@ pub fn build_send_tx_slate<T: ?Sized, C, K>(
|
||||||
(
|
(
|
||||||
Slate,
|
Slate,
|
||||||
Context,
|
Context,
|
||||||
impl FnOnce(&mut T, &str) -> Result<(), Error>,
|
impl FnOnce(&mut T, &Transaction) -> Result<(), Error>,
|
||||||
),
|
),
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
|
@ -94,42 +95,47 @@ where
|
||||||
|
|
||||||
// Return a closure to acquire wallet lock and lock the coins being spent
|
// Return a closure to acquire wallet lock and lock the coins being spent
|
||||||
// so we avoid accidental double spend attempt.
|
// so we avoid accidental double spend attempt.
|
||||||
let update_sender_wallet_fn = move |wallet: &mut T, tx_hex: &str| {
|
let update_sender_wallet_fn = move |wallet: &mut T, tx: &Transaction| {
|
||||||
let mut batch = wallet.batch()?;
|
let tx_entry = {
|
||||||
let log_id = batch.next_tx_log_id(&parent_key_id)?;
|
let mut batch = wallet.batch()?;
|
||||||
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id);
|
let log_id = batch.next_tx_log_id(&parent_key_id)?;
|
||||||
t.tx_slate_id = Some(slate_id);
|
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id);
|
||||||
t.fee = Some(fee);
|
t.tx_slate_id = Some(slate_id);
|
||||||
t.tx_hex = Some(tx_hex.to_owned());
|
let filename = format!("{}.grintx", slate_id);
|
||||||
let mut amount_debited = 0;
|
t.tx_hex = Some(filename);
|
||||||
t.num_inputs = lock_inputs.len();
|
t.fee = Some(fee);
|
||||||
for id in lock_inputs {
|
let mut amount_debited = 0;
|
||||||
let mut coin = batch.get(&id).unwrap();
|
t.num_inputs = lock_inputs.len();
|
||||||
coin.tx_log_entry = Some(log_id);
|
for id in lock_inputs {
|
||||||
amount_debited = amount_debited + coin.value;
|
let mut coin = batch.get(&id).unwrap();
|
||||||
batch.lock_output(&mut coin)?;
|
coin.tx_log_entry = Some(log_id);
|
||||||
}
|
amount_debited = amount_debited + coin.value;
|
||||||
|
batch.lock_output(&mut coin)?;
|
||||||
|
}
|
||||||
|
|
||||||
t.amount_debited = amount_debited;
|
t.amount_debited = amount_debited;
|
||||||
|
|
||||||
// write the output representing our change
|
// write the output representing our change
|
||||||
for (change_amount, id) in &change_amounts_derivations {
|
for (change_amount, id) in &change_amounts_derivations {
|
||||||
t.num_outputs += 1;
|
t.num_outputs += 1;
|
||||||
t.amount_credited += change_amount;
|
t.amount_credited += change_amount;
|
||||||
batch.save(OutputData {
|
batch.save(OutputData {
|
||||||
root_key_id: parent_key_id.clone(),
|
root_key_id: parent_key_id.clone(),
|
||||||
key_id: id.clone(),
|
key_id: id.clone(),
|
||||||
n_child: id.to_path().last_path_index(),
|
n_child: id.to_path().last_path_index(),
|
||||||
value: change_amount.clone(),
|
value: change_amount.clone(),
|
||||||
status: OutputStatus::Unconfirmed,
|
status: OutputStatus::Unconfirmed,
|
||||||
height: current_height,
|
height: current_height,
|
||||||
lock_height: 0,
|
lock_height: 0,
|
||||||
is_coinbase: false,
|
is_coinbase: false,
|
||||||
tx_log_entry: Some(log_id),
|
tx_log_entry: Some(log_id),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
batch.save_tx_log_entry(t, &parent_key_id)?;
|
batch.save_tx_log_entry(t.clone(), &parent_key_id)?;
|
||||||
batch.commit()?;
|
batch.commit()?;
|
||||||
|
t
|
||||||
|
};
|
||||||
|
wallet.store_tx(&format!("{}", tx_entry.tx_slate_id.unwrap()), tx)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,10 @@
|
||||||
|
|
||||||
//! Transaction building functions
|
//! Transaction building functions
|
||||||
|
|
||||||
use crate::util;
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::core::core::Transaction;
|
||||||
use crate::core::libtx::slate::Slate;
|
use crate::core::libtx::slate::Slate;
|
||||||
use crate::core::ser;
|
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::keychain::{Identifier, Keychain};
|
||||||
use crate::libwallet::internal::{selection, updater};
|
use crate::libwallet::internal::{selection, updater};
|
||||||
use crate::libwallet::types::{Context, NodeClient, TxLogEntryType, WalletBackend};
|
use crate::libwallet::types::{Context, NodeClient, TxLogEntryType, WalletBackend};
|
||||||
|
@ -74,7 +73,7 @@ pub fn create_send_tx<T: ?Sized, C, K>(
|
||||||
(
|
(
|
||||||
Slate,
|
Slate,
|
||||||
Context,
|
Context,
|
||||||
impl FnOnce(&mut T, &str) -> Result<(), Error>,
|
impl FnOnce(&mut T, &Transaction) -> Result<(), Error>,
|
||||||
),
|
),
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
|
@ -200,19 +199,13 @@ where
|
||||||
Ok((tx.confirmed, tx.tx_hex))
|
Ok((tx.confirmed, tx.tx_hex))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the stored hex transaction (this update needs to happen when the TX is finalised)
|
/// Update the stored transaction (this update needs to happen when the TX is finalised)
|
||||||
pub fn update_tx_hex<T: ?Sized, C, K>(
|
pub fn update_stored_tx<T: ?Sized, C, K>(wallet: &mut T, slate: &Slate) -> Result<(), Error>
|
||||||
wallet: &mut T,
|
|
||||||
_parent_key_id: &Identifier,
|
|
||||||
slate: &Slate,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
where
|
||||||
T: WalletBackend<C, K>,
|
T: WalletBackend<C, K>,
|
||||||
C: NodeClient,
|
C: NodeClient,
|
||||||
K: Keychain,
|
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
|
// finalize command
|
||||||
let tx_vec = updater::retrieve_txs(wallet, None, Some(slate.id), None)?;
|
let tx_vec = updater::retrieve_txs(wallet, None, Some(slate.id), None)?;
|
||||||
let mut tx = None;
|
let mut tx = None;
|
||||||
|
@ -223,14 +216,11 @@ where
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut tx = match tx {
|
let tx = match tx {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => return Err(ErrorKind::TransactionDoesntExist(slate.id.to_string()))?,
|
None => return Err(ErrorKind::TransactionDoesntExist(slate.id.to_string()))?,
|
||||||
};
|
};
|
||||||
tx.tx_hex = Some(tx_hex);
|
wallet.store_tx(&format!("{}", tx.tx_slate_id.unwrap()), &slate.tx)?;
|
||||||
let batch = wallet.batch()?;
|
|
||||||
batch.save_tx_log_entry(tx.clone(), &tx.parent_key_id)?;
|
|
||||||
batch.commit()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ use crate::core::libtx::aggsig;
|
||||||
use crate::core::ser;
|
use crate::core::ser;
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::keychain::{Identifier, Keychain};
|
||||||
use crate::libwallet::error::{Error, ErrorKind};
|
use crate::libwallet::error::{Error, ErrorKind};
|
||||||
use crate::util;
|
|
||||||
use crate::util::secp::key::{PublicKey, SecretKey};
|
use crate::util::secp::key::{PublicKey, SecretKey};
|
||||||
use crate::util::secp::{self, pedersen, Secp256k1};
|
use crate::util::secp::{self, pedersen, Secp256k1};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
|
@ -102,6 +101,12 @@ where
|
||||||
/// Gets an account path for a given label
|
/// Gets an account path for a given label
|
||||||
fn get_acct_path(&self, label: String) -> Result<Option<AcctPathMapping>, Error>;
|
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
|
/// Create a new write batch to update or remove output data
|
||||||
fn batch<'a>(&'a mut self) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error>;
|
fn batch<'a>(&'a mut self) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error>;
|
||||||
|
|
||||||
|
@ -156,7 +161,7 @@ where
|
||||||
fn tx_log_iter(&self) -> Box<dyn Iterator<Item = TxLogEntry>>;
|
fn tx_log_iter(&self) -> Box<dyn Iterator<Item = TxLogEntry>>;
|
||||||
|
|
||||||
/// save a tx log entry
|
/// 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
|
/// save an account label -> path mapping
|
||||||
fn save_acct_path(&mut self, mapping: AcctPathMapping) -> Result<(), Error>;
|
fn save_acct_path(&mut self, mapping: AcctPathMapping) -> Result<(), Error>;
|
||||||
|
@ -595,6 +600,7 @@ pub struct TxLogEntry {
|
||||||
pub amount_debited: u64,
|
pub amount_debited: u64,
|
||||||
/// Fee
|
/// Fee
|
||||||
pub fee: Option<u64>,
|
pub fee: Option<u64>,
|
||||||
|
// TODO: rename this to 'stored_tx_file' or something for mainnet
|
||||||
/// The transaction json itself, stored for reference or resending
|
/// The transaction json itself, stored for reference or resending
|
||||||
pub tx_hex: Option<String>,
|
pub tx_hex: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -636,17 +642,6 @@ impl TxLogEntry {
|
||||||
pub fn update_confirmation_ts(&mut self) {
|
pub fn update_confirmation_ts(&mut self) {
|
||||||
self.confirmation_ts = Some(Utc::now());
|
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
|
/// Map of named accounts to BIP32 paths
|
||||||
|
|
|
@ -16,18 +16,29 @@ use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{fs, path};
|
use std::{fs, path};
|
||||||
|
|
||||||
|
// for writing storedtransaction files
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain};
|
use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain};
|
||||||
use crate::store::{self, option_to_not_found, to_key, to_key_u64};
|
use crate::store::{self, option_to_not_found, to_key, to_key_u64};
|
||||||
|
|
||||||
|
use crate::core::core::Transaction;
|
||||||
|
use crate::core::ser;
|
||||||
use crate::libwallet::types::*;
|
use crate::libwallet::types::*;
|
||||||
use crate::libwallet::{internal, Error, ErrorKind};
|
use crate::libwallet::{internal, Error, ErrorKind};
|
||||||
use crate::types::{WalletConfig, WalletSeed};
|
use crate::types::{WalletConfig, WalletSeed};
|
||||||
|
use crate::util;
|
||||||
use crate::util::secp::pedersen;
|
use crate::util::secp::pedersen;
|
||||||
|
|
||||||
pub const DB_DIR: &'static str = "db";
|
pub const DB_DIR: &'static str = "db";
|
||||||
|
pub const TX_SAVE_DIR: &'static str = "saved_txs";
|
||||||
|
|
||||||
const COMMITMENT_PREFIX: u8 = 'C' as u8;
|
const COMMITMENT_PREFIX: u8 = 'C' as u8;
|
||||||
const OUTPUT_PREFIX: u8 = 'o' as u8;
|
const OUTPUT_PREFIX: u8 = 'o' as u8;
|
||||||
|
@ -69,10 +80,16 @@ impl<C, K> LMDBBackend<C, K> {
|
||||||
let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
|
let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
|
||||||
fs::create_dir_all(&db_path).expect("Couldn't create wallet backend directory!");
|
fs::create_dir_all(&db_path).expect("Couldn't create wallet backend directory!");
|
||||||
|
|
||||||
|
let stored_tx_path = path::Path::new(&config.data_file_dir).join(TX_SAVE_DIR);
|
||||||
|
fs::create_dir_all(&stored_tx_path)
|
||||||
|
.expect("Couldn't create wallet backend tx storage directory!");
|
||||||
|
|
||||||
let lmdb_env = Arc::new(store::new_env(db_path.to_str().unwrap().to_string()));
|
let lmdb_env = Arc::new(store::new_env(db_path.to_str().unwrap().to_string()));
|
||||||
let store = store::Store::open(lmdb_env, DB_DIR);
|
let store = store::Store::open(lmdb_env, DB_DIR);
|
||||||
|
|
||||||
// Make sure default wallet derivation path always exists
|
// Make sure default wallet derivation path always exists
|
||||||
|
// as well as path (so it can be retrieved by batches to know where to store
|
||||||
|
// completed transactions, for reference
|
||||||
let default_account = AcctPathMapping {
|
let default_account = AcctPathMapping {
|
||||||
label: "default".to_owned(),
|
label: "default".to_owned(),
|
||||||
path: LMDBBackend::<C, K>::default_path(),
|
path: LMDBBackend::<C, K>::default_path(),
|
||||||
|
@ -228,6 +245,37 @@ where
|
||||||
self.db.get_ser(&acct_key).map_err(|e| e.into())
|
self.db.get_ser(&acct_key).map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn store_tx(&self, uuid: &str, tx: &Transaction) -> Result<(), Error> {
|
||||||
|
let filename = format!("{}.grintx", uuid);
|
||||||
|
let path = path::Path::new(&self.config.data_file_dir)
|
||||||
|
.join(TX_SAVE_DIR)
|
||||||
|
.join(filename);
|
||||||
|
let path_buf = Path::new(&path).to_path_buf();
|
||||||
|
let mut stored_tx = File::create(path_buf)?;
|
||||||
|
let tx_hex = util::to_hex(ser::ser_vec(tx).unwrap());;
|
||||||
|
stored_tx.write_all(&tx_hex.as_bytes())?;
|
||||||
|
stored_tx.sync_all()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_stored_tx(&self, entry: &TxLogEntry) -> Result<Option<Transaction>, Error> {
|
||||||
|
let filename = match entry.tx_hex.clone() {
|
||||||
|
Some(f) => f,
|
||||||
|
None => return Ok(None),
|
||||||
|
};
|
||||||
|
let path = path::Path::new(&self.config.data_file_dir)
|
||||||
|
.join(TX_SAVE_DIR)
|
||||||
|
.join(filename);
|
||||||
|
let tx_file = Path::new(&path).to_path_buf();
|
||||||
|
let mut tx_f = File::open(tx_file)?;
|
||||||
|
let mut content = String::new();
|
||||||
|
tx_f.read_to_string(&mut content)?;
|
||||||
|
let tx_bin = util::from_hex(content).unwrap();
|
||||||
|
Ok(Some(
|
||||||
|
ser::deserialize::<Transaction>(&mut &tx_bin[..]).unwrap(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn batch<'a>(&'a mut self) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error> {
|
fn batch<'a>(&'a mut self) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error> {
|
||||||
Ok(Box::new(Batch {
|
Ok(Box::new(Batch {
|
||||||
_store: self,
|
_store: self,
|
||||||
|
@ -403,17 +451,21 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_tx_log_entry(&self, t: TxLogEntry, parent_id: &Identifier) -> Result<(), Error> {
|
fn save_tx_log_entry(
|
||||||
|
&mut self,
|
||||||
|
tx_in: TxLogEntry,
|
||||||
|
parent_id: &Identifier,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let tx_log_key = to_key_u64(
|
let tx_log_key = to_key_u64(
|
||||||
TX_LOG_ENTRY_PREFIX,
|
TX_LOG_ENTRY_PREFIX,
|
||||||
&mut parent_id.to_bytes().to_vec(),
|
&mut parent_id.to_bytes().to_vec(),
|
||||||
t.id as u64,
|
tx_in.id as u64,
|
||||||
);
|
);
|
||||||
self.db
|
self.db
|
||||||
.borrow()
|
.borrow()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.put_ser(&tx_log_key, &t)?;
|
.put_ser(&tx_log_key, &tx_in)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,8 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
// Now repost from cached
|
// Now repost from cached
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||||
let (_, txs) = api.retrieve_txs(true, None, Some(slate.id))?;
|
let (_, txs) = api.retrieve_txs(true, None, Some(slate.id))?;
|
||||||
api.post_tx(&txs[0].get_stored_tx().unwrap(), false)?;
|
let stored_tx = api.get_stored_tx(&txs[0])?;
|
||||||
|
api.post_tx(&stored_tx.unwrap(), false)?;
|
||||||
bh += 1;
|
bh += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
@ -214,7 +215,8 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
// Now repost from cached
|
// Now repost from cached
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||||
let (_, txs) = api.retrieve_txs(true, None, Some(slate.id))?;
|
let (_, txs) = api.retrieve_txs(true, None, Some(slate.id))?;
|
||||||
api.post_tx(&txs[0].get_stored_tx().unwrap(), false)?;
|
let stored_tx = api.get_stored_tx(&txs[0])?;
|
||||||
|
api.post_tx(&stored_tx.unwrap(), false)?;
|
||||||
bh += 1;
|
bh += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
|
@ -252,7 +252,8 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
.iter()
|
.iter()
|
||||||
.find(|t| t.tx_slate_id == Some(slate.id))
|
.find(|t| t.tx_slate_id == Some(slate.id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
sender_api.post_tx(&tx.get_stored_tx().unwrap(), false)?;
|
let stored_tx = sender_api.get_stored_tx(&tx)?;
|
||||||
|
sender_api.post_tx(&stored_tx.unwrap(), false)?;
|
||||||
let (_, wallet1_info) = sender_api.retrieve_summary_info(true, 1)?;
|
let (_, wallet1_info) = sender_api.retrieve_summary_info(true, 1)?;
|
||||||
// should be mined now
|
// should be mined now
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in a new issue