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

use pool cookie time instead of wall time #5

Open
wants to merge 2 commits into
base: sync-rpc-call
Choose a base branch
from

Conversation

jeffro256
Copy link

Using time(NULL) to order incoming transactions has problems because the following could happen:

  1. Wallet asks for current daemon time and daemon responds with time A
  2. Daemon system time resynchronizes and falls backwards in time to time B (B < A)
  3. Daemon add transaction T to mempool at time C (B < C < A)
  4. Wallet asks for incremental changes since time A, daemon responds
  5. Since C < A, transaction T is not sent to wallet
  6. Wallet refresh is now in inconsistent state

j-berman and others added 2 commits February 17, 2023 16:22
- `/getblocks.bin` respects the `RESTRICTED_TX_COUNT` (=100) when
returning pool txs via a restricted RPC daemon.
- A restricted RPC daemon includes a max of `RESTRICTED_TX_COUNT` txs
in the `added_pool_txs` field, and returns any remaining pool hashes
in the `remaining_added_pool_txids` field. The client then requests
the remaining txs via `/gettransactions` in chunks.
- `/gettransactions` no longer does expensive no-ops for ALL pool txs
if the client requests a subset of pool txs. Instead it searches for
the txs the client explicitly requests.
- Reset `m_pool_info_query_time` when a user:
  (1) rescans the chain (so the wallet re-requests the whole pool)
  (2) changes the daemon their wallets points to (a new daemon would
      have a different view of the pool)
- `/getblocks.bin` respects the `req.prune` field when returning
pool txs.
- Pool extension fields in response to `/getblocks.bin` are optional
with default 0'd values.
Using `time(NULL)` to order incoming transactions has problems because the following could happen:
1. Wallet asks for current daemon time and daemon responds with time A
2. Daemon system time resynchronizes and falls backwards in time to time B (B < A)
3. Daemon add transaction T to mempool at time C (B < C < A)
4. Wallet asks for incremental changes since time A, daemon responds
5. Since C < A, transaction T is not sent to wallet
6. Wallet refresh is now in inconsistent state
Copy link
Owner

@rbrunner7 rbrunner7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this PR, interesting approach. I went through the code, I think I understand it, and I think it does what you intended.

However I still claim that with the system as I implemented it, after the daemon suffers a local time change, things self-correct fast, as each connected client will only miss new pool transactions exactly once and will see those missed transactions anyway with the next block.

And with this in mind, I am not sure whether the trade-offs are favorable - rare event of daemon local time change versus added complexity to read and and write that "logical timestamp" in the DB.

Plus, if the daemon crashes, your system may result in problems, where my time-base system doesn't, because you won't be able anymore to update the DB with the new value, as @moneromooo mentioned on IRC. Tough question whether local time changes or daemon crashes are more frequent ...

But anyway, if @j-berman views this favorably, I am ready to merge.

if (m_removed_txs_by_time.size() > MAX_REMOVED)
{
auto erase_it = m_removed_txs_by_time.begin();
decltype(m_removed_txs_by_time)::iterator erase_it = m_removed_txs_by_time.begin();
std::advance(erase_it, MAX_REMOVED / 4 + 1);
m_removed_txs_by_time.erase(m_removed_txs_by_time.begin(), erase_it);
m_removed_txs_start_time = m_removed_txs_by_time.begin()->first;
MDEBUG("Erased old transactions from big removed list, leaving " << m_removed_txs_by_time.size());
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit unfortunate that we can't delete anymore within a certain time period. If you had an early burst of transactions and then a lull of a few hours you will delete pretty far back.

@@ -1957,7 +1947,7 @@ namespace cryptonote
}

m_mine_stem_txes = mine_stem_txes;
m_cookie = 0;
m_cookie = m_blockchain.get_txpool_logical_timestamp();

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was that your question on IRC, whether you can use that m_blockchain object already at the time of this init method here? I guess the answer was a sure "yes".

@j-berman
Copy link

j-berman commented Mar 3, 2023

As mentioned, the following still looks possible:

  1. Wallet asks for current daemon time and daemon responds with logical time A
  2. Daemon has an ungraceful shutdown and restarts with logical time B (B < A)
  3. Daemon add transaction T to mempool at logical time C (B < C < A)
  4. Wallet asks for incremental changes since logical time A, daemon responds
  5. Since C < A, transaction T is not sent to wallet
  6. Wallet refresh is now in inconsistent state

If I'm reading it right, I appreciate that this code only reads from/writes to the db on startup/close because another db read/write wouldn't be ideal in the pool update code, but as a result there is the issue of potential inconsistent state on crash. This could be improved by saving the logical timestamp in the mempool's on_idle loop, but the issue still remains.

As mentioned in no-wallet-left-behind, either the daemon could start responding with a session ID and the client can handle that, or if the client loses its connection to the daemon it could be sure to re-request all pool txs from that node by resetting m_pool_info_query_time in the correct places. The latter would probably be the lower hanging fruit, while the former is a safer path.

On an immediate path forward, I think @rbrunner7's point here is especially valid:

with the system as I implemented it, after the daemon suffers a local time change, things self-correct fast, as each connected client will only miss new pool transactions exactly once and will see those missed transactions anyway with the next block.

Because of this, I think we should try to move forward with monero-project#8076 as is, and can perfect it in a later PR.

@jeffro256
Copy link
Author

This could be improved by saving the logical timestamp in the mempool's on_idle loop, but the issue still remains.

Technically, you would only need to save values which users have seen, so you only need to save when the value was updated + fetched to save some reads/writes.

But at any rate, I guess I'm fine with keeping the timing as-is on the condition that the wallet is time source agnostic.

@rbrunner7
Copy link
Owner

on the condition that the wallet is time source agnostic

Not sure how you mean that, @jeffro256. You mean you see actually using the "real" daemon tool as an info leak that we have to solve still within the frame of this PR?

@jeffro256
Copy link
Author

No, just if future steady clock replacements on the daemon side are backwards compatible with wallets on this PR.

rbrunner7 pushed a commit that referenced this pull request Mar 24, 2023
multisig: fix segfault restoring encrypted multisig seed
rbrunner7 pushed a commit that referenced this pull request Mar 24, 2023
12e7c41 Merge pull request #5 from j-berman/restore-msig-encrypted-seed (Justin Berman)
848a0c0 Fix segfault restoring encrypted multisig seed (j-berman)
401f5d9 Require user ack multisig is experimental to restore (j-berman)
fc8a5d6 multisig: fix monero-project#8537 seed restore (suggestions by @UkoeHB) (j-berman)
rbrunner7 pushed a commit that referenced this pull request Jun 28, 2024
…p_speedup

src: update internal data structure to boost::bimap.
rbrunner7 pushed a commit that referenced this pull request Jun 28, 2024
…r_startup_speedup"

This reverts commit efd4e0e, reversing
changes made to a3ac4d0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants