Commit b3bfb3c7 authored by Mark Tyneway's avatar Mark Tyneway

resource-metering: change params

parent 4f96e19c
......@@ -397,17 +397,15 @@ RLPWriter_writeUint_Test:test_writeUint_smallint_succeeds() (gas: 7280)
RLPWriter_writeUint_Test:test_writeUint_zero_succeeds() (gas: 7749)
ResolvedDelegateProxy_Test:test_fallback_addressManagerNotSet_reverts() (gas: 605906)
ResolvedDelegateProxy_Test:test_fallback_delegateCallBar_reverts() (gas: 24783)
ResourceMeteringCustom_Test:test_meter_generateArtifact_succeeds() (gas: 1042150946)
ResourceMetering_Test:test_meter_initialBaseFee_succeeds() (gas: 7245)
ResourceMetering_Test:test_meter_initialBaseFee_succeeds() (gas: 7025)
ResourceMetering_Test:test_meter_initialResourceParams_succeeds() (gas: 8983)
ResourceMetering_Test:test_meter_minBaseFeeLessThanMaxBaseFee_succeeds() (gas: 6420)
ResourceMetering_Test:test_meter_updateNoGasDelta_succeeds() (gas: 2008226)
ResourceMetering_Test:test_meter_updateOneEmptyBlock_succeeds() (gas: 18645)
ResourceMetering_Test:test_meter_minBaseFeeLessThanMaxBaseFee_succeeds() (gas: 6194)
ResourceMetering_Test:test_meter_updateNoGasDelta_succeeds() (gas: 4008242)
ResourceMetering_Test:test_meter_updateOneEmptyBlock_succeeds() (gas: 18441)
ResourceMetering_Test:test_meter_updateParamsNoChange_succeeds() (gas: 14005)
ResourceMetering_Test:test_meter_updateTenEmptyBlocks_succeeds() (gas: 21651)
ResourceMetering_Test:test_meter_updateTwoEmptyBlocks_succeeds() (gas: 21607)
ResourceMetering_Test:test_meter_useMaxWithMaxBaseFee_succeeds() (gas: 29466331)
ResourceMetering_Test:test_meter_useMax_succeeds() (gas: 8017710)
ResourceMetering_Test:test_meter_updateTenEmptyBlocks_succeeds() (gas: 21243)
ResourceMetering_Test:test_meter_updateTwoEmptyBlocks_succeeds() (gas: 21199)
ResourceMetering_Test:test_meter_useMax_succeeds() (gas: 20017420)
ResourceMetering_Test:test_meter_useMoreThanMax_reverts() (gas: 16142)
SafeCall_call_Test:test_callWithMinGas_noLeakageHigh_succeeds() (gas: 2075873614)
SafeCall_call_Test:test_callWithMinGas_noLeakageLow_succeeds() (gas: 753665282)
......
......@@ -29,13 +29,14 @@ abstract contract ResourceMetering is Initializable {
/**
* @notice Maximum amount of the resource that can be used within this block.
* This value cannot be larger than the L2 block gas limit.
*/
int256 public constant MAX_RESOURCE_LIMIT = 8_000_000;
int256 public constant MAX_RESOURCE_LIMIT = 20_000_000;
/**
* @notice Along with the resource limit, determines the target resource limit.
*/
int256 public constant ELASTICITY_MULTIPLIER = 4;
int256 public constant ELASTICITY_MULTIPLIER = 5;
/**
* @notice Target amount of the resource that should be used within this block.
......@@ -50,22 +51,21 @@ abstract contract ResourceMetering is Initializable {
/**
* @notice Minimum base fee value, cannot go lower than this.
*/
int256 public constant MINIMUM_BASE_FEE = 10_000;
int256 public constant MINIMUM_BASE_FEE = 1 gwei;
/**
* @notice Maximum base fee value, cannot go higher than this.
* This value must be small enough to allow a user to request the
* MAX_RESOURCE_LIMIT when the base fee is at its max value.
* Setting this value too large can result in more gas being
* consumed than the L1 block gas limit.
* It is possible for the MAXIMUM_BASE_FEE to raise to a value
* that is so large it will consume the entire gas limit of
* an L1 block.
*/
int256 public constant MAXIMUM_BASE_FEE = int256(uint256((type(uint32).max / 7) * 6));
int256 public constant MAXIMUM_BASE_FEE = int256(uint256((type(uint128).max)));
/**
* @notice Initial base fee value. This value must be smaller than the
* MAXIMUM_BASE_FEE.
*/
uint128 public constant INITIAL_BASE_FEE = 1_000_000_000;
uint128 public constant INITIAL_BASE_FEE = 1 gwei;
/**
* @notice EIP-1559 style gas parameters.
......@@ -89,10 +89,12 @@ abstract contract ResourceMetering is Initializable {
// Run the underlying function.
_;
// Run the metering function.
_metered(_amount, initialGas);
}
/**
* @notice An internal function that holds all of the logic for metering a resource.
*
* @param _amount Amount of the resource requested.
......
......@@ -32,7 +32,7 @@ contract SetPrevBaseFee_Test is Portal_Initializer {
// In order to achieve this we make no assertions, and handle everything else in the setUp()
// function.
contract GasBenchMark_OptimismPortal is Portal_Initializer {
uint128 INITIAL_BASE_FEE;
uint128 internal INITIAL_BASE_FEE;
// Reusable default values for a test withdrawal
Types.WithdrawalTransaction _defaultTx;
......@@ -124,7 +124,7 @@ contract GasBenchMark_OptimismPortal is Portal_Initializer {
}
contract GasBenchMark_L1CrossDomainMessenger is Messenger_Initializer {
uint128 INITIAL_BASE_FEE;
uint128 internal INITIAL_BASE_FEE;
function setUp() public virtual override {
super.setUp();
......@@ -153,7 +153,7 @@ contract GasBenchMark_L1CrossDomainMessenger is Messenger_Initializer {
}
contract GasBenchMark_L1StandardBridge_Deposit is Bridge_Initializer {
uint128 INITIAL_BASE_FEE;
uint128 internal INITIAL_BASE_FEE;
function setUp() public virtual override {
super.setUp();
......
......@@ -46,8 +46,8 @@ contract ResourceMetering_Test is Test {
uint256 max = uint256(meter.MAXIMUM_BASE_FEE());
uint256 min = uint256(meter.MINIMUM_BASE_FEE());
uint256 initial = uint256(meter.INITIAL_BASE_FEE());
assertTrue(max > initial);
assertTrue(min < initial);
assertTrue(max >= initial);
assertTrue(min <= initial);
}
/**
......@@ -83,8 +83,7 @@ contract ResourceMetering_Test is Test {
meter.use(0);
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
// Base fee decreases by 12.5%
assertEq(prevBaseFee, 875000000);
assertEq(prevBaseFee, 1 gwei);
assertEq(prevBoughtGas, 0);
assertEq(prevBlockNum, initialBlockNum + 1);
}
......@@ -94,7 +93,7 @@ contract ResourceMetering_Test is Test {
meter.use(0);
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
assertEq(prevBaseFee, 765624999);
assertEq(prevBaseFee, 1 gwei);
assertEq(prevBoughtGas, 0);
assertEq(prevBlockNum, initialBlockNum + 2);
}
......@@ -104,7 +103,7 @@ contract ResourceMetering_Test is Test {
meter.use(0);
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
assertEq(prevBaseFee, 263075576);
assertEq(prevBaseFee, 1 gwei);
assertEq(prevBoughtGas, 0);
assertEq(prevBlockNum, initialBlockNum + 10);
}
......@@ -130,8 +129,7 @@ contract ResourceMetering_Test is Test {
vm.roll(initialBlockNum + 1);
meter.use(0);
(uint128 postBaseFee, , ) = meter.params();
// Base fee increases by 1/8 the difference
assertEq(postBaseFee, 1375000000);
assertEq(postBaseFee, 1500000000);
}
function test_meter_useMoreThanMax_reverts() external {
......@@ -141,36 +139,6 @@ contract ResourceMetering_Test is Test {
meter.use(target * elasticity + 1);
}
/**
* @notice The max resource limit should be able to be used when the L1
* deposit base fee is at its max value. This previously would
* revert because prevBaseFee is a uint128 and checked math when
* multiplying against a uint64 _amount can result in an overflow
* even though its assigning to a uint256. The values MUST be casted
* to uint256 when doing the multiplication to prevent overflows.
* The function is called with the L1 block gas limit to ensure that
* the MAX_RESOURCE_LIMIT can be consumed at the MAXIMUM_BASE_FEE.
*/
function test_meter_useMaxWithMaxBaseFee_succeeds() external {
uint128 _prevBaseFee = uint128(uint256(meter.MAXIMUM_BASE_FEE()));
uint64 _prevBoughtGas = 0;
uint64 _prevBlockNum = uint64(block.number);
meter.set({
_prevBaseFee: _prevBaseFee,
_prevBoughtGas: _prevBoughtGas,
_prevBlockNum: _prevBlockNum
});
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
assertEq(prevBaseFee, _prevBaseFee);
assertEq(prevBoughtGas, _prevBoughtGas);
assertEq(prevBlockNum, _prevBlockNum);
uint64 gasRequested = uint64(uint256(meter.MAX_RESOURCE_LIMIT()));
meter.use{ gas: 30_000_000 }(gasRequested);
}
// Demonstrates that the resource metering arithmetic can tolerate very large gaps between
// deposits.
function testFuzz_meter_largeBlockDiff_succeeds(uint64 _amount, uint256 _blockDiff) external {
......@@ -187,11 +155,11 @@ contract ResourceMetering_Test is Test {
}
/**
* @title MeterUserCustom
* @title CustomMeterUser
* @notice A simple wrapper around `ResourceMetering` that allows the initial
* params to be set in the constructor.
*/
contract MeterUserCustom is ResourceMetering {
contract CustomMeterUser is ResourceMetering {
uint256 public startGas;
uint256 public endGas;
......@@ -215,17 +183,20 @@ contract MeterUserCustom is ResourceMetering {
}
/**
* @title ResourceMeteringCustom_Test
* @title ArtifactResourceMetering_Test
* @notice A table test that sets the state of the ResourceParams and then requests
* various amounts of gas. This test ensures that a wide range of values
* can safely be used with the `ResourceMetering` contract.
* It also writes a CSV file to disk that includes useful information
* about how much gas is used and how expensive it is in USD terms to
* purchase the deposit gas.
* This contract is designed to have only a single test.
*/
contract ResourceMeteringCustom_Test is Test {
MeterUser internal base;
contract ArtifactResourceMetering_Test is Test {
uint128 internal minimumBaseFee;
uint128 internal maximumBaseFee;
uint64 internal maxResourceLimit;
uint64 internal targetResourceLimit;
string internal outfile;
// keccak256(abi.encodeWithSignature("Error(string)", "ResourceMetering: cannot buy more gas than available gas limit"))
......@@ -234,23 +205,26 @@ contract ResourceMeteringCustom_Test is Test {
// keccak256(abi.encodeWithSignature("Panic(uint256)", 0x11))
bytes32 internal overflowErr =
0x1ca389f2c8264faa4377de9ce8e14d6263ef29c68044a9272d405761bab2db27;
// keccak256(hex"")
bytes32 internal emptyReturnData =
0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
/**
* @notice Sets the initial block number to something sane for the
* deployment of MeterUser. Delete the CSV file if it exists
* then write the first line of the CSV.
* @notice Sets up the tests by getting constants from the ResourceMetering
* contract.
*/
function setUp() public {
vm.roll(1_000_000);
base = new MeterUser();
outfile = string.concat(vm.projectRoot(), "/.resource-metering.csv");
MeterUser base = new MeterUser();
minimumBaseFee = uint128(uint256(base.MINIMUM_BASE_FEE()));
maximumBaseFee = uint128(uint256(base.MAXIMUM_BASE_FEE()));
maxResourceLimit = uint64(uint256(base.MAX_RESOURCE_LIMIT()));
targetResourceLimit = uint64(uint256(base.TARGET_RESOURCE_LIMIT()));
outfile = string.concat(vm.projectRoot(), "/.resource-metering.csv");
try vm.removeFile(outfile) {} catch {}
vm.writeLine(
outfile,
"prevBaseFee,prevBoughtGas,prevBlockNumDiff,l1BaseFee,requestedGas,gasConsumed,ethPrice,usdCost,success"
);
}
/**
......@@ -259,19 +233,22 @@ contract ResourceMeteringCustom_Test is Test {
* gas, it can take very long to execute.
*/
function test_meter_generateArtifact_succeeds() external {
vm.writeLine(
outfile,
"prevBaseFee,prevBoughtGas,prevBlockNumDiff,l1BaseFee,requestedGas,gasConsumed,ethPrice,usdCost,success"
);
// prevBaseFee value in ResourceParams
uint128[] memory prevBaseFees = new uint128[](5);
prevBaseFees[0] = uint128(uint256(base.MAXIMUM_BASE_FEE()));
prevBaseFees[1] = uint128(uint256(base.MINIMUM_BASE_FEE()));
prevBaseFees[2] = uint128(uint256(base.INITIAL_BASE_FEE()));
prevBaseFees[3] = uint128(100_000);
prevBaseFees[4] = uint128(500_000);
prevBaseFees[0] = minimumBaseFee;
prevBaseFees[1] = maximumBaseFee;
prevBaseFees[2] = uint128(50 gwei);
prevBaseFees[3] = uint128(100 gwei);
prevBaseFees[4] = uint128(200 gwei);
// prevBoughtGas value in ResourceParams
uint64[] memory prevBoughtGases = new uint64[](3);
prevBoughtGases[0] = uint64(uint256(base.MAX_RESOURCE_LIMIT()));
prevBoughtGases[1] = uint64(uint256(base.TARGET_RESOURCE_LIMIT()));
prevBoughtGases[2] = uint64(0);
uint64[] memory prevBoughtGases = new uint64[](1);
prevBoughtGases[0] = uint64(0);
// prevBlockNum diff, simulates blocks with no deposits when non zero
uint64[] memory prevBlockNumDiffs = new uint64[](2);
......@@ -280,8 +257,8 @@ contract ResourceMeteringCustom_Test is Test {
// The amount of L2 gas that a user requests
uint64[] memory requestedGases = new uint64[](3);
requestedGases[0] = uint64(uint256(base.MAX_RESOURCE_LIMIT()));
requestedGases[1] = uint64(uint256(base.TARGET_RESOURCE_LIMIT()));
requestedGases[0] = maxResourceLimit;
requestedGases[1] = targetResourceLimit;
requestedGases[2] = uint64(100_000);
// The L1 base fee
......@@ -315,7 +292,7 @@ contract ResourceMeteringCustom_Test is Test {
vm.fee(l1BaseFee);
MeterUserCustom meter = new MeterUserCustom({
CustomMeterUser meter = new CustomMeterUser({
_prevBaseFee: prevBaseFee,
_prevBoughtGas: prevBoughtGas,
_prevBlockNum: uint64(block.number)
......@@ -323,6 +300,8 @@ contract ResourceMeteringCustom_Test is Test {
vm.roll(block.number + prevBlockNumDiff);
// Call the metering code and catch the various
// types of errors.
uint256 gasConsumed = 0;
try meter.use{ gas: 30_000_000 }(requestedGas) returns (
uint256 _gasConsumed
......@@ -334,13 +313,14 @@ contract ResourceMeteringCustom_Test is Test {
result = "ResourceMetering: cannot buy more gas than available gas limit";
} else if (hash == overflowErr) {
result = "arithmetic overflow/underflow";
} else if (hash == emptyReturnData) {
result = "out of gas";
} else {
result = "UNKNOWN ERROR";
}
}
// Compute the USD cost of the gas used, don't
// worry too much about loss of precison under $1
// Compute the USD cost of the gas used
uint256 usdCost = (gasConsumed * l1BaseFee * ethPrice) / 1 ether;
vm.writeLine(
......
......@@ -20,7 +20,7 @@ fuzz_runs = 16
no_match_contract = 'EchidnaFuzz'
fs_permissions = [
{ 'access'='read-write', 'path'='./' },
{ 'access'='read-write', 'path'='./.resource-metering.csv' },
]
[profile.ci]
......
......@@ -28,7 +28,7 @@
"test": "yarn build:differential && yarn build:fuzz && forge test",
"coverage": "yarn build:differential && yarn build:fuzz && forge coverage",
"coverage:lcov": "yarn build:differential && yarn build:fuzz && forge coverage --report lcov",
"gas-snapshot": "yarn build:differential && yarn build:fuzz && forge snapshot --no-match-test 'testDiff|testFuzz|invariant|ResourceMeteringCustom'",
"gas-snapshot": "yarn build:differential && yarn build:fuzz && forge snapshot --no-match-test 'testDiff|testFuzz|invariant|generateArtifact'",
"storage-snapshot": "./scripts/storage-snapshot.sh",
"validate-spacers": "hardhat compile && hardhat validate-spacers",
"slither": "./scripts/slither.sh",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment