-
Notifications
You must be signed in to change notification settings - Fork 36
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
Bridge gas optimisations #301
Conversation
1 similar comment
I specifically checked
|
Using keccak256(keccak256(script), walletPubKeyHash) gives higher performance in some circumstances. Update the key calculation method in tests to match what is implemented in the contracts.
👀 |
); | ||
// Make sure the actual output script matches either the P2PKH | ||
// or P2WPKH format. | ||
uint256 scriptLen = output.length - 8; |
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.
We could note why it's - 8
, something like:
// The output consists of an 8-byte value and a variable length script.
// To extract just the script, we ignore the first 8 bytes.
uint256 scriptLen = output.length - 8;
This could be helpful, especially that later we also slice32(8)
.
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.
// Move movingFundsTxMaxTotalFee to the next storage slot for a more | ||
// efficient variable layout | ||
// slither-disable-next-line unused-state | ||
bytes8 __depositAlignmentGap; |
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.
Is it actually moving movingFundsTxMaxTotalFee
to the next slot? Shouldn't we use bytes16
instead?
Slot 1: Bank bank
Slot 2: IRelay relay | uint96 txProofDifficultyFactor
Slot 3: EcdsaWalletRegistry ecdsaWalletRegistry
Slot 4: address treasury | uint64 depositDustThreshold
Slot 5: uint64 depositTreasuryFeeDivisor | uint64 depositTxMaxFee | bytes8 __depositAlignmentGap | uint64 movingFundsTxMaxTotalFee
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.
If this was bytes16
, then the next alignment gap would match:
Slot 6: uint64 movingFundsTxMaxTotalFee | uint64 movingFundsDustThreshold | uint32 movingFundsTimeoutResetDelay | uint32 movingFundsTimeout
Slot 7: uint96 movingFundsTimeoutSlashingAmount
Slot 8: uint256 movingFundsTimeoutNotifierRewardMultiplier
Slot 9: uint64 movedFundsSweepTxMaxTotalFee | uint32 movedFundsSweepTimeout | uint96 movedFundsSweepTimeoutSlashingAmount | uint64 movedFundsSweepTimeoutNotifierRewardMultiplier
Slot 10: uint64 redemptionDustThreshold | uint64 redemptionTreasuryFeeDivisor | uint64 redemptionTxMaxFee | bytes8 __redemptionAlignmentGap
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.
// Time after which the redemption request can be reported as | ||
// timed out. It is counted from the moment when the redemption | ||
// request was created via `requestRedemption` call. Reported | ||
// timed out requests are cancelled and locked TBTC is returned | ||
// to the redeemer in full amount. | ||
uint256 redemptionTimeout; | ||
uint64 redemptionTimeout; |
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.
All other timeouts (movingFundsTimeout
, movedFundsSweepTimeout
, fraudChallengeDefeatTimeout
) are uint32
. We could also make redemptionTimeout
uint32
for consistency. I think it does not break the layout we want to achieve because the next uint96
will not fit into the 10th storage slot anyway.
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.
@@ -129,14 +119,7 @@ library BridgeState { | |||
// The percentage of the notifier reward from the staking contract |
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.
We could change movingFundsTimeoutNotifierRewardMultiplier
into uint32
and add bytes16
gap. That would merge:
Slot 7: uint96 movingFundsTimeoutSlashingAmount
Slot 8: uint256 movingFundsTimeoutNotifierRewardMultiplier
together into one slot:
Slot 7: uint96 movingFundsTimeoutSlashingAmount | uint32 movingFundsTimeoutNotifierRewardMultiplier | bytes16 movingFundsTimeoutSlashingGap
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.
Furthermore, we could change movedFundsSweepTimeoutNotifierRewardMultiplier
to uint32
. It's not going to destroy the layout of 9th slot. We could also change redemptionTimeoutNotifierRewardMultiplier
to uint32
because it's not going to destroy the layout of 11th slot. And this way, all *RewardMultiplier*
fields would be uint32
consistently.
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.
/// @notice Calculate redemption key without allocations. | ||
/// @param walletPubKeyHash the pubkey hash of the wallet. | ||
/// @param script the output script of the redemption. | ||
/// @return The key = keccak256(keccak256(script), walletPubKeyHash). |
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.
We need to adjust all occurrences of keccak256(walletPubKeyHash | redeemerOutputScript)
in the documentation when we talk about pendingRedemptions
or timedOutRedemptions
.
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.
/* solhint-disable-next-line no-inline-assembly */ | ||
assembly { | ||
outputScriptHash := keccak256( | ||
add(redemptionTxOutputVector, add(outputScriptStart, 32)), |
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.
Can we explain 32 in a comment? My understanding of this line is:
The first argument to assembly keccak256 is the pointer. We point to redemptionTxOutputVector
but at the position indicated by outputScriptStart
. To load that position, we need to call add(outputScriptStart, 32)
because outputScriptStart
has 32 bytes.
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.
@@ -783,24 +782,33 @@ library Redemption { | |||
// https://github.com/keep-network/tbtc-v2/issues/257 |
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.
This TODO can now be removed.
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.
processInfo.outputStartingIndex | ||
); | ||
|
||
uint256 scriptLength = outputLength - 8; |
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.
We could move this line below the comment explaining 8-byte value and variable length script.
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.
// This function should be called only if the given output is | ||
// supposed to represent a redemption. Build the redemption key | ||
// to perform that check. |
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.
We could add
/// @dev This function should be called only if the given output is supposed to represent redemption.
to the documentation of this function.
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 detector was complaining about calls to bitcoin-spv which is a trusted library.
The bridge is mostly fairly close to the limit of achievable performance, but a few optimisations could be identified:
BridgeState
can be aligned and packed so that multiple accesses are minimisedbitcoin-spv
All in all, single percent improvements can be made in some functions (particularly proof submissions) and rarely called operations involving storage (initialisation, updating parameters) become significantly cheaper
Refs #260