Skip to content
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

Auto 8888 properly account for l 1 gas overhead for l 2 chains op scroll arb #11983

Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
93908bb
AUTO-8804: added a chain specific module for automation
FelixFan1992 Jan 24, 2024
38cbca8
add modules
FelixFan1992 Jan 24, 2024
e5a1bd7
create specific modules for different chains
FelixFan1992 Jan 25, 2024
75a8a30
implement modules
FelixFan1992 Jan 25, 2024
76d22eb
addressed some feedbacks
FelixFan1992 Jan 25, 2024
f70c770
update tests
FelixFan1992 Jan 26, 2024
91e0856
generate wrappers
FelixFan1992 Jan 26, 2024
8e486d6
fix foundry
FelixFan1992 Jan 26, 2024
6533ae4
run yarn prettier:write
shileiwill Jan 26, 2024
d253968
remove unnecessary import
FelixFan1992 Jan 26, 2024
4495a08
remove unnecessary checks
FelixFan1992 Jan 26, 2024
66d140d
update gas overheads to pass tests
FelixFan1992 Jan 29, 2024
efb2e02
regen wrappers
FelixFan1992 Jan 29, 2024
c0dfbc9
fix sonarcube issues
FelixFan1992 Jan 29, 2024
e285b03
address some comments
FelixFan1992 Jan 30, 2024
5db66dc
adjust gas overheads
FelixFan1992 Jan 30, 2024
125c20d
prettier
FelixFan1992 Jan 30, 2024
0f35ee5
remove only
FelixFan1992 Jan 30, 2024
fedf5cb
adjust gas overhead again
FelixFan1992 Jan 30, 2024
4c04799
dont use const
shileiwill Feb 5, 2024
2dae7dc
rebase to latest and add chainmodule getter
shileiwill Feb 9, 2024
73f7880
Merge branch 'develop' into AUTO-8804
shileiwill Feb 9, 2024
c52d8b7
refactor gas overhead usage
RyanRHall Feb 9, 2024
5c33c75
Merge branch 'develop' into AUTO-8888-properly-account-for-l-1-gas-ov…
infiloop2 Feb 14, 2024
0d5b171
Cleanup and rename variables
infiloop2 Feb 14, 2024
c340d32
add chain module overhead calculation
infiloop2 Feb 14, 2024
dab784a
inline max overhead function
infiloop2 Feb 14, 2024
25669ec
remove underfunded upkeep check
infiloop2 Feb 14, 2024
e7b9897
simplify max link payment
infiloop2 Feb 14, 2024
18a152f
minor improvements
infiloop2 Feb 14, 2024
1048b7c
cleanup maxLinkPayment
infiloop2 Feb 14, 2024
7ec67f7
Revert "cleanup maxLinkPayment"
infiloop2 Feb 14, 2024
a6b23d7
fixc small issues
infiloop2 Feb 14, 2024
34e9c35
fix some tests, adjust overheads, regen wrappers
FelixFan1992 Feb 15, 2024
fe3fe7c
run prettier
FelixFan1992 Feb 15, 2024
ad83277
fix tests
FelixFan1992 Feb 15, 2024
2a8173c
add some todos
infiloop2 Feb 15, 2024
3570d5a
update comments
infiloop2 Feb 15, 2024
0299bc8
regen master interface
infiloop2 Feb 15, 2024
c12040c
regen wrappers and update tests
FelixFan1992 Feb 15, 2024
3758a62
improve tests
infiloop2 Feb 15, 2024
c723350
add per signer transmit overhead
infiloop2 Feb 16, 2024
21a03fe
fix conditional overhead test
infiloop2 Feb 16, 2024
9915be9
fix overhead tests
infiloop2 Feb 16, 2024
7b43985
Fix batching tests
infiloop2 Feb 16, 2024
91398f6
refactor linkForGas in tests
infiloop2 Feb 16, 2024
351104a
Divide l1 fee according to performdata weight
infiloop2 Feb 16, 2024
61f9f5d
format tests
infiloop2 Feb 16, 2024
536dfdb
add test for l1 split
infiloop2 Feb 16, 2024
d401fc6
adjust comment
infiloop2 Feb 16, 2024
5a8ce60
update comment
infiloop2 Feb 16, 2024
decec28
format tests
infiloop2 Feb 16, 2024
943fb32
iformat tests
infiloop2 Feb 16, 2024
de686ea
add tests for reorg protection flag
infiloop2 Feb 16, 2024
acaeeb8
update go wrappers
FelixFan1992 Feb 16, 2024
a7f634f
remove i keeper registry 2.2 wrapper
FelixFan1992 Feb 16, 2024
1b2322c
Polish minBalance test
infiloop2 Feb 16, 2024
78baf8d
Merge branch 'develop' into AUTO-8888-properly-account-for-l-1-gas-ov…
infiloop2 Feb 16, 2024
6ef9595
formatting
infiloop2 Feb 16, 2024
19c0b63
refine constants
infiloop2 Feb 16, 2024
dd88ccb
update
FelixFan1992 Feb 16, 2024
e8b97b1
udpate wrappers
FelixFan1992 Feb 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions contracts/src/v0.8/automation/dev/chains/ArbitrumModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ contract ArbitrumModule is ChainModuleBase {

function getMaxL1Fee(uint256 dataSize) external view override returns (uint256) {
(, uint256 perL1CalldataUnit, , , , ) = ARB_GAS.getPricesInWei();
// TODO: Verify this is an accurate estimate
return perL1CalldataUnit * dataSize * 16;
}

function getGasOverhead()
external
view
override
returns (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead)
{
// TODO: Calculate
return (0, 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,13 @@ contract ChainModuleBase is IChainModule {
function getMaxL1Fee(uint256) external view virtual returns (uint256) {
return 0;
}

function getGasOverhead()
external
view
virtual
returns (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead)
{
return (0, 0);
}
}
12 changes: 12 additions & 0 deletions contracts/src/v0.8/automation/dev/chains/OptimismModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,25 @@ contract OptimismModule is ChainModuleBase {
OVM_GasPriceOracle private constant OVM_GASPRICEORACLE = OVM_GasPriceOracle(OVM_GASPRICEORACLE_ADDR);

function getCurrentL1Fee() external view override returns (uint256) {
// TODO: Verify this is accurate calculation with appropriate padding
return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(msg.data, OP_L1_DATA_FEE_PADDING));
}

function getMaxL1Fee(uint256 dataSize) external view override returns (uint256) {
// fee is 4 per 0 byte, 16 per non-zero byte. Worst case we can have all non zero-bytes.
// Instead of setting bytes to non-zero, we initialize 'new bytes' of length 4*dataSize to cover for zero bytes.
bytes memory txCallData = new bytes(4 * dataSize);
// TODO: Verify this is an accurate estimate
return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(txCallData, OP_L1_DATA_FEE_PADDING));
}

function getGasOverhead()
external
view
override
returns (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead)
{
// TODO: Calculate
return (0, 0);
}
}
12 changes: 12 additions & 0 deletions contracts/src/v0.8/automation/dev/chains/ScrollModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,26 @@ contract ScrollModule is ChainModuleBase {
IScrollL1GasPriceOracle private constant SCROLL_ORACLE = IScrollL1GasPriceOracle(SCROLL_ORACLE_ADDR);

function getCurrentL1Fee() external view override returns (uint256) {
// TODO: Verify this is accurate calculation with appropriate padding
return SCROLL_ORACLE.getL1Fee(bytes.concat(msg.data, SCROLL_L1_FEE_DATA_PADDING));
}

function getMaxL1Fee(uint256 dataSize) external view override returns (uint256) {
// fee is 4 per 0 byte, 16 per non-zero byte. Worst case we can have all non zero-bytes.
// Instead of setting bytes to non-zero, we initialize 'new bytes' of length 4*dataSize to cover for zero bytes.
// this is the same as OP.
// TODO: Verify this is an accurate estimate
bytes memory txCallData = new bytes(4 * dataSize);
return SCROLL_ORACLE.getL1Fee(bytes.concat(txCallData, SCROLL_L1_FEE_DATA_PADDING));
}

function getGasOverhead()
external
view
override
returns (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead)
{
// TODO: Calculate
return (0, 0);
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,20 @@ interface IChainModule {

// retrieve the L1 data fee for a L2 transaction. it should return 0 for L1 chains and
// L2 chains which don't have L1 fee component. it uses msg.data to estimate L1 data so
// it must be used with a transaction.
// it must be used with a transaction. Return value in wei.
function getCurrentL1Fee() external view returns (uint256);

// retrieve the L1 data fee for a L2 simulation. it should return 0 for L1 chains and
// L2 chains which don't have L1 fee component.
// L2 chains which don't have L1 fee component. Return value in wei.
function getMaxL1Fee(uint256 dataSize) external view returns (uint256);

// Returns an upper bound on execution gas cost for one invocation of blockNumber(),
// one invocation of blockHash() and one invocation of getCurrentL1Fee().
// Returns two values, first value indicates a fixed cost and the second value is
// the cost per msg.data byte (As some chain module's getCurrentL1Fee execution cost
// scales with calldata size)
function getGasOverhead()
external
view
returns (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead);
}
76 changes: 40 additions & 36 deletions contracts/src/v0.8/automation/dev/v2_2/AutomationRegistry2_2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ contract AutomationRegistry2_2 is AutomationRegistryBase2_2, OCR2Abstract, Chain
Chainable(address(logicA))
{}

/**
* @notice holds the variables used in the transmit function, necessary to avoid stack too deep errors
*/
struct TransmitVars {
uint16 numUpkeepsPassedChecks;
uint256 totalCalldataWeight;
uint96 totalReimbursement;
uint96 totalPremium;
}

// ================================================================
// | ACTIONS |
// ================================================================
Expand Down Expand Up @@ -96,21 +106,20 @@ contract AutomationRegistry2_2 is AutomationRegistryBase2_2, OCR2Abstract, Chain

function _handleReport(HotVars memory hotVars, Report memory report, uint256 gasOverhead) private {
UpkeepTransmitInfo[] memory upkeepTransmitInfo = new UpkeepTransmitInfo[](report.upkeepIds.length);
uint16 numUpkeepsPassedChecks;
TransmitVars memory transmitVars = TransmitVars({
numUpkeepsPassedChecks: 0,
totalCalldataWeight: 0,
totalReimbursement: 0,
totalPremium: 0
});

uint256 blocknumber = hotVars.chainModule.blockNumber();
uint256 l1Fee = hotVars.chainModule.getCurrentL1Fee();

for (uint256 i = 0; i < report.upkeepIds.length; i++) {
upkeepTransmitInfo[i].upkeep = s_upkeep[report.upkeepIds[i]];
upkeepTransmitInfo[i].triggerType = _getTriggerType(report.upkeepIds[i]);
upkeepTransmitInfo[i].maxLinkPayment = _getMaxLinkPayment(
hotVars,
upkeepTransmitInfo[i].triggerType,
uint32(report.gasLimits[i]),
uint32(report.performDatas[i].length),
report.fastGasWei,
report.linkNative,
true
);

(upkeepTransmitInfo[i].earlyChecksPassed, upkeepTransmitInfo[i].dedupID) = _prePerformChecks(
report.upkeepIds[i],
blocknumber,
Expand All @@ -120,7 +129,7 @@ contract AutomationRegistry2_2 is AutomationRegistryBase2_2, OCR2Abstract, Chain
);

if (upkeepTransmitInfo[i].earlyChecksPassed) {
numUpkeepsPassedChecks += 1;
transmitVars.numUpkeepsPassedChecks += 1;
} else {
continue;
}
Expand All @@ -132,66 +141,61 @@ contract AutomationRegistry2_2 is AutomationRegistryBase2_2, OCR2Abstract, Chain
report.performDatas[i]
);

// To split L1 fee across the upkeeps, assign a weight to this upkeep based on the length
// of the perform data and calldata overhead
upkeepTransmitInfo[i].calldataWeight =
report.performDatas[i].length +
TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD +
(TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD * (hotVars.f + 1));
transmitVars.totalCalldataWeight += upkeepTransmitInfo[i].calldataWeight;

// Deduct that gasUsed by upkeep from our running counter
gasOverhead -= upkeepTransmitInfo[i].gasUsed;

// Store last perform block number / deduping key for upkeep
_updateTriggerMarker(report.upkeepIds[i], blocknumber, upkeepTransmitInfo[i]);
}
// No upkeeps to be performed in this report
if (numUpkeepsPassedChecks == 0) {
if (transmitVars.numUpkeepsPassedChecks == 0) {
return;
}

// This is the overall gas overhead that will be split across performed upkeeps
// Take upper bound of 16 gas per callData bytes, which is approximated to be reportLength
// Rest of msg.data is accounted for in accounting overheads
// NOTE in process of changing accounting, so pre-emptively changed reportLength to msg.data.length
gasOverhead =
(gasOverhead - gasleft() + 16 * msg.data.length) +
ACCOUNTING_FIXED_GAS_OVERHEAD +
(ACCOUNTING_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1));
gasOverhead = gasOverhead / numUpkeepsPassedChecks + ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD;
// Take upper bound of 16 gas per callData bytes
gasOverhead = (gasOverhead - gasleft()) + (16 * msg.data.length) + ACCOUNTING_FIXED_GAS_OVERHEAD;
gasOverhead = gasOverhead / transmitVars.numUpkeepsPassedChecks + ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD;

uint96 totalReimbursement;
uint96 totalPremium;
{
uint96 reimbursement;
uint96 premium;
for (uint256 i = 0; i < report.upkeepIds.length; i++) {
if (upkeepTransmitInfo[i].earlyChecksPassed) {
upkeepTransmitInfo[i].gasOverhead = _getCappedGasOverhead(
gasOverhead,
upkeepTransmitInfo[i].triggerType,
uint32(report.performDatas[i].length),
hotVars.f
);

(reimbursement, premium) = _postPerformPayment(
hotVars,
report.upkeepIds[i],
upkeepTransmitInfo[i],
upkeepTransmitInfo[i].gasUsed,
report.fastGasWei,
report.linkNative,
numUpkeepsPassedChecks
gasOverhead,
(l1Fee * upkeepTransmitInfo[i].calldataWeight) / transmitVars.totalCalldataWeight
);
totalPremium += premium;
totalReimbursement += reimbursement;
transmitVars.totalPremium += premium;
transmitVars.totalReimbursement += reimbursement;

emit UpkeepPerformed(
report.upkeepIds[i],
upkeepTransmitInfo[i].performSuccess,
reimbursement + premium,
upkeepTransmitInfo[i].gasUsed,
upkeepTransmitInfo[i].gasOverhead,
gasOverhead,
report.triggers[i]
);
}
}
}
// record payments
s_transmitters[msg.sender].balance += totalReimbursement;
s_hotVars.totalPremium += totalPremium;
s_transmitters[msg.sender].balance += transmitVars.totalReimbursement;
s_hotVars.totalPremium += transmitVars.totalPremium;
}

/**
Expand Down
Loading
Loading