wormhole-foundation / wormhole

A reference implementation for the Wormhole blockchain interoperability protocol.
https://wormhole.com
Other
1.67k stars 687 forks source link

As an integrator, I want to get signed EVM messages at and earlier than finality #1660

Closed evan-gray closed 1 year ago

evan-gray commented 2 years ago

Expected Behavior

For chains which feature finality but not instant finality (Ethereum, Moonbeam, Polygon, etc), I should have the option to accept the risk of emitting a message prior to finality. For chains that have explicit block statuses, e.g. how post-merge Ethereum has Unfinalized and Unfinalized (Safe), I should be able to specify at which status I want my message emitted.

Furthermore, the default postMessage behavior should be to wait for finality and not longer. It doesn't make sense to wait for 1 block after a finalized block. This would make explainer pages like https://book.wormhole.com/reference/contracts.html#blockchain-finality-recommendations only necessary for advanced integrators who want to go faster, into unsafe territory.

Current Behavior

The EVM watcher puts all messages into a pending queue, which only releases messages after their block + consistency has been finalized. Even on the lowest consistency, 1, chains in which blocks are final require waiting until the following final block.

Possible Solution

Given that the existing EVM spec has consistency as a uint8, a 'magic number' could be specified to represent these special state exceptions for chains. For example:

Then, when the watcher receives a message with the consistency set to 200, it could instantly publish it instead of adding it to the pending queue. To handle achieving faster finality without unnecessarily waiting additional blocks, for any other values the watcher could use minConfirmations (and probably rename that finalityConfirmations or something). This could be set to 0 for all chains except for BSC which 15 is recommended.

That leaves the only odd case of 201 on Ethereum. Since every epoch should yield a new final batch and a safe batch, the watcher could leave the "Safe" number 201 which could be checked in the pending loop on new blocks and fall into a new, special path which uses getBlock("safe").

tbjump commented 2 years ago

I propose allocating the entire range of 200-255 (inclusive) of consistency_level for magic numbers and have the guardians not process any messages with consistency_level in that range where a magic number has not been allocated. (on all chains). We should also check if there are any xApps who are actively using values in that range (I hope not). I also propose not using the same magic number across multiple chains, e.g. if 201 means "safe" on Ethereum, guardians should not process messages with the value 201 originating on other chains.

tbjump commented 2 years ago

What do you think of adding a special magic value (maybe zero) that is valid across all chains and would default to the Wormhole recommendations for ensured consensus specific to each chain, i.e. the values here: https://book.wormhole.com/reference/contracts.html#blockchain-finality-recommendations.

That way, integrators have a secure default, which is very convenient for deploying the same code on multiple chains.

tbjump commented 2 years ago

Q: I'm curious what you think consistency_level in the range of 1-32 should map to after making this change. I think it should map to the amount of blocks after "latest", i.e. not wait for eth "safe" to be reached. This could have unintended consequences for xApps already deployed, so we'd need to announce this change well in advance and give time to xApps to upgrade.

tbjump commented 2 years ago

In summary I'm proposing the following course of action:

evan-gray commented 2 years ago

What do you think of adding a special magic value (maybe zero) that is valid across all chains and would default to the Wormhole recommendations for ensured consensus specific to each chain, i.e. the values here: https://book.wormhole.com/reference/contracts.html#blockchain-finality-recommendations.

That way, integrators have a secure default, which is very convenient for deploying the same code on multiple chains.

Personally, I'd prefer any non-reserved value to be safe - the only tricky one is BSC 🤔

evan-gray commented 2 years ago

Q: I'm curious what you think consistency_level in the range of 1-32 should map to after making this change. I think it should map to the amount of blocks after "latest", i.e. not wait for eth "safe" to be reached. This could have unintended consequences for xApps already deployed, so we'd need to announce this change well in advance and give time to xApps to upgrade.

Quick note, Eth waits for "finalized" not "safe". Outside of BSC, setting any number here is rather irrelevant or wouldn't do the right thing, so I'm not keen on maintaining the existing functionality. Instead, I suggest all values should simply be treated as 'finalized + 0`

evan-gray commented 2 years ago

I believe there was a reason that 0 should not be set for consistency (maybe because it's a default uninitialized value) and it's also kinda odd to me that 0 would be finalized but 1 wouldn't be. @hendrikhofstadt can opine.

tbjump commented 2 years ago

But do you think there are xApps who might want to go even faster on Ethereum than "safe", i.e. n blocks where 0<=n<32. I could think of a scenario where an xApp only cares about making sure that the message was validated on chain and doesn't care about consensus. An example would be Pyth, although Pyth is not emitting from Ethereum.

evan-gray commented 2 years ago

But do you think there are xApps who might want to go even faster on Ethereum than "safe", i.e. n blocks where 0<=n<32. I could think of a scenario where an xApp only cares about making sure that the message was validated on chain and doesn't care about consensus. An example would be Pyth, although Pyth is not emitting from Ethereum.

I assume you're using 32 here because that's an epoch? Absolutely folks want to go faster, that's why my original suggestion here was 200 = "as soon as the watcher sees it". I honestly don't see a great cause for waiting, like, 3 blocks instead of just 1. Seems like on Eth today you want your options to be:

which would map to

panoel commented 2 years ago

I propose allocating the entire range of 200-255 (inclusive) of consistency_level for magic numbers and have the guardians not process any messages with consistency_level in that range where a magic number has not been allocated. (on all chains). We should also check if there are any xApps who are actively using values in that range (I hope not). I also propose not using the same magic number across multiple chains, e.g. if 201 means "safe" on Ethereum, guardians should not process messages with the value 201 originating on other chains.

I wonder if 55 levels may not be enough if we are reserving, potentially, 2+ per chain. I wonder if we can group chains together. eg. 200 => immediate for Eth and all EVMs, 210 => immediate for all cosmwasm chains?

evan-gray commented 2 years ago

I propose allocating the entire range of 200-255 (inclusive) of consistency_level for magic numbers and have the guardians not process any messages with consistency_level in that range where a magic number has not been allocated. (on all chains). We should also check if there are any xApps who are actively using values in that range (I hope not). I also propose not using the same magic number across multiple chains, e.g. if 201 means "safe" on Ethereum, guardians should not process messages with the value 201 originating on other chains.

I wonder if 55 levels may not be enough if we are reserving, potentially, 2+ per chain. I wonder if we can group chains together. eg. 200 => immediate for Eth and all EVMs, 210 => immediate for all cosmwasm chains?

@panoel this is only applicable to EVM chains, since this is specific to the EVM watcher. The core Solidity contract has this consistencyLevel parameter on the publishMessage function, which does not exist on every implementation (e.g. cosmwasm's PostMessage has no equivalent as Tendermint has instant finality). Similarly, Solana has its own enum system where 0 is confirmed and 1 is finalized. That said, I expect most EVM chains will not have that many permutations of these concepts and we can certainly reuse the enums across chains - so 200 would mean publish immediately on all chains that use the EVM watcher / Solidity contracts, and 201 would mean safe for all chains that have that concept (currently only Ethereum, though more may follow this RPC API) and default to finalized if not.