Compare commits

...

204 Commits

Author SHA1 Message Date
xermicus 75a83af4da ci: clippy (#227)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-21 16:43:09 +01:00
xermicus 9c330ef8fc llvm-builder: only run expensive tests on linux (#226)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-21 16:38:44 +01:00
Yuri Volkov 687cec31ef Using released LLVM in revive build (#220) 2025-02-21 16:30:26 +01:00
Yuri Volkov 48a019e0ad Fix: add llvm- prefix to llvm version tag (#225)
Needed both for differentiating them from regular releases and for
filtering the tags in automation
2025-02-21 12:05:40 +01:00
xermicus 17a2d2f9f2 update README.md (#223)
Signed-off-by: xermicus <cyrill@parity.io>
2025-02-21 10:51:40 +01:00
Yuri Volkov 6ad7908c5e Using workflow_dispatch for LLVM releases (#222) 2025-02-20 20:00:33 +01:00
Yuri Volkov 840a736fc5 LLVM release workflows (#207)
Co-authored-by: xermicus <cyrill@parity.io>
2025-02-20 12:30:52 +01:00
xermicus 89cdfefab4 remove some dead code leftovers (#218)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-19 10:41:32 +01:00
xermicus 6c2c633651 release resolc v0.1.0-dev.11 (#214)
Signed-off-by: xermicus <cyrill@parity.io>
2025-02-18 08:08:20 +01:00
xermicus a73b0925c6 ci: do not run bun tests (#215) 2025-02-17 17:04:53 +01:00
xermicus ee650cf03a ci: use upstream evm for tests (#213)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-17 11:33:30 +01:00
Evgeny Snitko c2210442b6 Release workflow (#201)
Co-authored-by: xermicus <cyrill@parity.io>
2025-02-17 11:09:10 +01:00
xermicus cb268850a9 llvm-context: remove the linear memory pointer indirection (#211) 2025-02-13 13:21:43 +01:00
xermicus f3a86588f3 update dependencies (#210)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-12 13:12:09 +01:00
xermicus 7233738f45 release resolc v0.1.0-dev.10 (#209)
Signed-off-by: xermicus <cyrill@parity.io>
2025-02-11 15:51:52 +01:00
Sebastian Miasojed 79ec4dd04b Add all resolc dependencies to resolc_web.js file (#176) 2025-02-11 11:55:24 +01:00
xermicus 374563bbe5 integration: add function pointer integration test (#205)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-10 18:50:12 +01:00
xermicus a921e425b4 CI: fix and pin geth (#206) 2025-02-10 17:39:44 +01:00
xermicus 60fc09f787 llvm-context: disable call re-entrancy for send and transfer (#196) 2025-02-06 16:49:50 +01:00
Sebastian Miasojed 10b8ff989c Align emscripten compilation options (#180) 2025-02-06 00:37:10 +01:00
xermicus 157647d5c1 remove superfluous warning and clippy allows (#194)
Signed-off-by: xermicus <cyrill@parity.io>
2025-02-05 12:44:29 +01:00
xermicus 35419e8202 solidity: update custom warnings and version validation (#193) 2025-02-05 11:42:35 +01:00
xermicus de3e7bf253 integration: add create2 test case with duplicate salt (#188)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-04 14:04:14 +01:00
xermicus 9fb24b607d disable werror (#191)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-04 12:43:56 +01:00
xermicus ba7310fdff integration: bugfix blob cache (#192)
Signed-off-by: xermicus <cyrill@parity.io>
2025-02-04 12:11:25 +01:00
dependabot[bot] 4ef495beea Bump openssl from 0.10.68 to 0.10.70 (#190)
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.68 to 0.10.70.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.68...openssl-v0.10.70)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-04 07:28:29 +01:00
xermicus 8ed689e7ec solidity: various small resolc fixes (#189) 2025-02-03 16:16:54 +01:00
xermicus bfda465c32 remove support for legacy evm assembly (#186) 2025-02-03 14:13:43 +01:00
xermicus ab90af49df Solidity: add --libraries to sources (#187)
* bugfix: add libraries to sources

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-01-31 18:08:11 +01:00
Sebastian Miasojed 8201401fef Fix stack overflow issue (#184) 2025-01-31 14:31:34 +01:00
xermicus 1a8a7926e9 implement the coinbase opcode (#179)
Signed-off-by: xermicus <cyrill@parity.io>
2025-01-29 15:24:45 +01:00
xermicus bec5d60b7c release resolc-0.1.0-dev.9 (#178)
Signed-off-by: xermicus <cyrill@parity.io>
2025-01-29 12:49:54 +01:00
xermicus 3608a5a143 runtime-api: pass call arguments in registers instead of spilling to stack (#174)
Companion to paritytech/polkadot-sdk#7319

Signed-off-by: xermicus <cyrill@parity.io>
2025-01-28 12:45:54 +01:00
Sebastian Miasojed 888723eb0d Fix issue with relative path in web worker (#169) 2025-01-22 23:58:47 +01:00
Cyrill Leutwiler fe1b3258d2 bump crate versions (#171)
- bump crate versions
- point out the supported polkadot sdk version in the changelog
2025-01-17 17:29:38 +01:00
Cyrill Leutwiler d8a72e580b release resolc-0.1.0-dev.8 (#170)
Signed-off-by: xermicus <cyrill@parity.io>
2025-01-17 17:00:25 +01:00
Cyrill Leutwiler bd1a22a702 update polkavm to 0.19 (#167)
paritytech/polkadot-sdk#7203 companion:

- Update the polkavm dependency to the latest version.
- Update the polkadot-sdk to the latest version.

Signed-off-by: xermicus <cyrill@parity.io>
2025-01-17 16:59:45 +01:00
Cyrill Leutwiler cec283986f llvm-builder: do not build clang by default (#168)
We only need LLD for cross compilation. This significantly reduces the LLVM build times in a cross compilation scenario. Update the README as a drive-by.
2025-01-17 16:03:04 +01:00
Siphamandla Mjoli 06f43083c3 multiple resolc fixes and improvements (#151)
- Error out early on compiler invocations with invalid base path or include path flags.
- Do not error out if no files and no errors were produced. This aligns resolc closer to sloc.
- Add a CLI test with an involved fixture containing multiple contract remappings to properly testing the standard JSON path.
- Fixes input normalization in the Wasm version.



Co-authored-by: Cyrill Leutwiler <cyrill@parity.io>
2025-01-17 10:10:47 +01:00
Sebastian Miasojed b78b2b2af9 Add test fixtures for the revive WASM version (#160) 2025-01-16 16:01:34 +01:00
Cyrill Leutwiler 8ffe072fee pin the LLVM version (#166)
Signed-off-by: xermicus <cyrill@parity.io>
2025-01-16 10:45:43 +01:00
Cyrill Leutwiler 71fb3ab8d6 vet the Makefile (#165)
- Move the emscripten target flags into the target configuration.
- Improve the readability of the Makefile.

Signed-off-by: xermicus <cyrill@parity.io>
2025-01-15 22:26:56 +01:00
Cyrill Leutwiler 3e7579580b vet workspace dependencies (#163)
- Update the used workspace dependencies.
- Remove the unused workspace dependencies.
- Add the machete CI workflow.
2025-01-15 20:14:54 +01:00
Cyrill Leutwiler ad805543b3 call and create set uncapped resource limits (#161)
- polkadot-sdk#6890 companion
- Adjust the gas price constant for the required polkadot-sdk version as a drive-by
2025-01-15 17:32:31 +01:00
Cyrill Leutwiler 4fbfb97b9e Fix the Wasm build cache (#159)
Follow-ups for https://github.com/paritytech/revive/pull/154
- Fix the cache in the Wasm build
- Remove a no longer needed script
- The Wasm build job uses parity-large
2025-01-15 11:36:59 +01:00
Sebastian Miasojed 939138d0cd Add the revive tests in the browsers (#158) 2025-01-14 22:29:02 +01:00
Cyrill Leutwiler 7f81f37e0c revive llvm builder utility (#154)
Pre-eliminary support for LLVM releases and resolc binary releases by streamlining the build process for all supported hosts platforms.

- Introduce the revive-llvm-builder crate with the revive-llvm builder utilty.
- Do not rely on the LLVM dependency in $PATH to decouple the system LLVM installation from the LLVM host dependency.
- Fix the emscripten build by decoupling the host and native LLVM dependencies. Thus allowing a single LLVM emscripten release that can be used on any host platform.
- An example Dockerfile building an alpine container with a fully statically linked resolc ELF binary.
- Remove the Debian builder utilities and workflow.
2025-01-13 15:58:27 +01:00
Cyrill Leutwiler fde9edab10 Remove the docs Makefile targets (#152)
Documentation of the contracts stack was moved into a dedicated repository.
2025-01-10 11:36:51 +01:00
Sebastian Miasojed d7d60da6f1 Add tests for the Revive WASM version (#147) 2025-01-10 09:12:43 +01:00
Cyrill Leutwiler f49d145e9a update the minium supported rust version to 1.81 (#144)
Signed-off-by: xermicus <cyrill@parity.io>
2024-12-21 09:10:14 +01:00
Cyrill Leutwiler 952c5cc894 resolc-0.1.0-dev.7 (#143)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-12-20 14:33:08 +01:00
Cyrill Leutwiler d8752ec6b5 the basefee opcode (#142)
Signed-off-by: xermicus <cyrill@parity.io>
2024-12-19 18:59:10 +01:00
Cyrill Leutwiler 6ad846a285 the base fee opcode (#141)
Signed-off-by: xermicus <cyrill@parity.io>
2024-12-19 12:44:15 +01:00
Cyrill Leutwiler 3f9771f838 update and fix the linker (#140) 2024-12-18 23:11:06 +01:00
Cyrill Leutwiler 22070a824d the gas limit opcode (#139)
Signed-off-by: xermicus <cyrill@parity.io>
2024-12-18 20:31:42 +01:00
Cyrill Leutwiler d299dd1a19 change getters to register version (#138) 2024-12-18 17:56:37 +01:00
Cyrill Leutwiler 14a598e840 implement the gas opcode (#136) 2024-12-18 17:19:32 +01:00
Cyrill Leutwiler 55ec0988e8 fix the CI runner version (#137)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-12-18 17:03:29 +01:00
Cyrill Leutwiler 909de515c4 Allow arbitrary call data size (#135)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-12-18 14:04:46 +01:00
Sebastian Miasojed afe44ad21b JS: Fix encoding conversion from utf16 to utf8 (#131) 2024-12-11 09:23:02 +01:00
Cyrill Leutwiler 2cb8f82266 calls: supply max ref_time and proof_size limits (#133)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-12-10 16:31:44 +01:00
Cyrill Leutwiler 6f2f158ef1 fix new clippy lint (#132)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-12-10 15:24:25 +01:00
Cyrill Leutwiler 4e5482bad2 fix the commit sha in the version (#129)
Signed-off-by: xermicus <cyrill@parity.io>
2024-12-03 12:34:17 +01:00
Cyrill Leutwiler 0110258d81 release 0.1.0 dev.6 (#128) 2024-11-29 17:45:47 +01:00
Cyrill Leutwiler f0d9d44dce Implement the gasprice opcode (#127) 2024-11-29 17:14:27 +01:00
Cyrill Leutwiler 3f6cd115ee update warnings (#126)
Signed-off-by: xermicus <cyrill@parity.io>
2024-11-29 16:23:36 +01:00
Cyrill Leutwiler 7c00bbb0fc remove unneeded utils (#125)
Signed-off-by: xermicus <cyrill@parity.io>
2024-11-29 16:21:24 +01:00
Cyrill Leutwiler 423a494621 Switch target to 64bit and enable the zbb feature (#120) 2024-11-29 15:56:10 +01:00
Cyrill Leutwiler 08112e3449 Fix broken link in README.md 2024-11-29 10:39:42 +01:00
Jeeyong Um db6ca1fcfa Fix broken link to introduction in README.md (#124) 2024-11-29 10:38:09 +01:00
Sebastian Miasojed 54d154a73c Merge pull request #123 from smiasojed/web
Add web worker compatibility
2024-11-29 10:22:59 +01:00
dependabot[bot] 93f1deb6a5 Bump rustls from 0.23.17 to 0.23.18 (#121)
Bumps [rustls](https://github.com/rustls/rustls) from 0.23.17 to 0.23.18.
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.17...v/0.23.18)

---
updated-dependencies:
- dependency-name: rustls
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-29 09:50:29 +01:00
Sebastian Miasojed 9a150b13f3 Remove hardcoded soljson 2024-11-28 16:54:27 +01:00
Sebastian Miasojed 677cef9c0f Remove comment 2024-11-27 15:30:49 +01:00
Sebastian Miasojed d25be523c1 Update deps 2024-11-27 15:28:04 +01:00
Sebastian Miasojed 6a4fd1e991 Add web worker compatibility 2024-11-27 15:17:26 +01:00
Sebastian Miasojed 81915ddbcb Merge pull request #122 from smiasojed/sync
Remove async JS calls
2024-11-27 14:03:26 +01:00
Sebastian Miasojed 0f25bac4bd Fix CI 2024-11-27 08:49:07 +01:00
Sebastian Miasojed 7d41495587 Fmt 2024-11-27 08:30:07 +01:00
Sebastian Miasojed d6d5acfcce Remove deps on solc 2024-11-26 22:35:18 +01:00
Sebastian Miasojed 130ac48bf0 Fix revive wasm CI 2024-11-26 22:11:26 +01:00
Sebastian Miasojed b65fa2e42c Remove async calls from revive 2024-11-26 22:03:57 +01:00
Sebastian Miasojed 1eb1083d40 Merge pull request #111 from smiasojed/resolc.js
Add compilation to NodeJS module
2024-11-26 14:44:44 +01:00
Sebastian Miasojed 4c0c74f7f4 Fix npm build 2024-11-25 15:36:36 +01:00
Sebastian Miasojed 229c0d452d Merge remote-tracking branch 'origin/main' into resolc.js 2024-11-25 10:54:44 +01:00
Sebastian Miasojed 4e024655a1 Add support for esm and cjs modules 2024-11-25 10:26:22 +01:00
Ermal Kaleci 01b5ed5ba3 Implement delegate_call (#80) 2024-11-23 18:05:21 +01:00
Sebastian Miasojed 892c9b5fbe Update clone-llvm.sh
Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-11-22 19:52:06 +01:00
xermicus 84d47fa738 fix missing semicolon
Signed-off-by: xermicus <cyrill@parity.io>
2024-11-22 16:14:07 +01:00
Cyrill Leutwiler dbb47fd13e experimental: support for debug info (#118)
Signed-off-by: wpt967 <matt.aw@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
2024-11-22 08:56:09 +01:00
Cyrill Leutwiler 87f2bcefb3 dump the elf shared object into the debug output directory (#119)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-11-21 21:48:42 +01:00
Sebastian Miasojed 05925f25f1 Update comment 2024-11-21 13:57:00 +01:00
Sebastian Miasojed 8990b2a486 Update emscripten-build-llvm.sh
Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-11-21 12:49:23 +01:00
Cyrill Leutwiler 89ddfb28c8 CI: ignore the broken test (#116)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-11-21 12:22:15 +01:00
Sebastian Miasojed 32d4b2309c Fix build script 2024-11-21 10:36:12 +01:00
Sebastian Miasojed a772ff1354 Fix build path 2024-11-21 10:29:21 +01:00
Sebastian Miasojed 0a82addf02 Add directory arg support to clone-llvm 2024-11-20 17:15:55 +01:00
Sebastian Miasojed 491850760f Update readme file 2024-11-20 12:57:41 +01:00
Sebastian Miasojed fcbe00f4a9 Merge branch 'main' into resolc.js 2024-11-20 12:51:10 +01:00
Sebastian Miasojed 77406264ea Improve description 2024-11-20 12:42:29 +01:00
Sebastian Miasojed cdebf69fc0 Fix stdin support 2024-11-20 10:54:15 +01:00
Sebastian Miasojed f36d62ca73 Add stdin support 2024-11-20 10:27:57 +01:00
Sebastian Miasojed 39e504703e Add test with standard json args 2024-11-18 16:52:56 +01:00
Sebastian Miasojed 63da7212a1 Add worker code to resolc.js 2024-11-18 14:49:35 +01:00
Sebastian Miasojed 3072c03600 Fix parallel feature 2024-11-18 13:59:48 +01:00
Sebastian Miasojed d88ddb25bd Refactor soljson compiler 2024-11-18 12:19:36 +01:00
Sebastian Miasojed 87dd77b784 Remove libsolc crate 2024-11-18 11:07:45 +01:00
Sebastian Miasojed cece20deb1 Cleanup 2024-11-18 10:18:21 +01:00
Sebastian Miasojed f57ab96eed Revert changes in llvm build 2024-11-15 16:08:36 +01:00
Cyrill Leutwiler 3232382d96 update dependencies (#115)
Signed-off-by: xermicus <cyrill@parity.io>
2024-11-15 13:50:55 +01:00
Cyrill Leutwiler 6a120463c2 implement the blockhash opcode (#114) 2024-11-15 13:11:04 +01:00
Sebastian Miasojed 881b88354c Rename compiler to solc 2024-11-14 17:09:03 +01:00
Cyrill Leutwiler c9dd347755 Add documentation portal (#99) 2024-11-14 14:21:48 +01:00
Sebastian Miasojed 140545ea15 Fix CI 2024-11-14 11:49:20 +01:00
Sebastian Miasojed 010a2ed223 Fmt 2024-11-14 11:44:48 +01:00
Sebastian Miasojed 563864dd25 Fix CI 2024-11-14 11:26:20 +01:00
Sebastian Miasojed ce8bf3d9ef Apply suggestions from previous review 2024-11-14 11:20:33 +01:00
Cyrill Leutwiler f947984671 update 64bit target flags (#113) 2024-11-14 10:29:21 +01:00
Sebastian Miasojed 14991f40ac Fix CI for wasm path 2024-11-13 15:34:41 +01:00
Sebastian Miasojed 6d16790f83 Update GHA 2024-11-12 17:22:15 +01:00
Sebastian Miasojed 64fefe76b5 Removed not needed libs from linking process 2024-11-12 16:07:21 +01:00
Sebastian Miasojed f59b47df7b Add ltinfo dep to GHA 2024-11-12 12:52:11 +01:00
Sebastian Miasojed 6e6fe20c71 Add Missing dep to GHA 2024-11-12 09:52:06 +01:00
Sebastian Miasojed 93d2f3b9d9 Log LLVM version in GHA 2024-11-12 09:47:43 +01:00
Sebastian Miasojed 8a225871ee Fix deps in GHA 2024-11-08 15:53:27 +01:00
Sebastian Miasojed 677aedc6f3 Switch GHA to ubuntu 2024-11-08 15:45:52 +01:00
Sebastian Miasojed 90423ffb6b Remove llvm-15 env from GHA 2024-11-08 15:36:00 +01:00
Sebastian Miasojed 255176978a Remove old llvm-15 from GHA 2024-11-08 15:27:11 +01:00
Sebastian Miasojed 9a8003afbf Install llvm in GHA 2024-11-08 15:10:42 +01:00
Sebastian Miasojed 7f3d0cecb2 Update cmake versions in GHA 2024-11-08 15:00:14 +01:00
Sebastian Miasojed 18376432f1 Fix GHA emsdk path 2024-11-08 14:01:18 +01:00
Sebastian Miasojed 007b79ee62 Use bash in GHA 2024-11-08 13:51:51 +01:00
Sebastian Miasojed 8c7d18aec7 Update GHA for wasm build 2024-11-08 13:46:00 +01:00
Sebastian Miasojed c0a82ce6d2 Update wasm GHA 2024-11-08 13:38:26 +01:00
Sebastian Miasojed c51d50bc88 Add GHA for wasm target 2024-11-08 13:28:45 +01:00
Sebastian Miasojed 94445bab93 Fix compilation for wasm target 2024-11-08 12:06:11 +01:00
Sebastian Miasojed a934ec204e Add temoprary wasm compilation output 2024-11-08 10:55:26 +01:00
Sebastian Miasojed b6baf6cfd9 Make wasm version to compile 2024-11-08 09:54:10 +01:00
Sebastian Miasojed b7b28efded Update solc compiler version check 2024-11-07 15:30:00 +01:00
Sebastian Miasojed d260472330 Fmt 2024-11-07 15:15:52 +01:00
Sebastian Miasojed 4f6debcbe3 Make native version to compaile again 2024-11-07 15:04:35 +01:00
Sebastian Miasojed 9b23e19479 Fix Cargo.toml 2024-11-07 09:43:44 +01:00
Sebastian Miasojed 88a888d138 Merge remote-tracking branch 'origin/main' into resolc.js 2024-11-06 15:04:34 +01:00
Cyrill Leutwiler 4cce4a729e pre-release v0.1.0-dev.5 (#110) 2024-10-31 15:22:34 +01:00
Cyrill Leutwiler 9267a2af02 use the long revive version string in the contract metadata (#109) 2024-10-31 14:52:06 +01:00
Cyrill Leutwiler 173ace72cb solidity: rename the revive metadata (#106)
Rename the revive metadata fields and includes the commit hash and LLVM version in the revive version (similar to what solc does).

Signed-off-by: xermicus <cyrill@parity.io>
2024-10-31 13:00:35 +01:00
Cyrill Leutwiler 37ab2b6782 declare immutable globals during in declare (#108)
Signed-off-by: xermicus <cyrill@parity.io>
2024-10-31 12:07:39 +01:00
Cyrill Leutwiler 43d2ef3ce9 implement the code size opcodes (#107) 2024-10-31 11:46:47 +01:00
Cyrill Leutwiler 68564f9866 display the git revision version information (#105)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-30 14:28:00 +01:00
Cyrill Leutwiler 36d9317831 update the polkadot-sdk and polkavm dependencies (#104)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-30 09:28:24 +01:00
Cyrill Leutwiler 5b3b90db83 support the origin opcode (#103)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-29 18:40:25 +01:00
Cyrill Leutwiler a4043ecde7 update LLVM target features (#102)
Signed-off-by: xermicus <cyrill@parity.io>
2024-10-29 18:17:29 +01:00
Cyrill Leutwiler f985f42370 update polkadot-sdk and inkwell dependencies (#101)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-29 11:27:44 +01:00
Ermal Kaleci aae25107a2 support full storage key space (#100)
- The storage pointer values will no longer be truncated to the register size, allowing for the use of arbitrary storage keys
- Failed storage value reads will now guarantee to return the zero value
2024-10-28 10:18:11 +01:00
Sebastian Miasojed cc38c37481 Set evm.deployedBytecode to the value of evm.bytecode (#95) 2024-10-24 14:59:50 +02:00
Cyrill Leutwiler e56feb95be standard json output: skip serializing keys instead of emitting a null object (#52)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-23 15:28:28 +02:00
Cyrill Leutwiler 995b115c5f bump polkadot-sdk and polkavm (#94)
Signed-off-by: xermicus <cyrill@parity.io>
2024-10-22 19:50:58 +02:00
Ermal Kaleci ee83d28a51 Implement extcodehash (#77) 2024-10-21 10:13:50 +02:00
Cyrill Leutwiler 82ae22c163 tidy up the runtime API crate (#85)
- remove unused runtime API imports and constants
- move runtime api symbols into the revive-runtime-api crate

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-17 10:55:27 +02:00
Cyrill Leutwiler 20e3560398 Makefile: remove duplicate workspace tests from the test target (#90)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-17 10:22:04 +02:00
Cyrill Leutwiler 5bf31db660 bump polkavm and polkadot-sdk (#87)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-15 10:46:20 +02:00
Cyrill Leutwiler f0f344a139 disable sbrk and emulate EVM linear memory internally (#76)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
2024-10-14 15:20:00 +02:00
Cyrill Leutwiler 92a18460e4 support solc 0.8.28 (#84)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-14 13:25:18 +02:00
Cyrill Leutwiler e5233fc46e revive-runner: consider non-reverted transactions as success (#82)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-14 13:24:59 +02:00
Ermal Kaleci adda5a0f12 improve runtime api return value names (#81) 2024-10-14 08:56:26 +02:00
Ermal Kaleci d9842b5427 Fix implementation for balance_of (#79)
The balance_of syscall is now available in pallet-revive.
- Fix balance_of implementation to use correct runtime api
- Add build_address_argument_store helper to be used for address arguments
2024-10-12 12:35:10 +02:00
Cyrill Leutwiler 6335c34a2b remove obsolete runtime builtins
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-11 15:58:28 +02:00
Cyrill Leutwiler 49d2157a84 remove near calls
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-11 15:58:28 +02:00
Cyrill Leutwiler e131eebf50 remove system mode and request memoization
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-11 15:58:28 +02:00
Cyrill Leutwiler 705d1d7866 run signed_remainder test in differential mode (#75) 2024-10-10 19:26:04 +02:00
Cyrill Leutwiler d5d419cefc implement immutable variables codegen (#70) 2024-10-10 13:33:00 +02:00
Cyrill Leutwiler 8b7fe8e3d7 deny clippy warnings by default (#73) 2024-10-09 20:19:12 +02:00
xermicus b344e0cff5 Revert "implement immutable variables codegen"
This reverts commit 0e6a6d12c3.
2024-10-09 03:43:05 +02:00
xermicus 0e6a6d12c3 implement immutable variables codegen
Signed-off-by: xermicus <cyrill@parity.io>
2024-10-09 03:37:56 +02:00
Cyrill Leutwiler 77fe683f18 remove the test encoding option (#65) 2024-10-04 09:59:27 +02:00
wpt967 e8fcd6118e Merge pull request #55 from wpt967/revive-debian-x86-build
[workflows] Add workflow for building revive in a debian container.
2024-09-30 17:25:08 +01:00
wpt967 ad46e94ebd [workflows] Add workflow for building revive in a debian container.
Makefile: Add target 'install-revive' to build revive with the
installation path specified by variable REVIVE_INSTALL_DIR.

Add utils directory with scripts for building revive in a container.

Add utils/build-revive.sh taking option argument '-o <install-dir>' to
build revive with the specified install directory.

Add utils/revive-builder-debian.dockerfile to make a docker container
for building revive in a Debian environment.
2024-09-30 12:02:57 +01:00
Cyrill Leutwiler 6585973e99 Updated call semantics (#56)
- Update pallet-revive dependency
- Implement calls according to pallet-revive call semantics
- Switch to the new return data API in pallet revive and get rid of return data buffer
- Remove a bunch of resulting dead code
2024-09-28 20:03:03 +02:00
Cyrill Leutwiler 066acc4663 set chain_id in test runtime
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-28 19:17:41 +02:00
Cyrill Leutwiler 287272b789 sync runtime with the pallet (#54) 2024-09-24 09:14:36 +02:00
Cyrill Leutwiler f621971a13 move the repository to paritytech org (#49) 2024-09-17 14:53:17 +02:00
Cyrill Leutwiler b8bd44b62a install solc 0.8.27 on CI (#47)
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-16 13:17:30 +02:00
Cyrill Leutwiler d8c708eba5 support solc 0.8.27
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-16 12:43:49 +02:00
Cyrill Leutwiler 72d958392b revise alloca at function entry later
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-16 12:42:50 +02:00
Cyrill Leutwiler 616f044633 always build alloca in the entry block (#46)
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-13 21:54:42 +02:00
xermicus 7dc8e6051e enable compressed instructions extension
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-13 14:55:16 +02:00
xermicus 783fa640e4 temporarily disable pvm linker optimizations
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-13 14:52:47 +02:00
xermicus f086c57442 bump up runner runtime limits
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-13 14:52:09 +02:00
xermicus 0f2b55f6ff fixed output size for transferred value
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-13 08:41:23 +02:00
wpt967 ac9215329c [solidity] Fix wrong check on recursive-process-input CLI option. (#42) 2024-09-10 19:11:36 +02:00
Cyrill Leutwiler 6635a0b337 fixed size event topics
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-10 09:09:52 +02:00
Cyrill Leutwiler 77df88b3cb update dependencies
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-10 09:04:55 +02:00
Cyrill Leutwiler 2955f77772 implement self balance
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-09 09:40:24 +02:00
Cyrill Leutwiler d77ee1e0d4 runner: endow test accounts on genesis
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-06 13:50:01 +02:00
xermicus c111bcbc4d common: remove unused constants
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-05 20:02:33 +02:00
xermicus 9e73c48150 remove the extra abi data
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-05 18:10:24 +02:00
Cyrill Leutwiler afd9f26aed runner: gate the solidity frontend behind a feature
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-04 20:12:27 +02:00
Cyrill Leutwiler a413238464 runner: CodeUpload specs action
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-04 18:03:30 +02:00
Cyrill Leutwiler d47539159b enable call context address tests
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-09-04 12:55:44 +02:00
Cyrill Leutwiler 393d90165e pallet_revive: Account20 (#41)
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-04 12:42:41 +02:00
xermicus 7c934e5ca1 fix some clippies
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-04 11:31:18 +02:00
Cyrill Leutwiler d2f76b645f switch to pallet_revive runtime (#40)
Signed-off-by: xermicus <cyrill@parity.io>
2024-09-03 17:18:22 +02:00
Sebastian Miasojed 5ac67bdc0d Initial wasm support 2024-08-29 17:28:31 +02:00
Sebastian Miasojed 41c8d4e955 Add support for --license arg (#38) 2024-08-29 16:26:06 +02:00
321 changed files with 16752 additions and 12979 deletions
+17
View File
@@ -0,0 +1,17 @@
[target.wasm32-unknown-emscripten]
rustflags = [
"-Clink-arg=-sEXPORTED_FUNCTIONS=_main,_free,_malloc",
"-Clink-arg=-sNO_INVOKE_RUN=1",
"-Clink-arg=-sEXIT_RUNTIME=1",
"-Clink-arg=-sALLOW_MEMORY_GROWTH=1",
"-Clink-arg=-sEXPORTED_RUNTIME_METHODS=FS,callMain,stringToNewUTF8",
"-Clink-arg=-sMODULARIZE=1",
"-Clink-arg=-sEXPORT_NAME=createRevive",
"-Clink-arg=-sWASM_ASYNC_COMPILATION=0",
"-Clink-arg=-sDYNAMIC_EXECUTION=0",
"-Clink-arg=-sALLOW_TABLE_GROWTH=1",
"-Clink-arg=--js-library=js/embed/soljson_interface.js",
"-Clink-arg=--pre-js=js/embed/pre.js",
"-Clink-arg=-sSTACK_SIZE=128kb",
"-Clink-arg=-sNODEJS_CATCH_EXIT=0"
]
+7
View File
@@ -0,0 +1,7 @@
emsdk
llvm*/
target-llvm/
target/
node_modules/
utils/
build/
+127
View File
@@ -0,0 +1,127 @@
name: Build revive-wasm
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
REVIVE_WASM_INSTALL_DIR: ${{ github.workspace }}/target/wasm32-unknown-emscripten/release
jobs:
build-revive-wasm:
runs-on: parity-large
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- name: Cache LLVM build
id: cache-llvm
uses: actions/cache@v3
with:
path: |
target-llvm/emscripten/target-final
target-llvm/gnu/target-final
# Use a unique key based on LLVM version or configuration files to avoid cache invalidation
key: llvm-build-${{ runner.os }}-${{ hashFiles('LLVM.lock', 'Cargo.toml', 'Cargo.lock', 'crates/llvm-builder/**', '.github/workflows/build-revive-wasm.yml') }}
- name: Install system dependencies
run: |
sudo apt-get update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld
- name: Install Rust stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
components: rust-src
target: wasm32-unknown-emscripten
- name: Install LLVM build dependencies
run: |
make install-llvm-builder
revive-llvm --target-env emscripten clone
- name: Setup revive environment variables
run: |
echo "LLVM_SYS_181_PREFIX=$(pwd)/target-llvm/gnu/target-final" >> $GITHUB_ENV
echo "REVIVE_LLVM_TARGET_PREFIX=$(pwd)/target-llvm/emscripten/target-final" >> $GITHUB_ENV
- name: Build host LLVM
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: |
revive-llvm build --llvm-projects lld --llvm-projects clang
- name: Build target LLVM
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: |
source emsdk/emsdk_env.sh
revive-llvm --target-env emscripten build --llvm-projects lld
- run: |
rustup show
cargo --version
rustup +nightly show
cargo +nightly --version
cmake --version
bash --version
- name: Use Cached LLVM
if: steps.cache-llvm.outputs.cache-hit == 'true'
run: |
echo "Using cached LLVM"
- name: Build revive
run: |
source emsdk/emsdk_env.sh
make install-wasm
- uses: actions/upload-artifact@v4
with:
name: revive-wasm
path: |
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.js
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.wasm
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc_web.js
retention-days: 1
test-revive-wasm:
needs: build-revive-wasm
strategy:
matrix:
os: ["ubuntu-24.04", "macos-14", "windows-2022"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Create Target Directory
run: mkdir -p ${{ env.REVIVE_WASM_INSTALL_DIR }}
- name: Download Artifact
uses: actions/download-artifact@v4
with:
name: revive-wasm
path: ${{ env.REVIVE_WASM_INSTALL_DIR }}
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- name: Install packages
run: npm install
- name: Run Playwright tests
run: |
cd js
npx playwright install --with-deps
npx playwright test
- name: Test revive
run: |
echo "Running tests for ${{ matrix.os }}"
npm run test:wasm
+36
View File
@@ -0,0 +1,36 @@
module.exports = async ({
octokit,
context,
releasePrefix,
artifactSuffix,
}) => {
let page = 1;
while (true) {
const res = await octokit.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
page,
});
if (res.data.length === 0) {
throw new Error(
`No LLVM releases with '${artifactSuffix}' atifacts found! Please release LLVM before running this workflow.`,
);
}
for (let release of res.data) {
if (release.tag_name.startsWith(releasePrefix)) {
for (let asset of release.assets) {
if (asset.name.includes(artifactSuffix)) {
return asset.browser_download_url;
}
}
console.warn(
`LLVM release ${release.tag_name} doesn't have a '${artifactSuffix}' artifact; searching for older releases...`,
);
}
}
page++;
}
};
+167
View File
@@ -0,0 +1,167 @@
name: Release LLVM
on:
workflow_dispatch:
inputs:
llvm_version:
type: string
required: true
description: llvm version in "x.x.x" format, e.g. "18.1.8"
env:
CARGO_TERM_COLOR: always
jobs:
create-release:
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.resolve-version.outputs.version }}
steps:
- id: resolve-version
run: |
echo "version=llvm-${{ inputs.llvm_version }}-revive.${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
- name: create release
uses: softprops/action-gh-release@v2
with:
name: "LLVM binaries release: ${{ steps.resolve-version.outputs.version }}"
body: "This release includes binaries of LLVM, used to compile revive itself"
make_latest: "false"
tag_name: ${{ steps.resolve-version.outputs.version }}
build-macos:
strategy:
matrix:
os: [macos-14, macos-13]
include:
- os: macos-13
arch: x64
- os: macos-14
arch: arm64
needs: create-release
runs-on: ${{ matrix.os }}
name: "build-macos-${{ matrix.arch }}"
env:
RUST_LOG: trace
permissions:
contents: write # for uploading assets to release
steps:
- uses: actions/checkout@v4
- name: install macos deps
run: |
brew install ninja
- name: versions
run: |
rustup show
cargo --version
cmake --version
echo "bash:" && bash --version
echo "ninja:" && ninja --version
echo "clang:" && clang --version
- name: Build LLVM
run: |
make install-llvm
- name: clean
# check removed files
run: |
cd target-llvm/gnu/target-final/bin/
rm diagtool llvm-libtool-darwin llvm-lipo llvm-pdbutil llvm-dwarfdump llvm-nm llvm-readobj llvm-cfi-verify \
sancov llvm-debuginfo-analyzer llvm-objdump llvm-profgen llvm-extract llvm-jitlink llvm-c-test llvm-gsymutil llvm-dwp \
dsymutil llvm-dwarfutil llvm-exegesis lli clang-rename bugpoint clang-extdef-mapping clang-refactor c-index-test \
llvm-reduce llvm-lto clang-linker-wrapper llc llvm-lto2
- name: package artifacts
run: |
tar -czf "${{ needs.create-release.outputs.version }}-macos-${{ matrix.arch }}.tar.gz" target-llvm/gnu/target-final
- name: upload archive to release
uses: softprops/action-gh-release@v2
with:
make_latest: "false"
tag_name: ${{ needs.create-release.outputs.version }}
files: |
${{ needs.create-release.outputs.version }}-macos-${{ matrix.arch }}.tar.gz
build-linux-all:
needs: create-release
runs-on: parity-large
env:
RUST_LOG: trace
permissions:
contents: write # for uploading assets to release
steps:
- uses: actions/checkout@v4
- name: install linux deps
run: |
sudo apt-get update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
components: rust-src
target: wasm32-unknown-emscripten
rustflags: ""
- name: versions
run: |
rustup show
cargo --version
cmake --version
echo "bash:" && bash --version
echo "ninja:" && ninja --version
echo "clang:" && clang --version
- name: Build host LLVM
run: |
make install-llvm
- name: Build gnu LLVM
run: |
revive-llvm clone
revive-llvm build --llvm-projects lld --llvm-projects clang
- name: Build musl LLVM
run: |
revive-llvm --target-env musl build --llvm-projects lld --llvm-projects clang
- name: Build emscripten LLVM
run: |
revive-llvm --target-env emscripten clone
source emsdk/emsdk_env.sh
revive-llvm --target-env emscripten build --llvm-projects lld
- name: clean
# check removed files
run: |
for target in gnu emscripten musl; do
cd target-llvm/${target}/target-final/bin/
rm -rf diagtool llvm-libtool-darwin llvm-lipo llvm-pdbutil llvm-dwarfdump llvm-nm llvm-readobj llvm-cfi-verify \
sancov llvm-debuginfo-analyzer llvm-objdump llvm-profgen llvm-extract llvm-jitlink llvm-c-test llvm-gsymutil llvm-dwp \
dsymutil llvm-dwarfutil llvm-exegesis lli clang-rename bugpoint clang-extdef-mapping clang-refactor c-index-test \
llvm-reduce llvm-lto clang-linker-wrapper llc llvm-lto2 llvm-otool llvm-readelf
cd -
done
- name: package artifacts
run: |
tar -czf "${{ needs.create-release.outputs.version }}-x86_64-linux-gnu-linux.tar.gz" target-llvm/gnu/target-final
tar -czf "${{ needs.create-release.outputs.version }}-x86_64-linux-musl.tar.gz" target-llvm/musl/target-final
tar -czf "${{ needs.create-release.outputs.version }}-wasm32-unknown-emscripten.tar.gz" target-llvm/emscripten/target-final
- name: upload archive to release
uses: softprops/action-gh-release@v2
with:
make_latest: "false"
tag_name: ${{ needs.create-release.outputs.version }}
files: |
${{ needs.create-release.outputs.version }}-x86_64-linux-gnu-linux.tar.gz
${{ needs.create-release.outputs.version }}-x86_64-linux-musl.tar.gz
${{ needs.create-release.outputs.version }}-wasm32-unknown-emscripten.tar.gz
+366
View File
@@ -0,0 +1,366 @@
name: Release
run-name: Release ${{ github.ref_name }}
on:
push:
branches:
- "main"
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
env:
#rust-musl-cross:x86_64-musl
RUST_MUSL_CROSS_IMAGE: messense/rust-musl-cross@sha256:68b86bc7cb2867259e6b233415a665ff4469c28b57763e78c3bfea1c68091561
RUST_LOG: trace
jobs:
tag:
runs-on: ubuntu-24.04
permissions:
contents: write
outputs:
TAG: ${{ steps.versions.outputs.TAG }}
PKG_VER: ${{ steps.versions.outputs.PKG_VER }}
RELEASE_NOTES: ${{ steps.versions.outputs.RELEASE_NOTES }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-tags: "true"
fetch-depth: 0
- name: Versions
id: versions
run: |
export CURRENT_TAG=$(git describe --tags --abbrev=0 --exclude "llvm-*")
export PKG_VER=v$(cat Cargo.toml | grep -A 5 package] | grep version | cut -d '=' -f 2 | tr -d '"' | tr -d " ")
echo "Current tag $CURRENT_TAG"
echo "Package version $PKG_VER"
#
echo "PKG_VER=$PKG_VER" >> $GITHUB_OUTPUT
if [[ $CURRENT_TAG == $PKG_VER ]];
then
echo "Tag is up to date. Nothing to do.";
export TAG=old;
else
echo "Tag was updated.";
export TAG=new;
fi
echo "TAG=$TAG" >> $GITHUB_OUTPUT
# Generating release notes early, in order to avoid checkout at the last step
export RELEASE_NOTES="$(sed '/^## '${PKG_VER}'/,/^## v/!d' CHANGELOG.md | sed -e '1d' -e '$d')"
echo "Release notes:"
echo "$RELEASE_NOTES"
echo 'RELEASE_NOTES<<EOF' >> $GITHUB_OUTPUT
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
build-macos:
strategy:
matrix:
os: [macos-14, macos-13]
include:
- os: macos-13
arch: x64
- os: macos-14
arch: arm64
if: ${{ needs.tag.outputs.TAG == 'new' }}
runs-on: ${{ matrix.os }}
name: "build-macos-${{ matrix.arch }}"
needs: [tag]
steps:
- uses: actions/checkout@v4
- name: Get latest macos ${{ matrix.arch }} LLVM release artifact
id: get-llvm-artifact
uses: actions/github-script@v7
with:
result-encoding: string
script: |
const getReleaseArtifact = require("./.github/workflows/get-release-artifact.js");
return await getReleaseArtifact({
octokit: github,
context,
releasePrefix: "llvm-",
artifactSuffix: "-macos-${{ matrix.arch }}"
});
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
components: rust-src
target: wasm32-unknown-emscripten
rustflags: ""
- name: install macos deps
run: |
brew install ninja
- name: versions
run: |
rustup show
cargo --version
cmake --version
echo "bash:" && bash --version
echo "ninja:" && ninja --version
echo "clang:" && clang --version
- name: download llvm
run: |
curl -L -o llvm.tar.gz "${{ steps.get-llvm-artifact.outputs.result }}"
tar -xvf llvm.tar.gz
- name: build revive
run: |
export LLVM_SYS_181_PREFIX=$PWD/target-llvm/gnu/target-final
make install-bin
cp ./target/release/resolc ./target/release/resolc-${{ matrix.arch }}
- name: check revive
run: |
mkdir solc
curl -sSLo solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.28/solc-macos
chmod +x solc/solc
PATH=$PWD/solc:$PATH
result=$(./target/release/resolc-${{ matrix.arch }} --bin crates/integration/contracts/flipper.sol)
echo $result
if [[ $result == *'0x50564d'* ]]; then exit 0; else exit 1; fi
- uses: actions/upload-artifact@v4
with:
name: "revive-macos-${{ matrix.arch }}"
path: |
./target/release/resolc-${{ matrix.arch }}
retention-days: 1
macos-universal-binary:
runs-on: macos-14
needs: [build-macos]
steps:
- uses: actions/download-artifact@v4
with:
pattern: revive-macos-*
path: revive-macos
- name: run lipo
run: |
lipo revive-macos/revive-macos-arm64/resolc-arm64 revive-macos/revive-macos-x64/resolc-x64 -create -output resolc-macos
- name: compress macos artifact
run: |
tar -czf resolc-macos.tar.gz ./resolc-macos
- uses: actions/upload-artifact@v4
with:
name: revive-macos
path: |
resolc-macos.tar.gz
retention-days: 1
build-linux-all:
if: ${{ needs.tag.outputs.TAG == 'new' }}
runs-on: parity-large
needs: [tag]
steps:
- uses: actions/checkout@v4
- name: Get latest linux LLVM release artifact
id: get-llvm-musl-artifact
uses: actions/github-script@v7
with:
result-encoding: string
script: |
const getReleaseArtifact = require("./.github/workflows/get-release-artifact.js")
return await getReleaseArtifact({
octokit: github,
context,
releasePrefix: "llvm-",
artifactSuffix: "-x86_64-linux-musl"
})
- name: install linux deps
run: |
sudo apt-get update && sudo apt-get install -y cmake ninja-build \
curl git libssl-dev pkg-config clang lld musl
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
components: rust-src
target: wasm32-unknown-emscripten
rustflags: ""
- name: versions
run: |
rustup show
cargo --version
cmake --version
echo "bash:" && bash --version
echo "ninja:" && ninja --version
echo "clang:" && clang --version
- name: download llvm
run: |
curl -L -o llvm.tar.gz "${{ steps.get-llvm-musl-artifact.outputs.result }}"
tar -xvf llvm.tar.gz
# Build revive
- name: build musl
run: |
mkdir resolc-out
docker run -v $PWD:/opt/revive $RUST_MUSL_CROSS_IMAGE /bin/bash -c "
cd /opt/revive
apt update && apt upgrade -y && apt install -y pkg-config
export LLVM_SYS_181_PREFIX=/opt/revive/target-llvm/musl/target-final
make install-bin
cp /root/.cargo/bin/resolc /opt/revive/resolc-out/resolc-static-linux
"
- name: check musl
run: |
mkdir solc
curl -sSLo solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.28/solc-static-linux
chmod +x solc/solc
PATH=$PWD/solc:$PATH
result=$(./resolc-out/resolc-static-linux --bin crates/integration/contracts/flipper.sol)
echo $result
if [[ $result == *'0x50564d'* ]]; then exit 0; else exit 1; fi
- name: compress musl artifact
run: |
tar --strip-components 1 -czf resolc-static-linux.tar.gz ./resolc-out/resolc-static-linux
- uses: actions/upload-artifact@v4
with:
name: revive-linux
path: |
./resolc-static-linux.tar.gz
retention-days: 1
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- name: Get latest emscripten LLVM release artifact
id: get-llvm-emscripten-artifact
uses: actions/github-script@v7
with:
result-encoding: string
script: |
const getReleaseArtifact = require("./.github/workflows/get-release-artifact.js")
return await getReleaseArtifact({
octokit: github,
context,
releasePrefix: "llvm-",
artifactSuffix: "-wasm32-unknown-emscripten"
})
- name: download llvm
run: |
curl -L -o llvm.tar.gz "${{ steps.get-llvm-emscripten-artifact.outputs.result }}"
tar -xvf llvm.tar.gz
- name: build wasm
run: |
make install-llvm-builder
revive-llvm --target-env emscripten clone
export LLVM_SYS_181_PREFIX=$PWD/target-llvm/musl/target-final
export REVIVE_LLVM_TARGET_PREFIX=$PWD/target-llvm/emscripten/target-final
source emsdk/emsdk_env.sh
rustup target add wasm32-unknown-emscripten
make install-wasm
- name: check wasm
run: |
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.28/soljson.js
node -e "
const soljson = require('solc/soljson');
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
const compiler = createRevive();
compiler.soljson = soljson;
const standardJsonInput =
{
language: 'Solidity',
sources: {
'MyContract.sol': {
content: 'pragma solidity ^0.8.0; contract MyContract { function greet() public pure returns (string memory) { return \'Hello\'; } }',
},
},
settings: { optimizer: { enabled: false } }
};
compiler.writeToStdin(JSON.stringify(standardJsonInput));
compiler.callMain(['--standard-json']);
// Collect output
const stdout = compiler.readFromStdout();
const stderr = compiler.readFromStderr();
if (stderr) { console.error(stderr); process.exit(1); }
let out = JSON.parse(stdout);
let bytecode = out.contracts['MyContract.sol']['MyContract'].evm.bytecode.object
console.log(bytecode);
if(!bytecode.startsWith('50564d')) { process.exit(1); }
"
- name: compress wasm artifact
run: |
tar --strip-components 3 -czf resolc-wasm.tar.gz \
./target/wasm32-unknown-emscripten/release/resolc.js \
./target/wasm32-unknown-emscripten/release/resolc.wasm \
./target/wasm32-unknown-emscripten/release/resolc_web.js
- uses: actions/upload-artifact@v4
with:
name: revive-wasm
path: |
resolc-wasm.tar.gz
retention-days: 1
create-release:
needs: [tag, build-linux-all, macos-universal-binary]
runs-on: ubuntu-24.04
permissions:
contents: write
outputs:
upload_url: ${{ steps.create_release.outputs.result }}
steps:
- name: Download revive-wasm
uses: actions/download-artifact@v4
with:
name: revive-wasm
path: resolc-wasm/
- name: Download revive-linux
uses: actions/download-artifact@v4
with:
name: revive-linux
path: resolc-linux/
- name: Download revive-macos
uses: actions/download-artifact@v4
with:
name: revive-macos
path: resolc-macos/
- name: create-release
uses: softprops/action-gh-release@v2
with:
body: ${{ needs.tag.outputs.RELEASE_NOTES }}
tag_name: ${{ needs.tag.outputs.PKG_VER }}
name: ${{ needs.tag.outputs.PKG_VER }}
draft: true
files: |
./resolc-linux/resolc-static-linux.tar.gz
./resolc-macos/resolc-macos.tar.gz
./resolc-wasm/resolc-wasm.tar.gz
+20 -8
View File
@@ -11,7 +11,7 @@ env:
jobs:
build-ubuntu-x86:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
@@ -19,19 +19,25 @@ jobs:
- name: Install solc
run: |
mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.26/solc-static-linux
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.28/solc-static-linux
chmod +x solc/solc
echo "$(pwd)/solc/" >> $GITHUB_PATH
- name: Install LLVM
run: |
curl -sSL --output llvm.tar.xz https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.4/clang+llvm-18.1.4-x86_64-linux-gnu-ubuntu-18.04.tar.xz
tar Jxf llvm.tar.xz
mv clang+llvm-18.1.4-x86_64-linux-gnu-ubuntu-18.04 llvm18/
echo "$(pwd)/llvm18/bin" >> $GITHUB_PATH
curl -sSL --output llvm.tar.xz https://github.com/paritytech/revive/releases/download/v0.1.0-dev.7/clang+llvm-18.1.8-x86_64-linux-gnu-ubuntu-24.04.tar.xz
mkdir llvm18
tar Jxf llvm.tar.xz -C llvm18/
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm18" >> $GITHUB_ENV
- name: Install apt dependencies
run: sudo apt update && sudo apt install -y libtinfo5
- name: Install geth
run: |
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt update
sudo apt install -y ethereum
- name: Machete
uses: bnjbvr/cargo-machete@main
- name: Format
run: make format
@@ -44,3 +50,9 @@ jobs:
- name: Test CLI
run: make test-cli
- uses: actions/upload-artifact@v4
with:
name: ${{ github.job }}-resolc
path: ./target/release/resolc
retention-days: 1
+7 -2
View File
@@ -1,4 +1,5 @@
/target
target-llvm
*.dot
.vscode/
.DS_Store
@@ -6,11 +7,15 @@
/*.yul
/*.ll
/*.s
/llvm-project
/llvm18.0
/llvm*
node_modules
artifacts
tmp
package-lock.json
/*.html
/build
soljson.js
test-results
playwright-report
.cache
emsdk
+141
View File
@@ -0,0 +1,141 @@
# Changelog
## Unreleased
This is a development pre-release.
Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`
## v0.1.0-dev.11
This is a development pre-release.
Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`
### Added
### Changed
### Fixed
- A bug causing incorrect loads from the emulated EVM linear memory.
- A missing integer truncate after switching to 64bit.
## v0.1.0-dev.10
This is a development pre-release.
Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`
### Added
- Support for the `coinbase` opcode.
- The resolc web JS version.
### Changed
- Missing the `--overwrite` flag emits an error instead of a warning.
- The `resolc` executable prints the help by default.
- Removed support for legacy EVM assembly (EVMLA) translation.
- integration: identify cached code blobs on source code to fix potential confusions.
- Setting base, include or allow paths in emscripten is now a hard error.
- Employ a heuristic to detect `address.transfer` and `address.send` calls.
If detected, the re-entrant call flag is not set and 0 deposit limit is endowed.
### Fixed
- Solidity: Add the solc `--libraries` files to sources.
- A data race in tests.
- Fix `broken pipe` errors.
- llvm-builder: Allow warnings.
- solidity: Fix the custom compiler warning messages.
## v0.1.0-dev.9
This is a development pre-release.
### Added
### Changed
- Syscalls with more than 6 arguments now pack them into registers.
### Fixed
- Remove reloading of the resolc.js file (fix issue with relative path in web worker)
## v0.1.0-dev.8
This is a development pre-release.
### Added
- The `revive-llvm-builder` crate with the `revive-llvm` helper utility for streamlined management of the LLVM framework dependency.
- Initial support for running `resolc` in the browser.
### Changed
- Suported contracts runtime is polkadot-sdk git version `d62a90c8c729acd98c7e9a5cab9803b8b211ffc5`.
- The minimum supported Rust version is `1.81.0`.
- Error out early instead of invoking `solc` with invalid base or include path flags.
### Fixed
- Decouple the LLVM target dependency from the LLVM host dependency.
- Do not error out if no files and no errors were produced. This aligns resolc closer to solc.
- Fixes input normalization in the Wasm version.
## v0.1.0-dev.7
This is a development pre-release.
### Added
- Implement the `GASPRICE` opcode.
- Implement the `BASEFEE` opcode.
- Implement the `GASLIMIT` opcode.
### Changed
- The `GAS` opcode now returns the remaining `ref_time`.
- Contracts can now be supplied call data input of arbitrary size.
- Some syscalls now return the value in a register, slightly improving emitted contract code.
- Calls forward maximum weight limits instead of 0, anticipating a change in polkadot-sdk where weight limits of 0 no longer interprets as uncapped limit.
### Fixed
- A linker bug which was preventing certain contracts from linking with the PVM linker.
- JS: Fix encoding conversion from JS string (UTF-16) to UTF-8.
- The git commit hash slug is always displayed in the version string.
## v0.1.0-dev.6
This is a development pre-release.
# Added
- Implement the `BLOCKHASH` opcode.
- Implement delegate calls.
- Implement the `GASPRICE` opcode. Currently hard-coded to return `1`.
- The ELF shared object contract artifact is dumped into the debug output directory.
- Initial support for emitting debug info (opt in via the `-g` flag)
# Changed
- resolc now emits 64bit PolkaVM blobs, reducing contract code size and execution time.
- The RISC-V bit-manipulation target feature (`zbb`) is enabled.
# Fixed
- Compilation to Wasm (for usage in node and web browsers)
## v0.1.0-dev.5
This is development pre-release.
# Added
- Implement the `CODESIZE` and `EXTCODESIZE` opcodes.
# Changed
- Include the full revive version in the contract metadata.
# Fixed
## v0.1.0-dev-4
This is development pre-release.
# Added
- Support the `ORIGIN` opcode.
# Changed
- Update polkavm to `v0.14.0`.
- Enable the `a`, `fast-unaligned-access` and `xtheadcondmov` LLVM target features, decreasing the code size for some contracts.
# Fixed
Generated
+3231 -1381
View File
File diff suppressed because it is too large Load Diff
+54 -46
View File
@@ -3,77 +3,85 @@ resolver = "2"
members = ["crates/*"]
[workspace.package]
version = "0.1.0"
version = "0.1.0-dev.11"
authors = [
"Cyrill Leutwiler <cyrill@parity.io>",
"Parity Technologies <admin@parity.io>",
]
license = "MIT/Apache-2.0"
edition = "2021"
repository = "https://github.com/xermicus/revive"
repository = "https://github.com/paritytech/revive"
rust-version = "1.81.0"
[workspace.dependencies]
revive-benchmarks = { version = "0.1.0", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0", path = "crates/builtins" }
revive-common = { version = "0.1.0", path = "crates/common" }
revive-differential = { version = "0.1.0", path = "crates/differential" }
revive-integration = { version = "0.1.0", path = "crates/integration" }
revive-linker = { version = "0.1.0", path = "crates/linker" }
lld-sys = { version = "0.1.0", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0", path = "crates/llvm-context" }
pallet-contracts-pvm-llapi = { version = "0.1.0", path = "crates/pallet-contracts-pvm-llapi" }
revive-runner = { version = "0.1.0", path = "crates/runner" }
revive-solidity = { version = "0.1.0", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0", path = "crates/stdlib" }
revive-benchmarks = { version = "0.1.0-dev.11", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0-dev.11", path = "crates/builtins" }
revive-common = { version = "0.1.0-dev.11", path = "crates/common" }
revive-differential = { version = "0.1.0-dev.11", path = "crates/differential" }
revive-integration = { version = "0.1.0-dev.11", path = "crates/integration" }
revive-linker = { version = "0.1.0-dev.11", path = "crates/linker" }
lld-sys = { version = "0.1.0-dev.11", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0-dev.11", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0-dev.11", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0-dev.11", path = "crates/runner" }
revive-solidity = { version = "0.1.0-dev.11", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0-dev.11", path = "crates/stdlib" }
revive-build-utils = { version = "0.1.0-dev.11", path = "crates/build-utils" }
hex = "0.4"
petgraph = "0.6"
cc = "1.0"
libc = "0.2"
tempfile = "3.8"
hex = "0.4.3"
cc = "1.2"
libc = "0.2.169"
tempfile = "3.17"
anyhow = "1.0"
semver = { version = "1.0", features = ["serde"] }
itertools = "0.12"
itertools = "0.14"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["arbitrary_precision"] }
regex = "1.10"
once_cell = "1.19"
num = "0.4"
once_cell = "1.20"
num = "0.4.3"
sha1 = "0.10"
sha2 = "0.10"
sha3 = "0.10"
md5 = "0.7"
colored = "2.1"
thiserror = "1.0"
which = "5.0"
thiserror = "2.0"
which = "7.0"
path-slash = "0.2"
rayon = "1.8"
clap = { version = "4", default-features = false, features = ["derive"] }
rand = "0.8"
polkavm-common = { git = "https://github.com/koute/polkavm.git", rev = "360029e" }
polkavm-linker = { git = "https://github.com/koute/polkavm.git", rev = "360029e" }
polkavm-disassembler = { git = "https://github.com/koute/polkavm.git", rev = "360029e" }
polkavm = { git = "https://github.com/koute/polkavm.git", rev = "360029e" }
alloy-primitives = "0.6"
alloy-sol-types = "0.6"
env_logger = { version = "0.10.0", default-features = false }
serde_stacker = "0.1"
criterion = { version = "0.5", features = ["html_reports"] }
log = { version = "0.4" }
polkavm-common = "0.21.0"
polkavm-linker = "0.21.0"
polkavm-disassembler = "0.21.0"
polkavm = "0.21.0"
alloy-primitives = { version = "0.8.21", features = ["serde"] }
alloy-sol-types = "0.8.21"
alloy-genesis = "0.11.1"
alloy-serde = "0.11.1"
env_logger = { version = "0.11.6", default-features = false }
serde_stacker = "0.1.11"
criterion = { version = "0.5.1", features = ["html_reports"] }
log = { version = "0.4.25" }
git2 = { version = "0.20.0", default-features = false }
downloader = "0.2.8"
flate2 = "1.0.35"
fs_extra = "1.3.0"
num_cpus = "1"
tar = "0.4"
toml = "0.8"
assert_cmd = "2.0"
assert_fs = "1.1"
# polkadot-sdk and friends
codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
scale-info = { version = "2.11.1", default-features = false }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "559fa1db0594a81d5dbf343613ba2f3fc16708da" }
# Benchmarking against EVM
primitive-types = { version = "0.12", features = ["codec"] }
evm-interpreter = { git = "https://github.com/xermicus/evm.git", branch = "separate-compilation" }
scale-info = { version = "2.11.6", default-features = false }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "274a781e8ca1a9432c7ec87593bd93214abbff50" }
# llvm
[workspace.dependencies.inkwell]
version = "0.5"
git = "https://github.com/TheDan64/inkwell.git"
rev = "7b410298b6a93450adaa90b1841d5805a3038f12"
default-features = false
features = ["serde", "llvm18-0", "no-libffi-linking", "target-riscv"]
[profile.benchmark]
[profile.bench]
inherits = "release"
lto = true
codegen-units = 1
+32
View File
@@ -0,0 +1,32 @@
FROM rust:1.84.0 AS llvm-builder
WORKDIR /opt/revive
RUN apt update && \
apt upgrade -y && \
apt install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl
COPY . .
RUN make install-llvm-builder
RUN revive-llvm --target-env musl clone
RUN revive-llvm --target-env musl build --llvm-projects lld --llvm-projects clang
FROM messense/rust-musl-cross:x86_64-musl AS resolc-builder
WORKDIR /opt/revive
RUN apt update && \
apt upgrade -y && \
apt install -y pkg-config
COPY . .
COPY --from=llvm-builder /opt/revive/target-llvm /opt/revive/target-llvm
ENV LLVM_SYS_181_PREFIX=/opt/revive/target-llvm/musl/target-final
RUN make install-bin
FROM alpine:latest
ADD https://github.com/ethereum/solidity/releases/download/v0.8.28/solc-static-linux /usr/bin/solc
COPY --from=resolc-builder /root/.cargo/bin/resolc /usr/bin/resolc
RUN apk add --no-cache libc6-compat
RUN chmod +x /usr/bin/solc
+3
View File
@@ -0,0 +1,3 @@
url = "https://github.com/llvm/llvm-project.git"
branch = "release/18.x"
ref = "3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff"
+58 -26
View File
@@ -1,4 +1,24 @@
.PHONY: install format test test-solidity test-cli test-integration test-workspace clean docs docs-build
.PHONY: \
install \
install-bin \
install-npm \
install-wasm \
install-llvm-builder \
install-llvm \
format \
clippy \
machete \
test \
test-integration \
test-solidity \
test-workspace \
test-cli \
test-wasm \
test-llvm-builder
bench \
bench-pvm \
bench-evm \
clean
install: install-bin install-npm
@@ -8,11 +28,28 @@ install-bin:
install-npm:
npm install && npm fund
install-wasm: install-npm
cargo build --target wasm32-unknown-emscripten -p revive-solidity --release --no-default-features
npm run build:package
install-llvm-builder:
cargo install --path crates/llvm-builder
install-llvm: install-llvm-builder
revive-llvm clone
revive-llvm build --llvm-projects lld --llvm-projects clang
format:
cargo fmt --all --check
test: format clippy test-cli test-workspace
cargo test --workspace
clippy:
cargo clippy --all-features --workspace --tests --benches -- --deny warnings
machete:
cargo install cargo-machete
cargo machete
test: format clippy machete test-cli test-workspace
test-integration: install-bin
cargo test --package revive-integration
@@ -21,42 +58,37 @@ test-solidity: install
cargo test --package revive-solidity
test-workspace: install
cargo test --workspace
cargo test --workspace --exclude revive-llvm-builder
test-cli: install
npm run test:cli
bench-prepare: install-bin
cargo criterion --bench prepare --features bench-evm,bench-pvm --message-format=json \
| criterion-table > crates/benchmarks/PREPARE.md
test-wasm: install-wasm
npm run test:wasm
bench-execute: install-bin
cargo criterion --bench execute --features bench-evm,bench-pvm --message-format=json \
| criterion-table > crates/benchmarks/EXECUTE.md
test-llvm-builder:
@echo "warning: the llvm-builder tests will take many hours"
cargo test --package revive-llvm-builder -- --test-threads=1
bench-extensive: install-bin
bench: install-bin
cargo criterion --all --all-features --message-format=json \
| criterion-table > crates/benchmarks/BENCHMARKS.md
bench-quick: install-bin
cargo criterion --all --features bench-evm
bench-pvm: install-bin
cargo criterion --bench execute --features bench-pvm-interpreter --message-format=json \
| criterion-table > crates/benchmarks/PVM.md
bench: install-bin
cargo criterion --all --features bench-evm,bench-pvm --message-format=json \
| criterion-table > crates/benchmarks/BENCHMARKS.md
clippy:
cargo clippy --all-features --workspace --tests --benches
docs: docs-build
mdbook serve --open docs/
docs-build:
mdbook test docs/ && mdbook build docs/
bench-evm: install-bin
cargo criterion --bench execute --features bench-evm --message-format=json \
| criterion-table > crates/benchmarks/EVM.md
clean:
cargo clean ; \
revive-llvm clean ; \
rm -rf node_modules ; \
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
cargo uninstall revive-solidity ; \
rm -f package-lock.json
cargo uninstall revive-llvm-builder ; \
rm -f package-lock.json ; \
rm -rf js/dist ; \
rm -f js/src/resolc.{wasm,js}
+86 -13
View File
@@ -1,38 +1,111 @@
![CI](https://github.com/xermicus/revive/actions/workflows/rust.yml/badge.svg)
![CI](https://github.com/paritytech/revive/actions/workflows/rust.yml/badge.svg)
[![Docs](https://img.shields.io/badge/Docs-contracts.polkadot.io-brightgreen.svg)](https://contracts.polkadot.io/revive_compiler/)
# revive
YUL and EVM assembly recompiler to LLVM, targetting RISC-V on [PolkaVM](https://github.com/koute/polkavm).
YUL recompiler to LLVM, targetting RISC-V on [PolkaVM](https://github.com/koute/polkavm).
[Frontend](https://github.com/matter-labs/era-compiler-solidity) and [code generator](https://github.com/matter-labs/era-compiler-llvm-context) are based of ZKSync `zksolc`.
Visit [contracts.polkadot.io](https://contracts.polkadot.io) to learn more about contracts on Polkadot!
## Status
This is experimental software in active development and not ready just yet for production usage.
This is experimental software in active development and not ready just yet for production usage. Please do report any compiler related issues or missing features that are [not yet known to us](https://contracts.polkadot.io/known_issues/) here.
Discussion around the development is hosted on the [Polkadot Forum](https://forum.polkadot.network/t/contracts-update-solidity-on-polkavm/6949#a-new-solidity-compiler-1).
## Installation
Please consult [the documentation](https://contracts.polkadot.io/revive_compiler/installation) for installation instructions.
`resolc` depends on the [solc](https://github.com/ethereum/solidity) binary installed on your system.
## Building from source
Building revive requires a [stable Rust installation](https://rustup.rs/) and a C++ toolchain for building [LLVM](https://github.com/llvm/llvm-project) on your system.
### LLVM
`revive` depends on a custom build of LLVM `v18.1.8` with the RISC-V _embedded_ target, including the `compiler-rt` builtins. You can either download a build from our releases (recommended for older hardware) or build it from source.
<details>
<summary>Download from our LLVM releases</summary>
Download the [latest LLVM build](https://github.com/paritytech/revive/releases?q=LLVM+binaries+release&expanded=true) from our releases.
> **MacOS** users need to clear the `downloaded` attribute from all binaries after extracting the archive:
> ```sh
> xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/*
> ```
After extracting the archive, point `$LLVM_SYS_181_PREFIX` to it:
```sh
export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final
```
</details>
<details>
<summary>Building from source</summary>
Use the provided [revive-llvm](crates/llvm-builder/README.md) utility to compile a compatible LLVM build locally and point `$LLVM_SYS_181_PREFIX` to the installation afterwards.
The `Makefile` provides a shortcut target to obtain a compatible LLVM build:
```sh
make install-llvm
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final
```
</details>
### The `resolc` Solidity frontend
To build the `resolc` Solidity frontend executable, make sure you have obtained a compatible LLVM build and did export the `LLVM_SYS_181_PREFIX` environment variable pointing to it (see [above](#LLVM)).
To install the `resolc` Solidity frontend executable:
```bash
bash build-llvm.sh
export PATH=${PWD}/llvm18.0/bin:$PATH
```sh
make install-bin
resolc --version
```
### LLVM
### Cross-compilation to Wasm
`revive` requires a build of LLVM 18.1.4 or later including `compiler-rt`. Use the provided [build-llvm.sh](build-llvm.sh) build script to compile a compatible LLVM build locally in `$PWD/llvm18.0` (don't forget to add that to `$PATH` afterwards).
Cross-compile the `resolc.js` frontend executable to Wasm for running it in a Node.js or browser environment. The `REVIVE_LLVM_TARGET_PREFIX` environment variable is used to control the target environment LLVM dependency.
### Development
<details>
<summary>Instructions for cross-compilation to wasm32-unknown-emscripten</summary>
```sh
# Build the host LLVM dependency with PolkaVM target support
make install-llvm
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final
# Build the target LLVM dependency with PolkaVM target support
revive-llvm --target-env emscripten clone
source emsdk/emsdk_env.sh
revive-llvm --target-env emscripten build --llvm-projects lld
export REVIVE_LLVM_TARGET_PREFIX=${PWD}/target-llvm/emscripten/target-final
# Build the resolc frontend executable
make install-wasm
make test-wasm
```
</details>
## Development
Please consult the [Makefile](Makefile) targets to learn how to run tests and benchmarks.
Ensure that your branch passes `make test` locally when submitting a pull request.
## Design overview
`revive` uses [solc](https://github.com/ethereum/solidity/), the Ethereum Solidity compiler, as the [Solidity frontend](crates/solidity/src/lib.rs) to process smart contracts written in Solidity. The YUL IR code (or legacy EVM assembly as a fallback for older `solc` versions) emitted by `solc` is then translated to LLVM IR, targetting a runtime similar to [Polkadots `contracts` pallet](https://docs.rs/pallet-contracts/latest/pallet_contracts/api_doc/trait.Current.html).
### Design overview
See the [relevant section in our documentation](https://contracts.polkadot.io/revive_compiler/architecture) to learn more about how the compiler works.
[Frontend](https://github.com/matter-labs/era-compiler-solidity) and [code generator](https://github.com/matter-labs/era-compiler-llvm-context) are based of ZKSync `zksolc` (the project started as a fork of the era compiler).
### Tests
Before running the tests, ensure that Geth (Go Ethereum) is installed on your system. Follow the installation guide here: [Installing Geth](https://geth.ethereum.org/docs/getting-started/installing-geth).
Once Geth is installed, you can run the tests using the following command:
```sh
make test
```
+17
View File
@@ -0,0 +1,17 @@
# Release checklist
Prior to the first stable release we neither have formal release processes nor do we follow a fixed release schedule.
To create a new pre-release:
1. Merge a release PR which updates the `-dev.X` versions in the workspace `Cargo.toml` and updates the `CHANGELOG.md` accordingly. The release workflow will attempt to build and publish a new release whenever the latest git tag does not match the cargo package version.
2. Wait for the `Release` workflow to finish. If the workflow fails after the `build-linux-all` step, check if a tag has been created and delete it before restarting or pushing updates. Note: It's more convenient to debug the release workflow in a fork (the fork has to be under the `paritytech` org to access `parity-large` runners).
3. Check draft release on [Releases page](https://github.com/paritytech/revive/releases) and publish (should contain `resolc.js`, `resolc.wasm`, `resolc-web.js`, and `resolc-static-linux` release assets)
4. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly
# LLVM release
To create a new LLVM release, run "Release LLVM" workflow. Use current LLVM version as parameter, e.g. `18.1.8`.
Version suffix will be resolved automatically.
The workflows will create new GitHub release, and upload LLVM binaries.
Next release of resolc will use newly created binaries.
+1
View File
@@ -0,0 +1 @@
https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/SECURITY.md
+30
View File
@@ -0,0 +1,30 @@
# Known issues
The following is known and we are either working on it or it is a hard limitation. Please do not open a new issue.
## Release
`0.1.0-dev-2`
## Missing features
- [Libraries with public functions are not supported](https://github.com/paritytech/revive/issues/91)
- [Automatic import resolution is not supported](https://github.com/paritytech/revive/issues/98)
- The emulated EVM linear contract memory is limited to 64kb in size. Will be fixed with support for metered dynamic memory.
- [The contract calldata is currently limited to 1kb in size](https://github.com/paritytech/revive/issues/57)
- [EIP-4844 opcodes are not supported](https://github.com/paritytech/revive/issues/64)
- [Delegate calls are not supported](https://github.com/paritytech/revive/issues/67)
- [The `blockhash` opcode is not supported](https://github.com/paritytech/revive/issues/61)
- [The `extcodesize` opcode is not supported](https://github.com/paritytech/revive/issues/58)
- [The `origin` opcode is not supported](https://github.com/paritytech/revive/issues/59)
- [Gas limits for contract calls are ignored](https://github.com/paritytech/revive/issues/60)
- [Gas related opcodes are not supported](https://github.com/paritytech/revive/issues/60)
- IPFS metadata hashes are not supported
- [Compiled contract artifacts can exceed the pallet static memory limit and fail to deploy](https://github.com/paritytech/revive/issues/96).
- [Transfers to inexistant accounts will fail if the transferred value lies below the ED.](https://github.com/paritytech/revive/issues/83) Will be fixed in the pallet to make the ED completely transparent for contracts.
## Wontfix
Please consult our documentation to learn more about Solidity and EVM features likely to remain unsupported (and why they will not be supported).
TODO: Insert link to the relevant documentation section.
-92
View File
@@ -1,92 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
INSTALL_DIR="${PWD}/llvm18.0"
mkdir -p ${INSTALL_DIR}
# Clone LLVM 18 (any revision after commit bd32aaa is supposed to work)
if [ ! -d "llvm-project" ]; then
git clone --depth 1 --branch release/18.x https://github.com/llvm/llvm-project.git
fi
# Build LLVM, clang
LLVM_SRC_PREFIX=${PWD}/llvm-project
LLVM_SRC_DIR=${LLVM_SRC_PREFIX}/llvm
LLVM_BUILD_DIR=${PWD}/build/llvm
if [ ! -d ${LLVM_BUILD_DIR} ] ; then
mkdir -p ${LLVM_BUILD_DIR}
fi
cmake -G Ninja \
-S ${LLVM_SRC_DIR} \
-B ${LLVM_BUILD_DIR} \
-DLLVM_ENABLE_ASSERTIONS=On \
-DLLVM_ENABLE_TERMINFO=Off \
-DLLVM_ENABLE_LIBXML2=Off \
-DLLVM_ENABLE_ZLIB=Off \
-DLLVM_ENABLE_PROJECTS='clang;lld' \
-DLLVM_TARGETS_TO_BUILD='RISCV' \
-DLLVM_ENABLE_ZSTD=Off \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}
cmake --build ${LLVM_BUILD_DIR}
cmake --install ${LLVM_BUILD_DIR}
# Build compiler builtins
COMPILER_RT_SRC_DIR=${LLVM_SRC_PREFIX}/compiler-rt
COMPILER_RT_BUILD_DIR=${PWD}/build/compiler-rt
if [ ! -d ${COMPILER_RT_BUILD_DIR} ] ; then
mkdir -p ${COMPILER_RT_BUILD_DIR}
fi
build_compiler_rt() {
case "$1" in
64) TARGET_ABI=lp64e ;;
32) TARGET_ABI=ilp32e ;;
*) exit -1
esac
CFLAGS="--target=riscv${1} -march=rv${1}em -mabi=${TARGET_ABI} -mcpu=generic-rv${1} -nostdlib -nodefaultlibs"
cmake -G Ninja \
-S ${COMPILER_RT_SRC_DIR} \
-B ${COMPILER_RT_BUILD_DIR} \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} \
-DCOMPILER_RT_BUILD_BUILTINS=ON \
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
-DCOMPILER_RT_BUILD_MEMPROF=OFF \
-DCOMPILER_RT_BUILD_PROFILE=OFF \
-DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DCOMPILER_RT_BUILD_XRAY=OFF \
-DCMAKE_C_COMPILER=${INSTALL_DIR}/bin/clang \
-DCMAKE_C_COMPILER_TARGET=riscv${1} \
-DCMAKE_ASM_COMPILER_TARGET=riscv${1} \
-DCMAKE_CXX_COMPILER_TARGET=riscv${1} \
-DCMAKE_C_TARGET_BITS=riscv${1} \
-DCMAKE_ASM_TARGET_BITS=riscv${1} \
-DCMAKE_AR=${INSTALL_DIR}/bin/llvm-ar \
-DCMAKE_NM=${INSTALL_DIR}/bin/llvm-nm \
-DCMAKE_RANLIB=${INSTALL_DIR}/bin/llvm-ranlib \
-DCOMPILER_RT_BAREMETAL_BUILD=ON \
-DLLVM_CONFIG_PATH=${INSTALL_DIR}/bin/llvm-config \
-DCMAKE_C_FLAGS="${CFLAGS}" \
-DCMAKE_ASM_FLAGS="${CFLAGS}" \
-DCOMPILER_RT_TEST_COMPILER=${INSTALL_DIR}/bin/clang \
-DCMAKE_CXX_FLAGS="${CFLAGS}" \
-DCMAKE_SYSTEM_NAME=unknown \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON
cmake --build ${COMPILER_RT_BUILD_DIR}
cmake --install ${COMPILER_RT_BUILD_DIR}
}
build_compiler_rt 32
build_compiler_rt 64
echo ""
echo "success"
echo "add this directory to your PATH: ${INSTALL_DIR}/bin/"
+73
View File
@@ -0,0 +1,73 @@
# Benchmarks
## Table of Contents
- [Benchmark Results](#benchmark-results)
- [Baseline](#baseline)
- [OddPorduct](#oddporduct)
- [TriangleNumber](#trianglenumber)
- [FibonacciRecursive](#fibonaccirecursive)
- [FibonacciIterative](#fibonacciiterative)
- [FibonacciBinet](#fibonaccibinet)
- [SHA1](#sha1)
## Benchmark Results
### Baseline
| | `EVM` | `PVMInterpreter` |
|:--------|:------------------------|:-------------------------------- |
| **`0`** | `3.36 us` (✅ **1.00x**) | `11.84 us` (❌ *3.52x slower*) |
### OddPorduct
| | `EVM` | `PVMInterpreter` |
|:-------------|:-------------------------|:-------------------------------- |
| **`10000`** | `3.11 ms` (✅ **1.00x**) | `1.53 ms` (🚀 **2.03x faster**) |
| **`100000`** | `30.70 ms` (✅ **1.00x**) | `15.54 ms` (🚀 **1.98x faster**) |
| **`300000`** | `92.68 ms` (✅ **1.00x**) | `45.47 ms` (🚀 **2.04x faster**) |
### TriangleNumber
| | `EVM` | `PVMInterpreter` |
|:-------------|:-------------------------|:-------------------------------- |
| **`10000`** | `2.29 ms` (✅ **1.00x**) | `1.09 ms` (🚀 **2.11x faster**) |
| **`100000`** | `22.84 ms` (✅ **1.00x**) | `10.66 ms` (🚀 **2.14x faster**) |
| **`360000`** | `82.29 ms` (✅ **1.00x**) | `37.01 ms` (🚀 **2.22x faster**) |
### FibonacciRecursive
| | `EVM` | `PVMInterpreter` |
|:---------|:--------------------------|:--------------------------------- |
| **`12`** | `135.67 us` (✅ **1.00x**) | `125.02 us` (✅ **1.09x faster**) |
| **`16`** | `903.75 us` (✅ **1.00x**) | `762.79 us` (✅ **1.18x faster**) |
| **`20`** | `6.12 ms` (✅ **1.00x**) | `4.96 ms` (✅ **1.23x faster**) |
| **`24`** | `42.05 ms` (✅ **1.00x**) | `33.86 ms` (✅ **1.24x faster**) |
### FibonacciIterative
| | `EVM` | `PVMInterpreter` |
|:----------|:-------------------------|:-------------------------------- |
| **`64`** | `15.04 us` (✅ **1.00x**) | `29.45 us` (❌ *1.96x slower*) |
| **`128`** | `26.36 us` (✅ **1.00x**) | `42.19 us` (❌ *1.60x slower*) |
| **`256`** | `48.61 us` (✅ **1.00x**) | `65.71 us` (❌ *1.35x slower*) |
### FibonacciBinet
| | `EVM` | `PVMInterpreter` |
|:----------|:-------------------------|:-------------------------------- |
| **`64`** | `15.22 us` (✅ **1.00x**) | `41.46 us` (❌ *2.72x slower*) |
| **`128`** | `17.05 us` (✅ **1.00x**) | `42.84 us` (❌ *2.51x slower*) |
| **`256`** | `19.00 us` (✅ **1.00x**) | `44.36 us` (❌ *2.34x slower*) |
### SHA1
| | `EVM` | `PVMInterpreter` |
|:----------|:--------------------------|:--------------------------------- |
| **`1`** | `110.04 us` (✅ **1.00x**) | `216.11 us` (❌ *1.96x slower*) |
| **`64`** | `209.04 us` (✅ **1.00x**) | `309.48 us` (❌ *1.48x slower*) |
| **`512`** | `903.65 us` (✅ **1.00x**) | `980.49 us` (✅ **1.09x slower**) |
---
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
+4 -9
View File
@@ -9,17 +9,16 @@ description = "revive compiler benchmarks"
[features]
default = ["bench-pvm-interpreter"]
bench-pvm-interpreter = []
bench-pvm = []
bench-pvm-interpreter = ["revive-runner"]
bench-evm = ["revive-differential"]
bench-extensive = []
[dependencies]
hex = { workspace = true }
polkavm = { workspace = true }
alloy-primitives = { workspace = true }
revive-integration = { workspace = true }
revive-differential = { workspace = true, optional = true }
alloy-primitives = { workspace = true }
revive-runner = { workspace = true, optional = true }
[dev-dependencies]
criterion = { workspace = true }
@@ -27,7 +26,3 @@ criterion = { workspace = true }
[[bench]]
name = "execute"
harness = false
[[bench]]
name = "prepare"
harness = false
+28 -114
View File
@@ -1,104 +1,42 @@
#![cfg(any(feature = "bench-pvm-interpreter", feature = "bench-evm"))]
use alloy_primitives::U256;
use criterion::{
criterion_group, criterion_main, measurement::Measurement, BenchmarkGroup, BenchmarkId,
Criterion,
criterion_group, criterion_main,
measurement::{Measurement, WallTime},
BenchmarkGroup, BenchmarkId, Criterion,
};
use revive_integration::cases::Contract;
fn bench<P, L, I, M>(mut group: BenchmarkGroup<'_, M>, parameters: &[P], labels: &[L], contract: I)
where
fn bench<P, L, I>(
mut group: BenchmarkGroup<'_, WallTime>,
parameters: &[P],
labels: &[L],
contract: I,
) where
P: Clone,
L: std::fmt::Display,
I: Fn(P) -> Contract,
M: Measurement,
{
assert_eq!(parameters.len(), labels.len());
group.sample_size(10);
for (p, l) in parameters.iter().zip(labels.iter()) {
let contract = contract(p.clone());
#[cfg(feature = "bench-evm")]
{
let contract = contract(p.clone());
group.bench_with_input(BenchmarkId::new("EVM", l), p, move |b, _| {
b.iter(|| {
revive_differential::execute(revive_differential::prepare(
contract.evm_runtime.clone(),
contract.calldata.clone(),
));
group.bench_with_input(BenchmarkId::new("EVM", l), p, |b, _| {
let code = &contract.evm_runtime;
let input = &contract.calldata;
b.iter_custom(|iters| revive_benchmarks::measure_evm(code, input, iters));
});
});
}
#[cfg(not(feature = "bench-extensive"))]
{
#[cfg(all(feature = "bench-pvm-interpreter", not(feature = "bench-extensive")))]
{
let contract = contract(p.clone());
let (transaction, mut instance, export) = revive_benchmarks::prepare_pvm(
&contract.pvm_runtime,
contract.calldata,
polkavm::BackendKind::Interpreter,
);
group.bench_with_input(BenchmarkId::new("PVMInterpreter", l), p, |b, _| {
b.iter(|| {
let _ = transaction.clone().call_on(&mut instance, export);
});
});
}
#[cfg(all(feature = "bench-pvm", not(feature = "bench-extensive")))]
{
let contract = contract(p.clone());
let (transaction, mut instance, export) = revive_benchmarks::prepare_pvm(
&contract.pvm_runtime,
contract.calldata,
polkavm::BackendKind::Compiler,
);
group.bench_with_input(BenchmarkId::new("PVM", l), p, |b, _| {
b.iter(|| {
let _ = transaction.clone().call_on(&mut instance, export);
});
});
}
}
#[cfg(feature = "bench-extensive")]
{
use revive_benchmarks::instantiate_engine;
use revive_integration::mock_runtime::{instantiate_module, recompile_code, State};
#[cfg(feature = "bench-pvm-interpreter")]
{
let contract = contract(p.clone());
let engine = instantiate_engine(polkavm::BackendKind::Interpreter);
let module = recompile_code(&contract.pvm_runtime, &engine);
let transaction = State::default()
.transaction()
.with_default_account(&contract.pvm_runtime)
.calldata(contract.calldata);
group.bench_with_input(BenchmarkId::new("PVMInterpreter", l), p, |b, _| {
b.iter(|| {
let (mut instance, export) = instantiate_module(&module, &engine);
let _ = transaction.clone().call_on(&mut instance, export);
let specs = revive_benchmarks::create_specs(&contract);
b.iter_custom(|iters| revive_benchmarks::measure_pvm(&specs, iters));
});
});
}
#[cfg(feature = "bench-pvm")]
{
let contract = contract(p.clone());
let engine = instantiate_engine(polkavm::BackendKind::Compiler);
let module = recompile_code(&contract.pvm_runtime, &engine);
let transaction = State::default()
.transaction()
.with_default_account(&contract.pvm_runtime)
.calldata(contract.calldata);
group.bench_with_input(BenchmarkId::new("PVM", l), p, |b, _| {
b.iter(|| {
let (mut instance, export) = instantiate_module(&module, &engine);
let _ = transaction.clone().call_on(&mut instance, export);
});
});
}
}
}
group.finish();
@@ -108,15 +46,7 @@ fn group<'error, M>(c: &'error mut Criterion<M>, group_name: &str) -> BenchmarkG
where
M: Measurement,
{
#[cfg(feature = "bench-extensive")]
{
let mut group = c.benchmark_group(group_name);
group.sample_size(10);
group
}
#[cfg(not(feature = "bench-extensive"))]
return c.benchmark_group(group_name);
c.benchmark_group(group_name)
}
fn bench_baseline(c: &mut Criterion) {
@@ -128,33 +58,21 @@ fn bench_baseline(c: &mut Criterion) {
fn bench_odd_product(c: &mut Criterion) {
let group = group(c, "OddPorduct");
#[cfg(feature = "bench-extensive")]
let parameters = &[300000, 1200000, 12000000, 180000000, 720000000];
#[cfg(not(feature = "bench-extensive"))]
let parameters = &[10_000, 100_000];
let parameters = &[10_000, 100_000, 300000];
bench(group, parameters, parameters, Contract::odd_product);
}
fn bench_triangle_number(c: &mut Criterion) {
let group = group(c, "TriangleNumber");
#[cfg(feature = "bench-extensive")]
let parameters = &[360000, 1440000, 14400000, 216000000, 864000000];
#[cfg(not(feature = "bench-extensive"))]
let parameters = &[10_000, 100_000];
let parameters = &[10_000, 100_000, 360000];
bench(group, parameters, parameters, Contract::triangle_number);
}
fn bench_fibonacci_recurisve(c: &mut Criterion) {
let group = group(c, "FibonacciRecursive");
#[cfg(feature = "bench-extensive")]
let parameters = [24, 27, 31, 36, 39]
.iter()
.map(|p| U256::from(*p))
.collect::<Vec<_>>();
#[cfg(not(feature = "bench-extensive"))]
let parameters = [12, 16, 20]
let parameters = [12, 16, 20, 24]
.iter()
.map(|p| U256::from(*p))
.collect::<Vec<_>>();
@@ -164,12 +82,6 @@ fn bench_fibonacci_recurisve(c: &mut Criterion) {
fn bench_fibonacci_iterative(c: &mut Criterion) {
let group = group(c, "FibonacciIterative");
#[cfg(feature = "bench-extensive")]
let parameters = [256, 162500, 650000, 6500000, 100000000, 400000000]
.iter()
.map(|p| U256::from(*p))
.collect::<Vec<_>>();
#[cfg(not(feature = "bench-extensive"))]
let parameters = [64, 128, 256]
.iter()
.map(|p| U256::from(*p))
@@ -193,7 +105,9 @@ fn bench_sha1(c: &mut Criterion) {
let parameters = &[vec![0xff], vec![0xff; 64], vec![0xff; 512]];
let labels = parameters.iter().map(|p| p.len()).collect::<Vec<_>>();
bench(group, parameters, &labels, Contract::sha1);
bench(group, parameters, &labels, |input| {
Contract::sha1(input.into())
});
}
criterion_group!(
-171
View File
@@ -1,171 +0,0 @@
use alloy_primitives::U256;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use revive_integration::cases::Contract;
fn bench(
c: &mut Criterion,
group_name: &str,
#[cfg(feature = "bench-evm")] evm_runtime: Vec<u8>,
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))] pvm_runtime: Vec<u8>,
) {
let mut group = c.benchmark_group(group_name);
let code_size = 0;
#[cfg(feature = "bench-evm")]
group.bench_with_input(
BenchmarkId::new("Evm", code_size),
&evm_runtime,
|b, code| b.iter(|| revive_differential::prepare(code.clone(), Vec::new())),
);
#[cfg(feature = "bench-pvm-interpreter")]
{
let engine = revive_benchmarks::instantiate_engine(polkavm::BackendKind::Interpreter);
group.bench_with_input(
BenchmarkId::new("PVMInterpreterCompile", code_size),
&(&pvm_runtime, engine),
|b, (code, engine)| {
b.iter(|| {
revive_integration::mock_runtime::recompile_code(code, engine);
});
},
);
}
#[cfg(feature = "bench-pvm-interpreter")]
{
let engine = revive_benchmarks::instantiate_engine(polkavm::BackendKind::Interpreter);
let module = revive_integration::mock_runtime::recompile_code(&pvm_runtime, &engine);
group.bench_with_input(
BenchmarkId::new("PVMInterpreterInstantiate", code_size),
&(module, engine),
|b, (module, engine)| {
b.iter(|| {
revive_integration::mock_runtime::instantiate_module(module, engine);
});
},
);
}
#[cfg(feature = "bench-pvm")]
{
let engine = revive_benchmarks::instantiate_engine(polkavm::BackendKind::Compiler);
group.bench_with_input(
BenchmarkId::new("PVMCompile", code_size),
&(&pvm_runtime, engine),
|b, (code, engine)| {
b.iter(|| {
revive_integration::mock_runtime::recompile_code(code, engine);
});
},
);
}
#[cfg(feature = "bench-pvm")]
{
let engine = revive_benchmarks::instantiate_engine(polkavm::BackendKind::Compiler);
let module = revive_integration::mock_runtime::recompile_code(&pvm_runtime, &engine);
group.bench_with_input(
BenchmarkId::new("PVMInstantiate", code_size),
&(module, engine),
|b, (module, engine)| {
b.iter(|| {
revive_integration::mock_runtime::instantiate_module(module, engine);
});
},
);
}
group.finish();
}
fn bench_baseline(c: &mut Criterion) {
bench(
c,
"PrepareBaseline",
#[cfg(feature = "bench-evm")]
Contract::baseline().evm_runtime,
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))]
Contract::baseline().pvm_runtime,
);
}
fn bench_odd_product(c: &mut Criterion) {
bench(
c,
"PrepareOddProduct",
#[cfg(feature = "bench-evm")]
Contract::odd_product(0).evm_runtime,
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))]
Contract::baseline().pvm_runtime,
);
}
fn bench_triangle_number(c: &mut Criterion) {
bench(
c,
"PrepareTriangleNumber",
#[cfg(feature = "bench-evm")]
Contract::triangle_number(0).evm_runtime,
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))]
Contract::triangle_number(0).pvm_runtime,
);
}
fn bench_fibonacci_recursive(c: &mut Criterion) {
bench(
c,
"PrepareFibonacciRecursive",
#[cfg(feature = "bench-evm")]
Contract::fib_recursive(U256::ZERO).evm_runtime,
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))]
Contract::fib_recursive(U256::ZERO).pvm_runtime,
);
}
fn bench_fibonacci_iterative(c: &mut Criterion) {
bench(
c,
"PrepareFibonacciIterative",
#[cfg(feature = "bench-evm")]
Contract::fib_iterative(U256::ZERO).evm_runtime,
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))]
Contract::fib_iterative(U256::ZERO).pvm_runtime,
);
}
fn bench_fibonacci_binet(c: &mut Criterion) {
bench(
c,
"PrepareFibonacciBinet",
#[cfg(feature = "bench-evm")]
Contract::fib_binet(U256::ZERO).evm_runtime,
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))]
Contract::fib_binet(U256::ZERO).pvm_runtime,
);
}
fn bench_sha1(c: &mut Criterion) {
bench(
c,
"PrepareSHA1",
#[cfg(feature = "bench-evm")]
Contract::sha1(Default::default()).evm_runtime,
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))]
Contract::sha1(Default::default()).pvm_runtime,
);
}
criterion_group!(
name = prepare;
config = Criterion::default();
targets = bench_baseline,
bench_odd_product,
bench_triangle_number,
bench_fibonacci_recursive,
bench_fibonacci_iterative,
bench_fibonacci_binet,
bench_sha1
);
criterion_main!(prepare);
+67 -25
View File
@@ -1,28 +1,70 @@
use polkavm::{BackendKind, Config, Engine, ExportIndex, Instance, SandboxKind};
use revive_integration::mock_runtime::{self, TransactionBuilder};
use revive_integration::mock_runtime::{State, Transaction};
pub fn prepare_pvm(
code: &[u8],
input: Vec<u8>,
backend: BackendKind,
) -> (TransactionBuilder, Instance<Transaction>, ExportIndex) {
let mut config = Config::new();
config.set_backend(Some(backend));
config.set_sandbox(Some(SandboxKind::Linux));
let (instance, export_index) = mock_runtime::prepare(code, Some(config));
let transaction = State::default()
.transaction()
.with_default_account(code)
.calldata(input);
(transaction, instance, export_index)
#[cfg(feature = "bench-pvm-interpreter")]
pub fn create_specs(contract: &revive_integration::cases::Contract) -> revive_runner::Specs {
use revive_runner::*;
use SpecsAction::*;
Specs {
differential: false,
actions: vec![
Instantiate {
code: Code::Bytes(contract.pvm_runtime.to_vec()),
origin: TestAddress::Alice,
data: Default::default(),
value: Default::default(),
gas_limit: Default::default(),
storage_deposit_limit: Default::default(),
salt: Default::default(),
},
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
data: contract.calldata.to_vec(),
value: Default::default(),
gas_limit: Default::default(),
storage_deposit_limit: Default::default(),
},
],
..Default::default()
}
}
pub fn instantiate_engine(backend: BackendKind) -> Engine {
let mut config = Config::new();
config.set_backend(Some(backend));
config.set_sandbox(Some(SandboxKind::Linux));
mock_runtime::setup(Some(config))
#[cfg(feature = "bench-pvm-interpreter")]
pub fn measure_pvm(specs: &revive_runner::Specs, iters: u64) -> std::time::Duration {
use revive_runner::*;
let mut total_time = std::time::Duration::default();
for _ in 0..iters {
let results = specs.clone().run();
let CallResult::Exec { result, wall_time } =
results.get(1).expect("contract should have been called")
else {
panic!("expected a execution result");
};
let ret = result.result.as_ref().unwrap();
assert!(!ret.did_revert());
total_time += *wall_time;
}
total_time
}
#[cfg(feature = "bench-evm")]
pub fn measure_evm(code: &[u8], input: &[u8], iters: u64) -> std::time::Duration {
let mut total_time = std::time::Duration::default();
let code = hex::encode(code);
for _ in 0..iters {
let log = revive_differential::Evm::default()
.code_blob(code.as_bytes().to_vec())
.input(input.to_vec().into())
.bench(true)
.run();
assert!(log.output.run_success(), "evm run failed: {log:?}");
total_time += log.execution_time().unwrap();
}
total_time
}
+14
View File
@@ -0,0 +1,14 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# IDE
/.idea/
/.vscode/
+15
View File
@@ -0,0 +1,15 @@
[package]
name = "revive-build-utils"
version.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
authors = [
"Cyrill Leutwiler <cyrill@parity.io>",
]
description = "Shared build utilities of the revive compiler"
[lib]
doctest = false
[dependencies]
+10
View File
@@ -0,0 +1,10 @@
# revive: Compiler Common
## License
This library is distributed under the terms of either
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.
+48
View File
@@ -0,0 +1,48 @@
//! The compiler build utilities library.
/// The revive LLVM host dependency directory prefix environment variable.
pub const REVIVE_LLVM_HOST_PREFIX: &str = "LLVM_SYS_181_PREFIX";
/// The revive LLVM target dependency directory prefix environment variable.
pub const REVIVE_LLVM_TARGET_PREFIX: &str = "REVIVE_LLVM_TARGET_PREFIX";
/// Constructs a path to the LLVM tool `name`.
///
/// Respects the [`REVIVE_LLVM_HOST_PREFIX`] environment variable.
pub fn llvm_host_tool(name: &str) -> std::path::PathBuf {
std::env::var_os(REVIVE_LLVM_HOST_PREFIX)
.map(Into::<std::path::PathBuf>::into)
.unwrap_or_else(|| {
panic!(
"install LLVM using the revive-llvm builder and export {REVIVE_LLVM_HOST_PREFIX}",
)
})
.join("bin")
.join(name)
}
/// Returns the LLVM lib dir.
///
/// Respects the [`REVIVE_LLVM_HOST_PREFIX`] environment variable.
pub fn llvm_lib_dir() -> std::path::PathBuf {
std::path::PathBuf::from(llvm_config("--libdir").trim())
}
/// Returns the LLVM CXX compiler flags.
///
/// Respects the [`REVIVE_LLVM_HOST_PREFIX`] environment variable.
pub fn llvm_cxx_flags() -> String {
llvm_config("--cxxflags")
}
/// Execute the `llvm-config` utility respecting the [`REVIVE_LLVM_HOST_PREFIX`] environment variable.
fn llvm_config(arg: &str) -> String {
let llvm_config = llvm_host_tool("llvm-config");
let output = std::process::Command::new(&llvm_config)
.arg(arg)
.output()
.unwrap_or_else(|error| panic!("`{} {arg}` failed: {error}", llvm_config.display()));
String::from_utf8(output.stdout)
.unwrap_or_else(|_| panic!("output of `{} {arg}` should be utf8", llvm_config.display()))
}
+2 -4
View File
@@ -8,7 +8,5 @@ authors.workspace = true
build = "build.rs"
description = "compiler builtins for the revive compiler"
[features]
riscv-64 = []
[dependencies]
[build-dependencies]
revive-build-utils = { workspace = true }
+18 -14
View File
@@ -1,30 +1,34 @@
use std::{env, fs, io::Read, path::Path, process::Command};
#[cfg(not(feature = "riscv-64"))]
pub const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv32.a";
#[cfg(feature = "riscv-64")]
pub const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv64.a";
fn main() {
let mut llvm_lib_dir = String::new();
println!(
"cargo:rerun-if-env-changed={}",
revive_build_utils::REVIVE_LLVM_HOST_PREFIX
);
Command::new("llvm-config")
.args(["--libdir"])
let llvm_config = revive_build_utils::llvm_host_tool("llvm-config");
let mut llvm_lib_dir = String::new();
Command::new(&llvm_config)
.arg("--libdir")
.output()
.expect("llvm-config should be able to provide LD path")
.unwrap_or_else(|_| {
panic!(
"{} should be able to provide LD path",
llvm_config.display()
)
})
.stdout
.as_slice()
.read_to_string(&mut llvm_lib_dir)
.expect("llvm-config output should be utf8");
let mut lib_path = std::path::PathBuf::from(llvm_lib_dir.trim())
.join("linux")
let lib_path = revive_build_utils::llvm_lib_dir()
.join("unknown")
.join(BUILTINS_ARCHIVE_FILE);
if !lib_path.exists() {
lib_path = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
.join(BUILTINS_ARCHIVE_FILE);
}
let archive = fs::read(lib_path).expect("clang builtins not found");
let archive = fs::read(&lib_path).expect("clang builtins not found");
println!("cargo:rerun-if-env-changed={}", lib_path.display());
let out_dir = env::var_os("OUT_DIR").expect("has OUT_DIR");
let archive_path = Path::new(&out_dir).join(BUILTINS_ARCHIVE_FILE);
Binary file not shown.
Binary file not shown.
-39
View File
@@ -1,39 +0,0 @@
---
name: Bug report
about: Use this template for reporting issues
title: ''
labels: bug
assignees: ''
---
### 🐛 Bug Report
#### 📝 Description
Provide a clear and concise description of the bug.
#### 🔄 Reproduction Steps
Steps to reproduce the behaviour
#### 🤔 Expected Behavior
Describe what you expected to happen.
#### 😯 Current Behavior
Describe what actually happened.
#### 🖥️ Environment
Any relevant environment details.
#### 📋 Additional Context
Add any other context about the problem here. If applicable, add screenshots to help explain.
#### 📎 Log Output
```
Paste any relevant log output here.
```
-21
View File
@@ -1,21 +0,0 @@
---
name: Feature request
about: Use this template for requesting features
title: ''
labels: feat
assignees: ''
---
### 🌟 Feature Request
#### 📝 Description
Provide a clear and concise description of the feature you'd like to see.
#### 🤔 Rationale
Explain why this feature is important and how it benefits the project.
#### 📋 Additional Context
Add any other context or information about the feature request here.
-20
View File
@@ -1,20 +0,0 @@
# What ❔
<!-- What are the changes this PR brings about? -->
<!-- Example: This PR adds a PR template to the repo. -->
<!-- (For bigger PRs adding more context is appreciated) -->
## Why ❔
<!-- Why are these changes done? What goal do they contribute to? What are the principles behind them? -->
<!-- Example: PR templates ensure PR reviewers, observers, and future iterators are in context about the evolution of repos. -->
## Checklist
<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->
- [ ] PR title corresponds to the body of PR.
- [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.
- [ ] Code has been formatted via `cargo fmt` and checked with `cargo clippy`.
-9
View File
@@ -1,9 +0,0 @@
name: Cargo license check
on: pull_request
jobs:
cargo-deny:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: EmbarkStudios/cargo-deny-action@v1
-23
View File
@@ -1,23 +0,0 @@
name: "Rust CI"
on:
pull_request:
jobs:
build:
name: cargo build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rust-lang/setup-rust-toolchain@v1
- run: cargo build --verbose
formatting:
name: cargo fmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: rustfmt
- name: Rustfmt Check
uses: actions-rust-lang/rustfmt@v1
-17
View File
@@ -1,17 +0,0 @@
name: Leaked Secrets Scan
on: [pull_request]
jobs:
TruffleHog:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
with:
fetch-depth: 0
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@0c66d30c1f4075cee1aada2e1ab46dabb1b0071a
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --debug --only-verified
-3
View File
@@ -13,9 +13,6 @@ description = "Shared constants of the revive compiler"
[lib]
doctest = false
[features]
riscv-64 = []
[dependencies]
anyhow = { workspace = true }
serde = { workspace = true, features = ["derive"] }
+1 -1
View File
@@ -20,7 +20,7 @@ pub const BIT_LENGTH_ETH_ADDRESS: usize =
pub const BIT_LENGTH_WORD: usize = crate::byte_length::BYTE_LENGTH_WORD * BIT_LENGTH_BYTE;
/// Bit length of the runtime value type.
pub const BIT_LENGTH_VALUE: usize = crate::byte_length::BYTE_LENGTH_VALUE * BIT_LENGTH_BYTE;
pub const BIT_LENGTH_VALUE: usize = BIT_LENGTH_WORD;
/// Bit length of thre runimte block number type.
pub const BIT_LENGTH_BLOCK_NUMBER: usize =
+5 -8
View File
@@ -6,15 +6,12 @@ pub const BYTE_LENGTH_BYTE: usize = 1;
/// The x86 word byte-length.
pub const BYTE_LENGTH_X32: usize = 4;
/// Native stack alignment size in bytes
#[cfg(not(feature = "riscv-64"))]
pub const BYTE_LENGTH_STACK_ALIGN: usize = 4;
#[cfg(feature = "riscv-64")]
pub const BYTE_LENGTH_STACK_ALIGN: usize = 8;
/// The x86_64 word byte-length.
pub const BYTE_LENGTH_X64: usize = 8;
/// EVM native stack alignment size in bytes
pub const BYTE_LENGTH_STACK_ALIGN: usize = 32;
/// The ETH address byte-length.
pub const BYTE_LENGTH_ETH_ADDRESS: usize = 20;
@@ -25,7 +22,7 @@ pub const BYTE_LENGTH_WORD: usize = 32;
pub const BYTE_LENGTH_VALUE: usize = 32;
/// Byte length of the runtime block number type.
pub const BYTE_LENGTH_BLOCK_NUMBER: usize = 8;
pub const BYTE_LENGTH_BLOCK_NUMBER: usize = 4;
/// Byte length of the runtime block timestamp type.
pub const BYTE_LENGTH_BLOCK_TIMESTAMP: usize = 8;
pub const BYTE_LENGTH_BLOCK_TIMESTAMP: usize = 4;
+1 -3
View File
@@ -1,6 +1,4 @@
//!
//! The exit code constants.
//!
//! The revive exit code constants.
/// The common application success exit code.
pub const EXIT_CODE_SUCCESS: i32 = 0;
+3 -6
View File
@@ -12,12 +12,6 @@ pub static EXTENSION_ABI: &str = "abi";
/// The Yul IR file extension.
pub static EXTENSION_YUL: &str = "yul";
/// The EVM legacy assembly IR file extension.
pub static EXTENSION_EVMLA: &str = "evmla";
/// The Ethereal IR file extension.
pub static EXTENSION_ETHIR: &str = "ethir";
/// The EVM file extension.
pub static EXTENSION_EVM: &str = "evm";
@@ -41,3 +35,6 @@ pub static EXTENSION_POLKAVM_ASSEMBLY: &str = "pvmasm";
/// The PolkaVM bytecode file extension.
pub static EXTENSION_POLKAVM_BINARY: &str = "pvm";
/// The ELF shared object file extension.
pub static EXTENSION_SHARED_OBJECT: &str = "so";
-2
View File
@@ -6,7 +6,6 @@ pub(crate) mod byte_length;
pub(crate) mod evm_version;
pub(crate) mod exit_code;
pub(crate) mod extension;
pub(crate) mod polkavm;
pub(crate) mod utils;
pub use self::base::*;
@@ -15,5 +14,4 @@ pub use self::byte_length::*;
pub use self::evm_version::EVMVersion;
pub use self::exit_code::*;
pub use self::extension::*;
pub use self::polkavm::address::*;
pub use self::utils::*;
-115
View File
@@ -1,115 +0,0 @@
//! The PolkaVM address constants.
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_TO_L1: u16 = 0xFFFF;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_PRECOMPILE: u16 = 0xFFFD;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_META: u16 = 0xFFFC;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_MIMIC_CALL: u16 = 0xFFFB;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SYSTEM_MIMIC_CALL: u16 = 0xFFFA;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_MIMIC_CALL_BYREF: u16 = 0xFFF9;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SYSTEM_MIMIC_CALL_BYREF: u16 = 0xFFF8;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_RAW_FAR_CALL: u16 = 0xFFF7;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_RAW_FAR_CALL_BYREF: u16 = 0xFFF6;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SYSTEM_CALL: u16 = 0xFFF5;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SYSTEM_CALL_BYREF: u16 = 0xFFF4;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SET_CONTEXT_VALUE_CALL: u16 = 0xFFF3;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SET_PUBDATA_PRICE: u16 = 0xFFF2;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_INCREMENT_TX_COUNTER: u16 = 0xFFF1;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_GET_GLOBAL_PTR_CALLDATA: u16 = 0xFFF0;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_GET_GLOBAL_CALL_FLAGS: u16 = 0xFFEF;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_GET_GLOBAL_PTR_RETURN_DATA: u16 = 0xFFEE;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_EVENT_INITIALIZE: u16 = 0xFFED;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_EVENT_WRITE: u16 = 0xFFEC;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_CALLDATA: u16 = 0xFFEB;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_RETURN_DATA: u16 = 0xFFEA;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_ADD: u16 = 0xFFE9;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_SHRINK: u16 = 0xFFE8;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_PACK: u16 = 0xFFE7;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_MULTIPLICATION_HIGH_REGISTER: u16 = 0xFFE6;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_GET_GLOBAL_EXTRA_ABI_DATA: u16 = 0xFFE5;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_LOAD: u16 = 0xFFE4;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_COPY: u16 = 0xFFE3;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_SIZE: u16 = 0xFFE2;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_CONST_ARRAY_DECLARE: u16 = 0xFFE1;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_CONST_ARRAY_SET: u16 = 0xFFE0;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_CONST_ARRAY_FINALIZE: u16 = 0xFFDF;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_CONST_ARRAY_GET: u16 = 0xFFDE;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_DECOMMIT: u16 = 0xFFDD;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_DECOMMIT: u16 = 0xFFDC;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_RETURN_FORWARD: u16 = 0xFFDB;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_REVERT_FORWARD: u16 = 0xFFDA;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_SWAP: u16 = 0xFFD9;
-5
View File
@@ -1,5 +0,0 @@
//!
//! The PolkaVM constants.
//!
pub mod address;
+7 -3
View File
@@ -7,6 +7,10 @@ authors.workspace = true
repository.workspace = true
[dependencies]
evm-interpreter = { workspace = true }
primitive-types = { workspace = true }
alloy-primitives = { workspace = true }
hex = { workspace = true }
tempfile = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
alloy-primitives = { workspace = true, features = ["serde"] }
alloy-genesis = { workspace = true }
alloy-serde = { workspace = true }
+47
View File
@@ -0,0 +1,47 @@
{
"config": {
"chainId": 420420420,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"arrowGlacierBlock": 0,
"grayGlacierBlock": 0,
"shanghaiTime": 0,
"cancunTime": 0,
"terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true,
"blobSchedule": {
"cancun": {
"target": 3,
"max": 6,
"baseFeeUpdateFraction": 3338477
}
}
},
"coinbase": "0xffffffffffffffffffffffffffffffffffffffff",
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0xffffffff",
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00",
"alloc": {
"0101010101010101010101010101010101010101": {
"balance": "1000000000"
},
"0202020202020202020202020202020202020202": {
"balance": "1000000000"
},
"0303030303030303030303030303030303030303": {
"balance": "1000000000"
}
}
}
+199
View File
@@ -0,0 +1,199 @@
use std::time::Duration;
/// Parse a go formatted duration.
///
/// Sources:
/// - https://crates.io/crates/go-parse-duration (fixed an utf8 bug)
/// - https://github.com/golang/go/blob/master/src/time/format.go
pub fn parse_go_duration(value: &str) -> Result<Duration, String> {
parse_duration(value).map(|ns| Duration::from_nanos(ns.unsigned_abs()))
}
fn parse_duration(string: &str) -> Result<i64, String> {
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
let mut s = string;
let mut d: i64 = 0; // duration to be returned
let mut neg = false;
// Consume [-+]?
if !s.is_empty() {
let c = *s.as_bytes().first().unwrap();
if c == b'-' || c == b'+' {
neg = c == b'-';
s = &s[1..];
}
}
// Special case: if all that is left is "0", this is zero.
if s == "0" {
return Ok(0);
}
if s.is_empty() {
return Err(format!("invalid duration: {string}"));
}
while !s.is_empty() {
// integers before, after decimal point
let mut v: i64;
let mut f: i64 = 0;
// value = v + f / scale
let mut scale: f64 = 1f64;
// The next character must be [0-9.]
let c = *s.as_bytes().first().unwrap();
if !(c == b'.' || c.is_ascii_digit()) {
return Err(format!("invalid duration: {string}"));
}
// Consume [0-9]*
let pl = s.len();
match leading_int(s) {
Ok((_v, _s)) => {
v = _v;
s = _s;
}
Err(_) => {
return Err(format!("invalid duration: {string}"));
}
}
let pre = pl != s.len(); // whether we consume anything before a period
// Consume (\.[0-9]*)?
let mut post = false;
if !s.is_empty() && *s.as_bytes().first().unwrap() == b'.' {
s = &s[1..];
let pl = s.len();
let (f_, scale_, s_) = leading_fraction(s);
{
f = f_;
scale = scale_;
s = s_;
}
post = pl != s.len();
}
if !pre && !post {
// no digits (e.g. ".s" or "-.s")
return Err(format!("invalid duration: {string}"));
}
// Consume unit.
let mut i = 0;
while i < s.len() {
let c = *s.as_bytes().get(i).unwrap();
if c == b'.' || c.is_ascii_digit() {
break;
}
i += 1;
}
if i == 0 {
return Err(format!("missing unit in duration: {string}"));
}
let u = &s[..i];
s = &s[i..];
let unit = match u {
"ns" => 1i64,
"us" => 1000i64,
"µs" => 1000i64, // U+00B5 = micro symbol
"μs" => 1000i64, // U+03BC = Greek letter mu
"ms" => 1000000i64,
"s" => 1000000000i64,
"m" => 60000000000i64,
"h" => 3600000000000i64,
_ => {
return Err(format!("unknown unit {u} in duration {string}"));
}
};
if v > (1 << (63 - 1)) / unit {
// overflow
return Err(format!("invalid duration {string}"));
}
v *= unit;
if f > 0 {
// f64 is needed to be nanosecond accurate for fractions of hours.
// v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
v += (f as f64 * (unit as f64 / scale)) as i64;
if v < 0 {
// overflow
return Err(format!("invalid duration {string}"));
}
}
d += v;
if d < 0 {
// overflow
return Err(format!("invalid duration {string}"));
}
}
if neg {
d = -d;
}
Ok(d)
}
fn leading_int(s: &str) -> Result<(i64, &str), String> {
let mut x = 0;
let mut i = 0;
while i < s.len() {
let c = s.chars().nth(i).unwrap();
if !c.is_ascii_digit() {
break;
}
if x > (1 << (63 - 1)) / 10 {
return Err("overflow".into());
}
let d = i64::from(c.to_digit(10).unwrap());
x = x * 10 + d;
if x < 0 {
// overflow
return Err("overflow".into());
}
i += 1;
}
Ok((x, &s[i..]))
}
fn leading_fraction(s: &str) -> (i64, f64, &str) {
let mut i = 0;
let mut x = 0i64;
let mut scale = 1f64;
let mut overflow = false;
while i < s.len() {
let c = s.chars().nth(i).unwrap();
if !c.is_ascii_digit() {
break;
}
if overflow {
continue;
}
if x > (1 << (63 - 1)) / 10 {
// It's possible for overflow to give a positive number, so take care.
overflow = true;
continue;
}
let d = i64::from(c.to_digit(10).unwrap());
let y = x * 10 + d;
if y < 0 {
overflow = true;
continue;
}
x = y;
scale *= 10f64;
i += 1;
}
(x, scale, &s[i..])
}
#[cfg(test)]
mod tests {
use super::parse_duration;
#[test]
fn test_parse_duration() {
assert_eq!(parse_duration("8.731µs"), Ok(8731));
assert_eq!(parse_duration("50ns"), Ok(50));
assert_eq!(parse_duration("3ms"), Ok(3000000));
assert_eq!(parse_duration("2us"), Ok(2000));
assert_eq!(parse_duration("4.0s"), Ok(4000000000));
assert_eq!(parse_duration("1h45m"), Ok(6300000000000));
assert_eq!(
parse_duration("1"),
Err(String::from("missing unit in duration: 1")),
);
}
}
+540 -129
View File
@@ -1,159 +1,570 @@
use alloy_primitives::{keccak256, Address, B256};
use evm_interpreter::{
interpreter::{EtableInterpreter, RunInterpreter},
trap::CallCreateTrap,
Context, Etable, ExitError, Log, Machine, RuntimeBackend, RuntimeBaseBackend,
RuntimeEnvironment, RuntimeState, TransactionContext, Valids,
use core::str;
use std::{
collections::BTreeMap,
io::Write,
path::PathBuf,
process::{Command, Stdio},
str::FromStr,
time::Duration,
};
use primitive_types::{H160, H256, U256};
static RUNTIME_ETABLE: Etable<RuntimeState, UnimplementedHandler, CallCreateTrap> =
Etable::runtime();
use alloy_genesis::{Genesis, GenesisAccount};
use alloy_primitives::{hex::ToHexExt, Address, Bytes, B256, U256};
use alloy_serde::storage::deserialize_storage_map;
use serde::{Deserialize, Serialize};
use serde_json::{Deserializer, Value};
use tempfile::{NamedTempFile, TempPath};
#[derive(Default)]
pub struct UnimplementedHandler {
logs: Vec<Log>,
pub use self::go_duration::parse_go_duration;
mod go_duration;
const GENESIS_JSON: &str = include_str!("../genesis.json");
const EXECUTABLE_NAME: &str = "evm";
const EXECUTABLE_ARGS: [&str; 8] = [
"--log.format=json",
"run",
"--dump",
"--nomemory=false",
"--noreturndata=false",
"--json",
"--codefile",
"-",
];
const EXECUTABLE_ARGS_BENCH: [&str; 6] = [
"run",
"--bench",
"--nomemory=false",
"--noreturndata=false",
"--codefile",
"-",
];
const GAS_USED_MARKER: &str = "EVM gas used:";
const REVERT_MARKER: &str = " error: ";
/// The geth EVM state dump structure
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct StateDump {
pub root: Bytes,
pub accounts: BTreeMap<Address, Account>,
}
impl RuntimeEnvironment for UnimplementedHandler {
fn block_hash(&self, _number: U256) -> H256 {
unimplemented!()
}
fn block_number(&self) -> U256 {
U256::from(123)
}
fn block_coinbase(&self) -> H160 {
unimplemented!()
}
fn block_timestamp(&self) -> U256 {
U256::from(456)
}
fn block_difficulty(&self) -> U256 {
unimplemented!()
}
fn block_randomness(&self) -> Option<H256> {
unimplemented!()
}
fn block_gas_limit(&self) -> U256 {
unimplemented!()
}
fn block_base_fee_per_gas(&self) -> U256 {
unimplemented!()
}
fn chain_id(&self) -> U256 {
unimplemented!()
impl From<StateDump> for Genesis {
fn from(value: StateDump) -> Self {
let mut genesis: Genesis = serde_json::from_str(GENESIS_JSON).unwrap();
genesis.alloc = value
.accounts
.iter()
.map(|(address, account)| (*address, account.clone().into()))
.collect();
genesis
}
}
impl RuntimeBaseBackend for UnimplementedHandler {
fn balance(&self, _address: H160) -> U256 {
unimplemented!()
}
fn code_size(&self, _address: H160) -> U256 {
unimplemented!()
}
fn code_hash(&self, _address: H160) -> H256 {
unimplemented!()
}
fn code(&self, _address: H160) -> Vec<u8> {
unimplemented!()
}
fn storage(&self, _address: H160, _index: H256) -> H256 {
unimplemented!()
/// The geth EVM state dump account structure
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Account {
pub balance: U256,
pub nonce: u64,
pub code: Option<Bytes>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_storage_map"
)]
pub storage: Option<BTreeMap<B256, B256>>,
pub key: Option<B256>,
}
fn exists(&self, _address: H160) -> bool {
unimplemented!()
impl From<Account> for GenesisAccount {
fn from(value: Account) -> Self {
GenesisAccount {
balance: value.balance,
nonce: Some(value.nonce),
code: value.code,
storage: value.storage,
private_key: value.key,
}
fn nonce(&self, _address: H160) -> U256 {
unimplemented!()
}
}
impl RuntimeBackend for UnimplementedHandler {
fn original_storage(&self, _address: H160, _index: H256) -> H256 {
unimplemented!()
/// Contains the output from geth `emv` invocations
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct EvmOutput {
pub output: Bytes,
#[serde(rename = "gasUsed")]
pub gas_used: U256,
pub error: Option<String>,
}
fn deleted(&self, _address: H160) -> bool {
unimplemented!()
}
fn is_cold(&self, _address: H160, _index: Option<H256>) -> bool {
unimplemented!()
}
fn mark_hot(&mut self, _address: H160, _index: Option<H256>) {
unimplemented!()
}
fn set_storage(&mut self, _address: H160, _index: H256, _value: H256) -> Result<(), ExitError> {
unimplemented!()
}
fn log(&mut self, log: Log) -> Result<(), ExitError> {
self.logs.push(log);
Ok(())
}
fn mark_delete(&mut self, _address: H160) {
unimplemented!()
}
fn reset_storage(&mut self, _address: H160) {
unimplemented!()
}
fn set_code(&mut self, _address: H160, _code: Vec<u8>) -> Result<(), ExitError> {
unimplemented!()
}
fn reset_balance(&mut self, _address: H160) {
unimplemented!()
}
fn deposit(&mut self, _address: H160, _value: U256) {
unimplemented!()
}
fn withdrawal(&mut self, _address: H160, _value: U256) -> Result<(), ExitError> {
unimplemented!()
}
fn inc_nonce(&mut self, _address: H160) -> Result<(), ExitError> {
unimplemented!()
impl EvmOutput {
/// Return if there was no error found.
///
/// Panics if the gas used is zero as this indicates nothing was run.
pub fn run_success(&self) -> bool {
assert_ne!(self.gas_used, U256::ZERO, "nothing was executed: {self:?}");
self.error.is_none()
}
}
#[derive(Clone)]
pub struct PreparedEvm {
pub valids: Valids,
pub vm: Machine<RuntimeState>,
/// Contains the full log from geth `emv` invocations
#[derive(Clone, Debug)]
pub struct EvmLog {
pub account_deployed: Option<Address>,
pub output: EvmOutput,
pub state_dump: StateDump,
pub stderr: String,
}
pub fn prepare(code: Vec<u8>, data: Vec<u8>) -> PreparedEvm {
let address = Address::default().create2(B256::default(), keccak256([]).0);
let caller = Address::default().create2(B256::default(), keccak256([]).0);
impl EvmLog {
pub const EXECUTION_TIME_MARKER: &'static str = "execution time:";
let state = RuntimeState {
context: Context {
address: H160::from(address.0 .0),
caller: H160::from(caller.0 .0),
apparent_value: U256::default(),
/// Parse the reported execution time from stderr (requires --bench)
pub fn execution_time(&self) -> Result<Duration, String> {
for line in self.stderr.lines() {
if let Some(value) = line.split("execution time:").nth(1) {
return parse_go_duration(value.trim());
}
}
Err(format!(
"execution time marker '{}' not found in raw EVM log",
Self::EXECUTION_TIME_MARKER
))
}
fn parse_gas_used_from_bench(&mut self) {
for line in self.stderr.lines() {
if let Some(gas_line) = line.split(GAS_USED_MARKER).nth(1) {
let gas_used = gas_line.trim().parse::<u64>().unwrap_or_else(|error| {
panic!("invalid output '{gas_line}' for gas used: {error}")
});
self.output.gas_used = U256::from(gas_used);
}
}
}
}
impl From<&str> for EvmLog {
fn from(value: &str) -> Self {
let mut output = None;
let mut state_dump = None;
for value in Deserializer::from_str(value).into_iter::<Value>() {
let Ok(value) = value else { continue };
if let Ok(value @ EvmOutput { .. }) = serde_json::from_value(value.clone()) {
output = Some(value);
continue;
}
if let Ok(value @ StateDump { .. }) = serde_json::from_value(value) {
state_dump = Some(value);
}
}
if let (Some(output), Some(state_dump)) = (output, state_dump) {
return Self {
account_deployed: None,
output,
state_dump,
stderr: value.into(),
};
}
EvmLog {
account_deployed: None,
output: EvmOutput {
error: value.find(REVERT_MARKER).map(|_| REVERT_MARKER.to_string()),
..Default::default()
},
transaction_context: TransactionContext {
gas_price: U256::default(),
origin: H160::default(),
state_dump: Default::default(),
stderr: Default::default(),
}
.into(),
retbuf: Vec::new(),
}
}
/// Builder for running contracts in geth `evm`
pub struct Evm {
genesis_json: Option<String>,
genesis_path: Option<PathBuf>,
code: Option<Vec<u8>>,
input: Option<Bytes>,
receiver: Option<String>,
sender: String,
value: Option<u128>,
gas: Option<u64>,
create: bool,
bench: bool,
}
impl Default for Evm {
fn default() -> Self {
Self {
genesis_json: Some(GENESIS_JSON.to_string()),
genesis_path: None,
code: None,
input: None,
receiver: None,
sender: Address::default().encode_hex(),
value: None,
gas: None,
create: false,
bench: false,
}
}
}
impl Evm {
/// Create a new EVM with the given `genesis`
pub fn from_genesis(genesis: Genesis) -> Self {
Self::default().genesis_json(genesis)
}
/// Run the `code`
pub fn code_blob(self, blob: Vec<u8>) -> Self {
Self {
code: Some(blob),
..self
}
}
/// Set the calldata
pub fn input(self, bytes: Bytes) -> Self {
Self {
input: (!bytes.is_empty()).then_some(bytes),
..self
}
}
/// Set the create flag
pub fn deploy(self, enable: bool) -> Self {
Self {
create: enable,
..self
}
}
/// Set the transferred value
pub fn value(self, value: u128) -> Self {
Self {
value: Some(value),
..self
}
}
/// Set the gas limit
pub fn gas(self, limit: u64) -> Self {
Self {
gas: Some(limit),
..self
}
}
/// Provide the prestate genesis configuration
pub fn genesis_json(self, genesis: Genesis) -> Self {
let genesis_json = serde_json::to_string(&genesis).expect("state dump should be valid");
// TODO: Investigate
let genesis_json = genesis_json.replace("\"0x0\"", "0").into();
Self {
genesis_json,
genesis_path: None,
..self
}
}
/// Provide a path to the genesis file to be used
pub fn genesis_path(self, path: PathBuf) -> Self {
Self {
genesis_path: Some(path),
genesis_json: None,
..self
}
}
/// Set the callee address
pub fn receiver(self, address: Address) -> Self {
Self {
receiver: Some(address.encode_hex()),
..self
}
}
/// Set the caller address
pub fn sender(self, address: Address) -> Self {
Self {
sender: address.encode_hex(),
..self
}
}
/// Run as a benchmark
pub fn bench(self, flag: bool) -> Self {
Self {
bench: flag,
..self
}
}
/// Calculate the address of the contract account this deploy call would create
pub fn expect_account_created(&self) -> Address {
assert!(self.create, "expected a deploy call");
let sender = Address::from_str(&self.sender).expect("sender address should be valid");
let genesis: Genesis = match (self.genesis_json.as_ref(), self.genesis_path.as_ref()) {
(Some(json), None) => serde_json::from_str(json).unwrap(),
(None, Some(path)) => {
serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()
}
_ => panic!("provided a genesis json and a genesis json path"),
};
let nonce = genesis
.alloc
.get(&sender)
.map(|account| account.nonce.unwrap_or(0))
.unwrap_or(0);
sender.create(nonce)
}
/// Return the path to the genesis file;
/// writes the genesis file into a tmpdir if necessary.
///
/// `TempPath`` will delete on drop, so need to keep it around
fn write_genesis_file(&self, temp_path: &mut Option<TempPath>) -> String {
match (self.genesis_json.as_ref(), self.genesis_path.as_ref()) {
(Some(json), None) => {
let mut temp_file = NamedTempFile::new().unwrap();
temp_file.write_all(json.as_bytes()).unwrap();
let path = temp_file.into_temp_path();
*temp_path = Some(path);
temp_path.as_ref().unwrap().display().to_string()
}
(None, Some(path)) => path.display().to_string(),
_ => panic!("provided a genesis json and a genesis json path"),
}
}
/// Run the call in a geth `evm` subprocess.
///
/// Definitively not a hairy plumbing function.
pub fn run(self) -> EvmLog {
let mut temp_path = None;
let genesis_json_path = &self.write_genesis_file(&mut temp_path);
// Static args
let mut command = Command::new(PathBuf::from(EXECUTABLE_NAME));
command
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
if self.bench {
command.args(EXECUTABLE_ARGS_BENCH);
} else {
command.args(EXECUTABLE_ARGS);
};
PreparedEvm {
valids: Valids::new(&code[..]),
vm: evm_interpreter::Machine::new(code.into(), data.to_vec().into(), 1024, 0xFFFF, state),
// Dynamic args
command.args(["--prestate", genesis_json_path]);
command.args(["--sender", &self.sender]);
if let Some(input) = &self.input {
command.args(["--input", hex::encode(input).as_str()]);
}
let account_deployed = if self.create {
command.arg("--create");
self.expect_account_created().into()
} else {
None
};
match (&self.code, &self.receiver) {
(Some(_), None) => {}
(None, Some(address)) => {
command.args(["--receiver", address]);
}
(Some(_), Some(_)) => panic!("code and receiver specified"),
_ => panic!("no code file or receiver specified"),
}
if let Some(gas) = self.gas {
command.args(["--gas", &format!("{gas}")]);
}
if let Some(value) = self.value {
command.args(["--value", &format!("{value}")]);
}
// Run the evm subprocess and assert success return value
let process = command.spawn().unwrap_or_else(|error| {
panic!("{EXECUTABLE_NAME} subprocess spawning error: {error:?}")
});
let buf = vec![];
process
.stdin
.as_ref()
.unwrap_or_else(|| panic!("{EXECUTABLE_NAME} stdin getting error"))
.write_all(self.code.as_ref().unwrap_or(&buf))
.unwrap_or_else(|err| panic!("{EXECUTABLE_NAME} stdin writing error: {err:?}"));
let output = process
.wait_with_output()
.unwrap_or_else(|err| panic!("{EXECUTABLE_NAME} subprocess output error: {err}"));
assert!(
output.status.success(),
"{EXECUTABLE_NAME} command failed: {output:?}",
);
drop(temp_path);
let stdout = str::from_utf8(output.stdout.as_slice())
.unwrap_or_else(|err| panic!("{EXECUTABLE_NAME} stdout failed to parse: {err}"));
let stderr = str::from_utf8(output.stderr.as_slice())
.unwrap_or_else(|err| panic!("{EXECUTABLE_NAME} stderr failed to parse: {err}"));
let mut log: EvmLog = format!("{stdout}{stderr}").as_str().into();
log.stderr = stderr.into();
if self.bench {
log.parse_gas_used_from_bench();
}
// Set the deployed account
log.account_deployed = account_deployed;
log
}
}
pub fn execute(pre: PreparedEvm) -> (Vec<u8>, Vec<Log>) {
let mut vm = EtableInterpreter::new_valid(pre.vm, &RUNTIME_ETABLE, pre.valids);
let mut handler = UnimplementedHandler::default();
vm.run(&mut handler).exit().unwrap().unwrap();
(vm.retval.clone(), handler.logs)
#[cfg(test)]
mod tests {
use std::{str::FromStr, time::Duration};
use alloy_genesis::Genesis;
use alloy_primitives::{Bytes, B256, U256};
use crate::{Evm, EvmLog, EvmOutput, StateDump};
const OUTPUT_JSON_OK: &str = r#"{"output":"0000000000000000000000000000000000000000000000000000000000000000","gasUsed":"0x11d"}"#;
const OUTPUT_JSON_REVERTED: &str =
r#"{"output":"","gasUsed":"0x2d","error":"execution reverted"}"#;
const STATE_DUMP: &str = r#"
{
"root": "eb5d51177cb9049b848ea92f87f9a3f00abfb683d0866c2eddecc5692ad27f86",
"accounts": {
"0x1f2a98889594024BFfdA3311CbE69728d392C06D": {
"balance": "0",
"nonce": 1,
"root": "0x63cfcda8d81a8b1840b1b9722c37f929a4037e53ad1ce6abdef31c0c8bac1f61",
"codeHash": "0xa6e0062c5ba829446695f179b97702a75f7d354e33445d2e928ed00e1a39e88f",
"code": "0x608060405260043610610028575f3560e01c80633fa4f2451461002c578063b144adfb1461004a575b5f80fd5b610034610086565b60405161004191906100c5565b60405180910390f35b348015610055575f80fd5b50610070600480360381019061006b919061013c565b61008d565b60405161007d91906100c5565b60405180910390f35b5f34905090565b5f8173ffffffffffffffffffffffffffffffffffffffff16319050919050565b5f819050919050565b6100bf816100ad565b82525050565b5f6020820190506100d85f8301846100b6565b92915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61010b826100e2565b9050919050565b61011b81610101565b8114610125575f80fd5b50565b5f8135905061013681610112565b92915050565b5f60208284031215610151576101506100de565b5b5f61015e84828501610128565b9150509291505056fea2646970667358221220a2109c2f05a629fff4640e9f0cf12a698bbea9b0858a4029901e88bf5d1c926964736f6c63430008190033",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "02"
},
"address": "0x1f2a98889594024bffda3311cbe69728d392c06d",
"key": "0xcbeeb4463624bc2f332dcfe2b479eddb1c380ec862ee63d9f31b31b854fb7c61"
}
}
}"#;
const EVM_BIN_FIXTURE: &str = "6080604052348015600e575f80fd5b506040516101403803806101408339818101604052810190602e9190607f565b805f806101000a81548160ff0219169083151502179055505060a5565b5f80fd5b5f8115159050919050565b606181604f565b8114606a575f80fd5b50565b5f81519050607981605a565b92915050565b5f602082840312156091576090604b565b5b5f609c84828501606d565b91505092915050565b608f806100b15f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063cde4efa914602a575b5f80fd5b60306032565b005b5f8054906101000a900460ff16155f806101000a81548160ff02191690831515021790555056fea264697066735822122046c92dd2fd612b1ed93d184dad4c49f61c44690722c4a6c7c746ebeb0aadeb4a64736f6c63430008190033";
const EVM_BIN_RUNTIME_FIXTURE: &str = "6080604052348015600e575f80fd5b50600436106026575f3560e01c8063cde4efa914602a575b5f80fd5b60306032565b005b5f8054906101000a900460ff16155f806101000a81548160ff02191690831515021790555056fea264697066735822122046c92dd2fd612b1ed93d184dad4c49f61c44690722c4a6c7c746ebeb0aadeb4a64736f6c63430008190033";
const EVM_BIN_FIXTURE_INPUT: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
const EVM_BIN_RUNTIME_FIXTURE_INPUT: &str = "cde4efa9";
const STDERR_BENCH_OK: &str = r#"EVM gas used: 560071
execution time: 1.460881ms
allocations: 29
allocated bytes: 2558
"#;
const STDERR_BENCH_REVERT: &str = r#"EVM gas used: 69
execution time: 10.11µs
allocations: 43
allocated bytes: 3711"#;
const STDOUT_BENCH_REVERT: &str = r#" error: execution reverted"#;
#[test]
fn parse_evm_output_ok() {
serde_json::from_str::<EvmOutput>(OUTPUT_JSON_OK).unwrap();
}
#[test]
fn parse_evm_output_revert() {
serde_json::from_str::<EvmOutput>(OUTPUT_JSON_REVERTED).unwrap();
}
#[test]
fn parse_evm_output_bench_ok() {
let mut log = EvmLog::from("");
log.stderr = STDERR_BENCH_OK.into();
log.parse_gas_used_from_bench();
assert!(log.output.run_success());
assert_eq!(log.execution_time().unwrap(), Duration::from_nanos(1460881));
}
#[test]
fn parse_evm_output_bench_revert() {
let mut log = EvmLog::from(STDOUT_BENCH_REVERT);
log.stderr = STDERR_BENCH_REVERT.into();
log.parse_gas_used_from_bench();
assert!(!log.output.run_success());
}
#[test]
fn parse_state_dump() {
serde_json::from_str::<StateDump>(STATE_DUMP).unwrap();
}
#[test]
fn evm_log_from_str() {
let log = format!("{OUTPUT_JSON_OK}\n{STATE_DUMP}");
let _ = EvmLog::from(log.as_str());
}
#[test]
fn generate_genesis() {
let log = format!("{OUTPUT_JSON_OK}\n{STATE_DUMP}");
let log = EvmLog::from(log.as_str());
let mut genesis: Genesis = log.state_dump.into();
let storage = genesis
.alloc
.pop_first()
.expect("should have one account in genesis")
.1
.storage
.expect("genesis account should have storage");
let storage_value = storage
.get(&B256::ZERO)
.expect("genesis account should have key 0 occupied");
assert_eq!(*storage_value, B256::from(U256::from(2)));
}
#[test]
fn flipper() {
let log_runtime = Evm::default()
.code_blob(EVM_BIN_RUNTIME_FIXTURE.as_bytes().to_vec())
.input(Bytes::from_str(EVM_BIN_RUNTIME_FIXTURE_INPUT).unwrap())
.run();
assert!(log_runtime.output.run_success());
}
#[test]
fn prestate() {
let log_deploy = Evm::default()
.code_blob(EVM_BIN_FIXTURE.as_bytes().to_vec())
.input(Bytes::from_str(EVM_BIN_FIXTURE_INPUT).unwrap())
.deploy(true)
.run();
assert!(log_deploy.output.run_success());
let address = log_deploy.account_deployed.unwrap();
let genesis: Genesis = log_deploy.state_dump.into();
let log_runtime = Evm::default()
.genesis_json(genesis)
.receiver(address)
.input(Bytes::from_str(EVM_BIN_RUNTIME_FIXTURE_INPUT).unwrap())
.run();
assert!(log_runtime.output.run_success(), "{:?}", log_runtime.output);
}
#[test]
#[ignore] // https://github.com/ethereum/go-ethereum/issues/30778
fn bench_flipper() {
let log_runtime = Evm::default()
.code_blob(EVM_BIN_RUNTIME_FIXTURE.as_bytes().to_vec())
.input(Bytes::from_str(EVM_BIN_RUNTIME_FIXTURE_INPUT).unwrap())
.bench(true)
.run();
assert!(log_runtime.output.run_success());
assert!(log_runtime.execution_time().unwrap() > Duration::from_nanos(0));
}
}
+2 -6
View File
@@ -8,17 +8,13 @@ authors.workspace = true
description = "revive compiler integration test cases"
[dependencies]
polkavm = { workspace = true }
alloy-primitives = { workspace = true }
alloy-sol-types = { workspace = true }
hex = { workspace = true }
env_logger = { workspace = true }
log = { workspace = true }
serde_json = { workspace = true }
revive-solidity = { workspace = true }
revive-differential = { workspace = true }
revive-llvm-context = { workspace = true }
revive-common = { workspace = true }
revive-runner = { workspace = true }
[dev-dependencies]
sha1 = { workspace = true }
+8 -8
View File
@@ -1,10 +1,10 @@
{
"Baseline": 934,
"Computation": 4360,
"DivisionArithmetics": 39824,
"ERC20": 46471,
"Events": 1749,
"FibonacciIterative": 2973,
"Flipper": 3563,
"SHA1": 32543
"Baseline": 1110,
"Computation": 2389,
"DivisionArithmetics": 14822,
"ERC20": 23973,
"Events": 1605,
"FibonacciIterative": 2023,
"Flipper": 1989,
"SHA1": 17026
}
+81
View File
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "BalanceReceiver"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Balance"
}
},
"value": 24
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "1c8d16b30000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "6ada15d90000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
}
}
]
}
*/
contract BalanceReceiver {
constructor() payable {}
fallback() external payable {}
}
contract Balance {
constructor() payable {
// 0 to EOA
transfer_to(payable(address(0xdeadbeef)), 0);
send_to(payable(address(0xdeadbeef)), 0);
// 1 to EOA
transfer_to(payable(address(0xcafebabe)), 1);
send_to(payable(address(0xcafebabe)), 1);
BalanceReceiver balanceReceiver = new BalanceReceiver();
// 0 to contract
transfer_to(payable(address(balanceReceiver)), 0);
send_to(payable(address(balanceReceiver)), 0);
// 1 to contract
transfer_to(payable(address(balanceReceiver)), 1);
send_to(payable(address(balanceReceiver)), 1);
}
function transfer_to(address payable _dest, uint _amount) public payable {
_dest.transfer(_amount);
}
function send_to(address payable _dest, uint _amount) public payable {
require(_dest.send(_amount));
}
}
+31
View File
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "BaseFee"
}
}
}
},
{
"VerifyCall": {
"success": true
}
}
]
}
*/
contract BaseFee {
constructor() payable {
assert(block.basefee == 0);
}
}
+15
View File
@@ -1,5 +1,20 @@
// SPDX-License-Identifier: MIT
/* runner.json
{
"actions": [
{
"Instantiate": {
"origin": "Alice",
"value": 0
}
}
]
}
*/
pragma solidity ^0.8;
contract Baseline {
+25
View File
@@ -2,6 +2,31 @@
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Bitwise"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "3fa4f245"
}
}
]
}
*/
contract Bitwise {
function opByte(uint i, uint x) public payable returns (uint ret) {
assembly {
+37
View File
@@ -2,12 +2,49 @@
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Block"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "8381f58a"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b80777ea"
}
}
]
}
*/
contract Block {
function timestamp() public view returns (uint ret) {
ret = block.timestamp;
}
function number() public view returns (uint ret) {
if (block.number == 0) {
ret = 1;
} else {
ret = block.number;
}
}
}
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "BlockHash"
}
},
"data": "4545454545454545454545454545454545454545454545454545454545454545"
}
}
]
}
*/
contract BlockHash {
constructor(bytes32 expected) payable {
assert(blockhash(0) == expected);
assert(blockhash(1) == 0);
assert(
blockhash(
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
) == 0
);
}
}
+46 -8
View File
@@ -2,19 +2,57 @@
pragma solidity ^0.8;
contract Call {
function value_transfer(address payable destination) public payable {
destination.transfer(msg.value);
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "Callee"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Caller"
}
},
"value": 123
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "5a6535fc00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000"
}
}
]
}
*/
contract Callee {
function echo(bytes memory payload) public pure returns (bytes memory) {
return payload;
}
function call(
address callee,
bytes memory payload
) public pure returns (bytes memory) {
return Call(callee).echo(payload);
receive() external payable {}
}
contract Caller {
constructor() payable {
Callee callee = new Callee();
payable(address(callee)).transfer(msg.value);
}
function call(bytes memory payload) public returns (bytes memory) {
Callee callee = new Callee();
return callee.echo(payload);
}
}
+27
View File
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Coinbase"
}
}
}
}
]
}
*/
contract Coinbase {
constructor() payable {
address coinbase = address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF);
assert(block.coinbase == coinbase);
}
}
@@ -2,6 +2,44 @@
pragma solidity ^0.8;
/* runner.json
{
"actions": [
{
"Instantiate": {}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "0f760610000000000000000000000000000000000000000000000000000000000000000d"
}
},
{
"VerifyCall": {
"success": true,
"output": "000000000000000000000000000000000000000000000000000000000000005b"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "00261b660000000000000000000000000000000000000000000000000000000000000005"
}
},
{
"VerifyCall": {
"success": true,
"output": "00000000000000000000000000000000000000000000000000000000000003b1"
}
}
]
}
*/
contract Computation {
function triangle_number(int64 n) public pure returns (int64 sum) {
unchecked {
+49
View File
@@ -2,6 +2,47 @@
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Context"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "846a1ee1"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fc9c8d39"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "3af973b1"
}
}
]
}
*/
contract Context {
function address_this() public view returns (address ret) {
ret = address(this);
@@ -10,4 +51,12 @@ contract Context {
function caller() public view returns (address ret) {
ret = msg.sender;
}
function chain_id() public view returns (uint) {
uint256 id;
assembly {
id := chainid()
}
return id;
}
}
+57 -6
View File
@@ -1,13 +1,64 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "CreateA"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "CreateB"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"value": 10000
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
}
]
}
*/
contract CreateA {
address creator;
constructor() payable {
creator = msg.sender;
}
constructor() payable {}
}
contract CreateB {
+50
View File
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "CreateA"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "CreateB"
}
},
"value": 100000
}
}
]
}
*/
contract CreateA {
constructor() payable {}
}
contract CreateB {
constructor() payable {
bytes32 salt = hex"ff";
try new CreateA{salt: salt}() returns (CreateA) {} catch {
revert("the first instantiation should succeed");
}
try new CreateA{salt: salt}() returns (CreateA) {} catch {
return;
}
revert("the second instantiation should have failed");
}
}
+35
View File
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "TestSha3"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "f9fbd5540000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c68656c6c6f20776f726c64210000000000000000000000000000000000000000"
}
}
]
}
*/
contract TestSha3 {
function test(string memory _pre) external payable returns (bytes32) {
bytes32 hash = keccak256(bytes(_pre));
return bytes32(uint(hash) + 1);
}
}
+84
View File
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "Logic"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Tester"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"value": 123,
"data": "6466414b0000000000000000000000000000000000000000000000000000000000000020"
}
}
]
}
*/
contract Logic {
// NOTE: storage layout must be the same as contract Tester
uint256 public num;
address public sender;
uint256 public value;
uint public immutable multiplier = 4;
event DidSetVars();
function setVars(uint256 _num) public payable returns (uint256) {
num = _num * multiplier;
sender = msg.sender;
value = msg.value;
emit DidSetVars();
return _num;
}
}
contract Tester {
uint256 public num;
address public sender;
uint256 public value;
uint public immutable multiplier = 2;
function setVars(uint256 _num) public payable returns (bool, bytes memory) {
Logic impl = new Logic();
// Tester's storage is set, Logic is not modified.
(bool success, bytes memory data) = address(impl).delegatecall(
abi.encodeWithSignature("setVars(uint256)", _num)
);
assert(success);
assert(impl.num() == 0);
assert(impl.sender() == address(0));
assert(impl.value() == 0);
assert(num == _num * 4);
assert(sender == msg.sender);
assert(value == msg.value);
return (success, data);
}
}
+49
View File
@@ -2,6 +2,32 @@
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "ERC20"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "ERC20Tester"
}
}
}
}
]
}
*/
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol
interface IERC20 {
function totalSupply() external view returns (uint);
@@ -72,3 +98,26 @@ contract ERC20 is IERC20 {
emit Transfer(msg.sender, address(0), amount);
}
}
contract ERC20Tester {
constructor() {
address BOB = address(0xffffffffffffffffffffffffffffffffffffff);
ERC20 token = new ERC20();
assert(token.decimals() == 18);
token.mint(300);
assert(token.balanceOf(address(this)) == 300);
token.transfer(BOB, 100);
assert(token.balanceOf(address(this)) == 200);
assert(token.balanceOf(BOB) == 100);
token.approve(address(this), 100);
token.transferFrom(address(this), BOB, 100);
assert(token.balanceOf(BOB) == 200);
assert(token.balanceOf(address(this)) == 100);
token.burn(100);
assert(token.balanceOf(address(this)) == 0);
}
}
+33
View File
@@ -2,6 +2,39 @@
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Events"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "4d43bec90000000000000000000000000000000000000000000000000000000000000000"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "4d43bec9000000000000000000000000000000000000000000000000000000000000007b"
}
}
]
}
*/
contract Events {
event A() anonymous;
event E(uint, uint indexed, uint indexed, uint indexed);
+12
View File
@@ -14,4 +14,16 @@ contract ExtCode {
ret := codesize()
}
}
function ExtCodeHash(address who) public view returns (bytes32 ret) {
assembly {
ret := extcodehash(who)
}
}
function CodeHash() public view returns (bytes32 ret) {
assembly {
ret := extcodehash(address())
}
}
}
+24 -1
View File
@@ -2,7 +2,29 @@
pragma solidity ^0.8;
// https://medium.com/coinmonks/fibonacci-in-solidity-8477d907e22a
/* runner.json
{
"actions": [
{
"Instantiate": {}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "6b83dd2e0000000000000000000000000000000000000000000000000000000000000006"
}
},
{
"VerifyCall": {
"success": true,
"output": "0000000000000000000000000000000000000000000000000000000000000008"
}
}
]
}
*/
contract FibonacciRecursive {
function f(uint n) internal pure returns (uint) {
@@ -36,6 +58,7 @@ contract FibonacciIterative {
}
}
// https://medium.com/coinmonks/fibonacci-in-solidity-8477d907e22a
contract FibonacciBinet {
function fib3(uint n) external pure returns (uint a) {
if (n == 0) {
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "FunctionPointer"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "26121ff0"
}
}
]
}
*/
contract FunctionPointer {
bool public flag = false;
function f0() public {
flag = true;
}
function f() public returns (bool) {
function() internal x = f0;
x();
return flag;
}
}
+32
View File
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "GasLeft"
}
}
}
},
{
"VerifyCall": {
"success": true
}
}
]
}
*/
contract GasLeft {
constructor() payable {
assert(gasleft() > gasleft());
assert(gasleft() > 0 && gasleft() < 0xffffffffffffffff);
}
}
+31
View File
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "GasLimit"
}
}
}
},
{
"VerifyCall": {
"success": true
}
}
]
}
*/
contract GasLimit {
constructor() payable {
assert(block.gaslimit == 2000000000000);
}
}
+31
View File
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "GasPrice"
}
}
}
},
{
"VerifyCall": {
"success": true
}
}
]
}
*/
contract GasPrice {
constructor() payable {
assert(tx.gasprice == 1000);
}
}
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "ImmutablesTester"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Immutables"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
}
]
}
*/
contract ImmutablesTester {
// Read should work in the runtime code
uint public immutable foo;
// Read should work in the runtime code
uint public immutable bar;
// Read should work in the runtime code
uint public immutable zoo;
// Assign and read should work in the constructor
constructor(uint _foo) payable {
foo = _foo;
bar = foo + 1;
zoo = bar + 2;
assert(zoo == _foo + 3);
}
}
contract Immutables {
fallback() external {
ImmutablesTester tester = new ImmutablesTester(127);
assert(tester.foo() == 127);
assert(tester.bar() == tester.foo() + 1);
assert(tester.zoo() == tester.bar() + 2);
}
}
+25
View File
@@ -2,6 +2,31 @@
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "MCopy"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "0ee188b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"
}
}
]
}
*/
contract MCopy {
function memcpy(bytes memory payload) public pure returns (bytes memory) {
return payload;
+40
View File
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "MLoad"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "e2179b8e"
}
}
]
}
*/
contract MLoad {
constructor() payable {
assert(g() == 0);
}
function g() public payable returns (uint m) {
assembly {
m := mload(0)
}
}
}
+34
View File
@@ -2,6 +2,40 @@
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "MSize",
"solc_optimizer": false
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "f016832c"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "f4a63aa5"
}
}
]
}
*/
contract MSize {
uint[] public data;
+101
View File
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "MStore8"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad4210000000000000000000000000000000000000000000000000000000000000000"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad4210000000000000000000000000000000000000000000000000000000000000001"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad4210000000000000000000000000000000000000000000000000000000000000002"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad42100000000000000000000000000000000000000000000000000000000000000ff"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad4210000000000000000000000000000000000000000000000000000000000000100"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad4210000000000000000000000000000000000000000000000000000000000000101"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad4210000000000000000000000000000000000000000000000000000000000000102"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad42100000000000000000000000000000000000000000000000000000000075bcd15"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "b09ad421ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
}
]
}
*/
contract MStore8 {
function mStore8(uint value) public pure returns (uint256 word) {
assembly {
mstore8(0x80, value)
word := mload(0x80)
}
}
}
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "Callee"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "ReturnDataOob"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
}
}
}
]
}
*/
contract Callee {
function echo(bytes memory payload) public pure returns (bytes memory) {
return payload;
}
}
contract ReturnDataOob {
fallback() external {
new Callee().echo(hex"1234");
assembly {
let pos := mload(64)
let size := add(returndatasize(), 1)
returndatacopy(pos, 0, size)
}
}
}
+25
View File
@@ -1,6 +1,31 @@
// SPDX-License-Identifier: BSD-2-Clause
pragma solidity ^0.8.4;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "SHA1"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "1605782b00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000200ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
}
]
}
*/
contract SHA1 {
function sha1(bytes memory data) public pure returns (bytes20 ret) {
assembly {
+75
View File
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Send"
}
},
"value": 211
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "1c8d16b30000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
}
},
{
"VerifyCall": {
"success": true
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fb9e8d050000000000000000000000000000000000000000000000000000000000000001"
}
},
{
"VerifyCall": {
"success": false
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fb9e8d050000000000000000000000000000000000000000000000000000000000000000"
}
},
{
"VerifyCall": {
"success": false
}
}
]
}
*/
contract Send {
constructor() payable {}
function transfer_self(uint _amount) public payable {
transfer_to(payable(address(this)), _amount);
}
function transfer_to(address payable _dest, uint _amount) public payable {
if (_dest.send(_amount)) {}
}
fallback() external {}
receive() external payable {}
}
+42 -1
View File
@@ -2,13 +2,54 @@
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Storage"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fabc9efaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "558b9f9bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
}
]
}
*/
contract Storage {
function transient(uint value) public returns (uint ret) {
assembly {
let slot := 123
let slot := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
tstore(slot, value)
let success := call(0, 0, 0, 0, 0, 0, 0)
ret := tload(slot)
}
}
function persistent(uint value) public returns (uint ret) {
assembly {
let slot := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
sstore(slot, value)
ret := sload(slot)
}
}
}
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "TransactionOrigin"
}
}
}
},
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "TransactionTester"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "f8a8fd6d"
}
}
]
}
*/
contract TransactionTester {
constructor() payable {
assert(tx.origin == new TransactionOrigin().test());
}
function test() public payable returns (address ret) {
ret = tx.origin;
}
}
contract TransactionOrigin {
function test() public payable returns (address ret) {
assert(msg.sender != tx.origin);
ret = tx.origin;
}
}
+75
View File
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": false,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Transfer"
}
},
"value": 211
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "1c8d16b30000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
}
},
{
"VerifyCall": {
"success": true
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fb9e8d050000000000000000000000000000000000000000000000000000000000000001"
}
},
{
"VerifyCall": {
"success": false
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "fb9e8d050000000000000000000000000000000000000000000000000000000000000000"
}
},
{
"VerifyCall": {
"success": false
}
}
]
}
*/
contract Transfer {
constructor() payable {}
function transfer_self(uint _amount) public payable {
transfer_to(payable(address(this)), _amount);
}
function transfer_to(address payable _dest, uint _amount) public payable {
_dest.transfer(_amount);
}
fallback() external {}
receive() external payable {}
}
+58 -5
View File
@@ -1,13 +1,66 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Upload": {
"code": {
"Solidity": {
"contract": "ValueTester"
}
}
}
},
{
"Instantiate": {
"value": 1024,
"code": {
"Solidity": {
"contract": "Value"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"value": 123,
"data": "3fa4f245"
}
}
]
}
*/
contract ValueTester {
constructor() payable {}
function balance_self() public view returns (uint ret) {
ret = address(this).balance;
}
}
contract Value {
constructor() payable {
ValueTester tester = new ValueTester{value: msg.value}();
// own account
assert(address(this).balance == 0);
// tester account
assert(address(tester).balance == msg.value);
assert(tester.balance_self() == msg.value);
// non-existant account
assert(address(0xdeadbeef).balance == 0);
}
function value() public payable returns (uint ret) {
ret = msg.value;
}
function balance_of(address _address) public view returns (uint ret) {
ret = _address.balance;
}
}
+38
View File
@@ -1,6 +1,44 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"actions": [
{
"Instantiate": {
"data": "0000000000000000000000000000000000000000000000000000000000000001"
}
},
{
"VerifyStorage": {
"contract": {
"Instantiated": 0
},
"key": "0000000000000000000000000000000000000000000000000000000000000000",
"expected": "0100000000000000000000000000000000000000000000000000000000000000"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "cde4efa9"
}
},
{
"VerifyStorage": {
"contract": {
"Instantiated": 0
},
"key": "0000000000000000000000000000000000000000000000000000000000000000",
"expected": "0000000000000000000000000000000000000000000000000000000000000000"
}
}
]
}
*/
contract Flipper {
bool coin;
-12
View File
@@ -1,12 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract MStore8 {
function mStore8(uint value) public pure returns (uint256 word) {
assembly {
mstore8(0x80, value)
word := mload(0x80)
}
}
}
+29 -27
View File
@@ -1,10 +1,8 @@
use alloy_primitives::{Address, I256, U256};
use alloy_primitives::{Address, Bytes, I256, U256};
use alloy_sol_types::{sol, SolCall, SolConstructor};
use revive_solidity::test_utils::*;
use crate::mock_runtime::{CallOutput, State};
#[derive(Clone)]
pub struct Contract {
pub name: &'static str,
@@ -93,7 +91,7 @@ sol!(
function sha1(bytes memory data) public pure returns (bytes20 ret);
}
);
case!("SHA1.sol", SHA1, sha1Call, sha1, pre: Vec<u8>);
case!("SHA1.sol", SHA1, sha1Call, sha1, pre: Bytes);
sol!(
contract ERC20 {
@@ -158,12 +156,26 @@ case!("DivisionArithmetics.sol", DivisionArithmetics, sdivCall, division_arithme
case!("DivisionArithmetics.sol", DivisionArithmetics, modCall, division_arithmetics_mod, n: U256, d: U256);
case!("DivisionArithmetics.sol", DivisionArithmetics, smodCall, division_arithmetics_smod, n: I256, d: I256);
sol!(
contract Send {
function transfer_self(uint _amount) public payable;
}
);
case!("Send.sol", Send, transfer_selfCall, send_self, amount: U256);
sol!(
contract Transfer {
function transfer_self(uint _amount) public payable;
}
);
case!("Transfer.sol", Transfer, transfer_selfCall, transfer_self, amount: U256);
sol!(
contract MStore8 {
function mStore8(uint value) public pure returns (uint256 word);
}
);
case!("mStore8.sol", MStore8, mStore8Call, mstore8, value: U256);
case!("MStore8.sol", MStore8, mStore8Call, mstore8, value: U256);
sol!(
contract Events {
@@ -180,17 +192,23 @@ sol!(
function ExtCodeSize(address who) public view returns (uint ret);
function CodeSize() public pure returns (uint ret);
function ExtCodeHash(address who) public view returns (bytes32 ret);
function CodeHash() public view returns (bytes32 ret);
}
);
case!("ExtCode.sol", ExtCode, ExtCodeSizeCall, ext_code_size, address: Address);
case!("ExtCode.sol", ExtCode, CodeSizeCall, code_size,);
case!("ExtCode.sol", ExtCode, ExtCodeHashCall, ext_code_hash, address: Address);
case!("ExtCode.sol", ExtCode, CodeHashCall, code_hash,);
sol!(
contract MCopy {
function memcpy(bytes memory payload) public pure returns (bytes memory);
}
);
case!("MCopy.sol", MCopy, memcpyCall, memcpy, payload: Vec<u8>);
case!("MCopy.sol", MCopy, memcpyCall, memcpy, payload: Bytes);
sol!(
contract Call {
@@ -205,15 +223,17 @@ sol!(
}
);
case!("Call.sol", Call, value_transferCall, call_value_transfer, destination: Address);
case!("Call.sol", Call, callCall, call_call, destination: Address, payload: Vec<u8>);
case!("Call.sol", Call, callCall, call_call, destination: Address, payload: Bytes);
case!("Call.sol", "Call", vec![], call_constructor);
sol!(
contract Value {
function balance_of(address _address) public view returns (uint ret);
function balance_self() public view returns (uint ret);
}
);
case!("Value.sol", Value, balance_ofCall, value_balance_of, address: Address);
case!("Value.sol", Value, balance_selfCall, value_balance_self,);
sol!(
contract Bitwise {
@@ -230,24 +250,6 @@ sol!(
case!("Storage.sol", Storage, transientCall, storage_transient, value: U256);
impl Contract {
/// Execute the contract.
///
/// Useful helper if the contract state can be ignored,
/// as it spares the deploy transaciton.
///
/// - Inserts an account with given `code` into a new state.
/// - Callee and caller account will be `Transaction::default_address()`.
/// - Sets the calldata.
/// - Doesn't execute the constructor or deploy code.
/// - Calls the "call" export on a default backend config.
pub fn execute(&self) -> (State, CallOutput) {
State::default()
.transaction()
.with_default_account(&self.pvm_runtime)
.calldata(self.calldata.clone())
.call()
}
fn build(calldata: Vec<u8>, name: &'static str, code: &str) -> Self {
Self {
name,
@@ -260,7 +262,7 @@ impl Contract {
#[cfg(test)]
mod tests {
use alloy_primitives::U256;
use alloy_primitives::{Bytes, U256};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::{de::Deserialize, Serialize};
use std::{collections::BTreeMap, fs::File};
@@ -305,7 +307,7 @@ mod tests {
(|| Contract::odd_product(0)) as fn() -> Contract,
(|| Contract::fib_iterative(U256::ZERO)) as fn() -> Contract,
Contract::erc20 as fn() -> Contract,
(|| Contract::sha1(Vec::new())) as fn() -> Contract,
(|| Contract::sha1(Bytes::new())) as fn() -> Contract,
(|| Contract::division_arithmetics_div(U256::ZERO, U256::ZERO)) as fn() -> Contract,
(|| Contract::event(U256::ZERO)) as fn() -> Contract,
]
-38
View File
@@ -1,42 +1,4 @@
use alloy_primitives::{Address, U256};
use cases::Contract;
use mock_runtime::{CallOutput, State};
use crate::mock_runtime::{Event, ReturnFlags};
pub mod cases;
pub mod mock_runtime;
#[cfg(test)]
mod tests;
pub fn assert_success(contract: &Contract, differential: bool) -> (State, CallOutput) {
let (state, output) = contract.execute();
assert_eq!(output.flags, ReturnFlags::Success);
if differential {
let evm =
revive_differential::prepare(contract.evm_runtime.clone(), contract.calldata.clone());
let (evm_output, evm_log) = revive_differential::execute(evm);
assert_eq!(output.data.clone(), evm_output);
assert_eq!(output.events.len(), evm_log.len());
assert_eq!(
output.events,
evm_log
.iter()
.map(|log| Event {
address: Address::from_slice(log.address.as_bytes()),
data: log.data.clone(),
topics: log
.topics
.iter()
.map(|topic| U256::from_be_bytes(topic.0))
.collect(),
})
.collect::<Vec<_>>()
);
}
(state, output)
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-5
View File
@@ -7,14 +7,9 @@ repository.workspace = true
authors.workspace = true
description = "revive compiler linker utils"
[features]
riscv-64 = []
[dependencies]
inkwell = { workspace = true }
tempfile = { workspace = true }
polkavm-linker = { workspace = true }
polkavm-common = { workspace = true }
libc = { workspace = true }
anyhow = { workspace = true }
+5 -15
View File
@@ -8,14 +8,7 @@ SECTIONS {
.text : { KEEP(*(.text.polkavm_export)) *(.text .text.*) }
}"#;
#[cfg(not(feature = "riscv-64"))]
const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv32.a";
#[cfg(feature = "riscv-64")]
const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv64.a";
#[cfg(not(feature = "riscv-64"))]
const BUILTINS_LIB_NAME: &str = "clang_rt.builtins-riscv32";
#[cfg(feature = "riscv-64")]
const BUILTINS_LIB_NAME: &str = "clang_rt.builtins-riscv64";
fn invoke_lld(cmd_args: &[&str]) -> bool {
@@ -29,9 +22,10 @@ fn invoke_lld(cmd_args: &[&str]) -> bool {
unsafe { LLDELFLink(args.as_ptr(), args.len()) == 0 }
}
fn polkavm_linker<T: AsRef<[u8]>>(code: T) -> anyhow::Result<Vec<u8>> {
pub fn polkavm_linker<T: AsRef<[u8]>>(code: T, strip_binary: bool) -> anyhow::Result<Vec<u8>> {
let mut config = polkavm_linker::Config::default();
config.set_strip(true);
config.set_strip(strip_binary);
config.set_optimize(true);
polkavm_linker::program_from_elf(config, code.as_ref())
.map_err(|reason| anyhow::anyhow!("polkavm linker failed: {}", reason))
@@ -63,6 +57,7 @@ pub fn link<T: AsRef<[u8]>>(input: T) -> anyhow::Result<Vec<u8>> {
"--relocatable",
"--emit-relocs",
"--no-relax",
"--unique",
"--gc-sections",
"--library-path",
dir.path().to_str().expect("should be utf8"),
@@ -78,10 +73,5 @@ pub fn link<T: AsRef<[u8]>>(input: T) -> anyhow::Result<Vec<u8>> {
return Err(anyhow::anyhow!("ld.lld failed"));
}
if env::var("PVM_LINKER_DUMP_SO").is_ok() {
fs::copy(&output_path, "/tmp/out.so")?;
};
let blob = fs::read(&output_path)?;
polkavm_linker(blob)
Ok(fs::read(&output_path)?)
}
+1
View File
@@ -13,3 +13,4 @@ libc = { workspace = true }
[build-dependencies]
cc = { workspace = true }
revive-build-utils = { workspace = true }
+74 -15
View File
@@ -1,17 +1,16 @@
fn llvm_config(arg: &str) -> String {
let output = std::process::Command::new("llvm-config")
.args([arg])
.output()
.unwrap_or_else(|_| panic!("`llvm-config {arg}` failed"));
String::from_utf8(output.stdout)
.unwrap_or_else(|_| panic!("output of `llvm-config {arg}` should be utf8"))
}
fn set_rustc_link_flags() {
println!("cargo:rustc-link-search=native={}", llvm_config("--libdir"));
let llvm_lib_path = match std::env::var(revive_build_utils::REVIVE_LLVM_TARGET_PREFIX) {
Ok(path) => std::path::PathBuf::from(path).join("lib"),
_ => revive_build_utils::llvm_lib_dir(),
};
println!(
"cargo:rustc-link-search=native={}",
llvm_lib_path.to_string_lossy()
);
for lib in [
// These are required by ld.lld
"lldELF",
"lldCommon",
"lldMachO",
@@ -22,19 +21,79 @@ fn set_rustc_link_flags() {
"LLVMTargetParser",
"LLVMBinaryFormat",
"LLVMDemangle",
// The `llvm-sys` crate relies on `llvm-config` to obtain a list of required LLVM libraries
// during the build process. This works well in typical native environments, where `llvm-config`
// can accurately list the necessary libraries.
// However, when cross-compiling to WebAssembly using Emscripten, `llvm-config` fails to recognize
// JavaScript-based libraries, making it necessary to manually inject the required dependencies.
"LLVMRISCVDisassembler",
"LLVMRISCVAsmParser",
"LLVMRISCVCodeGen",
"LLVMRISCVDesc",
"LLVMRISCVInfo",
"LLVMExecutionEngine",
"LLVMOption",
"LLVMMCDisassembler",
"LLVMPasses",
"LLVMHipStdPar",
"LLVMCFGuard",
"LLVMCoroutines",
"LLVMipo",
"LLVMVectorize",
"LLVMInstrumentation",
"LLVMFrontendOpenMP",
"LLVMFrontendOffloading",
"LLVMGlobalISel",
"LLVMAsmPrinter",
"LLVMSelectionDAG",
"LLVMCodeGen",
"LLVMTarget",
"LLVMObjCARCOpts",
"LLVMCodeGenTypes",
"LLVMIRPrinter",
"LLVMScalarOpts",
"LLVMInstCombine",
"LLVMAggressiveInstCombine",
"LLVMTransformUtils",
"LLVMBitWriter",
"LLVMAnalysis",
"LLVMProfileData",
"LLVMDebugInfoDWARF",
"LLVMObject",
"LLVMMCParser",
"LLVMIRReader",
"LLVMAsmParser",
"LLVMMC",
"LLVMDebugInfoCodeView",
"LLVMBitReader",
"LLVMRemarks",
"LLVMBitstreamReader",
] {
println!("cargo:rustc-link-lib=static={lib}");
}
#[cfg(target_os = "linux")]
{
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
let target_env = std::env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
if target_os == "linux" {
if target_env == "musl" {
println!("cargo:rustc-link-lib=static=c++");
} else {
println!("cargo:rustc-link-lib=dylib=stdc++");
println!("cargo:rustc-link-lib=tinfo");
}
}
}
fn main() {
llvm_config("--cxxflags")
println!(
"cargo:rerun-if-env-changed={}",
revive_build_utils::REVIVE_LLVM_HOST_PREFIX
);
println!(
"cargo:rerun-if-env-changed={}",
revive_build_utils::REVIVE_LLVM_TARGET_PREFIX
);
revive_build_utils::llvm_cxx_flags()
.split_whitespace()
.fold(&mut cc::Build::new(), |builder, flag| builder.flag(flag))
.flag("-Wno-unused-parameter")
+38
View File
@@ -0,0 +1,38 @@
[package]
name = "revive-llvm-builder"
description = "revive LLVM compiler framework builder"
authors = [
"Oleksandr Zarudnyi <a.zarudnyy@matterlabs.dev>",
"Anton Baliasnikov <aba@matterlabs.dev>",
"Cyrill Leutwiler <cyrill@parity.io>",
]
version.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
[[bin]]
name = "revive-llvm"
path = "src/revive_llvm/main.rs"
[lib]
doctest = false
[dependencies]
clap = { workspace = true, features = ["help", "std", "derive"] }
anyhow = { workspace = true }
serde = { workspace = true, features = [ "derive" ] }
toml = { workspace = true }
num_cpus = { workspace = true }
fs_extra = { workspace = true }
path-slash = { workspace = true }
regex = { workspace = true }
downloader = { workspace = true }
tar = { workspace = true }
flate2 = { workspace = true }
env_logger = { workspace = true }
log = { workspace = true }
[dev-dependencies]
assert_cmd = { workspace = true }
assert_fs = { workspace = true }
+132
View File
@@ -0,0 +1,132 @@
# revive LLVM builder
Parity fork of the [Matter Labs zksync LLVM builder](https://github.com/matter-labs/era-compiler-llvm-builder) helper utility for compiling [revive](https://github.com/paritytech/revive) compatible LLVM builds.
## Installation and usage
The LLVM compiler framework for revive must be built with our tool called `revive-llvm`.
This is because the revive compiler has requirements not fullfilled in upstream builds:
- Special builds for compiling the frontend into statically linked ELF binaries and also Wasm executables
- The RISC-V target (the PolkaVM target)
- The compiler-rt builtins for the PolkaVM target
- We want to leave the assertions always on
- Various other specific configurations and optimization may be applied
Obtain a compatible build for your host platform from the release section of this repository (TODO). Alternatively follow below steps to get a custom build:
<details>
<summary>1. Install the system prerequisites.</summary>
* Linux (Debian):
Install the following packages:
```shell
apt install cmake ninja-build curl git libssl-dev pkg-config clang lld
```
* Linux (Arch):
Install the following packages:
```shell
pacman -Syu which cmake ninja curl git pkg-config clang lld
```
* MacOS:
* Install the [HomeBrew](https://brew.sh) package manager.
* Install the following packages:
```shell
brew install cmake ninja coreutils
```
* Install your choice of a recent LLVM/[Clang](https://clang.llvm.org) compiler, e.g. via [Xcode](https://developer.apple.com/xcode/), [Apples Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager.
</details>
<details>
<summary>2. Install Rust.</summary>
* Follow the latest [official instructions](https://www.rust-lang.org/tools/install:
```shell
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. ${HOME}/.cargo/env
```
> Currently we are not pinned to any specific version of Rust, so just install the latest stable build for your platform.
</details>
<details>
<summary>3. Install the revive LLVM framework builder.</summary>
* Install the builder using `cargo`:
```shell
cargo install --git https://github.com/paritytech/revive-llvm-builder --force --locked
```
> The builder is not the LLVM framework itself, but a tool that clones its repository and runs a sequence of build commands. By default it is installed in `~/.cargo/bin/`, which is recommended to be added to your `$PATH`.
</details>
<details>
<summary>4. (Optional) Create the `LLVM.lock` file.</summary>
* The `LLVM.lock` dictates the LLVM source tree being used.
A default `./LLVM.lock` pointing to the release used for development is already provided.
</details>
<details>
<summary>5. Build LLVM.</summary>
* Clone and build the LLVM framework using the `revive-llvm` tool.
The clang and lld projects are required for the `resolc` Solidity frontend executable; they are enabled by default. LLVM assertions are also enabled by default.
```shell
revive-llvm clone
revive-llvm build --llvm-projects lld --llvm-projects clang
```
Build artifacts end up in the `./target-llvm/gnu/target-final/` directory by default.
The `gnu` directory depends on the supported archticture and will either be `gnu`, `musl` or `emscripten`.
You now need to export the final target directory `$LLVM_SYS_181_PREFIX`: `export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final`
If built with the `--enable-tests` option, test tools will be in the `./target-llvm/gnu/build-final/` directory, along with copies of the build artifacts. For all supported build options, run `revive-llvm build --help`.
</details>
## Supported target architectures
The following target platforms are supported:
- Linux GNU (x86)
- Linux MUSL (x86)
- MacOS (aarch64)
- Windows GNU (x86)
- Emscripten (wasm32)
<details>
<summary>Building for MUSL</summary>
* Via a musl build we can build revive into fully static ELF binaries.
Which is desirable for reproducible Solidity contracts builds.
The resulting binary is also very portable, akin to the`solc` frontend binary distribution.
Clone and build the LLVM framework using the `revive-llvm` tool:
```shell
revive-llvm --target-env musl clone
revive-llvm --target-env musl build --enable-assertions --llvm-projects clang --llvm-projects lld
```
</details>
<details>
<summary>Building for Emscripten</summary>
* Via an emsdk build we can run revive in the browser and on node.js.
Clone and build the LLVM framework using the `revive-llvm` tool:
```shell
revive-llvm --target-env emscripten clone
revive-llvm --target-env emscripten build --enable-assertions --llvm-projects clang --llvm-projects lld
```
</details>
+39
View File
@@ -0,0 +1,39 @@
//! The revive LLVM build type.
/// The revive LLVM build type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuildType {
/// The debug build.
Debug,
/// The release build.
Release,
/// The release with debug info build.
RelWithDebInfo,
/// The minimal size release build.
MinSizeRel,
}
impl std::str::FromStr for BuildType {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"Debug" => Ok(Self::Debug),
"Release" => Ok(Self::Release),
"RelWithDebInfo" => Ok(Self::RelWithDebInfo),
"MinSizeRel" => Ok(Self::MinSizeRel),
value => Err(format!("Unsupported build type: `{}`", value)),
}
}
}
impl std::fmt::Display for BuildType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Debug => write!(f, "Debug"),
Self::Release => write!(f, "Release"),
Self::RelWithDebInfo => write!(f, "RelWithDebInfo"),
Self::MinSizeRel => write!(f, "MinSizeRel"),
}
}
}
+137
View File
@@ -0,0 +1,137 @@
//! Utilities for compiling the LLVM compiler-rt builtins.
/// Static CFLAGS variable passed to the compiler building the compiler-rt builtins.
const C_FLAGS: [&str; 6] = [
"--target=riscv64",
"-march=rv64emac",
"-mabi=lp64e",
"-mcpu=generic-rv64",
"-nostdlib",
"-nodefaultlibs",
];
/// Static CMAKE arguments for building the compiler-rt builtins.
const CMAKE_STATIC_ARGS: [&str; 14] = [
"-DCOMPILER_RT_BUILD_BUILTINS='On'",
"-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_PROFILE='Off'",
"-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
"-DCOMPILER_RT_BUILD_XRAY='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
"-DCOMPILER_RT_BAREMETAL_BUILD='On'",
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
"-DCMAKE_EXPORT_COMPILE_COMMANDS='On'",
"-DCMAKE_SYSTEM_NAME='unknown'",
"-DCMAKE_C_COMPILER_TARGET='riscv64'",
"-DCMAKE_ASM_COMPILER_TARGET='riscv64'",
"-DCMAKE_CXX_COMPILER_TARGET='riscv64'",
];
/// Dynamic cmake arguments for building the compiler-rt builtins.
fn cmake_dynamic_args(
build_type: crate::BuildType,
target_env: crate::target_env::TargetEnv,
) -> anyhow::Result<[String; 13]> {
let llvm_compiler_rt_target = crate::LLVMPath::llvm_target_compiler_rt()?;
// The Emscripten target needs to use the host LLVM tools.
let llvm_target_host = if target_env == crate::target_env::TargetEnv::Emscripten {
crate::LLVMPath::llvm_build_host()?
} else {
crate::LLVMPath::llvm_target_final()?
};
let mut clang_path = llvm_target_host.to_path_buf();
clang_path.push("bin/clang");
let mut clangxx_path = llvm_target_host.to_path_buf();
clangxx_path.push("bin/clang++");
let mut llvm_config_path = llvm_target_host.to_path_buf();
llvm_config_path.push("bin/llvm-config");
let mut ar_path = llvm_target_host.to_path_buf();
ar_path.push("bin/llvm-ar");
let mut nm_path = llvm_target_host.to_path_buf();
nm_path.push("bin/llvm-nm");
let mut ranlib_path = llvm_target_host.to_path_buf();
ranlib_path.push("bin/llvm-ranlib");
let mut linker_path = llvm_target_host.to_path_buf();
linker_path.push("bin/ld.lld");
Ok([
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
llvm_compiler_rt_target.to_string_lossy().as_ref(),
),
format!("-DCMAKE_BUILD_TYPE='{build_type}'"),
format!(
"-DCOMPILER_RT_TEST_COMPILER='{}'",
clang_path.to_string_lossy()
),
format!("-DCMAKE_C_FLAGS='{}'", C_FLAGS.join(" ")),
format!("-DCMAKE_ASM_FLAGS='{}'", C_FLAGS.join(" ")),
format!("-DCMAKE_CXX_FLAGS='{}'", C_FLAGS.join(" ")),
format!("-DCMAKE_C_COMPILER='{}'", clang_path.to_string_lossy()),
format!("-DCMAKE_ASM_COMPILER='{}'", clang_path.to_string_lossy()),
format!("-DCMAKE_CXX_COMPILER='{}'", clangxx_path.to_string_lossy()),
format!("-DCMAKE_AR='{}'", ar_path.to_string_lossy()),
format!("-DCMAKE_NM='{}'", nm_path.to_string_lossy()),
format!("-DCMAKE_RANLIB='{}'", ranlib_path.to_string_lossy()),
format!(
"-DLLVM_CONFIG_PATH='{}'",
llvm_config_path.to_string_lossy()
),
])
}
/// Build the compiler-rt builtins library.
pub fn build(
build_type: crate::BuildType,
target_env: crate::target_env::TargetEnv,
default_target: Option<crate::TargetTriple>,
extra_args: &[String],
ccache_variant: Option<crate::ccache_variant::CcacheVariant>,
sanitizer: Option<crate::sanitizer::Sanitizer>,
) -> anyhow::Result<()> {
log::info!("building compiler-rt for rv64emac");
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("ninja")?;
let llvm_module_compiler_rt = crate::LLVMPath::llvm_module_compiler_rt()?;
let llvm_compiler_rt_build = crate::LLVMPath::llvm_build_compiler_rt()?;
crate::utils::command(
std::process::Command::new("cmake")
.args([
"-S",
llvm_module_compiler_rt.to_string_lossy().as_ref(),
"-B",
llvm_compiler_rt_build.to_string_lossy().as_ref(),
"-G",
"Ninja",
])
.args(CMAKE_STATIC_ARGS)
.args(cmake_dynamic_args(build_type, target_env)?)
.args(extra_args)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
))
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
))
.args(crate::platforms::shared::shared_build_opts_sanitizers(
sanitizer,
)),
"LLVM compiler-rt building cmake",
)?;
crate::utils::ninja(&llvm_compiler_rt_build)?;
Ok(())
}

Some files were not shown because too many files have changed in this diff Show More