-
Notifications
You must be signed in to change notification settings - Fork 660
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
base: master
Are you sure you want to change the base?
Conversation
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: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
bot fmt |
@xermicus https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7457393 was started for your command Comment |
@xermicus Command |
There was a problem hiding this 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?
@@ -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, |
There was a problem hiding this comment.
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.
{ | ||
unsafe { sys::get_immutable_data(output.as_mut_ptr(), &mut output_len) }; | ||
} |
There was a problem hiding this comment.
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?
/// After running the constructor, the new immutable data is already stored in | ||
/// `self.immutable_data` at the address of the (reverted) contract instantiation. |
There was a problem hiding this comment.
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.
let immutable_data_deposit = | ||
T::DepositPerByte::get().saturating_mul(self.immutable_bytes.into()); |
There was a problem hiding this comment.
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.
// 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); |
There was a problem hiding this comment.
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.
let data = self.ext.get_immutable_data()?; | ||
self.charge_gas(RuntimeCosts::GetImmutableData(data.len() as u32))?; |
There was a problem hiding this comment.
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.
fn immutable_data_works() { | ||
let (code, _) = compile_module("immutable_data").unwrap(); | ||
|
||
ExtBuilder::default().existential_deposit(100).build().execute_with(|| { |
There was a problem hiding this comment.
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).
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
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>
bot fmt |
@xermicus https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7494314 was started for your command Comment |
@xermicus Command |
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 duringset_code_hash
. This will be implemented in a follow up PR.