Skip to content
Snippets Groups Projects
  1. Oct 08, 2024
  2. Oct 05, 2024
    • Cyrill Leutwiler's avatar
      [pallet-revive] immutable data storage (#5861) · a8ebe9af
      Cyrill Leutwiler authored
      
      This PR introduces the concept of immutable storage data, used for
      [Solidity immutable
      variables](https://docs.soliditylang.org/en/latest/contracts.html#immutable).
      
      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.
      
      ---------
      
      Signed-off-by: default avatarCyrill Leutwiler <bigcyrill@hotmail.com>
      Signed-off-by: default avatarxermicus <cyrill@parity.io>
      Co-authored-by: command-bot <>
      Co-authored-by: default avatarAlexander Theißen <alex.theissen@me.com>
      Co-authored-by: default avatarPG Herveou <pgherveou@gmail.com>
      a8ebe9af
  3. Oct 03, 2024
  4. Sep 25, 2024
    • Cyrill Leutwiler's avatar
      [pallet-revive] last call return data API (#5779) · c77095f5
      Cyrill Leutwiler authored
      
      This PR introduces 2 new syscalls: `return_data_size` and
      `return_data_copy`, resembling the semantics of the EVM `RETURNDATASIZE`
      and `RETURNDATACOPY` opcodes.
      
      The ownership of `ExecReturnValue` (the return data) has moved to the
      `Frame`. This allows implementing the new contract API functionality in
      ext with no additional copies. Returned data is passed via contract
      memory, memory is (will be) metered, hence the amount of returned data
      can not be statically known, so we should avoid storing copies of the
      returned data if we can. By moving the ownership of the exectuables
      return value into the `Frame` struct we achieve this.
      
      A zero-copy implementation of those APIs would be technically possible
      without that internal change by making the callsite in the runtime
      responsible for moving the returned data into the frame after any call.
      However, resetting the stored output needs to be handled in ext, since
      plain transfers will _not_ affect the stored return data (and we don't
      want to handle this special call case inside the `runtime` API). This
      has drawbacks:
      - It can not be tested easily in the mock.
      - It introduces an inconsistency where resetting the stored output is
      handled in ext, but the runtime API is responsible to store it back
      correctly after any calls made. Instead, with ownership of the data in
      `Frame`, both can be handled in a single place. Handling both in `fn
      run()` is more natural and leaves less room for runtime API bugs.
      
      The returned output is reset each time _before_ running any executable
      in a nested stack. This change should not incur any overhead to the
      overall memory usage as _only_ the returned data from the last executed
      frame will be kept around at any time.
      
      ---------
      
      Signed-off-by: default avatarCyrill Leutwiler <bigcyrill@hotmail.com>
      Signed-off-by: default avatarxermicus <cyrill@parity.io>
      Co-authored-by: command-bot <>
      Co-authored-by: default avatarPG Herveou <pgherveou@gmail.com>
      c77095f5
  5. Sep 23, 2024
  6. Sep 18, 2024
    • Cyrill Leutwiler's avatar
      [pallet-revive] write sandbox output according to the provided output buffer length (#5743) · c0d5c4d8
      Cyrill Leutwiler authored
      
      Instead of error out if the provided output buffer is smaller than what
      we want to write, we can just write what fits into the output buffer
      instead. We already write back the actual bytes written to the in-out
      pointer, so contracts can check it anyways.
      
      This in turn introduces the benefit of allowing contracts to implicitly
      request only a portion of the returned data from calls and incantations.
      Which is especially beneficial for YUL as the `call` family opcodes have
      a return data size argument and this change removes the need to work
      around it in contract code.
      
      ---------
      
      Signed-off-by: default avatarxermicus <cyrill@parity.io>
      c0d5c4d8
  7. Sep 13, 2024
    • Cyrill Leutwiler's avatar
      [pallet-revive] Add balance_of syscyall for fetching foreign balances (#5675) · 766ab828
      Cyrill Leutwiler authored
      
      This adds an API method `balance_of`, corresponding to the
      [BALANCE](https://www.evm.codes/#31?fork=cancun) EVM opcode.
      
      In `Ext`, `balance` and `balance_of` are internally routed through the
      same new `account_balance` method: `balance` is technically the same as
      `balance_of` with the caller address. This avoids duplicating all the
      tests and avoids a small inefficiency (in theory, `balance` directly
      call `balance_of` however this introduces a round trip of converting the
      target address to a H160 and back).
      
      ---------
      
      Signed-off-by: default avatarCyrill Leutwiler <bigcyrill@hotmail.com>
      Signed-off-by: default avatarxermicus <cyrill@parity.io>
      Co-authored-by: command-bot <>
      766ab828
  8. Sep 12, 2024
  9. Sep 11, 2024
    • Alexander Theißen's avatar
      Send balance when contract doesn't exist (#5664) · ea5fb02e
      Alexander Theißen authored
      Fixes #5577 
      
      I decided to bubble up the error from where we actually try to load the
      contract info. This helps to make sure that we don't miss some entry
      point by accident. The draw back is that we have to live with some
      additional `.expect`.
      
      @pgherveou
      
       With this logic the proxy and its runtime part should be
      completely unaware whether something is a contract call or a balance
      transfer. They should just route everything into pallet_revive.
      
      ---------
      
      Co-authored-by: default avatarCyrill Leutwiler <cyrill@parity.io>
      ea5fb02e
  10. Sep 08, 2024
    • PG Herveou's avatar
      [pallet-revive] update generic runtime types (#5608) · 868a36bd
      PG Herveou authored
      
      fix #5574
      
      - Use U256 instead of BalanceOf<T> and MomentOf<T> in Ext trait
      - Enforce H256 for T::Hash
      
      The Ext trait still depends on the associated type `T: Config`, we can
      look into refactoring it even more later but even in the current state
      it should not influence how the data is encoded / decoded between the
      contract and the host
      ```
      fn caller(&self) -> Origin<Self::T>;
      -> only use to extract the address of the caller 
      
      fn account_id(&self) -> &AccountIdOf<Self::T>;
       -> only used to expose the address or access the account_id internally   
      
      fn gas_meter(&self) -> &GasMeter<Self::T>;
      fn gas_meter_mut(&mut self) -> &mut GasMeter<Self::T>;
       -> encoding does not depend on T
      
      fn call_runtime(&self, call: <Self::T as Config>::RuntimeCall) -> DispatchResultWithPostInfo;
      -> Substrate specific, just an opaque blob of bytes from the contract's perspective
      
      fn contract_info(&mut self) -> &mut ContractInfo<Self::T>;
      fn transient_storage(&mut self) -> &mut TransientStorage<Self::T>;
      -> gated by #[cfg(any(test, feature = "runtime-benchmarks"))]
      ```
      
      ---------
      
      Co-authored-by: default avatarAlexander Theißen <alex.theissen@me.com>
      868a36bd
  11. Sep 05, 2024
  12. Sep 03, 2024
    • Alexander Theißen's avatar
      revive: Make `salt` salt optional to allow for CREATE1 semantics (#5556) · 020cda33
      Alexander Theißen authored
      Before we only supported CREATE2 semantics for contract address
      derivations. In order to be compatible we also want to allow CREATE1
      semantics. We accomplish this to make the salt an `Option` in all places
      where it is used. Supplying `None` will use CREATE1 semantics by just
      using the deployers account nonce.
      
      ## Todo
      - [x] Add new tests specific for CREATE1
      020cda33
  13. Sep 02, 2024
  14. Aug 23, 2024
    • Alexander Theißen's avatar
      Add initial version of `pallet_revive` (#5293) · 559fa1db
      Alexander Theißen authored
      This is a heavily modified and stripped down version of
      `pallet_contracts`. We decided to fork instead of extend the old pallet.
      Reasons for that are:
      
      - There is no benefit of supporting both on the same pallet as the
      intended payload for the new pallet (recompiled YUL) will be using a
      different ABI.
      - It is much easier since it allows us to remove all the code that was
      necessary to support Wasm and focus fully on running cross compiled YUL
      contracts.
      
      **The code is reviewable but can't be merged because it depends on an
      unreleased version of PolkaVM via git.**
      
      ## Current state
      
      All tests are passing and the code is not quick and dirty but written to
      last. The work is not finished, though. It is included in the
      `kitchensink-runtime` and a node can be built. However, we merge early
      in order to be able to start testing other components as early as
      possible.
      
      Outstanding changes are tracked here and will be merged separately:
      https://github.com/paritytech/polkadot-sdk/issues/5308
      
      ## Syscall Interface
      
      The syscall interface is best explored by generating the docs of this
      crate and looking at the `SyscallDoc` trait. Arguments are passed in
      registers a0-a5 in the order they are listed. If there are more than 6
      arguments (call, instantiate) a pointer to a packed struct of the
      arguments is expected as the only argument. I plan to create variants of
      those syscalls with less arguments specifically for YUL.
      
      Functions are just referenced by their name as ASCII within the PolkaVM
      container. Rather than by a syscall number as it was the case in the
      last implementation.
       
      
      ## Changes vs. `pallet_contracts`
      
      The changes are too numerous to list them all here. This is an
      incomplete list:
      
      - Use PolkaVM instead of wasmi to execute contracts
      - Made Runtime generic over a new `Memory` trait as we can't map memory
      directly on PolkaVM anymore
      - No static verification on code upload. Everything is a determinstic
      runtime failure
      - Removed all migrations and reset the pallet version
      - Removed the nonce storage item and instead use the deployers account
      nonce to generate a unique trie
      - We now bump the deployers account nonce on contract instantiation to
      they are bumped even within a batch transaction
      - Removed the instantiation nonce host function: We should add a new
      `instantiate` variant as a replacement for thos
      - ContractInfoOf of uses the indentity hasher now
      - Remove the determinism feature: User of that feature should switch to
      soft floats
      - The `unstable` attribute has been replaced by a `api_version`
      attribute to declare at which version an API became available
      	- leaving out that attribute makes the API effectively unstable
      - a new `api_version` field on the CodeInfo makes sure that old
      contracts can't access new APIs (necessary due to lack of static
      verification.
      - Added a `behaviour_version` field to CodeInfo that can used if we need
      to introduce breaking changes and keep the old behaviour for existing
      contracts
      - Unified storage vs. transient and fixed vs. variable sized keys all
      into one set of multiplexing host functions
      - Removed all contract observeable limits from the `Config` trait and
      instead hardcode them
      - Removed the Schedule
      - Removed all deprecated host functions
      - Simplify chain extension as preperation for making it a pre-compile
      
      ---------
      
      Co-authored-by: command-bot <>
      559fa1db