From 4a3d006f37441c1dd305398b498f0139c616d447 Mon Sep 17 00:00:00 2001 From: syntrust Date: Mon, 30 Sep 2024 15:44:12 +0800 Subject: [PATCH] use bitmap --- contracts/EthStorageContractL2.sol | 21 ++++++++++-------- contracts/test/EthStorageContractL2Test.t.sol | 22 ++++++++++++++++--- contracts/test/TestEthStorageContractL2.sol | 6 +++-- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/contracts/EthStorageContractL2.sol b/contracts/EthStorageContractL2.sol index 1d1e1dd..ec45ef3 100644 --- a/contracts/EthStorageContractL2.sol +++ b/contracts/EthStorageContractL2.sol @@ -28,10 +28,9 @@ contract EthStorageContractL2 is EthStorageContract2 { IL1Block internal constant L1_BLOCK = IL1Block(0x4200000000000000000000000000000000000015); /// @notice The rate limit to update blobs per block uint256 internal immutable UPDATE_LIMIT; - /// @notice The blobs updated within current block - uint256 internal blobsUpdated; - /// @notice The block last update happens - uint256 internal blockLastUpdate; + + /// @notice Bitmap to store blobsUpdated and blockLastUpdate + uint256 internal updateStateBitmap; /// @notice Constructs the EthStorageContractL2 contract. constructor( @@ -68,13 +67,17 @@ contract EthStorageContractL2 is EthStorageContract2 { /// @notice Check the update rate limit of blobs put. function _checkUpdateLimit(uint256 _blobs) internal override { - if (blockLastUpdate == _blockNumber()) { - blobsUpdated = blobsUpdated + _blobs; + uint256 currentBlock = _blockNumber(); + uint256 blockLastUpdate = updateStateBitmap & type(uint128).max; + if (blockLastUpdate == currentBlock) { + uint256 blobsUpdated = updateStateBitmap >> 128; + blobsUpdated += _blobs; + require(blobsUpdated <= UPDATE_LIMIT, "EthStorageContractL2: exceeds update rate limit"); + updateStateBitmap = (blobsUpdated << 128) | currentBlock; } else { - blockLastUpdate = _blockNumber(); - blobsUpdated = _blobs; + require(_blobs <= UPDATE_LIMIT, "EthStorageContractL2: exceeds update rate limit"); + updateStateBitmap = (_blobs << 128) | currentBlock; } - require(blobsUpdated <= UPDATE_LIMIT, "EthStorageContractL2: exceeds update rate limit"); } /// @notice Getter for UPDATE_LIMIT diff --git a/contracts/test/EthStorageContractL2Test.t.sol b/contracts/test/EthStorageContractL2Test.t.sol index d50932b..ad621a9 100644 --- a/contracts/test/EthStorageContractL2Test.t.sol +++ b/contracts/test/EthStorageContractL2Test.t.sol @@ -10,7 +10,7 @@ contract EthStorageContractL2Test is Test { uint256 constant SHARD_SIZE_BITS = 19; uint256 constant MAX_KV_SIZE = 17; uint256 constant PREPAID_AMOUNT = 0; - uint256 constant UPDATE_LIMIT = 12; + uint256 constant UPDATE_LIMIT = 16; TestEthStorageContractL2 storageContract; address owner = address(0x1); @@ -27,7 +27,7 @@ contract EthStorageContractL2Test is Test { storageContract = TestEthStorageContractL2(address(proxy)); } - function testCheckUpdateLimitWithinSameBlock() public { + function testUpdateLimit() public { uint256 size = 6; bytes32[] memory hashes = new bytes32[](size); bytes32[] memory keys = new bytes32[](size); @@ -52,12 +52,28 @@ contract EthStorageContractL2Test is Test { storageContract.putBlobs(keys, blobIdxs, lengths); assertEq(storageContract.getBlobsUpdated(), 5); assertEq(storageContract.getBlockLastUpdate(), 10000); + // Update all 6 storageContract.putBlobs(keys, blobIdxs, lengths); assertEq(storageContract.getBlobsUpdated(), 11); - // Update all 6 again, exceeds 12 + + // Update all 6 again, exceeds UPDATE_LIMIT = 16 vm.expectRevert("EthStorageContractL2: exceeds update rate limit"); storageContract.putBlobs(keys, blobIdxs, lengths); assertEq(storageContract.getBlockLastUpdate(), 10000); + + vm.roll(block.number + 1); + + // Update all 6 + storageContract.putBlobs(keys, blobIdxs, lengths); + assertEq(storageContract.getBlobsUpdated(), 6); + assertEq(storageContract.getBlockLastUpdate(), 10001); + + // Update till exceeds UPDATE_LIMIT = 16 + storageContract.putBlobs(keys, blobIdxs, lengths); + assertEq(storageContract.getBlobsUpdated(), 12); + assertEq(storageContract.getBlockLastUpdate(), 10001); + vm.expectRevert("EthStorageContractL2: exceeds update rate limit"); + storageContract.putBlobs(keys, blobIdxs, lengths); } } diff --git a/contracts/test/TestEthStorageContractL2.sol b/contracts/test/TestEthStorageContractL2.sol index c5c54c1..943704e 100644 --- a/contracts/test/TestEthStorageContractL2.sol +++ b/contracts/test/TestEthStorageContractL2.sol @@ -12,12 +12,14 @@ contract TestEthStorageContractL2 is EthStorageContractL2 { uint256 _updateLimit ) EthStorageContractL2(_config, _startTime, _storageCost, _dcfFactor, _updateLimit) {} + /// @notice Get the number of blobs updated within the current block. function getBlobsUpdated() public view returns (uint256) { - return blobsUpdated; + return updateStateBitmap >> 128; } + /// @notice Get the block number of the last update. function getBlockLastUpdate() public view returns (uint256) { - return blockLastUpdate; + return updateStateBitmap & type(uint128).max; } function _blockNumber() internal view virtual override returns (uint256) {