-
Notifications
You must be signed in to change notification settings - Fork 695
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
node: Add Transfer Verifier mechanism #4169
base: main
Are you sure you want to change the base?
node: Add Transfer Verifier mechanism #4169
Conversation
0f118a9
to
c711b03
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.
Not done reviewing yet, but I wanted to post the comments I have so far.
&txverifier.TVAddresses{ | ||
CoreBridgeAddr: common.HexToAddress(*evmCoreContract), | ||
TokenBridgeAddr: common.HexToAddress(*evmTokenBridgeContract), | ||
// TODO: should be a CLI parameter so that we could support other EVM chains |
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.
Do you want to address this TODO now? Seems like would be easy to add.
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.
The code should hopefully be generic enough to work with other EVM chains but the only testing I've done is with Ethereum. For that reason my preference would be to merge this as effectively Ethereum-only for now, with the idea that transfer verification could be extended to other chains later if we need it.
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.
Well, this means this will only work on ETH mainnet. Users might have the impression that they can set the RPC and the core and token bridge address for either Sepolia or any other EVM, but things will not work correctly because the WETH address would be wrong, right?
suiRPC *string | ||
suiCoreContract *string | ||
suiTokenBridgeEmitter *string | ||
// TODO: rename to package ID |
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.
Should you do this before people start using the command so they don't have to update later?
// } | ||
|
||
// Filter to be used for querying events | ||
// The `MoveEventType` filter doesn't seem to be available in the documentation. However, there is an example |
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.
Are you saying the way the watcher does this is undocumented? That seems...odd..
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.
Yeah the docs don't offer this event filter: https://docs.sui.io/guides/developer/sui-101/using-events
// - ensure that the coin types match | ||
func (o ObjectChange) ValidateTypeInformation(expectedPackageId string) (success bool) { | ||
// AI generated regex | ||
re := regexp.MustCompile(`^0x2::dynamic_field::Field<([^:]+)::token_registry::Key<([^>]+)>, ([^:]+)::([^<]+)<([^>]+)>>$`) |
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.
I think this panics on error. That seems a bit extreme? Should we consider something less extreme?
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.
I was thinking about this, and the thing is that the actual regex remains static. Is there a reason it would compile during tests, but not during a live production run?
8661aea
to
6ae4219
Compare
func (s *Subscription) Subscribe(ctx context.Context) { | ||
go func() { | ||
for { | ||
select { |
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.
Do you need to handle ctx.Done()
?
&txverifier.TVAddresses{ | ||
CoreBridgeAddr: common.HexToAddress(*evmCoreContract), | ||
TokenBridgeAddr: common.HexToAddress(*evmTokenBridgeContract), | ||
// TODO: should be a CLI parameter so that we could support other EVM chains |
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.
Well, this means this will only work on ETH mainnet. Users might have the impression that they can set the RPC and the core and token bridge address for either Sepolia or any other EVM, but things will not work correctly because the WETH address would be wrong, right?
} | ||
|
||
// Get the full transaction receipt for this log. | ||
receipt, txReceiptErr := tv.evmConnector.TransactionReceipt(ctx, vLog.Raw.TxHash) |
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.
I know it's not applicable in this standalone app, but it will matter when this is bolted into the watcher. The watcher will have already called TransactionReceipt
, so you will want to restructure this code so that can be passed in.
Transfer Verifier
This PR is a joint effort between myself, @pleasew8t, and @mdulin2.
Overview
This PR introduces the Transfer Verifier, a mechanism to improve Token
Bridge security by validating transaction receipts that correspond to Publish
Message events emitted from the Core Bridge.
When the core bridge emits a Publish Message event, the Transfer Verifier does
the following:
(e.g. an Ethereum receipt transaction)
emitted by the Token Bridge contract
transfers into the token bridge
into the Token Bridge, the program emits an error to signal to the node that
there is a security incident.
This provides protection in the event that an attacker devises a way to emit
arbitrary publish message events from the core contract or else somehow tricks
the Token Bridge into making token transfer calls without any backing tokens.
While existing Integrity Checks (Governor and Accountant) would help mitigate
this attack, Transfer Verifier acts as another layer of protection.
What this PR contains
This PR contains two initial implementations for Ethereum and Sui.
Both implementations are bundled into a Transfer Verifier package. This package
is used by a new
transfer-verifier
binary that exists as a subcommand withinguardiand
. This binary can be configured to monitor the mainnet token bridge and corebridge contracts for this chain.
Testing
Both implementations contain a large number of unit tests. They can be invoked
as a normal part of testing the node via
make test
.The Ethereum implementation has integration tests built into the Tilt set-up:
invoked to monitor the Ethereum devnet
cast
(partof the Foundry toolset)
returns a success when it appears
In order to impersonate a call from the Token Bridge to the Core Bridge, the
--auto-impersonate
flag was added to theanvil
invocation in eth-devnet.Future Work
The Transfer Verifier package is used here as a standalone binary. Its
fundamental output are logs that can be monitored and manually acted upon.
The next iteration of this project will be to integrate the package directly in
the Ethereum and Sui watchers
Integration into the Ethereum watcher
Ethereum has an advantage over the Sui implementation due to the robust logging
and tooling present in the EVM and its ecosystem. We can validate the relevant
information for Transfer Verification in a highly robust way and detect
violations of its invariants with certainty.
As a result, we can use the logic in the Transfer Verifier to block
transactions at the level of the Ethereum watcher so that malicious message
publications will not be processed by the network.
Integration into the Sui watcher
The nature of Sui makes it relatively difficult to provide guarantees about the
state of the core bridge relative to the token bridge. The Sui implementation
cannot provide the same guarantees as the Ethereum implementation due to limits
inherent in the chain.
It is still possible to integrate this protection into the Sui watcher but it
would be better to delay messages for e.g. 24h in this case rather than reject
them outright.
Additional implementations for other chains
This is an abstract algorithm that can in theory be applied to any chain supported by the Token Bridge.
Designing a Solana implementation of this script would be a fruitful choice
given that it is one of the chains that makes the most use of the Token Bridge.