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

evm tx skips a block before confirmation #2286

Open
shunjizhan opened this issue May 8, 2023 · 7 comments
Open

evm tx skips a block before confirmation #2286

shunjizhan opened this issue May 8, 2023 · 7 comments

Comments

@shunjizhan
Copy link

Problem

When sending tx at block X, it is supposed to be mined at block X + 1, assuming no congestion. However, there seems to be a shared issue among substrate evms: such tx is usuallly mined at block X + 2, which basically mysteriously skipped a block.

This causes a terrible UX. For 12s block time, expected confimation time should be 12/2 = 6s on average, which is great. However, with the current issue, expected confirmation time increases to 12/2 + 12 = 18s. This is super slow compared to these alternative evm networks, which usually confirms in less than 5s, sometimes even 2s.

18s confirmation time could be a huge blocker for mass adoption. Users will escape.

Reproduce Script

https://github.com/shunjizhan/tx-confirmation-test

@crystalin
Copy link
Collaborator

crystalin commented May 8, 2023

This is how currently the Polkadot/Substrate mechanism works for parachains. paritytech/polkadot#5022 will introduce a new mechanism that will allow shorter block time and bigger blocks also.

Currently, a block is produced when it receives the relay block specifying the previous parachain has been included in the relay. The inclusion of a parachain block takes 2 relay blocks (2* 6s) so 12s but because the parachain block needs to be created as fast as possible to be included, here is what happens:

  1. parachain receives relay block n°123 (0s)
  2. parachain produces para block n°1 (0s)
  3. relay block n°124 checks para block n°1 (6s)
  4. relay block n°125 includes para block n°1 (12s) => block n°1 is marked as "best"
  5. parachain receives relay block n°124 (12s)
  6. parachain produces para block n°2 (12s)
  7. relay block n°124 checks para block n°2 (18s)
  8. relay block n°125 includes para block n°2 (24s) => block n°2 is marked as "best"

So every transaction that is sent after the block n°1 (between 0 and 12s) will wait between 12 and 24s before being considered "best" and returned by the API.

@shunjizhan
Copy link
Author

shunjizhan commented May 8, 2023

gotcha, thanks for your clarification!

So basically it takes 2 extra relay blocks (2 * 6s = 12s) for the para block to be considered "best", before it is returned by api.

I was wondering if it makes sense to consider a tx to be "mined" at step 6, and return the receipt? I am assuming step 7 and 8 is to prevent forking, but in the normal evm context, the tx receipt can be found as soon as it's mined. Current substrate behavior looks like it uses safe tag as the default behavior.

@shunjizhan
Copy link
Author

shunjizhan commented May 8, 2023

I think a more optimized behavior would be:

  • default: return receipt as soon as it's mined. (similar to "latest" tag, takes 0-12s)
  • safe way: alternatively we can pass "safe" tag when getting a receipt, this will be the current substrate behavior, only return after 2 relay blocks (takes 12-24s).
  • finalize: same for "finalized" tag

In this way users will be able to feel "instant confirmation" by default, whereas projects still have the option for "safe" tag if there business logic requires so.

@crystalin
Copy link
Collaborator

I think a more optimized behavior would be:

  • default: return receipt as soon as it's mined. (similar to "latest" tag)
  • safe way: alternatively we can pass "safe" tag when getting a receipt, this will be the current substrate behavior, only return after 2 relay blocks.
  • finalize: same for "finalized" tag

@tgmichel or @sorpaas , what do you think about it ? I remember we thought about doing that at the very beginning of frontier but chose not to. I don't see a reason not to do it so now

@crystalin crystalin reopened this May 8, 2023
@shunjizhan
Copy link
Author

shunjizhan commented May 8, 2023

I personally feel like 'latest' and 'finalized' state would be enough for most use cases:

  • if smooth UX is more important, such as a DEX, or a simple token transfer, use 'latest'
  • if 100% safety is required, such as a bridge, use 'finalized'

'safe' state (current behavior) is somehow in the middle: not that smooth, and not that safe 😂

@tgmichel
Copy link
Contributor

tgmichel commented May 8, 2023

There are some nuances in the parachain context regarding best - as described in polkadot-evm/frontier#423.

In the above PR, a special SyncStrategy was introduced to prevent a different pace between the sync worker and the rest of the rpc impl, which mostly uses what's considered to be the best block as a reference. In other words, with the introduction of SyncStrategy the ethereum data (block and transactions) is mapped on best, and not before, so it will not be available until then.

Give me some time to think if there is a solution for providing faster receipts that is compatible with what I just mentioned.

Edit: the most inmediate/obvious solution I think is to remove SyncStrategy altogether and do the necessary checks at impl level for eth_getTransactionByHash, eth_getTransactionReceipt etc, introduce this non-standard tag param in the necessary rpcs, and then set a default value of this tag to safe. Note that we cannot set a default behaviour to latest because that will break use cases like the one described in the above PR. This way default behaviour should be equivalent to what's currently deployed, and projects with latest needs can still use the optional non-standard param.

@shunjizhan
Copy link
Author

shunjizhan commented May 9, 2023

If my understanding is correct, after the tx is mined, we will have to wait 12s for relay chain validation before the new state is applied. So even if we support latest tag, it's different that normal evm latest tag, which means "tx is mined and state changed". However, in parachain context latest only means "tx is mined and state will be updated in 12s, please wait 12s for next operation".

So the current behavior in above PR's example is:

  • Bob has 0 token.
  • Alice sends Bob 1 token in transaction A at block X
  • Dapp polls receipt for A until it's mined (block X + 1), and relay chain validated it (12s). So receipt is available on block X + 1 + 12s, which is block X + 2.
  • Dapp sends from Bob to Charlie in transaction B at block X + 2
  • transaction B succeed at block X + 4

But this doesn't seem to be a "standard" evm behavior, where we should be able to send next tx on next block, with the new state already applied, so the expected behavior is:

  • Alice sends Bob 1 token in transaction A at block X
  • Dapp sends from Bob to Charlie in transaction B at block X + 1
  • transaction B succeed at block X + 2

I understand that in the engineering point of view, there might be some technical limitation. But just saying in a user's perspective (as a real moonbeam user myself), such X + 2 behavior is very laggy compared to other alternative evm networks (12-24s vs 3-5s confirmation time). So I was wondering if there is any possible solution to achieve the "expected behavior" mentioned above

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

No branches or pull requests

3 participants