mirror of
https://github.com/monero-project/monero.git
synced 2025-12-08 16:11:28 +09:00
Merge pull request #10153
9239d36 wallet: identify spends in pool when scanning (j-berman)
This commit is contained in:
commit
3cc9d65c93
@ -922,6 +922,11 @@ bool get_short_payment_id(crypto::hash8 &payment_id8, const tools::wallet2::pend
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t get_outgoing_amount(const cryptonote::transaction &tx, const uint64_t amount_spent)
|
||||
{
|
||||
return tx.version == 1 ? get_outs_money_amount(tx) : (amount_spent - tx.rct_signatures.txnFee);
|
||||
}
|
||||
|
||||
tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev)
|
||||
{
|
||||
tools::wallet2::tx_construction_data construction_data = ptx.construction_data;
|
||||
@ -2712,10 +2717,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
LOG_ERROR("spent funds are from different subaddress accounts; count of incoming/outgoing payments will be incorrect");
|
||||
subaddr_account = td.m_subaddr_index.major;
|
||||
subaddr_indices.insert(td.m_subaddr_index.minor);
|
||||
LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << txid);
|
||||
set_spent(it->second, height);
|
||||
if (!pool)
|
||||
{
|
||||
LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << txid);
|
||||
set_spent(it->second, height);
|
||||
if (!ignore_callbacks && 0 != m_callback)
|
||||
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
|
||||
|
||||
@ -2804,21 +2809,33 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
|
||||
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
|
||||
|
||||
if (tx_money_spent_in_ins > 0 && !pool)
|
||||
if (tx_money_spent_in_ins > 0)
|
||||
{
|
||||
uint64_t self_received = std::accumulate<decltype(tx_money_got_in_outs.begin()), uint64_t>(tx_money_got_in_outs.begin(), tx_money_got_in_outs.end(), 0,
|
||||
[&subaddr_account] (uint64_t acc, const std::pair<cryptonote::subaddress_index, uint64_t>& p)
|
||||
{
|
||||
return acc + (p.first.major == *subaddr_account ? p.second : 0);
|
||||
});
|
||||
process_outgoing(txid, tx, height, ts, tx_money_spent_in_ins, self_received, *subaddr_account, subaddr_indices);
|
||||
// if sending to yourself at the same subaddress account, set the outgoing payment amount to 0 so that it's less confusing
|
||||
if (tx_money_spent_in_ins == self_received + fee)
|
||||
if (!pool)
|
||||
{
|
||||
auto i = m_confirmed_txs.find(txid);
|
||||
THROW_WALLET_EXCEPTION_IF(i == m_confirmed_txs.end(), error::wallet_internal_error,
|
||||
"confirmed tx wasn't found: " + string_tools::pod_to_hex(txid));
|
||||
i->second.m_change = self_received;
|
||||
process_outgoing(txid, tx, height, ts, tx_money_spent_in_ins, self_received, *subaddr_account, subaddr_indices);
|
||||
// if sending to yourself at the same subaddress account, set the outgoing payment amount to 0 so that it's less confusing
|
||||
if (tx_money_spent_in_ins == self_received + fee)
|
||||
{
|
||||
auto i = m_confirmed_txs.find(txid);
|
||||
THROW_WALLET_EXCEPTION_IF(i == m_confirmed_txs.end(), error::wallet_internal_error,
|
||||
"confirmed tx wasn't found: " + string_tools::pod_to_hex(txid));
|
||||
i->second.m_change = self_received;
|
||||
}
|
||||
}
|
||||
else if (!m_unconfirmed_txs.count(txid))
|
||||
{
|
||||
// Add to unconfirmed txs if not already there (e.g. restoring wallet, or running the wallet in parallel to the sending wallet w/same seed)
|
||||
add_unconfirmed_tx(txid, tx, tx_money_spent_in_ins, {}/*don't know dests*/, crypto::null_hash/*don't know payment_id*/, self_received, *subaddr_account, subaddr_indices);
|
||||
auto i = m_unconfirmed_txs.find(txid);
|
||||
THROW_WALLET_EXCEPTION_IF(i == m_unconfirmed_txs.end(), error::wallet_internal_error,
|
||||
"unconfirmed tx wasn't found: " + string_tools::pod_to_hex(txid));
|
||||
i->second.m_amount_out = get_outgoing_amount(tx, tx_money_spent_in_ins);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2967,10 +2984,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
|
||||
// wallet (eg, we're a cold wallet and the hot wallet sent it). For RCT transactions,
|
||||
// we only see 0 input amounts, so have to deduce amount out from other parameters.
|
||||
entry.first->second.m_amount_in = spent;
|
||||
if (tx.version == 1)
|
||||
entry.first->second.m_amount_out = get_outs_money_amount(tx);
|
||||
else
|
||||
entry.first->second.m_amount_out = spent - tx.rct_signatures.txnFee;
|
||||
entry.first->second.m_amount_out = get_outgoing_amount(tx, spent);
|
||||
entry.first->second.m_change = received;
|
||||
|
||||
std::vector<tx_extra_field> tx_extra_fields;
|
||||
@ -4081,6 +4095,18 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
|
||||
// Lighwallet refresh done
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_first_refresh_done)
|
||||
{
|
||||
// We want to process the whole pool again, in case we identify received outputs in the chain we might have spent in the pool
|
||||
m_pool_info_query_time = 0;
|
||||
m_scanned_pool_txs[0].clear();
|
||||
m_scanned_pool_txs[1].clear();
|
||||
// Clear unconfirmed (received) payments because the data is 100% recovered when scanning
|
||||
m_unconfirmed_payments.clear();
|
||||
// Don't clear unconfirmed (sent) txs because some data is not recover-able when scanning (dests)
|
||||
}
|
||||
|
||||
received_money = false;
|
||||
blocks_fetched = 0;
|
||||
uint64_t added_blocks = 0;
|
||||
@ -7475,9 +7501,9 @@ uint64_t wallet2::select_transfers(uint64_t needed_money, std::vector<size_t> un
|
||||
return found_money;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices)
|
||||
void wallet2::add_unconfirmed_tx(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices)
|
||||
{
|
||||
unconfirmed_transfer_details& utd = m_unconfirmed_txs[cryptonote::get_transaction_hash(tx)];
|
||||
unconfirmed_transfer_details& utd = m_unconfirmed_txs[txid];
|
||||
utd.m_amount_in = amount_in;
|
||||
utd.m_amount_out = 0;
|
||||
for (const auto &d: dests)
|
||||
@ -7590,7 +7616,7 @@ void wallet2::commit_tx(pending_tx& ptx)
|
||||
for(size_t idx: ptx.selected_transfers)
|
||||
amount_in += m_transfers[idx].amount();
|
||||
}
|
||||
add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
|
||||
add_unconfirmed_tx(txid, ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
|
||||
if (store_tx_info() && ptx.tx_key != crypto::null_skey)
|
||||
{
|
||||
m_tx_keys[txid] = ptx.tx_key;
|
||||
|
||||
@ -1875,7 +1875,7 @@ private:
|
||||
bool prepare_file_names(const std::string& file_path);
|
||||
void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height);
|
||||
void process_outgoing(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height, uint64_t ts, uint64_t spent, uint64_t received, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices);
|
||||
void add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices);
|
||||
void add_unconfirmed_tx(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices);
|
||||
void generate_genesis(cryptonote::block& b) const;
|
||||
void check_genesis(const crypto::hash& genesis_hash) const; //throws
|
||||
bool generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const;
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import print_function
|
||||
import json
|
||||
import random
|
||||
|
||||
"""Test multisig transfers
|
||||
@ -408,10 +409,37 @@ class MultisigTest():
|
||||
assert len(res.tx_hash_list) == 1
|
||||
txid = res.tx_hash_list[0]
|
||||
|
||||
# Retrieve spent key images from daemon
|
||||
res = daemon.get_transactions([txid], decode_as_json = True)
|
||||
assert len(res.txs) == 1
|
||||
tx = res.txs[0]
|
||||
assert tx.tx_hash == txid
|
||||
assert len(tx.as_json) > 0
|
||||
try:
|
||||
j = json.loads(tx.as_json)
|
||||
except:
|
||||
j = None
|
||||
assert j
|
||||
assert len(j['vin']) >= 1
|
||||
spent_key_images = [vin['key']['k_image'] for vin in j['vin']]
|
||||
assert len(spent_key_images) == len(j['vin'])
|
||||
|
||||
for i in range(len(self.wallet)):
|
||||
# Check if the wallet knows about any spent key images (all signers *should*, non-signers *might*)
|
||||
is_a_signer = len([x for x in signers if x == i]) > 0
|
||||
knows_key_image = False
|
||||
for ki in spent_key_images:
|
||||
try:
|
||||
res = self.wallet[i].frozen(ki)
|
||||
knows_key_image = True
|
||||
except AssertionError:
|
||||
if is_a_signer:
|
||||
raise ValueError('Signer should know about spent key image')
|
||||
pass
|
||||
self.wallet[i].refresh()
|
||||
res = self.wallet[i].get_transfers()
|
||||
assert len([x for x in (res['pending'] if 'pending' in res else []) if x.txid == txid]) == (1 if i == signers[-1] else 0)
|
||||
# Any wallet that knows about any spent key images should be able to detect the spend in the pool
|
||||
assert len([x for x in (res['pending'] if 'pending' in res else []) if x.txid == txid]) == (1 if knows_key_image else 0)
|
||||
assert len([x for x in (res['out'] if 'out' in res else []) if x.txid == txid]) == 0
|
||||
|
||||
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
|
||||
@ -507,9 +535,13 @@ class MultisigTest():
|
||||
txid = res.tx_hash_list[0]
|
||||
|
||||
for i in range(len(self.wallet)):
|
||||
# Make sure wallet knows about the key image
|
||||
frozen = self.wallet[i].frozen(ki).frozen
|
||||
assert not frozen
|
||||
self.wallet[i].refresh()
|
||||
res = self.wallet[i].get_transfers()
|
||||
assert len([x for x in (res['pending'] if 'pending' in res else []) if x.txid == txid]) == (1 if i == signers[-1] else 0)
|
||||
# Since all wallets should have key image, all wallets should be able to detect the spend in the pool
|
||||
assert len([x for x in (res['pending'] if 'pending' in res else []) if x.txid == txid]) == 1
|
||||
assert len([x for x in (res['out'] if 'out' in res else []) if x.txid == txid]) == 0
|
||||
|
||||
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
|
||||
|
||||
@ -58,6 +58,17 @@ def diff_incoming_transfers(actual_transfers, expected_transfers):
|
||||
# wallet2 m_transfers container is ordered and order should be the same across rescans
|
||||
diff_transfers(actual_transfers, expected_transfers, ignore_order = False)
|
||||
|
||||
def restore_wallet(wallet, seed, restore_height = 0, filename = '', password = ''):
|
||||
try: wallet.close_wallet()
|
||||
except: pass
|
||||
if filename != '':
|
||||
util_resources.remove_wallet_files(filename)
|
||||
wallet.auto_refresh(enable = False)
|
||||
wallet.restore_deterministic_wallet(seed = seed, restore_height = restore_height, filename = filename, password = password)
|
||||
res = wallet.get_transfers()
|
||||
assert not 'in' in res or len(res['in']) == 0
|
||||
assert not 'out' in res or len(res.out) == 0
|
||||
|
||||
class TransferTest():
|
||||
def run_test(self):
|
||||
self.reset()
|
||||
@ -78,6 +89,7 @@ class TransferTest():
|
||||
self.check_background_sync()
|
||||
self.check_background_sync_reorg_recovery()
|
||||
self.check_subaddress_lookahead()
|
||||
self.check_pool_scanner()
|
||||
|
||||
def reset(self):
|
||||
print('Resetting blockchain')
|
||||
@ -265,6 +277,7 @@ class TransferTest():
|
||||
assert len(res.multisig_txset) == 0
|
||||
assert len(res.unsigned_txset) == 0
|
||||
tx_blob = res.tx_blob
|
||||
running_balances[0] -= 1000000000000 + fee
|
||||
|
||||
res = daemon.send_raw_transaction(tx_blob)
|
||||
assert res.not_relayed == False
|
||||
@ -306,7 +319,6 @@ class TransferTest():
|
||||
|
||||
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
|
||||
res = daemon.getlastblockheader()
|
||||
running_balances[0] -= 1000000000000 + fee
|
||||
running_balances[0] += res.block_header.reward
|
||||
self.wallet[1].refresh()
|
||||
running_balances[1] += 1000000000000
|
||||
@ -1154,14 +1166,6 @@ class TransferTest():
|
||||
except: invalid_password = True
|
||||
assert invalid_password
|
||||
|
||||
def restore_wallet(wallet, seed, filename = '', password = ''):
|
||||
wallet.close_wallet()
|
||||
if filename != '':
|
||||
util_resources.remove_wallet_files(filename)
|
||||
wallet.restore_deterministic_wallet(seed = seed, filename = filename, password = password)
|
||||
wallet.auto_refresh(enable = False)
|
||||
assert wallet.get_transfers() == {}
|
||||
|
||||
def assert_correct_transfers(wallet, expected_transfers, expected_inc_transfers, expected_balance):
|
||||
diff_transfers(wallet.get_transfers(), expected_transfers)
|
||||
diff_incoming_transfers(wallet.incoming_transfers(transfer_type = 'all'), expected_inc_transfers)
|
||||
@ -1171,10 +1175,7 @@ class TransferTest():
|
||||
# We're testing a sweep because it makes sure background sync can
|
||||
# properly pick up txs which do not have a change output back to sender.
|
||||
sender_wallet = self.wallet[0]
|
||||
try: sender_wallet.close_wallet()
|
||||
except: pass
|
||||
sender_wallet.restore_deterministic_wallet(seed = seeds[0])
|
||||
sender_wallet.auto_refresh(enable = False)
|
||||
restore_wallet(sender_wallet, seeds[0])
|
||||
sender_wallet.refresh()
|
||||
res = sender_wallet.incoming_transfers(transfer_type = 'available')
|
||||
unlocked = [x for x in res.transfers if x.unlocked and x.amount > 0]
|
||||
@ -1193,10 +1194,7 @@ class TransferTest():
|
||||
|
||||
# set up receiver_wallet
|
||||
receiver_wallet = self.wallet[1]
|
||||
try: receiver_wallet.close_wallet()
|
||||
except: pass
|
||||
receiver_wallet.restore_deterministic_wallet(seed = seeds[1])
|
||||
receiver_wallet.auto_refresh(enable = False)
|
||||
restore_wallet(receiver_wallet, seeds[1])
|
||||
receiver_wallet.refresh()
|
||||
res = receiver_wallet.get_transfers()
|
||||
in_len = 0 if 'in' not in res else len(res['in'])
|
||||
@ -1267,7 +1265,7 @@ class TransferTest():
|
||||
|
||||
# Check stopping a wallet with wallet files saved to disk
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
sender_wallet.start_background_sync()
|
||||
@ -1279,7 +1277,7 @@ class TransferTest():
|
||||
|
||||
# Close wallet while background syncing, then reopen
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
sender_wallet.start_background_sync()
|
||||
@ -1293,7 +1291,7 @@ class TransferTest():
|
||||
|
||||
# Close wallet while syncing normally, then reopen
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
sender_wallet.refresh()
|
||||
@ -1305,7 +1303,7 @@ class TransferTest():
|
||||
|
||||
# Create background cache using custom password, then use it to sync, then reopen main wallet
|
||||
for background_cache_password in ['background_password', '']:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
sender_wallet.setup_background_sync(background_sync_type = custom_password, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
@ -1321,7 +1319,7 @@ class TransferTest():
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
# Check that main wallet keeps background cache encrypted with custom password in sync
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = 'background_password')
|
||||
sender_wallet.refresh()
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
@ -1330,7 +1328,7 @@ class TransferTest():
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
# Try using wallet password as custom background password
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
same_password = False
|
||||
@ -1342,7 +1340,7 @@ class TransferTest():
|
||||
|
||||
# Turn off background sync
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
if background_sync_type == custom_password:
|
||||
@ -1367,8 +1365,7 @@ class TransferTest():
|
||||
sender_wallet.open_wallet('test1', password = 'test_password')
|
||||
|
||||
# Sanity check against outgoing wallet restored at height 0
|
||||
sender_wallet.close_wallet()
|
||||
sender_wallet.restore_deterministic_wallet(seed = seeds[0], restore_height = 0)
|
||||
restore_wallet(sender_wallet, seeds[0], restore_height = 0)
|
||||
sender_wallet.refresh()
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
@ -1417,7 +1414,7 @@ class TransferTest():
|
||||
assert receiver_wallet.get_balance().balance == expected_receiver_balance
|
||||
|
||||
# Check a fresh incoming wallet with wallet files saved to disk and encrypted with password
|
||||
restore_wallet(receiver_wallet, seeds[1], 'test2', 'test_password')
|
||||
restore_wallet(receiver_wallet, seeds[1], filename = 'test2', password = 'test_password')
|
||||
receiver_wallet.setup_background_sync(background_sync_type = reuse_password, wallet_password = 'test_password')
|
||||
receiver_wallet.start_background_sync()
|
||||
receiver_wallet.refresh()
|
||||
@ -1427,7 +1424,7 @@ class TransferTest():
|
||||
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
|
||||
|
||||
# Close receiver's wallet while background sync is enabled then reopen
|
||||
restore_wallet(receiver_wallet, seeds[1], 'test2', 'test_password')
|
||||
restore_wallet(receiver_wallet, seeds[1], filename = 'test2', password = 'test_password')
|
||||
receiver_wallet.setup_background_sync(background_sync_type = reuse_password, wallet_password = 'test_password')
|
||||
receiver_wallet.start_background_sync()
|
||||
receiver_wallet.refresh()
|
||||
@ -1440,8 +1437,7 @@ class TransferTest():
|
||||
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
|
||||
|
||||
# Sanity check against incoming wallet restored at height 0
|
||||
receiver_wallet.close_wallet()
|
||||
receiver_wallet.restore_deterministic_wallet(seed = seeds[1], restore_height = 0)
|
||||
restore_wallet(receiver_wallet, seeds[1], restore_height = 0)
|
||||
receiver_wallet.refresh()
|
||||
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
|
||||
|
||||
@ -1558,5 +1554,62 @@ class TransferTest():
|
||||
assert balance_info_0_999['blocks_to_unlock'] == 9
|
||||
assert balance_info_0_999['time_to_unlock'] == 0
|
||||
|
||||
def check_pool_scanner(self):
|
||||
daemon = Daemon()
|
||||
|
||||
print('Checking pool scanner')
|
||||
|
||||
# Sync first wallet
|
||||
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
|
||||
self.wallet[0].refresh()
|
||||
|
||||
# Open second wallet with same seed as first
|
||||
restore_wallet(self.wallet[1], seeds[0])
|
||||
assert self.wallet[0].get_address().address == self.wallet[1].get_address().address
|
||||
|
||||
# Send to another wallet, spending from first wallet
|
||||
dst = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1000000000000}
|
||||
res = self.wallet[0].transfer([dst])
|
||||
assert len(res.tx_hash) == 32*2
|
||||
txid = res.tx_hash
|
||||
assert res.fee > 0
|
||||
fee = res.fee
|
||||
|
||||
# Sync both wallets
|
||||
self.wallet[0].refresh()
|
||||
self.wallet[1].refresh()
|
||||
|
||||
# Both wallets should be able to detect the spend tx in the pool
|
||||
res_wallet0 = self.wallet[0].get_transfers()
|
||||
res_wallet1 = self.wallet[1].get_transfers()
|
||||
|
||||
# After restoring, should still be able to detect the spend in the pool
|
||||
restore_wallet(self.wallet[1], seed = seeds[0])
|
||||
self.wallet[1].refresh()
|
||||
res_wallet1_after_restore = self.wallet[1].get_transfers()
|
||||
|
||||
for res in [res_wallet0, res_wallet1, res_wallet1_after_restore]:
|
||||
assert len(res.pending) == 1
|
||||
assert not 'pool' in res or len(res.pool) == 0
|
||||
assert not 'failed' in res or len(res.failed) == 0
|
||||
e = res.pending[0]
|
||||
assert e.txid == txid
|
||||
assert e.payment_id in ['', '0000000000000000']
|
||||
assert e.type == 'pending'
|
||||
assert e.unlock_time == 0
|
||||
assert e.subaddr_index.major == 0
|
||||
assert e.subaddr_indices == [{'major': 0, 'minor': 0}]
|
||||
assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||
assert e.double_spend_seen == False
|
||||
assert not 'confirmations' in e or e.confirmations == 0
|
||||
assert e.amount == dst['amount']
|
||||
assert e.fee == fee
|
||||
|
||||
# Mine a block to mine the tx and reset 2nd wallet
|
||||
daemon.generateblocks('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 1)
|
||||
restore_wallet(self.wallet[1], seeds[1])
|
||||
self.wallet[1].refresh()
|
||||
self.wallet[0].refresh()
|
||||
|
||||
if __name__ == '__main__':
|
||||
TransferTest().run_test()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user