-
Notifications
You must be signed in to change notification settings - Fork 691
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
Implementation of 'Flow Cancel' modifications to Governor calculations #3798
Implementation of 'Flow Cancel' modifications to Governor calculations #3798
Conversation
Couldn't this be done more easily / efficiently by adding the cancelling transfers into This would mean making the payload of the transfers array have the value as a separate data item so it could be negative. You would also have to change Could add a Happy to discuss this offline if you like. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my comment above.
@bruce-riley I don't have objections to that method in general, and I looked into it following our intial discussion. The main caveat that most of the values in question (in the structs and database IIRC) are using unsigned types, so it's not trivial to modify the code to use negative values. This would also limit the effective upper bound of the values (since half of the data type would need to be reserved to represent negative values.) It may be possible to change to e.g. |
The value is in USD, so I don't think we need to worry about exceeding the max of an int64. Also, I'm not proposing changing the DB. That would need to stay what's in the actual transfer. The signed value could be stored in the transfers array in addition to the DB Transfer object (so the new payload in that array would be a struct containing the DB transfer and a signed value). Anyway, I think it would be useful to have another face to face discussion to talk through the alternatives. |
6726218
to
2aa0f75
Compare
8569353
to
21c96c1
Compare
6ec50c2
to
8ae3b11
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of nits, mostly style stuff since I know you're not a gopher natively, but this is good. I couldn't find anything obviously bad and this is definitely a big improvement.
Use the concept of a 'negative transfer' to represent flow-cancelling. This required the following modifications: - Add wrapped struct around db.Transfer that includes a int64 value for negative calcuations. It is used only by the Governor for these calculations `chainEntry` struct - modify to use the wrapped struct that includes int64 value - Added comments to clarify the purpose of transfers with negative values `tokenEntry` struct - modify to use a `flowCancel` boolean that marks whether incoming transfers of this asset should reduce the Governor limit for the Target chain `TrimAndSumValue` function - Modify to return signed integer - ensure it cannot go below 0 (underflow). Instead, negative sums will just return 0 to signal that the Governor has no 'usage' in the sense of the rate-limiting budget. In general, calling code and function signatures were modified to accept the new transfer type and signed integers instead of unsigned where necessary. This commit also adds validation functions that make it easier to add flow cancelling transfers to a chainEntry. It also adds two 'checked math' functions in the style of Rust to allow for easier overflow checking.
Also remove commented code from a previous commit
also cleanup comments
- Add a comment to the helper method to mention that the calling code is responsible for verifying that a flow cancel asset should actually flow cancel. (This is done via the `tokens` property in the Governor struct - Add comments to calling code mentioning that the verification is necessary - Modify the unit tests to perform this verification
Added Solana testnet USDC to the config for devnet and testnet Address sourced from Circle docs: https://developers.circle.com/stablecoins/docs/usdc-on-test-networks
wormhole-foundation#3798) Flow Cancel A 'flow cancel' transfer occurs when all of the following are true: An emitter chain is governed by the Governor A transfer has a TargetChain equal to the emitter A transfer's Timestamp is within the usual 24 hour window used by the Governor The asset in the transfer has fields OriginChain and OriginAddress equal to an entry in the allow list Example scenario A particular USDC implementation minted on Ethereum. It is allow-listed. A transfer of $1,000 of this asset is sent from Solana to Sui. Before the transfer, Sui's usage is $10,000. Before the transfer, Solana's usage is $0. After the transfer is processed, Sui's new usage will be $9,000 (flow cancel) and Solana's new usage will be $1,000 (as usual).
EDIT
The flow cancel logic has been rewritten following Bruce's feedback. Updated design can be found in the commit message here: 21c96c1
Overview
This pull requests contains modifications to the Governor.
In particular, it allows a certain allow-list of incoming tokens to "pay down" the Governor usage for the destination chain.
Note: This implementation is meant to be minimally invasive to highlight the flow cancel design and mechanism. As a result, it is not very efficient. Once the overall design is clear and agreed upon, I am more than happy to refactor the code to make it more performant.Background
The motivation and design document for this change is detailed in the GitHub Discussion "Wormhole Governor - Flow-Canceling Design Proposal (Temp Check)".
Note that this feature depends on and includes commits from Bruce's pull request, namely the modifications to(The other PR was merged and this one is rebased to include it)node/pkg/db/governor.go
.Details
Allow list
The allow-list is in the same format as other hard-coded token implementations in Wormhole, such as the 'manual token list'.
Currently, the allow list contains all implementations of UDSC, USDT, and DAI that are present in the 'generated mainnet token list'
Flow Cancel
A 'flow cancel' transfer occurs when all of the following are true:
emitter
chain is governed by the GovernorTargetChain
equal to theemitter
Timestamp
is within the usual 24 hour window used by the GovernorOriginChain
andOriginAddress
equal to an entry in the allow listExample scenario
USDC
implementation minted on Ethereum. It is allow-listed.After the transfer is processed, Sui's new usage will be $9,000 (flow cancel) and Solana's new usage will be $1,000 (as usual).
Areas of interest for reviewers
Efficiency(resolved by rewrite)There is a triple for-loop involved in the calculations. (For every governed chain --> for every transfer --> for every allow-listed asset ...)
Obviously this isn't optimal. However, I wanted to implement the logic using the existing database structure and Go structs where possible so that this change is not too intrusive.
In general, anything we can do to optimize the way
Transfer
s are filtered and accessed would be a big improvement. While there are 3 loops involved here, the token list andgov.chains
are small, fixed numbers. Our real issue is processing the transfers.One clear improvement would be to make a struct similar to
chainEntry
that indexes based on target chain, rather than emitter chain. This would allow for more efficient lookups when calculating the net flows into a chain via theFlowCancellingTransfersForChain()
.Another possible approach is to cache the Governor usage calculations, perhaps in the
ChainGovernor
.Some limitations:
sum
values in governor.go as well as the Value of transfers are unsigned ints.chainEntry
's are indexed by source (emitter) chains, not destination (target).Another area for improvement:
FlowCancelTokenList()
is a function, not a field ofChainGovernor
but it probably could be (similarly to its fieldstokens
andtokensByCoinGeckoId
).Contents of the allow-list
Are there any assets that should be removed?
I wanted to include all stablecoins from the generated mainnet tokens list and to avoid making editiorial decisions about specific tokens.Felix suggested in a review to use only the assets originating from Ethereum and Solana chains for an initial rollout.That said, there are some likely candidates for removal; the following appear to have de-pegged:https://www.coingecko.com/en/coins/bridged-tether-orbit-bridge
{chain: 13, addr: "000000000000000000000000cee8faf64bb97a73bb51e115aa89c17ffa8dd167", symbol: "oUSDT", coinGeckoId: "orbit-bridge-klaytn-usd-tether", decimals: 6, price: 0.490247}, // Addr: 0xcee8faf64bb97a73bb51e115aa89c17ffa8dd167, Notional: 1.5499198124759999Z}
https://www.coingecko.com/en/coins/klaytn-dai
{chain: 13, addr: "0000000000000000000000005c74070fdea071359b86082bd9f9b3deaafbe32b", symbol: "KDAI", coinGeckoId: "klaytn-dai", decimals: 18, price: 0.490008}, // Addr: 0x5c74070fdea071359b86082bd9f9b3deaafbe32b, Notional: 0.00980016
Test coverage
Unit tests
I added unit tests to cover the new functionality. I'm happy to add more if others have suggestions.
Dynamic test coverage
I got as far as running Tilt on my machine but I'm not exactly clear on the best way to run smoke tests for this feature.
Benchmarking
As we refine these changes, it would be beneficial to benchmark the Flow Cancelling calculations with a large number of transfers as it is likely to introduce a performance hit.