aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/wallet.cpp5
-rw-r--r--src/wallet/api/wallet.h1
-rw-r--r--src/wallet/wallet2.cpp81
-rw-r--r--src/wallet/wallet2.h26
-rw-r--r--src/wallet/wallet2_api.h6
5 files changed, 109 insertions, 10 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 134ea601c..d21d8b900 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -469,7 +469,10 @@ uint64_t WalletImpl::blockChainHeight() const
{
return m_wallet->get_blockchain_current_height();
}
-
+uint64_t WalletImpl::approximateBlockChainHeight() const
+{
+ return m_wallet->get_approximate_blockchain_height();
+}
uint64_t WalletImpl::daemonBlockChainHeight() const
{
std::string err;
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 372d6efd7..02a46da8c 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -76,6 +76,7 @@ public:
uint64_t balance() const;
uint64_t unlockedBalance() const;
uint64_t blockChainHeight() const;
+ uint64_t approximateBlockChainHeight() const;
uint64_t daemonBlockChainHeight() const;
uint64_t daemonBlockChainTargetHeight() const;
bool synchronized() const;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 02346e0eb..15a134257 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -631,11 +631,16 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
}
// Don't try to extract tx public key if tx has no ouputs
- if (!tx.vout.empty())
+ size_t pk_index = 0;
+ while (!tx.vout.empty())
{
+ // if tx.vout is not empty, we loop through all tx pubkeys
+
tx_extra_pub_key pub_key_field;
- if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field))
+ if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++))
{
+ if (pk_index > 1)
+ break;
LOG_PRINT_L0("Public key wasn't found in the transaction extra. Skipping transaction " << txid());
if(0 != m_callback)
m_callback->on_skip_transaction(height, tx);
@@ -2004,6 +2009,19 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const std::stri
m_account_public_address = m_account.get_keys().m_account_address;
m_watch_only = false;
+ if(m_refresh_from_block_height == 0 && !recover){
+ // Wallets created offline don't know blockchain height.
+ // Set blockchain height calculated from current date/time
+ // -1 month for fluctuations in block time and machine date/time setup.
+ // avg seconds per block
+ const int seconds_per_block = DIFFICULTY_TARGET_V2;
+ // ~num blocks per month
+ const uint64_t blocks_per_month = 60*60*24*30/seconds_per_block;
+ uint64_t approx_blockchain_height = get_approximate_blockchain_height();
+ if(approx_blockchain_height > 0) {
+ m_refresh_from_block_height = approx_blockchain_height - blocks_per_month;
+ }
+ }
bool r = store_keys(m_keys_file, password, false);
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
@@ -2948,6 +2966,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
unsigned_tx_set txs;
for (auto &tx: ptx_vector)
txs.txes.push_back(tx.construction_data);
+ txs.transfers = m_transfers;
std::string s = obj_to_json_str(txs);
if (s.empty())
return false;
@@ -2958,7 +2977,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + s);
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::function<bool(const unsigned_tx_set&)> accept_func)
+bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, std::function<bool(const unsigned_tx_set&)> accept_func)
{
std::string s;
boost::system::error_code errcode;
@@ -2993,6 +3012,8 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s
return false;
}
+ import_outputs(exported_txs.transfers);
+
// sign the transactions
signed_tx_set signed_txes;
for (size_t n = 0; n < exported_txs.txes.size(); ++n)
@@ -3038,6 +3059,17 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s
ptx.tx_key = rct::rct2sk(rct::identity()); // don't send it back to the untrusted view wallet
ptx.dests = sd.splitted_dsts;
ptx.construction_data = sd;
+
+ txs.push_back(ptx);
+ }
+
+ // add key images
+ signed_txes.key_images.resize(m_transfers.size());
+ for (size_t i = 0; i < m_transfers.size(); ++i)
+ {
+ if (!m_transfers[i].m_key_image_known)
+ LOG_PRINT_L0("WARNING: key image not known in signing wallet at index " << i);
+ signed_txes.key_images[i] = m_transfers[i].m_key_image;
}
s = obj_to_json_str(signed_txes);
@@ -3087,6 +3119,23 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
return false;
}
+ // import key images
+ if (signed_txs.key_images.size() > m_transfers.size())
+ {
+ LOG_PRINT_L1("More key images returned that we know outputs for");
+ return false;
+ }
+ for (size_t i = 0; i < signed_txs.key_images.size(); ++i)
+ {
+ transfer_details &td = m_transfers[i];
+ if (td.m_key_image_known && td.m_key_image != signed_txs.key_images[i])
+ LOG_PRINT_L0("WARNING: imported key image differs from previously known key image at index " << i << ": trusting imported one");
+ td.m_key_image = signed_txs.key_images[i];
+ m_key_images[m_transfers[i].m_key_image] = i;
+ td.m_key_image_known = true;
+ m_pub_keys[m_transfers[i].get_public_key()] = i;
+ }
+
ptx = signed_txs.ptx;
return true;
@@ -4578,6 +4627,21 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
return resp_t.result.target_height;
}
+uint64_t wallet2::get_approximate_blockchain_height() const
+{
+ if (m_testnet) return 0;
+ // time of v2 fork
+ const time_t fork_time = 1458748658;
+ // v2 fork block
+ const uint64_t fork_block = 1009827;
+ // avg seconds per block
+ const int seconds_per_block = DIFFICULTY_TARGET_V2;
+ // Calculated blockchain height
+ uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
+ LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
+ return approx_blockchain_height;
+}
+
void wallet2::set_tx_note(const crypto::hash &txid, const std::string &note)
{
m_tx_notes[txid] = note;
@@ -4717,6 +4781,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
for (size_t n = 0; n < signed_key_images.size(); ++n)
{
m_transfers[n].m_key_image = signed_key_images[n].first;
+ m_key_images[m_transfers[n].m_key_image] = n;
m_transfers[n].m_key_image_known = true;
}
@@ -4777,17 +4842,19 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail
std::vector<tx_extra_field> tx_extra_fields;
tx_extra_pub_key pub_key_field;
- THROW_WALLET_EXCEPTION_IF(td.m_tx.vout.empty(), error::wallet_internal_error, "tx with no outputs at index " + i);
+ THROW_WALLET_EXCEPTION_IF(td.m_tx.vout.empty(), error::wallet_internal_error, "tx with no outputs at index " + boost::lexical_cast<std::string>(i));
THROW_WALLET_EXCEPTION_IF(!parse_tx_extra(td.m_tx.extra, tx_extra_fields), error::wallet_internal_error,
- "Transaction extra has unsupported format at index " + i);
+ "Transaction extra has unsupported format at index " + boost::lexical_cast<std::string>(i));
THROW_WALLET_EXCEPTION_IF(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field), error::wallet_internal_error,
- "Public key wasn't found in the transaction extra at index " + i);
+ "Public key wasn't found in the transaction extra at index " + boost::lexical_cast<std::string>(i));
cryptonote::generate_key_image_helper(m_account.get_keys(), pub_key_field.pub_key, td.m_internal_output_index, in_ephemeral, td.m_key_image);
td.m_key_image_known = true;
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key,
- error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + i);
+ error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i));
+ m_key_images[td.m_key_image] = m_transfers.size();
+ m_pub_keys[td.get_public_key()] = m_transfers.size();
m_transfers.push_back(td);
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 417e754a5..6168873d5 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -133,6 +133,21 @@ namespace tools
bool is_rct() const { return m_rct; }
uint64_t amount() const { return m_amount; }
const crypto::public_key &get_public_key() const { return boost::get<const cryptonote::txout_to_key>(m_tx.vout[m_internal_output_index].target).key; }
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELD(m_block_height)
+ FIELD(m_tx)
+ FIELD(m_txid)
+ FIELD(m_internal_output_index)
+ FIELD(m_global_output_index)
+ FIELD(m_spent)
+ FIELD(m_spent_height)
+ FIELD(m_key_image)
+ FIELD(m_mask)
+ FIELD(m_amount)
+ FIELD(m_rct)
+ FIELD(m_key_image_known)
+ END_SERIALIZE()
};
struct payment_details
@@ -226,16 +241,20 @@ namespace tools
struct unsigned_tx_set
{
std::vector<tx_construction_data> txes;
+ wallet2::transfer_container transfers;
BEGIN_SERIALIZE_OBJECT()
FIELD(txes)
+ FIELD(transfers)
END_SERIALIZE()
};
struct signed_tx_set
{
std::vector<pending_tx> ptx;
+ std::vector<crypto::key_image> key_images;
BEGIN_SERIALIZE_OBJECT()
FIELD(ptx)
+ FIELD(key_images)
END_SERIALIZE()
};
@@ -377,7 +396,7 @@ namespace tools
void commit_tx(pending_tx& ptx_vector);
void commit_tx(std::vector<pending_tx>& ptx_vector);
bool save_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename);
- bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::function<bool(const unsigned_tx_set&)> accept_func = NULL);
+ bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, std::function<bool(const unsigned_tx_set&)> accept_func = NULL);
bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
std::vector<pending_tx> create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon);
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon);
@@ -492,7 +511,10 @@ namespace tools
std::string get_daemon_address() const;
uint64_t get_daemon_blockchain_height(std::string& err);
uint64_t get_daemon_blockchain_target_height(std::string& err);
-
+ /*!
+ * \brief Calculates the approximate blockchain height from current date/time.
+ */
+ uint64_t get_approximate_blockchain_height() const;
std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool trusted_daemon);
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f);
std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon);
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 6fe15d1e3..e624ffa69 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -282,6 +282,12 @@ struct Wallet
virtual uint64_t blockChainHeight() const = 0;
/**
+ * @brief approximateBlockChainHeight - returns approximate blockchain height calculated from date/time
+ * @return
+ */
+ virtual uint64_t approximateBlockChainHeight() const = 0;
+
+ /**
* @brief daemonBlockChainHeight - returns daemon blockchain height
* @return 0 - in case error communicating with the daemon.
* status() will return Status_Error and errorString() will return verbose error description