[CHECKLIST] Smart Anchor Updates v2
Overview
The purpose of this document is to outline the features and intended functionality that will ship smart anchor updates on the relayer.
-
We have implemented the Smart Anchor Updates before in this PR https://github.com/webb-tools/relayer/pull/53 but, that implementation was not that all good, nor tested.
-
Smart Anchors Updates aims to save up gas and transactions to update Anchor’s state.
-
To understand how the smart anchor updates should be implemented, you first needs to understand how is the current system works.
Example
Alice deposits on chain
Aand sets the destination chainB. There are 8 chains interconnected in this example: {A, B, C, D, E, F, G, H}. The relayer(s) notice that the state of the anchor on chainAhas changed because a new leaf has been added to the Merkle tree, and a new root has been calculated. We need to update the other chains with this new root. For each chain connected to chainA, we create a proposal calledAnchorUpdate. This proposal is sent to a signing system (which could be a DKG system, multisig system, or a mocked signing system). When this proposal is signed, we callexecuteProposalWithSignatureon the Signature Bridge contract. That contract verifies and updates the anchor's neighbor root of chainA, meaning we will do(N - 1)updates.Each Relayer will try to send these transactions, but the blockchain will only accept one and reject the others. This can result in a loss of tokens due to the gas paid. However, before sending the transaction, the relayer will check if another relayer has updated the target anchor already. If this is the case, the relayer will cancel the transaction from their queue.
The biggest problem is that we shouldn't rush to update or send our signed proposals. Instead, we should wait and watch for the situation to change, and only send it if nobody else has done so.
Perviously, the implementation was like the following:
- Check if we have the
smart_anchor_updatesfeature is enabled. - if no, just do send the transaction immediately.
- if yes, we do compare that proposal leaf index and the latest leaf index on the other chain. if it is less than the one on the smart contract, we skip that proposal as it means that someone else already update it.
- if the
leaf_indexis greater than thedest_chain.leaf_indexwe sleep in a random interval between 10s to 60s first and then we retry again step 3. - if we reached the max retries, we go ahead and send that updated to the smart contract.
- Check if we have the
Features
To improve the implementation of Smart Anchor Updates, we propose the following changes:
- Rather than eagerly sending signed proposals, the Relayer should wait and observe the state of the Anchor on the source chain and its connected chains.
- When a new leaf is inserted in the merkle tree, the Relayer should wait for a certain period of time before attempting to update the state on the connected chains. During this waiting period, the Relayer should monitor the state changes on the connected chains. If another Relayer updates the state during this period, the current Relayer should cancel the update and wait for the next change.
- If no other Relayer updates the state during the waiting period, the current Relayer should proceed with the update.
- Worth mentioning that, if we did see another update that targets the same anchor with a higher leaf index, we shall cancel all the other older updates with lower leaf indices, as it does not matter here the order of these transactions, we only care about the latest update with the higher leaf index.
By waiting and observing the state, we can avoid sending duplicate proposals and reduce the amount of gas used for updates. This will result in significant cost savings for the Relayer(s) and improve the efficiency of the Smart Anchor Updates feature.
In addition, we suggest implementing the following features to further improve the efficiency of Smart Anchor Updates:
- Priority Queue: For the Priority Queue implementation, we recommend taking the leaf index as the priority value. This means that transactions with a higher leaf index will be executed first, and any other updates with lower leaf indices will be automatically cancelled. This will ensure that the latest update is always executed first, and will further optimize the efficiency of the Smart Anchor Updates feature.
- Dynamic Wait Time: The waiting period before attempting to update the state on the connected chains can be dynamically adjusted based on the transaction volume and state changes on the chains. This will ensure that the waiting period is optimized for efficiency and cost savings.
By implementing these additional features, we can further optimize Smart Anchor Updates and improve the overall efficiency of the Relayer system.
Checklist
-
Wait and observe Anchor state:
- [ ] Do not eagerly send signed proposals.
- [ ] Wait and observe the state of the Anchor on the source chain and its connected chains.
-
Wait for new Root:
- [ ] Wait for a certain period of time before attempting to update the state on the connected chains.
- [ ] Monitor the state changes on the connected chains.
- [ ] Cancel update if another Relayer updates during waiting period.
-
Proceed with update:
- [ ] If no other Relayer updates the state during the waiting period, proceed with the update.
-
Cancel older updates:
- [ ] If another update for the same anchor with a higher leaf index is seen, cancel all older updates with lower leaf indices.
-
Implement Priority Queue:
- [ ] Take leaf index as the priority value.
- [ ] Execute transactions with higher leaf index first.
- [ ] Automatically cancel any other updates with lower leaf indices.
-
Implement dynamic wait time:
- [ ] Dynamically adjust waiting period based on transaction volume and state changes.
- [ ] Optimize waiting period for efficiency and cost savings.
There are two parts/milestones for this TASK:
- [x] #513
- [ ] #514
- [x] #530
The first part is mostly SPEC'ed out, the second part should be implemented after finishing the first part.
Since this task is quite complex, we will split it into smaller tasks where we can parallelize the work.