-
Notifications
You must be signed in to change notification settings - Fork 545
Introduce a gas-based Storage limit per tx #1142
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
Merged
boundless-forest
merged 49 commits into
polkadot-evm:master
from
moonbeam-foundation:ahmad-add-storage-limit-per-tx
Dec 11, 2024
Merged
Changes from 28 commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
5b8860f
A new trait for recording foreign metrics
ahmadkaouk d692104
Remove Metric trait
ahmadkaouk 523b18c
rename BasicMetric to Metric
ahmadkaouk b168105
add unit tests and a new MetricError enum
ahmadkaouk ce75d15
Add ProofSizeMeter
ahmadkaouk 26a85ad
Add ProofSizeMeter to WeightInfo
ahmadkaouk 78273fb
formatting
ahmadkaouk df4f5cf
Add RefTimeMeter to WeightInfo
ahmadkaouk 1f86da7
add storage meter to WeightInfo
ahmadkaouk 230879a
rename metric to resource
ahmadkaouk 54b7c01
code refactor
ahmadkaouk d9f04e2
remove unused functions
ahmadkaouk af358ad
make clippy happy
ahmadkaouk 8fa4dd2
minor improvements
ahmadkaouk 65d8b97
rename meter to resource
ahmadkaouk 6a344db
compute new storage created by SSTORE
ahmadkaouk dea63f6
revert changes
ahmadkaouk 4c45d4f
compute storage growth for opcodes
ahmadkaouk cea9817
compute the storage quota per tx
ahmadkaouk e412643
pin evm temporarily
ahmadkaouk dbf0370
record storage growth for opcodes
ahmadkaouk 84b487f
update GAS_LIMIT_STORAGE_GROWTH_RATIO for tests
ahmadkaouk cce7cf5
add support to record storage growth for precompiles
ahmadkaouk 4670129
fix tests
ahmadkaouk dee68d8
fix formatting
ahmadkaouk f110333
fix storage growth parameters for tests
ahmadkaouk 332bde7
add rust integration tests
ahmadkaouk 1623f9c
fix typo
ahmadkaouk 19ba629
fix recording storage growth of a special use case of SSTORE
ahmadkaouk 7578175
use saturating add
ahmadkaouk d0304fe
minor improvements
ahmadkaouk fb31dac
add license to meter.rs
ahmadkaouk a6da7ef
fix clippy warnings
ahmadkaouk 4a6ea48
pin evm to master
ahmadkaouk ba9552d
update evm to the latest commit
ahmadkaouk f14d3e2
check limit exceedance before updating the usage
ahmadkaouk ca9e4d3
Use BtreeSet
ahmadkaouk 21bf9d0
Merge remote-tracking branch 'upstream/master' into ahmad-add-storage…
ahmadkaouk 4a343e6
add support for storage growth in precompiles
ahmadkaouk e72809d
clippy warnings
ahmadkaouk de7876e
Merge remote-tracking branch 'upstream/master' into ahmad-add-storage…
ahmadkaouk e46e222
Merge remote-tracking branch 'upstream/master' into ahmad-add-storage…
ahmadkaouk 553984f
update to evm 0.41.0
ahmadkaouk 063ea9d
Update Cargo.toml
ahmadkaouk 74f321c
update Cargo.lock
ahmadkaouk 433a346
Merge branch 'master' into ahmad-add-storage-limit-per-tx
ahmadkaouk 7aaf093
format
ahmadkaouk ec34143
fix tests
ahmadkaouk b246fe3
update license information in meter.rs to Apache-2.0
ahmadkaouk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // SPDX-License-Identifier: GPL-3.0-only | ||
| pragma solidity ^0.8.2; | ||
|
|
||
| contract StorageGrowthTest { | ||
| mapping(uint256 => uint256) public map; | ||
| uint256 foo; | ||
| uint256 bar; | ||
| uint256 baz; | ||
|
|
||
| constructor() { | ||
| foo = 1; | ||
| bar = 2; | ||
| baz = 3; | ||
| } | ||
|
|
||
| function store() public { | ||
| map[0] = 1; | ||
| map[1] = 2; | ||
| map[2] = 3; | ||
| } | ||
|
|
||
| function update() public { | ||
| foo = 2; | ||
| bar = 3; | ||
| baz = 4; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 608060405234801561001057600080fd5b506001808190555060028081905550600380819055506101c7806100356000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063975057e714610046578063a2e6204514610050578063b8dda9c71461005a575b600080fd5b61004e61008a565b005b6100586100d6565b005b610074600480360381019061006f919061011d565b6100f0565b6040516100819190610155565b60405180910390f35b6001600080808152602001908152602001600020819055506002600080600181526020019081526020016000208190555060036000806002815260200190815260200160002081905550565b600260018190555060036002819055506004600381905550565b60006020528060005260406000206000915090505481565b6000813590506101178161017a565b92915050565b60006020828403121561012f57600080fd5b600061013d84828501610108565b91505092915050565b61014f81610170565b82525050565b600060208201905061016a6000830184610146565b92915050565b6000819050919050565b61018381610170565b811461018e57600080fd5b5056fea2646970667358221220b25685afab962e465f0b43f6c4de10c82a565f50f6995c1cd444b002bcdd43e964736f6c63430008020033 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| use evm::{gasometer::GasCost, Opcode}; | ||
ahmadkaouk marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| use fp_evm::ACCOUNT_STORAGE_PROOF_SIZE; | ||
| use sp_core::H256; | ||
|
|
||
| /// A meter for tracking the storage growth. | ||
| #[derive(Clone, Copy)] | ||
| pub struct StorageMeter { | ||
| usage: u64, | ||
| limit: u64, | ||
| } | ||
|
|
||
| /// An error that is returned when the storage limit has been exceeded. | ||
| #[derive(Debug, PartialEq)] | ||
| pub enum MeterError { | ||
| LimitExceeded, | ||
| } | ||
|
|
||
| impl StorageMeter { | ||
| /// Creates a new storage meter with the given limit. | ||
| pub fn new(limit: u64) -> Self { | ||
| Self { usage: 0, limit } | ||
| } | ||
|
|
||
| /// Records the given amount of storage usage. The amount is added to the current usage. | ||
| /// If the limit is reached, an error is returned. | ||
| pub fn record(&mut self, amount: u64) -> Result<(), MeterError> { | ||
| self.usage = self.usage.checked_add(amount).ok_or_else(|| { | ||
| self.usage = self.limit; | ||
| MeterError::LimitExceeded | ||
| })?; | ||
|
|
||
| if self.usage > self.limit { | ||
| return Err(MeterError::LimitExceeded); | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
||
| /// Records the storage growth for the given Opcode. | ||
| pub fn record_dynamic_opcode_cost( | ||
| &mut self, | ||
| _opcode: Opcode, | ||
| gas_cost: GasCost, | ||
| ) -> Result<(), MeterError> { | ||
| match gas_cost { | ||
| GasCost::SStore { original, new, .. } | ||
| if original == H256::default() && !new.is_zero() => | ||
ahmadkaouk marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| self.record(ACCOUNT_STORAGE_PROOF_SIZE) | ||
| } | ||
| _ => Ok(()), | ||
| } | ||
| } | ||
|
|
||
| /// Returns the current usage of storage. | ||
| pub fn usage(&self) -> u64 { | ||
| self.usage | ||
| } | ||
|
|
||
| /// Returns the limit of storage. | ||
| pub fn limit(&self) -> u64 { | ||
| self.limit | ||
| } | ||
|
|
||
| /// Returns the amount of storage that is available before the limit is reached. | ||
| pub fn available(&self) -> u64 { | ||
| self.limit.saturating_sub(self.usage) | ||
| } | ||
|
|
||
| /// Map storage usage to the gas cost. | ||
| pub fn storage_to_gas(&self, ratio: u64) -> u64 { | ||
| self.usage.saturating_mul(ratio) | ||
| } | ||
| } | ||
| #[cfg(test)] | ||
| mod test { | ||
| use super::*; | ||
|
|
||
| /// Tests the basic functionality of StorageMeter. | ||
| #[test] | ||
| fn test_basic_functionality() { | ||
| let limit = 100; | ||
| let mut meter = StorageMeter::new(limit); | ||
|
|
||
| assert_eq!(meter.usage(), 0); | ||
| assert_eq!(meter.limit(), limit); | ||
|
|
||
| let amount = 10; | ||
| meter.record(amount).unwrap(); | ||
| assert_eq!(meter.usage(), amount); | ||
| } | ||
|
|
||
| /// Tests the behavior of StorageMeter when reaching the limit. | ||
| #[test] | ||
| fn test_reaching_limit() { | ||
| let limit = 100; | ||
| let mut meter = StorageMeter::new(limit); | ||
|
|
||
| // Approaching the limit without exceeding | ||
| meter.record(limit - 1).unwrap(); | ||
| assert_eq!(meter.usage(), limit - 1); | ||
|
|
||
| // Reaching the limit exactly | ||
| meter.record(1).unwrap(); | ||
| assert_eq!(meter.usage(), limit); | ||
|
|
||
| // Exceeding the limit | ||
| let res = meter.record(1); | ||
| assert_eq!(meter.usage(), limit + 1); | ||
| assert!(res.is_err()); | ||
| assert_eq!(res, Err(MeterError::LimitExceeded)); | ||
| } | ||
|
|
||
| /// Tests the record of dynamic opcode cost. | ||
| #[test] | ||
| fn test_record_dynamic_opcode_cost() { | ||
| let limit = 200; | ||
| let mut meter = StorageMeter::new(limit); | ||
|
|
||
| // Existing storage entry is updated. No change in storage growth. | ||
| let gas_cost = GasCost::SStore { | ||
| original: H256::from_low_u64_be(1), | ||
| current: Default::default(), | ||
| new: H256::from_low_u64_be(2), | ||
| target_is_cold: false, | ||
| }; | ||
| meter | ||
| .record_dynamic_opcode_cost(Opcode::SSTORE, gas_cost) | ||
| .unwrap(); | ||
| assert_eq!(meter.usage(), 0); | ||
|
|
||
| // New storage entry is created. Storage growth is recorded. | ||
| let gas_cost = GasCost::SStore { | ||
| original: H256::default(), | ||
| current: Default::default(), | ||
| new: H256::from_low_u64_be(1), | ||
| target_is_cold: false, | ||
| }; | ||
| meter | ||
| .record_dynamic_opcode_cost(Opcode::SSTORE, gas_cost) | ||
| .unwrap(); | ||
| assert_eq!(meter.usage(), ACCOUNT_STORAGE_PROOF_SIZE); | ||
|
|
||
| // New storage entry is created. Storage growth is recorded. The limit is reached. | ||
| let gas_cost = GasCost::SStore { | ||
| original: H256::default(), | ||
| current: Default::default(), | ||
| new: H256::from_low_u64_be(2), | ||
| target_is_cold: false, | ||
| }; | ||
| let res = meter.record_dynamic_opcode_cost(Opcode::SSTORE, gas_cost); | ||
| assert!(res.is_err()); | ||
| assert_eq!(res, Err(MeterError::LimitExceeded)); | ||
| assert_eq!(meter.usage(), 232); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.