Skip to content
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
5 changes: 1 addition & 4 deletions src/cpp/daemon/py_monero_daemon_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,10 +631,7 @@ void PyMoneroSubmitTxResult::from_property_tree(const boost::property_tree::ptre
else if (key == std::string("too_big")) result->m_is_too_big = it->second.get_value<bool>();
else if (key == std::string("sanity_check_failed")) result->m_sanity_check_failed = it->second.get_value<bool>();
else if (key == std::string("credits")) result->m_credits = it->second.get_value<uint64_t>();
else if (key == std::string("top_hash")) {
std::string top_hash = it->second.data();
if (!top_hash.empty()) result->m_top_block_hash = top_hash;
}
else if (key == std::string("top_hash") && !it->second.data().empty()) result->m_top_block_hash = it->second.data();
else if (key == std::string("tx_extra_too_big")) result->m_is_tx_extra_too_big = it->second.get_value<bool>();
else if (key == std::string("nonzero_unlock_time")) result->m_is_nonzero_unlock_time = it->second.get_value<bool>();
}
Expand Down
2 changes: 1 addition & 1 deletion src/cpp/wallet/py_monero_wallet_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ bool PyMoneroTxWallet::decode_rpc_type(const std::string &rpc_type, const std::s
is_outgoing = true;
tx->m_is_confirmed = false;
tx->m_in_tx_pool = false;
tx->m_is_relayed = true;
tx->m_is_relayed = false;
tx->m_relay = true;
tx->m_is_failed = true;
tx->m_is_miner_tx = false;
Expand Down
138 changes: 137 additions & 1 deletion tests/test_monero_wallet_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
WalletType, IntegrationTestUtils,
ViewOnlyAndOfflineWalletTester,
WalletNotificationCollector,
MiningUtils, SendAndUpdateTxsTester
MiningUtils, SendAndUpdateTxsTester,
SyncWithPoolSubmitTester
)

logger: logging.Logger = logging.getLogger("TestMoneroWalletCommon")
Expand Down Expand Up @@ -264,6 +265,136 @@ def test_validate_inputs_sending_funds(self, wallet: MoneroWallet) -> None:
if str(e) != "Invalid destination address":
raise

