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

WASM modules as libraries #17

Open
axic opened this issue Jul 28, 2016 · 11 comments
Open

WASM modules as libraries #17

axic opened this issue Jul 28, 2016 · 11 comments

Comments

@axic
Copy link
Member

axic commented Jul 28, 2016

EVM doesn't have a real concept of libraries, rather it was added retroactively with DELEGATECALL and that Solidity ensures a contract defined as a library cannot make use of SSTORE/SLOAD. The VM however still needs to consider it the same as other contracts and ensure that proper rollback mechanism is in place.

A WASM code is called a module, which defines the memory needed and has one or more functions.

One of the premises of using WASM is that we wouldn't need precompiled contracts given the speed loss caused by the bytecode is insignificant compared to EVM. Not using precompiles can also lead to a lot of code duplication.

I think it could be useful supporting a way to store WASM modules on the blockchain, which could be loaded by contracts during the linking stage. Perhaps these modules would be special contracts, which are not meant to be executed.

Ideas welcome how this could fit into the blockchain model we have.

@wanderer
Copy link
Member

Another way we could use it is to replace or supplement CALLs, for(import "contract_address" "method"). This could also offer clients an opportunity to populate a cache of contracts based on the import table.

@axic
Copy link
Member Author

axic commented Aug 24, 2016

So with https://github.com/WebAssembly/design/blob/master/DynamicLinking.md we could make this a reality.

Basically, we could define that an import where the module is an Ethereum address, will load the code from that address, and look up the export table to find the referenced method.

e.g.

  • a library (deployed at 0x4200000000000000000000000000000000000001) has an exported method sha3:
(module
  (export "sha3" $sha3)
  (func $sha3
    (param $offset i32)
    (param $length i32)
    (param $outputOffset i32)
    ..
  )
)
  • a contract can use it in the following manner:
(module
  (import $sha3 "0x4200000000000000000000000000000000000001" "sha3" (param i32 i32 i32))
)

The important bit is that this will run as a single WebAssembly instance and we don't need to do CALL based message passing.

Appropriate cost must be defined. When the module is loaded, each import statement must cost gas in order to avoid DoS attacks (where a contract imports a lot of addresses, each of them must be looked up).

Additionally, to have pure libraries, we can define a library as a module, which doesn't have a symbol exported as "main". Every contract must have "main" exported as the entry point.

This avoids the problem of having libraries which can receive normal contract invocations.

@wanderer
Copy link
Member

Additionally, to have pure libraries, we can define a library as a module, which doesn't have a symbol exported as "main". Every contract must have "main" exported as the entry point.

still not clear on why having main would be a problem. If main was imported and ran it would run in the current environment. So that storage from the imported contract would not be mutable from from a thirdparty contract. Also allowing main would give us a way to easily use EVM1 contracts as libs.

@axic
Copy link
Member Author

axic commented Aug 25, 2016

The problem is not when importing library:main into the contract, but it enabled the library to be executed as a contract as not only loaded as a module.

I don't think eWASM contracts + EVM1 libraries can be mixed.

@wanderer
Copy link
Member

wanderer commented Aug 26, 2016

but it enabled the library to be executed as a contract as not only loaded as a module

Yeah but you still can do that. For example.

(func $main_redux
  (call $main)
)

(export $main)
(export $main_redux)

I don't think you can outright disable main

@axic
Copy link
Member Author

axic commented Aug 26, 2016

If we define a contract as an eWASM module, which has an export called main and no other exports; and we define a library as an eWASM module, which doesn't have an export called main, but has at least one other export,then:

  • when executing a CALL, the destination account and its code is loaded, and if it is eWASM, it follows the contract semantics. e.g., no main - failure ("not a contract")
  • if a contract (which passed the above criteria) is loaded, it can import other libraries

If a destination account has code and cannot be executed, then it cannot receive financial value transfers either and there's no way it can access its account storage.

@axic
Copy link
Member Author

axic commented Jul 16, 2018

A new idea: offer deploy time linking.

Following the above semantics we do run into a problem: should this dynamic linking be done at runtime? If so, how do we charge for that?

A possible solution is to do linking at deploy time and this linking would be done by a metered process, such as the sentinel contract.

One downside is that the state could blow up (linking in large libraries). Therefore it seems to make more sense that the state contains the unlinked binary, but during deployment we do charge for linking. Then clients can make a decision (and choose whichever is better for them):
a) keep the linked binary in the local database
b) link at runtime

Second caveat: linking with the library at the time of deployment has a benefit, that no versioning is needed, but it closes the door from upgradeable libraries.

@jakelang
Copy link
Member

jakelang commented Jul 16, 2018 via email

@poemm
Copy link
Contributor

poemm commented Jul 16, 2018

Good ideas and good points. I just want to write down the design problem.

ewasm contracts will be Wasm modules. So we have the option to use Wasm's import/export infrastructure to allow contracts to link against each other's memory, globals, funcs, and table. Import/export linking is done at module instantiation-time, so ewasm contracts can be linked at contract deploy-time or contract call-time. Using Wasm linking may allow us to eliminate some (or all) *CALL opcodes. There are trade-offs in simplicity, bloat, upgradable libraries, run-time efficiency, maybe others.

This design problem affects things like metering, account abstraction, maybe others.

This is a major design problem. It would be useful to list possibilities, with description/pros/cons of each.

@poemm
Copy link
Contributor

poemm commented Jul 19, 2018

Another possibility for calling functions in other modules: Using call_indirect.

Brief description:

  • A contract can import the table and use call_indirect to call functions based on their index in that table.
  • The Wasm embedding API allows creating, growing, and writing a table. So the Ethereum node can create a custom table with everything a contract requests.
  • Importing occurs at module instantiation-time, so it can be done at contract deploy-time or call-time. In fact, a module instance's table address can be updated any time, but this destroys invariants from validation.

Pros:

  • Wasm already supports importing tables (and importing functions).
  • If importing occurs at call-time, then there is no need to modify the Wasm binary with names of the imported functions, like we would have to do if we allow importing arbitrary functions at call-time.

Cons:

  • Type-checking at run-time. But the Ethereum node may also perform this type-checking to prevent traps.
  • Static analysis is difficult -- since the function called depends on an index which may only be known at run-time.

@axic
Copy link
Member Author

axic commented Jun 8, 2019

Relocations specification: https://github.com/webassembly/tool-conventions/blob/master/Linking.md

It also touches on the producers section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants