Cache code size/hash in storage#893
Conversation
|
Should I wait for an evm crate release or use git dependency? @sorpaas |
sorpaas
left a comment
There was a problem hiding this comment.
We shouldn't use lazy evaluation here. The security property is hard to guarantee. It's unsafe especially just around pre-/post-runtime upgrade time.
Please generate the code metadata on code creation instead. You can keep the current fallback code path just in case and/or use it in manual migrations.
Metadata is inserted in |
|
|
||
| /// Get the account metadata (hash and size) from storage if it exists, | ||
| /// or compute it from code and store it if it doesn't exist. | ||
| pub fn account_code_metadata(address: H160) -> CodeMetadata { |
There was a problem hiding this comment.
I think this function should return an option to express the case where the account not have any code.
| use sha3::Digest; | ||
|
|
||
| let size = code.len() as u64; | ||
| let hash = H256::from_slice(sha3::Keccak256::digest(&code).as_slice()); |
There was a problem hiding this comment.
If the account not have any code, we will compute a hash of an empty bytes vector at runtime, I wonder if it's the expected behavior.
If it's expected it's till unoptimized, it would be better to check if code.is_empty() and return an hardcoded constant in that case.
There was a problem hiding this comment.
I think the metadata should not even be computed and stored for an empty code, because it could be an address that later gets code deployed.
| return meta; | ||
| } | ||
|
|
||
| let code = <AccountCodes<T>>::get(&address); |
There was a problem hiding this comment.
It seems to me really unsafe, and not compatible with Weight v2, to force the reading of the code if the metadata are not set.
It would be better to return None and create a dedicated call for migration.
There was a problem hiding this comment.
In this case we need to patch evm so that Handler::code_size / Handler::code_hash can return error. It's relatively trivial.
However, my view is that this is optional. If a chain is upgraded, then they should be recommended to "touch" all contracts upon upgrade (probably through a multi-call to ensure no other code are executed in between). If a chain starts with the new runtime, then the None path will never happen.
There was a problem hiding this comment.
my view is that this is optional. If a chain is upgraded, then they should be recommended to "touch" all contracts upon upgrade (probably through a multi-call to ensure no other code are executed in between)
This is not possible for parachains, it will make a too big storage proof size. For decentralized parachains, metadata must be computed offchain and injected onchain by a referendum via governance, which requires the code to support hybrid state.
There was a problem hiding this comment.
I agree that data should be inserted via governance.
However in the meantime knowing the code hash and size is necessary and require to read the full code. Once it is computed it is better to store it than to have to compute it again the next time. Thus it seems better to not return an Option and keep the unhappy path, which will never be reached once all contracts have been migrated.
|
This pull request has been mentioned on Polkadot Forum. There might be relevant details there: https://forum.polkadot.network/t/frontier-support-for-evm-weight-v2/2470/1 |
|
Please update the |
|
LGTM and CI is green, @sorpaas can you merge it? |
|
Sorry. Let me publish a new release (not yet, will ping you) and then change the evm version to that before merge. Otherwise things will be difficult to manage. |
@sorpaas before release a new version of evm, maybe we could release a new version of ethereum firstly? |
| pub type AccountCodes<T: Config> = StorageMap<_, Blake2_128Concat, H160, Vec<u8>, ValueQuery>; | ||
|
|
||
| #[pallet::storage] | ||
| #[pallet::getter(fn account_codes_metadata)] |
There was a problem hiding this comment.
better not to add pallet::getter syntax for new storages, because it will be deprecated by upstream.
We'll have to merge PR #1032 first then. |
|
I'm dealing with rust-ethereum/evm#162 and rust-ethereum/evm#163 Sorry about all the delays! |
Depends on rust-ethereum/evm#140
Cache the code size/hash of an account in storage to avoid reading the full code to compute those values. Aims to reduce storage proof size.