# Can sync with txs in the pool sent from/to the same account
# TODO this test fails because wallet does not recognize pool tx sent from/to same account
@pytest.mark.skipif(TestUtils.TEST_RELAYS is False, reason="TEST_RELAYS disabled")
def test_sync_with_pool_same_accounts(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
config: MoneroTxConfig = MoneroTxConfig()
config.account_index = 0
config.address = wallet.get_primary_address()
config.amount = TxUtils.MAX_FEE * 5
config.relay = True
self._test_sync_with_pool_submit(daemon, wallet, config)

# Can sync with txs submitted and flushed from the pool
# This test takes at least 500 seconds to catchup failed txs
# (see wallet2::process_unconfirmed_transfer)
@pytest.mark.skipif(TestUtils.TEST_RELAYS is False, reason="TEST_RELAYS disabled")
@pytest.mark.skipif(TestUtils.LITE_MODE, reason="LITE_MODE enabled")
def test_sync_with_pool_submit_and_flush(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
config: MoneroTxConfig = MoneroTxConfig()
config.account_index = 2
config.address = wallet.get_primary_address()
config.amount = TxUtils.MAX_FEE * 5
config.relay = False
self._test_sync_with_pool_submit(daemon, wallet, config)

# Can sync with txs submitted and relayed from the pool
@pytest.mark.skipif(TestUtils.TEST_RELAYS is False, reason="TEST_RELAYS disabled")
@pytest.mark.skipif(TestUtils.LITE_MODE, reason="LITE_MODE enabled")
def test_sync_with_pool_submit_and_relay(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
config: MoneroTxConfig = MoneroTxConfig()
config.account_index = 2
config.address = wallet.get_primary_address()
config.amount = TxUtils.MAX_FEE * 5
config.relay = True
self._test_sync_with_pool_submit(daemon, wallet, config)

# can sync with txs relayed to the pool
@pytest.mark.skipif(TestUtils.TEST_RELAYS is False, reason="TEST_RELAYS disabled")
@pytest.mark.skipif(TestUtils.LITE_MODE, reason="LITE_MODE enabled")
def test_sync_with_pool_relay(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
# wait one time for wallet txs in the pool to clear
TestUtils.WALLET_TX_TRACKER.wait_for_txs_to_clear_pool(wallet)

# record wallet balances before submitting tx to pool
balance_before: int = wallet.get_balance()
unlocked_balance_before: int = wallet.get_unlocked_balance()

# create config
config: MoneroTxConfig = MoneroTxConfig()
config.account_index = 2
config.address = wallet.get_primary_address()
config.amount = TxUtils.MAX_FEE * 5

# create tx to relay
tx: MoneroTxWallet = wallet.create_tx(config)
assert tx.hash is not None
assert tx.full_hex is not None
assert tx.fee is not None

# create another tx using same config which would be double spend
tx_double_spend: MoneroTxWallet = wallet.create_tx(config)
assert tx_double_spend.hash is not None
assert tx_double_spend.full_hex is not None

# relay first tx directly to daemon
result: MoneroSubmitTxResult = daemon.submit_tx_hex(tx.full_hex)
assert result.is_good, "Transaction could not be submitted to the pool"

# sync wallet which updates from pool
wallet.sync()

# collect issues to report at end of test
issues: list[str] = []

# wallet should be aware of tx
fetched: MoneroTxWallet | None = wallet.get_tx(tx.hash)
assert fetched is not None, "Wallet should be aware of its tx in pool after syncing"

# test wallet balances
if unlocked_balance_before == wallet.get_unlocked_balance():
issues.append("unlocked balance should have decreased after relaying tx directly to the daemon")

if balance_before == wallet.get_balance():
issues.append("balance should have decreased after relaying tx directly to the daemon")

expected_balance: int = balance_before - tx.fee
if expected_balance != wallet.get_balance():
issues.append(f"expected balance after relaying tx directly to the daemon to be {expected_balance} but was {wallet.get_balance()}")

# submit double spend tx
result_double_spend: MoneroSubmitTxResult = daemon.submit_tx_hex(tx_double_spend.full_hex)
if result_double_spend.is_good:
daemon.flush_tx_pool(tx_double_spend.hash)
issues.append("Tx submit result should have been double spend")

# sync wallet which updates from pool
wallet.sync()

# create tx using same config which is no longer double spend
tx2: MoneroTxWallet | None = None
try:
config_copy: MoneroTxConfig = config.copy()
config_copy.relay = True
tx2 = wallet.create_tx(config_copy)
except Exception as e:
logger.warning(e)
# TODO monero-project: this fails meaning wallet did not recognize tx relayed directly to pool
issues.append("creating and sending tx through wallet should succeed after syncing wallet with pool but creates a double spend")

# submit the transaction to the pool and test
if tx2 is not None:
assert tx2.hash is not None
assert tx2.full_hex is not None
result2: MoneroSubmitTxResult = daemon.submit_tx_hex(tx2.full_hex, True)
if result2.is_double_spend:
issues.append("creating and submitting tx to daemon should succeed after syncing wallet with pool but was a double spend")
else:
assert result2.is_good

wallet.sync()
if wallet.get_tx(tx2.hash) is None:
issues.append("wallet should be aware of tx created and relayed through it after syncing with pool")

daemon.flush_tx_pool(tx2.hash)

# should be no issues
for issue in issues:
logger.warning(issue)

assert len(issues) == 0, f"test_sync_with_pool_relay has {len(issues)} issues"

# Can send to self
@pytest.mark.skipif(TestUtils.TEST_RELAYS is False, reason="TEST_RELAYS disabled")
def test_send_to_self(self, wallet: MoneroWallet) -> None:
Expand Down Expand Up @@ -3814,6 +3945,11 @@ def _test_send_and_update_txs(cls, daemon: MoneroDaemonRpc, wallet: MoneroWallet
tester: SendAndUpdateTxsTester = SendAndUpdateTxsTester(daemon, wallet, config)
tester.test()

@classmethod
def _test_sync_with_pool_submit(cls, daemon: MoneroDaemonRpc, wallet: MoneroWallet, config: MoneroTxConfig) -> None:
tester: SyncWithPoolSubmitTester = SyncWithPoolSubmitTester(daemon, wallet, config)
tester.test()

#endregion

#endregion
20 changes: 20 additions & 0 deletions tests/test_monero_wallet_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,26 @@ def test_update_locked_different_accounts(self, daemon: MoneroDaemonRpc, wallet:
def test_update_locked_different_accounts_split(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
return super().test_update_locked_different_accounts_split(daemon, wallet)

@pytest.mark.not_supported
@override
def test_sync_with_pool_same_accounts(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
return super().test_sync_with_pool_same_accounts(daemon, wallet)

@pytest.mark.not_supported
@override
def test_sync_with_pool_submit_and_flush(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
return super().test_sync_with_pool_submit_and_flush(daemon, wallet)

@pytest.mark.not_supported
@override
def test_sync_with_pool_submit_and_relay(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
return super().test_sync_with_pool_submit_and_relay(daemon, wallet)

@pytest.mark.not_supported
@override
def test_sync_with_pool_relay(self, daemon: MoneroDaemonRpc, wallet: MoneroWallet) -> None:
return super().test_sync_with_pool_relay(daemon, wallet)

#endregion

#region Tests
Expand Down
4 changes: 3 additions & 1 deletion tests/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from .sync_progress_tester import SyncProgressTester
from .sync_seed_tester import SyncSeedTester
from .send_and_update_txs_tester import SendAndUpdateTxsTester
from .sync_with_pool_submit_tester import SyncWithPoolSubmitTester

__all__ = [
'WalletUtils',
Expand Down Expand Up @@ -67,5 +68,6 @@
'WalletSyncTester',
'SyncProgressTester',
'SyncSeedTester',
'SendAndUpdateTxsTester'
'SendAndUpdateTxsTester',
'SyncWithPoolSubmitTester'
]
Loading
Loading