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

[pallet-revive] immutable data storage #5861

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open

[pallet-revive] immutable data storage #5861

wants to merge 26 commits into from

Conversation

xermicus
Copy link
Member

This PR introduces the concept of immutable storage data, used for Solidity immutable variables.

This is a minimal implementation. Immutable data is attached to a contract; to keep ContractInfo fixed in size, we only store the length there, and store the immutable data in a dedicated storage map instead. Which comes at the cost of requiring an additional storage read (costly) for contracts using this feature.

We discussed more optimal solutions not requiring any additional storage accesses internally, but they turned out to be non-trivial to implement. Another optimization benefiting multiple calls to the same contract in a single call stack would be to cache the immutable data in Stack. However, this potential creates a DOS vulnerability (the attack vector is to call into as many contracts in a single stack as possible, where they all have maximum immutable data to fill the cache as efficiently as possible). So this either has to be guaranteed to be a non-issue by limits, or, more likely, to have some logic to bound the cache. Eventually, we should think about introducing the concept of warm and cold storage reads (akin to EVM). Since immutable variables are commonly used in contracts, this change is blocking our initial launch and we should only optimize it properly in follow-ups.

This PR also disables the set_code_hash API (which isn't usable for Solidity contracts without pre-compiles anyways). With immutable storage attached to contracts, we now want to run the constructor of the new code hash to collect the immutable data during set_code_hash. This will be implemented in a follow up PR.

xermicus and others added 16 commits September 25, 2024 19:09
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
@xermicus xermicus added R0-silent Changes should not be mentioned in any release notes T7-smart_contracts This PR/Issue is related to smart contracts. labels Sep 27, 2024
Signed-off-by: xermicus <cyrill@parity.io>
@xermicus
Copy link
Member Author

bot fmt

@command-bot
Copy link

command-bot bot commented Sep 27, 2024

@xermicus https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7457393 was started for your command "$PIPELINE_SCRIPTS_DIR/commands/fmt/fmt.sh". Check out https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/pipelines?page=1&scope=all&username=group_605_bot to know what else is being executed currently.

Comment bot cancel 3-00b383a4-2df6-4f13-884d-24631d5a4793 to cancel this command or bot cancel to cancel all commands in this pull request.

@command-bot
Copy link

command-bot bot commented Sep 27, 2024

@xermicus Command "$PIPELINE_SCRIPTS_DIR/commands/fmt/fmt.sh" has finished. Result: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7457393 has finished. If any artifacts were generated, you can download them from https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7457393/artifacts/download.

Copy link
Member

@athei athei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your editor seems to be adding ; to return statements. It adds some noise and rustfmt doesn't seem to care. Can you disable?

substrate/frame/revive/src/lib.rs Outdated Show resolved Hide resolved
@@ -75,6 +75,8 @@ pub struct ContractInfo<T: Config> {
/// to the map can not be removed from the chain state and can be safely used for delegate
/// calls.
delegate_dependencies: DelegateDependencyMap<T>,
/// The size of the immutable data of this contract.
pub immutable_bytes: u32,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please no new pub fields here. I want to restrict modification outside of this module if possible. The existing pub fields are just legacy could that need to be converted.

Comment on lines 509 to 511
{
unsafe { sys::get_immutable_data(output.as_mut_ptr(), &mut output_len) };
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this outer block for?

Comment on lines +1692 to +1693
/// After running the constructor, the new immutable data is already stored in
/// `self.immutable_data` at the address of the (reverted) contract instantiation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to mention that set_code host fn stays disabled (unversioned) until this change has happened.

Comment on lines 255 to 256
let immutable_data_deposit =
T::DepositPerByte::get().saturating_mul(self.immutable_bytes.into());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing the deposit for the additional storage item. Creating a Diff here like info_deposit is probably the easiest way to express that.

Comment on lines 254 to 260
// Immutable data is unique per contract and part of the base deposit.
let immutable_data_deposit =
T::DepositPerByte::get().saturating_mul(self.immutable_bytes.into());

let deposit = info_deposit
.saturating_add(upload_deposit)
.saturating_add(immutable_data_deposit);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK it is not gonna work like this. update_base_deposit is called from charge_instantiate which is called before the constructor is run. So immutable_bytes will always be 0. It is called before because it pulls the contract into existence which is necessary before running the constructor.

Comment on lines 1531 to 1532
let data = self.ext.get_immutable_data()?;
self.charge_gas(RuntimeCosts::GetImmutableData(data.len() as u32))?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to pre-charge and refund here. Otherwise you can cause a storage read and then fail because not enough gas.

Comment on lines +4359 to +4362
fn immutable_data_works() {
let (code, _) = compile_module("immutable_data").unwrap();

ExtBuilder::default().existential_deposit(100).build().execute_with(|| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need some assertion here that the charged deposit is correct. I think it is buggy (see other comment).

xermicus and others added 2 commits October 3, 2024 07:35
xermicus and others added 6 commits October 3, 2024 08:20
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
@xermicus
Copy link
Member Author

xermicus commented Oct 3, 2024

bot fmt

@command-bot
Copy link

command-bot bot commented Oct 3, 2024

@xermicus https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7494314 was started for your command "$PIPELINE_SCRIPTS_DIR/commands/fmt/fmt.sh". Check out https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/pipelines?page=1&scope=all&username=group_605_bot to know what else is being executed currently.

Comment bot cancel 12-0aadee30-72f5-4b03-bfcf-f143be07c04f to cancel this command or bot cancel to cancel all commands in this pull request.

@command-bot
Copy link

command-bot bot commented Oct 3, 2024

@xermicus Command "$PIPELINE_SCRIPTS_DIR/commands/fmt/fmt.sh" has finished. Result: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7494314 has finished. If any artifacts were generated, you can download them from https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7494314/artifacts/download.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
R0-silent Changes should not be mentioned in any release notes T7-smart_contracts This PR/Issue is related to smart contracts.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants