Skip to content

Commit

Permalink
Report L1 base fee set by L2s (#111)
Browse files Browse the repository at this point in the history
* CCIP plugin code sketch

* revert models changes

* update gas price encoding and deviation

* udpate exec cost estimation

* Update exec cost estimation

* update offchain config

* use gas price struct instead of encoding where applicable

* do not use v2 suffix for latest version of offchain config

* add nil check for gas update

* Adding price estimator interfaces

* update commit plugin

* update name to prices

* update exec plugin

* comments and nits

* change the loaders to also return version

* address comments

* making tests build

* validate observed token prices match token with decimals

* fixed commit reporting tests

* add test for validateObservations

* pass tests

* add test for exec getPrice

* couple more tests in exec price estimator

* complete exec price estimator test

* add da price estimator test

* resolve exec logpoller fiter test

* address comments

* remove price estimator deviation and computeCost opts

* fix 1.21 import
  • Loading branch information
matYang authored Oct 2, 2023
1 parent cfba858 commit 37b87f0
Show file tree
Hide file tree
Showing 29 changed files with 2,507 additions and 488 deletions.
4 changes: 2 additions & 2 deletions contracts/src/v0.8/ccip/libraries/Internal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ library Internal {
uint256 public constant MESSAGE_FIXED_BYTES = 32 * 17;

/// @dev Each token transfer adds 1 EVMTokenAmount and 1 bytes.
/// When abiEncoded, each EVMTokenAmount takes 2 slots, each bytes takes 2 slots.
uint256 public constant MESSAGE_BYTES_PER_TOKEN = 32 * 4;
/// When abiEncoded, each EVMTokenAmount takes 2 slots, each bytes takes 2 slots, excl bytes contents
uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * 4;

function _toAny2EVMMessage(
EVM2EVMMessage memory original,
Expand Down
13 changes: 7 additions & 6 deletions contracts/src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ contract EVM2EVMOnRamp is IEVM2AnyOnRamp, ILinkAvailable, AggregateRateLimiter,
address router; // ─────────────────────────╮ Router address
uint16 maxTokensLength; // │ Maximum number of ERC20 token transfers per message
uint32 destGasOverhead; // │ Extra gas charged on top of the gasLimit
uint16 destGasPerPayloadByte; // │ Destination chain gas charged per byte of `data` payload
uint32 destDataAvailabilityOverheadGas; // │ Extra data availability gas charged on top of message data
uint16 destGasPerDataAvailabilityByte; // ──╯ Amount of gas to charge per byte of data that needs availability
uint16 destGasPerPayloadByte; // │ Destination chain gas charged for passing each byte of `data` payload to receiver
uint32 destDataAvailabilityOverheadGas; // │ Extra data availability gas charged on top of the message, e.g. for OCR
uint16 destGasPerDataAvailabilityByte; // ──╯ Amount of gas to charge per byte of message data that needs availability
uint16 destDataAvailabilityMultiplier; // ──╮ Multiplier for data availability gas, multiples of 1e-4, or 0.0001
address priceRegistry; // │ Price registry address
uint32 maxDataSize; // │ Maximum payload data size, max 4GB
Expand Down Expand Up @@ -116,7 +116,7 @@ contract EVM2EVMOnRamp is IEVM2AnyOnRamp, ILinkAvailable, AggregateRateLimiter,
struct TokenTransferFeeConfig {
uint16 ratio; // ───────────────────╮ Ratio of token transfer value to charge as fee, multiples of 0.1bps, or 1e-5
uint32 destGasOverhead; // │ Gas charged to execute the token transfer on the destination chain
uint32 destBytesOverhead; // ───────╯ Extra data availability bytes on top of transfer data, e.g. USDC offchain data
uint32 destBytesOverhead; // ───────╯ Extra data availability bytes on top of fixed transfer data, e.g. USDC source token data and offchain data
}

/// @dev Same as TokenTransferFeeConfig
Expand All @@ -125,7 +125,7 @@ contract EVM2EVMOnRamp is IEVM2AnyOnRamp, ILinkAvailable, AggregateRateLimiter,
address token; // ──────────────────╮ Token address
uint16 ratio; // │ Ratio of token transfer value to charge as fee, multiples of 0.1bps, or 1e-5
uint32 destGasOverhead; // │ Gas charged to execute the token transfer on the destination chain
uint32 destBytesOverhead; // ───────╯ Extra data availability bytes on top of transfer data, e.g. USDC offchain data
uint32 destBytesOverhead; // ───────╯ Extra data availability bytes on top of fixed transfer data, e.g. USDC source token data and offchain data
}

/// @dev Nop address and weight, used to set the nops and their weights
Expand Down Expand Up @@ -559,9 +559,10 @@ contract EVM2EVMOnRamp is IEVM2AnyOnRamp, ILinkAvailable, AggregateRateLimiter,
) internal view returns (uint256 dataAvailabilityCostUSD) {
uint256 dataAvailabilityLengthBytes = Internal.MESSAGE_FIXED_BYTES +
messageDataLength +
(numberOfTokens * Internal.MESSAGE_BYTES_PER_TOKEN) +
(numberOfTokens * Internal.MESSAGE_FIXED_BYTES_PER_TOKEN) +
tokenTransferBytesOverhead;

// destDataAvailabilityOverheadGas is a separate config value for flexibility to be updated independently of message cost.
uint256 dataAvailabilityGas = (dataAvailabilityLengthBytes * s_dynamicConfig.destGasPerDataAvailabilityByte) +
s_dynamicConfig.destDataAvailabilityOverheadGas;

Expand Down
4 changes: 2 additions & 2 deletions contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRamp.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ contract EVM2EVMOnRamp_getDataAvailabilityCostUSD is EVM2EVMOnRamp_getFeeSetup {

uint256 dataAvailabilityLengthBytes = Internal.MESSAGE_FIXED_BYTES +
100 +
(5 * Internal.MESSAGE_BYTES_PER_TOKEN) +
(5 * Internal.MESSAGE_FIXED_BYTES_PER_TOKEN) +
50;
uint256 dataAvailabilityGas = dynamicConfig.destDataAvailabilityOverheadGas +
dynamicConfig.destGasPerDataAvailabilityByte *
Expand Down Expand Up @@ -757,7 +757,7 @@ contract EVM2EVMOnRamp_getDataAvailabilityCostUSD is EVM2EVMOnRamp_getFeeSetup {

uint256 dataAvailabilityLengthBytes = Internal.MESSAGE_FIXED_BYTES +
messageDataLength +
(numberOfTokens * Internal.MESSAGE_BYTES_PER_TOKEN) +
(numberOfTokens * Internal.MESSAGE_FIXED_BYTES_PER_TOKEN) +
tokenTransferBytesOverhead;

uint256 dataAvailabilityGas = destDataAvailabilityOverheadGas +
Expand Down
14 changes: 8 additions & 6 deletions core/services/ocr2/plugins/ccip/commit_inflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,28 +67,30 @@ func (c *inflightCommitReportsContainer) maxInflightSeqNr() uint64 {
return max
}

// latestGasPriceUpdate return the latest inflight gas price update or nil if there is no inflight gas price update.
func (c *inflightCommitReportsContainer) getLatestInflightGasPriceUpdate() *update {
// getLatestInflightGasPriceUpdate returns the latest inflight gas price update, and bool flag on if update exists.
func (c *inflightCommitReportsContainer) getLatestInflightGasPriceUpdate() (update, bool) {
c.locker.RLock()
defer c.locker.RUnlock()
var latestGasPriceUpdate *update
updateFound := false
latestGasPriceUpdate := update{}
var latestEpochAndRound uint64
for _, inflight := range c.inFlightPriceUpdates {
if inflight.priceUpdates.DestChainSelector == 0 {
// Price updates did not include a gas price
continue
}
if latestGasPriceUpdate == nil || inflight.epochAndRound > latestEpochAndRound {
if !updateFound || inflight.epochAndRound > latestEpochAndRound {
// First price found or found later update, set it
latestGasPriceUpdate = &update{
updateFound = true
latestGasPriceUpdate = update{
timestamp: inflight.createdAt,
value: inflight.priceUpdates.UsdPerUnitGas,
}
latestEpochAndRound = inflight.epochAndRound
continue
}
}
return latestGasPriceUpdate
return latestGasPriceUpdate, updateFound
}

// latestInflightTokenPriceUpdates returns a map of the latest token price updates
Expand Down
18 changes: 13 additions & 5 deletions core/services/ocr2/plugins/ccip/commit_inflight_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,28 @@ func TestCommitInflight(t *testing.T) {
})

// Initially should be empty
assert.Nil(t, c.getLatestInflightGasPriceUpdate())
inflightUpdate, hasUpdate := c.getLatestInflightGasPriceUpdate()
assert.Equal(t, inflightUpdate, update{})
assert.False(t, hasUpdate)
assert.Equal(t, uint64(0), c.maxInflightSeqNr())

epochAndRound := uint64(1)

// Add a single report inflight
root1 := utils.Keccak256Fixed(hexutil.MustDecode("0xaa"))
require.NoError(t, c.add(lggr, commit_store.CommitStoreCommitReport{Interval: commit_store.CommitStoreInterval{Min: 1, Max: 2}, MerkleRoot: root1}, epochAndRound))
assert.Nil(t, c.getLatestInflightGasPriceUpdate())
inflightUpdate, hasUpdate = c.getLatestInflightGasPriceUpdate()
assert.Equal(t, inflightUpdate, update{})
assert.False(t, hasUpdate)
assert.Equal(t, uint64(2), c.maxInflightSeqNr())
epochAndRound++

// Add another price report
root2 := utils.Keccak256Fixed(hexutil.MustDecode("0xab"))
require.NoError(t, c.add(lggr, commit_store.CommitStoreCommitReport{Interval: commit_store.CommitStoreInterval{Min: 3, Max: 4}, MerkleRoot: root2}, epochAndRound))
assert.Nil(t, c.getLatestInflightGasPriceUpdate())
inflightUpdate, hasUpdate = c.getLatestInflightGasPriceUpdate()
assert.Equal(t, inflightUpdate, update{})
assert.False(t, hasUpdate)
assert.Equal(t, uint64(4), c.maxInflightSeqNr())
epochAndRound++

Expand All @@ -51,8 +57,10 @@ func TestCommitInflight(t *testing.T) {
DestChainSelector: uint64(1),
UsdPerUnitGas: big.NewInt(1),
}}, epochAndRound))
latest := c.getLatestInflightGasPriceUpdate()
assert.Equal(t, big.NewInt(1), latest.value)

inflightUpdate, hasUpdate = c.getLatestInflightGasPriceUpdate()
assert.Equal(t, big.NewInt(1), inflightUpdate.value)
assert.True(t, hasUpdate)
assert.Equal(t, uint64(4), c.maxInflightSeqNr())
epochAndRound++

Expand Down
5 changes: 3 additions & 2 deletions core/services/ocr2/plugins/ccip/commit_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func jobSpecToCommitPluginConfig(lggr logger.Logger, jb job.Job, pr pipeline.Run
if err != nil {
return nil, nil, errors.Wrap(err, "get chainset")
}
commitStore, err := contractutil.LoadCommitStore(common.HexToAddress(spec.ContractID), CommitPluginLabel, destChain.Client())
commitStore, commitStoreVersion, err := contractutil.LoadCommitStore(common.HexToAddress(spec.ContractID), CommitPluginLabel, destChain.Client())
if err != nil {
return nil, nil, errors.Wrap(err, "failed loading commitStore")
}
Expand All @@ -79,7 +79,7 @@ func jobSpecToCommitPluginConfig(lggr logger.Logger, jb job.Job, pr pipeline.Run
if err != nil {
return nil, nil, errors.Wrap(err, "unable to open source chain")
}
offRamp, err := contractutil.LoadOffRamp(common.HexToAddress(pluginConfig.OffRamp), CommitPluginLabel, destChain.Client())
offRamp, _, err := contractutil.LoadOffRamp(common.HexToAddress(pluginConfig.OffRamp), CommitPluginLabel, destChain.Client())
if err != nil {
return nil, nil, errors.Wrap(err, "failed loading offRamp")
}
Expand Down Expand Up @@ -121,6 +121,7 @@ func jobSpecToCommitPluginConfig(lggr logger.Logger, jb job.Job, pr pipeline.Run
sourceChainSelector: staticConfig.SourceChainSelector,
destClient: destChain.Client(),
commitStore: commitStore,
commitStoreVersion: commitStoreVersion,
}, &BackfillArgs{
sourceLP: sourceChain.LogPoller(),
destLP: destChain.LogPoller(),
Expand Down
Loading

0 comments on commit 37b87f0

Please sign in to comment.