Compare commits

..

33 Commits

Author SHA1 Message Date
PG Herveou 761fd8d6a4 Add compiler optimizer option to npm package (#310) 2025-05-08 12:38:27 +02:00
pgherveou 8b1a36eddf Run lint:fix 2025-05-08 12:20:38 +02:00
xermicus 11d47d74ac apply size optimizations by default (#298)
So far if no optimization level was specified, optimizations for
execution time were applied. However, we currently are a bit limited on
code size. Add to that, this setting is not available in solc and people
generally ignore the docs, generating a lot of support requests.

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-07 15:35:48 +02:00
xermicus e3a9c95d32 llvm-builder: use the ninja generator for building the builtins on windows (#299)
The builtins build should use the Ninja generator (MSVC does not build a
valid archive).

Tested and verified here:
https://github.com/paritytech/revive-alex-workflowtest/releases/tag/untagged-f02d0f574bab8404fead

Closes #305

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-07 11:10:58 +02:00
PG Herveou a560b2d919 Fix npm-release job (#297)
follow up from #295
2025-04-30 21:48:11 +02:00
PG Herveou e07d0f0cb7 Move @parity/resolc from js-revive (#296)
- Move npm package from paritytech/js-revive 
- Rename package to `@parity/resolc`
2025-04-30 17:24:52 +02:00
xermicus f6a412eef4 release resolc v0.1.0-dev.14 (#289)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-24 11:57:46 +02:00
xermicus 20e77cb0b5 configurable stack and heap memory size (#288)
- Allow configuration of the maximum heap and stack size via CLI flags
and JSON input settings.
- Increase the default value for the stack size to 32kb.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-24 10:47:38 +02:00
xermicus 357bf58868 allow dynamic configuration of the heap memory (#287)
This PR changes the implementation of the emulated EVM heap memory:
Instead of linking in a C implementation the code is emitted directly
into the contract module. Which allows making it configurable via a
compiler parameter (a follow up PR to this).

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-23 20:25:55 +02:00
xermicus f937188991 revive-runner: install with locked dependencies (#286)
Make the installation of  `revive-runner` easier:
- Use locked dependencies to avoid issues with downstream crates
- Make the llvm-context crate an optional dependency to the runner
- Add it to the default `test` target ensuring that this actually works

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-22 19:46:18 +02:00
xermicus 6e44488b4f revive-runner: add a utility binary for local contract execution (#284)
I had this in mind for a while but never implemented a standalone binary
so far because I always end up writing an integration test anyways.

However, using a standalone version of the pallet based on the
revive-runner crate is something people filing in bug reports do
anyways, for example:
https://github.com/paritytech/revive/issues/266
https://github.com/paritytech/contract-issues/issues/54
---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-22 15:34:51 +02:00
xermicus 5003f3e9ac llvm-context: alloca at the function entry if possible (#283)
Closes  #48

Change the code size test to no longer emit debug info as to get a more
accurate picture.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-15 15:22:24 +02:00
xermicus 431b5a2ce5 llvm-context: lazy handling of function arguments and immutable data (#282)
- Lazily load function arguments so that they can be passed as pointers.
- Lazily call the immutable store function to avoid storing zero sized
immutable data.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-14 15:54:59 +02:00
xermicus ad3315346c release resolc-0.1.0-dev.13 (#279) 2025-04-08 09:10:13 +02:00
dependabot[bot] 516f79ee0f Bump tokio from 1.43.0 to 1.44.2 (#281)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.43.0 to 1.44.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/tokio/releases">tokio's
releases</a>.</em></p>
<blockquote>
<h2>Tokio v1.44.2</h2>
<p>This release fixes a soundness issue in the broadcast channel. The
channel
accepts values that are <code>Send</code> but <code>!Sync</code>.
Previously, the channel called
<code>clone()</code> on these values without synchronizing. This release
fixes the channel
by synchronizing calls to <code>.clone()</code> (Thanks Austin Bonander
for finding and
reporting the issue).</p>
<h3>Fixed</h3>
<ul>
<li>sync: synchronize <code>clone()</code> call in broadcast channel (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7232">#7232</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tokio/issues/7232">#7232</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7232">tokio-rs/tokio#7232</a></p>
<h2>Tokio v1.44.1</h2>
<h1>1.44.1 (March 13th, 2025)</h1>
<h3>Fixed</h3>
<ul>
<li>rt: skip defer queue in <code>block_in_place</code> context (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7216">#7216</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tokio/issues/7216">#7216</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7216">tokio-rs/tokio#7216</a></p>
<h2>Tokio v1.44.0</h2>
<h1>1.44.0 (March 7th, 2025)</h1>
<p>This release changes the <code>from_std</code> method on sockets to
panic if a blocking socket is provided. We determined this change is not
a breaking change as Tokio is not intended to operate using blocking
sockets. Doing so results in runtime hangs and should be considered a
bug. Accidentally passing a blocking socket to Tokio is one of the most
common user mistakes. If this change causes an issue for you, please
comment on <a
href="https://redirect.github.com/tokio-rs/tokio/issues/7172">#7172</a>.</p>
<h3>Added</h3>
<ul>
<li>coop: add <code>task::coop</code> module (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7116">#7116</a>)</li>
<li>process: add <code>Command::get_kill_on_drop()</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7086">#7086</a>)</li>
<li>sync: add <code>broadcast::Sender::closed</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/6685">#6685</a>,
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7090">#7090</a>)</li>
<li>sync: add <code>broadcast::WeakSender</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7100">#7100</a>)</li>
<li>sync: add <code>oneshot::Receiver::is_empty()</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7153">#7153</a>)</li>
<li>sync: add <code>oneshot::Receiver::is_terminated()</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7152">#7152</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>fs: empty reads on <code>File</code> should not start a background
read (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7139">#7139</a>)</li>
<li>process: calling <code>start_kill</code> on exited child should not
fail (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7160">#7160</a>)</li>
<li>signal: fix <code>CTRL_CLOSE</code>, <code>CTRL_LOGOFF</code>,
<code>CTRL_SHUTDOWN</code> on windows (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7122">#7122</a>)</li>
<li>sync: properly handle panic during mpsc drop (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7094">#7094</a>)</li>
</ul>
<h3>Changes</h3>
<ul>
<li>runtime: clean up magic number in registration set (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7112">#7112</a>)</li>
<li>coop: make coop yield using waker defer strategy (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7185">#7185</a>)</li>
<li>macros: make <code>select!</code> budget-aware (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7164">#7164</a>)</li>
<li>net: panic when passing a blocking socket to <code>from_std</code>
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7166">#7166</a>)</li>
<li>io: clean up buffer casts (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7142">#7142</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tokio-rs/tokio/commit/ec4b1d7215a3e1e91797ad3fb6ba0f7c7f3d2566"><code>ec4b1d7</code></a>
chore: forward port 1.43.x</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/e3c3a56718d201fb7bb430567f05fbb64b2ef082"><code>e3c3a56</code></a>
Merge branch 'tokio-1.43.x' into forward-port-1.43.x</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/a7b658c35bd40f6811e557aeb97cbb361b612c56"><code>a7b658c</code></a>
chore: prepare Tokio v1.43.1 release</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/c1c8d1033d637d7027fdc137ec8008c5801cbc0d"><code>c1c8d10</code></a>
Merge remote-tracking branch 'origin/tokio-1.38.x' into
forward-port-1.38.x</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/aa303bc2051f7c21b48bb7bfcafe8fd4f39afd21"><code>aa303bc</code></a>
chore: prepare Tokio v1.38.2 release</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/7b6ccb515ff067151ed62db835f735e5653f8784"><code>7b6ccb5</code></a>
chore: backport CI fixes</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/4b174ce2c95fe1d1a217917db93fcc935e17e0da"><code>4b174ce</code></a>
sync: fix cloning value when receiving from broadcast channel</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/d413c9c02af8f2b4fea14b769b86484b12f46595"><code>d413c9c</code></a>
chore: prepare Tokio v1.44.1 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7217">#7217</a>)</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/addbfb9204be25a8621feb3f20b44a7c1f00edbd"><code>addbfb9</code></a>
rt: skip defer queue in <code>block_in_place</code> context (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7216">#7216</a>)</li>
<li><a
href="https://github.com/tokio-rs/tokio/commit/8182ecf2628d5e80dac52b8ed1ea466dbb0925b9"><code>8182ecf</code></a>
chore: prepare Tokio v1.44.0 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7202">#7202</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/tokio/compare/tokio-1.43.0...tokio-1.44.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tokio&package-manager=cargo&previous-version=1.43.0&new-version=1.44.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/paritytech/revive/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: xermicus <cyrill@parity.io>
2025-04-08 08:26:06 +02:00
Alexander Samusev 9f5443b6d6 Remove path from release json and add sha256 (#280)
PR addresses
https://github.com/paritytech/revive/issues/162#issuecomment-2783173447
2025-04-08 08:18:35 +02:00
Alexander Samusev 0dafc779ce ci: update release flow and publish list.json (#276)
This pull request adds changes described in **this comment**:

- `.github/scripts/json_generator.py` - a small script that generates
several json files for different platforms.
-
[generate_versions.yml](https://github.com/paritytech/revive/compare/as-release-json?expand=1#diff-2aee05b96020ac60943e6dfcb30597e53898f31542aeb570468b970d9a13a5a6)
- the workflow that runs when release is published, creates info.json
files and pushes them into resolc-bin repo
- `js/build.js` is adjusted in order to set `RESOLC_WASM_URI` from env
variable
- ⚠️ Release workflow is changed: 
  - In PRs and main branch it'll only build artifacts
- Release will happen automatically only on the `v*` tag push. This is
needed for revive_web.js to have the necessary `RESOLC_WASM_URI`
- workflow will check that version in Cargo.toml is the same as the tag
when the new tag is pushed

cc https://github.com/paritytech/revive/issues/162
cc https://github.com/paritytech/devops/issues/3890
2025-04-07 13:39:56 +02:00
xermicus 7d8fa75a0f storage keys and values should be big endian (#277)
Storage keys and values are big endian. Keeping them LE was a pre-mature
optimization because for the contract itself it this is a no-op and thus
not observable. However we should consider the storage layout as part of
the contract ABI. The endianness of transient storage values are still
kept as-is.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-07 10:34:44 +02:00
dependabot[bot] 80f94b5c76 Bump openssl from 0.10.71 to 0.10.72 (#278)
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.71
to 0.10.72.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/sfackler/rust-openssl/releases">openssl's
releases</a>.</em></p>
<blockquote>
<h2>openssl-v0.10.72</h2>
<h2>What's Changed</h2>
<ul>
<li>make set_rsa_oaep_md visible to boringssl config by <a
href="https://github.com/frncs-rss"><code>@​frncs-rss</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2372">sfackler/rust-openssl#2372</a></li>
<li>Fix typo in openssl-sys build script by <a
href="https://github.com/rushilmehra"><code>@​rushilmehra</code></a> in
<a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2375">sfackler/rust-openssl#2375</a></li>
<li>Unify the two BoringSSL codepaths a bit and simplify init by <a
href="https://github.com/davidben"><code>@​davidben</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2377">sfackler/rust-openssl#2377</a></li>
<li>pkey_ctx: Fix link to the corresponding OpenSSL function by <a
href="https://github.com/Jakuje"><code>@​Jakuje</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2378">sfackler/rust-openssl#2378</a></li>
<li>fix test on MSRV by <a
href="https://github.com/alex"><code>@​alex</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2383">sfackler/rust-openssl#2383</a></li>
<li>Add support for AWS-LC to openssl and openssl-sys crates by <a
href="https://github.com/skmcgrail"><code>@​skmcgrail</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/1805">sfackler/rust-openssl#1805</a></li>
<li>Enable additional capabilities for AWS-LC by <a
href="https://github.com/skmcgrail"><code>@​skmcgrail</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2386">sfackler/rust-openssl#2386</a></li>
<li>Use --experimental with bindgen-cli with aws-lc build by <a
href="https://github.com/skmcgrail"><code>@​skmcgrail</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2389">sfackler/rust-openssl#2389</a></li>
<li>Fixed two UAFs and bumped versions for release by <a
href="https://github.com/alex"><code>@​alex</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2390">sfackler/rust-openssl#2390</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Jakuje"><code>@​Jakuje</code></a> made
their first contribution in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2378">sfackler/rust-openssl#2378</a></li>
<li><a href="https://github.com/skmcgrail"><code>@​skmcgrail</code></a>
made their first contribution in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/1805">sfackler/rust-openssl#1805</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.71...openssl-v0.10.72">https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.71...openssl-v0.10.72</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/87085bd67896b7f92e6de35d081f607a334beae4"><code>87085bd</code></a>
Merge pull request <a
href="https://redirect.github.com/sfackler/rust-openssl/issues/2390">#2390</a>
from alex/uaf-fix</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/d1a12e21573e95727b2e38b8b65273cb389be7e4"><code>d1a12e2</code></a>
Fixed two UAFs and bumped versions for release</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/7c7b2e6c9f95e77e56ab37af70b16de75beff387"><code>7c7b2e6</code></a>
Merge pull request <a
href="https://redirect.github.com/sfackler/rust-openssl/issues/2389">#2389</a>
from skmcgrail/aws-lc-follow-up</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/34a477bff20cbe43492915338d3c12597430c345"><code>34a477b</code></a>
Use --experimental with bindgen-cli with aws-lc build</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/d4bf0710640e4725b8b237968040aef3e5f4ab9a"><code>d4bf071</code></a>
Merge pull request <a
href="https://redirect.github.com/sfackler/rust-openssl/issues/2386">#2386</a>
from skmcgrail/aws-lc-follow-up</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/a86bf670c4cba3ee5531838b52419356791d966e"><code>a86bf67</code></a>
Remove comment</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/705dbfb2ee3f2d7151ff313d840bf558435d4379"><code>705dbfb</code></a>
Fix test</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/e0df413d46a89303c42e15bf7d4566193b242466"><code>e0df413</code></a>
Skip final call for LibreSSL 4.1.0 for CCM mode</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/2f1164b5e838d3665dd10a9fac19e22174289ea3"><code>2f1164b</code></a>
Enable additional capabilities for AWS-LC</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/dde9ffb36071249ff98474eec853fd830aea44f5"><code>dde9ffb</code></a>
Merge pull request <a
href="https://redirect.github.com/sfackler/rust-openssl/issues/1805">#1805</a>
from skmcgrail/aws-lc-support-final</li>
<li>Additional commits viewable in <a
href="https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.71...openssl-v0.10.72">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=openssl&package-manager=cargo&previous-version=0.10.71&new-version=0.10.72)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/paritytech/revive/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-05 12:25:52 +02:00
xermicus dab29bc89b bugfix missing byte swap for the create2 salt value (#272)
Found in https://github.com/paritytech/contract-issues/issues/45, thanks
@albertov19 and @sekisamu

---------

Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-03 15:20:22 +02:00
xermicus 313c033261 fix Rust 1.86.0 clippy (#273)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-03 15:03:49 +02:00
xermicus 87c1d7a8be Suport passing arbitrary llvm arguments (#271)
- Support for passing LLVM command line options via the prcoess input or
providing one or more `--llvm-arg='..'` resolc CLI flag. This allows
more fine-grained control over the LLVM backend configuration.
- Make LLVM initialization idempotent.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-03 13:21:00 +02:00
xermicus 8a98346a9c Fix CI badge link (#270) 2025-04-01 07:52:39 +02:00
Alexander Samusev 1b4d2c6bb8 ci: modify release according to #162 (#269)
PR modifies release workflow according to changes requested in
https://github.com/paritytech/revive/issues/162#issuecomment-2751287953
2025-03-26 12:06:51 +01:00
xermicus 004b8ac16c Update release.yml (#265)
The Release workflow used to work with a fetch-depth: 0 - not sure why this is required but yolo-ing it in for a test
2025-03-20 20:07:04 +01:00
xermicus 497dae2494 factor out solc JSON interface crate (#264)
The differential testing framework will make a second consumer. There
seems to be no re-usable Rust crate for this. But we already have
everything here, just needs a small refactor to make it fully re-usable.

- Mostly decouple the solc JSON-input-output interface types from the
`solidity` frontend crate
- Expose the JSON-input-output interface types in a dedicated crate

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-03-20 17:11:40 +01:00
Pavlo Khrystenko 36ea69b50f Add --supported-solc-versions CLI command (#260)
### Description 

Adds `--supported-solc-versions` cli command to return a semver range of
supported `solc` versions.
Is a hack until #162 is implemented.

---------

Co-authored-by: xermicus <cyrill@parity.io>
2025-03-19 16:07:48 +01:00
xermicus 2bbc5d713d remove support for webkit (#262)
Signed-off-by: xermicus <cyrill@parity.io>
2025-03-18 15:00:55 +01:00
xermicus 4a9b651235 Support solc v0.8.29 (#261)
No observable changes w.r.t. YUL compilation.
- Mark solc v0.8.29 as the latest supported version
- Add integration test for solc v0.8.29 specific feature
- Use the latest version on CI
- Drive-by fix linter complaints and a two types in the CI yaml files

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
2025-03-18 13:01:15 +01:00
Alexander Theißen 66f9a4d64f Release Windows Version (#251)
With LLVM working only minor changes were necessary to get resolc
running on Windows.

Release in my branch here:
https://github.com/paritytech/revive-alex-workflowtest/releases/tag/v0.1.0-dev.12
2025-03-01 13:49:04 +01:00
xermicus 76f4cf71d6 ci: re-enable the machete (#249)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-02-28 16:05:53 +01:00
xermicus 77e0344d80 llvm-context: remove dead code (#247)
- remove the __sha3 function symbol: this is provided by the pallet
- remove the storage address spaces: they are not mapped into memory

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
2025-02-28 15:38:42 +01:00
Alexander Theißen 2fb8beee62 Build LLVM for Windows (#248)
This PR changes the CI build scripts to also build LLVM for windows.
**It doesn't build `revive` itself for windows**. This will come in a
follow up. But once we have a LLVM binary release the turn around time
will be much quicker for experimenting with the revive windows build.

I manually uploaded the release those changes produce
[here](https://github.com/paritytech/revive-alex-workflowtest/releases/tag/llvm-18.1.8-revive.22f3ceb).
This enables this PR's CI to find the proper release. This is necessary
because I am also making changes to the folder structure and artifact
naming that the other CI jobs are depending on.

Releases generated from this branch can be inspected here:
https://github.com/paritytech/revive-alex-workflowtest/releases/tag/v0.1.0-dev.12

Summary of changes:
- Change `llvm-builder` to use MSVC toolchain on windows
- Fix `llvm-builder` to work with `.exe` files
- Unify the llvm release jobs into a single one. This removed a lot of
copy pasted code and also speeds up the build by giving each their own
runner.
- Use the LLVM target triple to name the binary releases instead of an
ad-hoc naming convention
- Remove the nested folder hierarchy inside the llvm release. Its just
now a single folder `llvm-<target>` that contains the toolchain.
- Give jobs and workflows consistent names
- Replace all runners bei their `*-latest` counterpart
- Only use `parity-large` to build llvm now. All other jobs use github
runners
2025-02-28 15:06:03 +01:00
165 changed files with 10567 additions and 1840 deletions
+2 -2
View File
@@ -10,8 +10,8 @@ rustflags = [
"-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=--js-library=js/emscripten/embed/soljson_interface.js",
"-Clink-arg=--pre-js=js/emscripten/embed/pre.js",
"-Clink-arg=-sSTACK_SIZE=128kb",
"-Clink-arg=-sNODEJS_CATCH_EXIT=0"
]
+2 -3
View File
@@ -1,4 +1,4 @@
name: "get emsdk"
name: "Get Emscripten SDK"
inputs:
version:
description: ""
@@ -9,7 +9,6 @@ inputs:
runs:
using: "composite"
steps:
- name: install emsdk
shell: bash
run: |
@@ -17,4 +16,4 @@ runs:
cd emsdk
git checkout tags/${{ inputs.version }}
./emsdk install ${{ inputs.version }}
./emsdk activate ${{ inputs.version }}
./emsdk activate ${{ inputs.version }}
+10 -31
View File
@@ -1,29 +1,12 @@
# example:
#
# - name: get llvm
# uses: ./.github/actions/get-llvm
# - uses: ./.github/actions/get-llvm
# with:
# releasePrefix: llvm-
# artifactArch: macos-arm64
# dir: target-llvm/macos
# target: x86_64-unknown-linux-gnu
name: "get llvm"
name: "Download LLVM"
inputs:
artifactArch:
target:
required: true
releasePrefix:
description: "LLVM release tag prefix to search"
required: false
default: "llvm-"
dir:
description: "Archive extract path (`tar -C`)"
required: false
default: "./"
stripComponents:
description: "Strip UMBER leading components from file names on extraction (`tar --strip-components`)"
required: false
default: 0
runs:
using: "composite"
@@ -32,16 +15,15 @@ runs:
id: find
uses: actions/github-script@v7
env:
releasePrefix: ${{ inputs.releasePrefix }}
artifactArch: ${{ inputs.artifactArch }}
target: ${{ inputs.target }}
with:
result-encoding: string
script: |
let page = 1;
let releases = [];
let releasePrefix = process.env.releasePrefix
let artifactArch = process.env.artifactArch
let releasePrefix = "llvm-"
let target = process.env.target
do {
const res = await github.rest.repos.listReleases({
@@ -61,10 +43,10 @@ runs:
});
if (llvmLatestRelease){
let asset = llvmLatestRelease.assets.find(asset =>{
return asset.name.includes(artifactArch);
return asset.name.includes(target);
});
if (!asset){
core.setFailed(`Artifact for '${artifactArch}' not found in release ${llvmLatestRelease.tag_name} (${llvmLatestRelease.html_url})`);
core.setFailed(`Artifact for '${target}' not found in release ${llvmLatestRelease.tag_name} (${llvmLatestRelease.html_url})`);
process.exit();
}
return asset.browser_download_url;
@@ -79,13 +61,10 @@ runs:
- name: download
shell: bash
run: |
mkdir -p ${{ inputs.dir }}
curl -sSLo llvm.tar.gz ${{ steps.find.outputs.result }}
ls -al
- name: unpack
shell: bash
run: |
tar -xf llvm.tar.gz -C ${{ inputs.dir }} --strip-components=${{ inputs.stripComponents }}
tar -xf llvm.tar.gz
rm llvm.tar.gz
ls -al ${{ inputs.dir }}
+36
View File
@@ -0,0 +1,36 @@
name: "Install Solidity Compiler"
description: "Installs the Ethereum solc Solidity compiler frontend executable"
runs:
using: "composite"
steps:
- name: Figure out Solc Download URL
shell: bash
run: |
if [[ "${{ runner.os }}" == "Linux" ]]; then
echo "SOLC_NAME=solc-static-linux" >> $GITHUB_ENV
elif [[ "${{ runner.os }}" == "Windows" ]]; then
echo "SOLC_NAME=solc-windows.exe" >> $GITHUB_ENV
else
echo "SOLC_NAME=solc-macos" >> $GITHUB_ENV
fi
- name: Download Solc
shell: bash
run: |
mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.29/${SOLC_NAME}
- name: Make Solc Executable
if: ${{ runner.os == 'Windows' }}
shell: bash
run: |
echo "$(pwd -W)\\solc" >> $GITHUB_PATH
mv solc/solc solc/solc.exe
- name: Make Solc Executable
if: ${{ runner.os != 'Windows' }}
shell: bash
run: |
echo "$(pwd)/solc" >> $GITHUB_PATH
chmod +x solc/solc
+165
View File
@@ -0,0 +1,165 @@
import os
import sys
import json
import requests
def validate_github_token():
"""Validate that GITHUB_TOKEN environment variable is set."""
if 'GITHUB_TOKEN' not in os.environ:
print("Error: GITHUB_TOKEN environment variable is not set.")
sys.exit(1)
def fetch_release_data(repo, tag):
"""Fetch release data from GitHub API."""
url = f"https://api.github.com/repos/{repo}/releases/tags/{tag}"
headers = {
'Authorization': f"Bearer {os.environ['GITHUB_TOKEN']}",
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28'
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Error fetching release data: {e}")
sys.exit(1)
def fetch_checksum_file(release_data):
"""
Fetch the checksum.txt file from the release assets
and parse it into a dictionary mapping file names to their SHA256 checksums.
"""
checksums = {}
# Find the checksum.txt asset URL
checksum_asset = None
for asset in release_data['assets']:
if asset['name'] == 'checksums.txt':
checksum_asset = asset
break
if not checksum_asset:
print("Warning: checksum.txt file not found in release assets.")
return checksums
# Download the checksum file
headers = {
'Authorization': f"Bearer {os.environ['GITHUB_TOKEN']}",
'Accept': 'application/octet-stream'
}
try:
response = requests.get(checksum_asset['browser_download_url'], headers=headers)
response.raise_for_status()
# Parse checksum file
for line in response.text.splitlines():
if line.strip():
checksum, filename = line.strip().split(None, 1)
checksums[filename] = checksum
return checksums
except requests.RequestException as e:
print(f"Error fetching checksum file: {e}")
return checksums
except Exception as e:
print(f"Error parsing checksum file: {e}")
return checksums
def extract_build_hash(target_commitish):
"""Extract the first 8 characters of the commit hash."""
return f"commit.{target_commitish[:8]}"
def generate_asset_json(release_data, asset, checksums):
"""Generate JSON for a specific asset."""
version = release_data['tag_name'].lstrip('v')
build = extract_build_hash(release_data['target_commitish'])
long_version = f"{version}+{build}"
# Get SHA256 checksum if available
sha256 = checksums.get(asset['name'], "")
return {
"name": asset['name'],
"version": version,
"build": build,
"longVersion": long_version,
"url": asset['browser_download_url'],
"sha256": sha256,
"firstSolcVersion": os.environ.get("FIRST_SOLC_VERSION", ""),
"lastSolcVersion": os.environ.get("LAST_SOLC_VERSION", "")
}
def save_platform_json(platform_folder, asset_json, tag):
"""Save asset JSON and update list.json for a specific platform."""
# Create platform folder if it doesn't exist
os.makedirs(platform_folder, exist_ok=True)
# Update or create list.json
list_file_path = os.path.join(platform_folder, "list.json")
if os.path.exists(list_file_path):
with open(list_file_path, 'r') as f:
try:
list_data = json.load(f)
except json.JSONDecodeError:
list_data = {"builds": [], "releases": {}, "latestRelease": ""}
else:
list_data = {"builds": [], "releases": {}, "latestRelease": ""}
# Remove any existing entry with the same path
list_data['builds'] = [
build for build in list_data['builds']
if build['version'] != asset_json['version']
]
# Add the new build
list_data['builds'].append(asset_json)
# Update releases
version = asset_json['version']
list_data['releases'][version] = f"{asset_json['name']}+{asset_json['longVersion']}"
# Update latest release
list_data['latestRelease'] = version
with open(list_file_path, 'w') as f:
json.dump(list_data, f, indent=4)
def main():
# Validate arguments
if len(sys.argv) != 3:
print("Usage: python script.py <repo> <tag>")
sys.exit(1)
repo, tag = sys.argv[1], sys.argv[2]
# Validate GitHub token
validate_github_token()
# Fetch release data
release_data = fetch_release_data(repo, tag)
# Fetch checksums
checksums = fetch_checksum_file(release_data)
# Mapping of asset names to platform folders
platform_mapping = {
'resolc-x86_64-unknown-linux-musl': 'linux',
'resolc-universal-apple-darwin': 'macos',
'resolc-x86_64-pc-windows-msvc.exe': 'windows',
'resolc_web.js': 'wasm'
}
# Process each asset
for asset in release_data['assets']:
platform_name = platform_mapping.get(asset['name'])
if platform_name:
platform_folder = os.path.join(platform_name)
asset_json = generate_asset_json(release_data, asset, checksums)
save_platform_json(platform_folder, asset_json, tag)
print(f"Processed {asset['name']} for {platform_name}")
if __name__ == "__main__":
main()
+64
View File
@@ -0,0 +1,64 @@
name: Generate JSON for resolc-bin
on:
release:
types: [published]
jobs:
generateJson:
runs-on: ubuntu-latest
if: contains(github.event.release.tag_name, 'llvm') == false
environment: tags
env:
# the token is needed for json_generator.py
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
path: tmp
- name: Checkout
uses: actions/checkout@v4
with:
repository: paritytech/resolc-bin
path: resolc-bin
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.REVIVE_JSON_APP_ID }}
private-key: ${{ secrets.REVIVE_JSON_APP_KEY }}
owner: paritytech
repositories: resolc-bin
- name: Generate json and push
env:
TOKEN: ${{ steps.app-token.outputs.token }}
APP_NAME: "paritytech-revive-json"
Green: "\e[32m"
NC: "\e[0m"
run: |
sudo apt-get update && sudo apt-get install -y wget
wget https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/resolc-x86_64-unknown-linux-musl
chmod +x resolc-x86_64-unknown-linux-musl
export FIRST_SOLC_VERSION=$(./resolc-x86_64-unknown-linux-musl --supported-solc-versions | cut -f 1 -d "," | tr -d ">=")
export LAST_SOLC_VERSION=$(./resolc-x86_64-unknown-linux-musl --supported-solc-versions | cut -f 2 -d "," | tr -d "<=")
cd resolc-bin
python ../tmp/.github/scripts/json_generator.py ${GITHUB_REPOSITORY} ${{ github.event.release.tag_name }}
echo "${Green}Add new remote with gh app token${NC}"
git remote set-url origin $(git config remote.origin.url | sed "s/github.com/${APP_NAME}:${TOKEN}@github.com/g")
echo "${Green}Remove http section that causes issues with gh app auth token${NC}"
sed -i.bak '/\[http/d' ./.git/config
sed -i.bak '/extraheader/d' ./.git/config
git config user.email "ci@parity.io"
git config user.name "${APP_NAME}"
git add .
git commit -m "Update json"
git push origin main
echo "::notice::info.list files were successfully published to https://github.com/paritytech/resolc-bin"
+76 -110
View File
@@ -1,5 +1,4 @@
name: Release LLVM
on:
workflow_dispatch:
inputs:
@@ -9,15 +8,15 @@ on:
description: llvm version in "x.x.x" format, e.g. "18.1.8"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
create-release:
runs-on: ubuntu-latest
create-release-draft:
runs-on: ubuntu-24.04
permissions:
contents: write
outputs:
@@ -27,145 +26,112 @@ jobs:
run: |
echo "version=llvm-${{ inputs.llvm_version }}-revive.${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
- name: create release
- 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"
name: ${{ steps.resolve-version.outputs.version }}
body: "LLVM is a dependency of revive. The LLVM releases are used by our CI to build revive."
draft: true
tag_name: ${{ steps.resolve-version.outputs.version }}
build-macos:
build:
strategy:
matrix:
os: [macos-14, macos-13]
target: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl, wasm32-unknown-emscripten, aarch64-apple-darwin, x86_64-apple-darwin, x86_64-pc-windows-msvc]
include:
- os: macos-13
arch: x64
- os: macos-14
arch: arm64
needs: create-release
runs-on: ${{ matrix.os }}
name: "build-macos-${{ matrix.arch }}"
- target: x86_64-unknown-linux-gnu
builder-arg: gnu
host: linux
runner: parity-large
- target: x86_64-unknown-linux-musl
builder-arg: musl
host: linux
runner: parity-large
- target: wasm32-unknown-emscripten
builder-arg: emscripten
host: linux
runner: parity-large
- target: aarch64-apple-darwin
builder-arg: gnu
host: macos
runner: macos-14
- target: x86_64-apple-darwin
builder-arg: gnu
host: macos
runner: macos-13
- target: x86_64-pc-windows-msvc
builder-arg: gnu
host: windows
runner: windows-2022
needs: create-release-draft
runs-on: ${{ matrix.runner }}
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
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
make_latest: "false"
tag_name: ${{ needs.create-release.outputs.version }}
files: |
${{ needs.create-release.outputs.version }}-macos-${{ matrix.arch }}.tar.gz
# without this it will override our rust flags
rustflags: ""
cache-key: ${{ matrix.target }}
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
- name: Install Dependencies
if: ${{ matrix.host == 'linux' }}
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
- name: Install Dependencies
if: ${{ matrix.host == 'macos' }}
run: |
rustup show
cargo --version
cmake --version
echo "bash:" && bash --version
echo "ninja:" && ninja --version
echo "clang:" && clang --version
brew install ninja
- name: Build host LLVM
- name: Install Dependencies
if: ${{ matrix.host == 'windows' }}
run: |
make install-llvm
choco install ninja
- name: Build gnu LLVM
- name: Install LLVM Builder
run: |
revive-llvm clone
revive-llvm build --llvm-projects lld --llvm-projects clang
cargo install --path crates/llvm-builder
- name: Build musl LLVM
- name: Clone LLVM
run: |
revive-llvm --target-env musl build --llvm-projects lld --llvm-projects clang
revive-llvm --target-env ${{ matrix.builder-arg }} clone
- name: Build emscripten LLVM
- name: Build LLVM
if: ${{ matrix.target != 'wasm32-unknown-emscripten' }}
run: |
revive-llvm --target-env ${{ matrix.builder-arg }} build --llvm-projects lld --llvm-projects clang
- name: Build LLVM
if: ${{ matrix.target == 'wasm32-unknown-emscripten' }}
run: |
revive-llvm --target-env emscripten clone
source emsdk/emsdk_env.sh
revive-llvm --target-env emscripten build --llvm-projects lld
revive-llvm --target-env ${{ matrix.builder-arg }} build --llvm-projects lld
- name: clean
# check removed files
- name: Remove Unnecessary Binaries
shell: bash
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
cd target-llvm/${{ matrix.builder-arg }}/target-final/bin/
rm -f 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* \
clang-repl* clang-check* clang-scan-deps*
cd -
- name: package artifacts
- name: Package Artifact
shell: bash
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
mv target-llvm/${{ matrix.builder-arg }}/target-final/ llvm-${{ matrix.target }}
tar -czf "${{ needs.create-release-draft.outputs.version }}-${{ matrix.target }}.tar.gz" llvm-${{ matrix.target }}
- name: upload archive to release
- name: Add Artifact to Release
uses: softprops/action-gh-release@v2
with:
make_latest: "false"
tag_name: ${{ needs.create-release.outputs.version }}
tag_name: ${{ needs.create-release-draft.outputs.version }}
draft: true
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
${{ needs.create-release-draft.outputs.version }}-${{ matrix.target }}.tar.gz
+207 -212
View File
@@ -1,59 +1,61 @@
name: Release
run-name: Release ${{ github.ref_name }}
name: Build & Release
on:
push:
branches:
- "main"
branches: ["main"]
tags:
- "v*"
pull_request:
types: [opened, synchronize, reopened, ready_for_review, labeled]
branches: ["main"]
types: [opened, synchronize, labeled, unlabeled]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
#rust-musl-cross:x86_64-musl
CARGO_TERM_COLOR: always
RUST_MUSL_CROSS_IMAGE: messense/rust-musl-cross@sha256:68b86bc7cb2867259e6b233415a665ff4469c28b57763e78c3bfea1c68091561
RUST_LOG: trace
jobs:
tag:
if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'release-test')
check-version-changed:
runs-on: ubuntu-24.04
permissions:
contents: write
env:
CURRENT_TAG: ${{ github.ref_name }}
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
- uses: actions/checkout@v4
- name: Versions
# Check that tag and version in Cargo.toml match
- name: Check versions
id: versions
run: |
export CURRENT_TAG=$(git describe --tags --abbrev=0 --exclude "llvm-*")
if [[ $CURRENT_TAG == 'main' ]];
then
echo "::notice::Tag $CURRENT_TAG is not a release tag, skipping the check in the main branch";
exit 0
fi
if [[ $CURRENT_TAG != "v"* ]];
then
echo "::notice::Tag $CURRENT_TAG is not a release tag, skipping the check in a PR";
exit 0
fi
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 ]];
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;
echo "::error::Tag $CURRENT_TAG doesn't match package version $PKG_VER in Cargo.toml, please fix";
exit 1
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')"
export RELEASE_NOTES="$(sed '/^## '${CURRENT_TAG}'/,/^## v/!d' CHANGELOG.md | sed -e '1d' -e '$d')"
echo "Release notes:"
echo "$RELEASE_NOTES"
@@ -62,191 +64,124 @@ jobs:
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
build-macos:
build:
strategy:
matrix:
os: [macos-14, macos-13]
target:
[
x86_64-unknown-linux-musl,
aarch64-apple-darwin,
x86_64-apple-darwin,
x86_64-pc-windows-msvc,
]
include:
- os: macos-13
arch: x64
- os: macos-14
arch: arm64
if: ${{ needs.tag.outputs.TAG == 'new' }}
runs-on: ${{ matrix.os }}
name: build-macos
needs: [tag]
- target: x86_64-unknown-linux-musl
type: musl
runner: ubuntu-24.04
- target: aarch64-apple-darwin
type: native
runner: macos-14
- target: x86_64-apple-darwin
type: native
runner: macos-13
- target: x86_64-pc-windows-msvc
type: native
runner: windows-2022
runs-on: ${{ matrix.runner }}
needs: [check-version-changed]
steps:
- uses: actions/checkout@v4
- name: get llvm
uses: ./.github/actions/get-llvm
with:
releasePrefix: llvm-
artifactArch: macos-${{ matrix.arch }}
dir: ./
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
components: rust-src
target: wasm32-unknown-emscripten
# without this it will override our rust flags
rustflags: ""
cache-key: ${{ matrix.target }}
- name: install macos deps
run: |
brew install ninja
- name: Download LLVM
uses: ./.github/actions/get-llvm
with:
target: ${{ matrix.target }}
- name: versions
- name: Build
if: ${{ matrix.type == 'native' }}
shell: bash
run: |
rustup show
cargo --version
cmake --version
echo "bash:" && bash --version
echo "ninja:" && ninja --version
echo "clang:" && clang --version
- name: build revive
run: |
export LLVM_SYS_181_PREFIX=$PWD/target-llvm/gnu/target-final
export LLVM_SYS_181_PREFIX=$PWD/llvm-${{ matrix.target }}
make install-bin
cp ./target/release/resolc ./target/release/resolc-${{ matrix.arch }}
mv target/release/resolc resolc-${{ matrix.target }} || mv target/release/resolc.exe resolc-${{ matrix.target }}.exe
- name: check revive
- name: Build
if: ${{ matrix.type == 'musl' }}
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
chmod +x resolc-macos
- name: compress macos artifact
run: |
tar -czf resolc-macos.tar.gz ./resolc-macos
- uses: actions/upload-artifact@v4
with:
name: resolc-macos.tar.gz
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: 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: get llvm musl
uses: ./.github/actions/get-llvm
with:
releasePrefix: llvm-
artifactArch: x86_64-linux-musl
dir: ./
# 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
chown -R root:root .
apt update && apt upgrade -y && apt install -y pkg-config
export LLVM_SYS_181_PREFIX=/opt/revive/target-llvm/musl/target-final
export LLVM_SYS_181_PREFIX=/opt/revive/llvm-${{ matrix.target }}
make install-bin
cp /root/.cargo/bin/resolc /opt/revive/resolc-out/resolc-static-linux
mv target/${{ matrix.target }}/release/resolc resolc-${{ matrix.target }}
"
sudo chown -R $(id -u):$(id -g) .
- name: check musl
- name: Install Solc
uses: ./.github/actions/get-solc
- name: Basic Sanity Check
shell: bash
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)
result=$(./resolc-${{ matrix.target }} --bin crates/integration/contracts/flipper.sol)
echo $result
if [[ $result == *'0x50564d'* ]]; then exit 0; else exit 1; fi
- name: compress musl artifact
run: |
tar -czf $(pwd)/resolc-static-linux.tar.gz -C ./resolc-out resolc-static-linux
- uses: actions/upload-artifact@v4
with:
name: resolc-static-linux.tar.gz
path: |
resolc-static-linux.tar.gz
name: resolc-${{ matrix.target }}
path: resolc-${{ matrix.target }}*
retention-days: 1
build-wasm:
runs-on: ubuntu-24.04
needs: [check-version-changed]
env:
RELEASE_RESOLC_WASM_URI: https://github.com/paritytech/revive-workflow-test/releases/download/${{ github.ref_name }}/resolc.wasm
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
target: wasm32-unknown-emscripten
# without this it will override our rust flags
rustflags: ""
- name: Download Host LLVM
uses: ./.github/actions/get-llvm
with:
target: x86_64-unknown-linux-gnu
- name: Download Wasm LLVM
uses: ./.github/actions/get-llvm
with:
target: wasm32-unknown-emscripten
- name: Download EMSDK
uses: ./.github/actions/get-emsdk
- name: Build
run: |
export LLVM_SYS_181_PREFIX=$PWD/llvm-x86_64-unknown-linux-gnu
export REVIVE_LLVM_TARGET_PREFIX=$PWD/llvm-wasm32-unknown-emscripten
source emsdk/emsdk_env.sh
make install-wasm
chmod -x ./target/wasm32-unknown-emscripten/release/resolc.wasm
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- name: get llvm emscripten
uses: ./.github/actions/get-llvm
with:
artifactArch: emscripten
- name: install emsdk
uses: ./.github/actions/get-emsdk
- name: build wasm
- name: Basic Sanity Check
run: |
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
chmod -x ./target/wasm32-unknown-emscripten/release/resolc.wasm
- name: check wasm
run: |
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.28/soljson.js
mkdir -p solc
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.29/soljson.js
node -e "
const soljson = require('solc/soljson');
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
@@ -281,59 +216,119 @@ jobs:
if(!bytecode.startsWith('50564d')) { process.exit(1); }
"
- name: compress wasm artifact
- name: Compress Artifact
run: |
tar -czf $(pwd)/resolc-wasm.tar.gz -C ./target/wasm32-unknown-emscripten/release/ \
resolc.js \
resolc.wasm \
resolc_web.js
mkdir -p resolc-wasm32-unknown-emscripten
mv ./target/wasm32-unknown-emscripten/release/resolc.js ./resolc-wasm32-unknown-emscripten/
mv ./target/wasm32-unknown-emscripten/release/resolc.wasm ./resolc-wasm32-unknown-emscripten/
mv ./target/wasm32-unknown-emscripten/release/resolc_web.js ./resolc-wasm32-unknown-emscripten/
- uses: actions/upload-artifact@v4
with:
name: resolc-wasm.tar.gz
path: |
resolc-wasm.tar.gz
name: resolc-wasm32-unknown-emscripten
path: resolc-wasm32-unknown-emscripten/*
retention-days: 1
create-release:
if: github.event_name != 'pull_request'
needs: [tag, build-linux-all, macos-universal-binary]
runs-on: ubuntu-24.04
permissions:
contents: write
if: startsWith(github.ref_name, 'v')
needs: [check-version-changed, build-wasm]
runs-on: macos-14
environment: tags
steps:
- name: Download revive-wasm
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
name: resolc-wasm.tar.gz
path: resolc-wasm/
merge-multiple: true
- name: Download revive-linux
uses: actions/download-artifact@v4
with:
name: resolc-static-linux.tar.gz
path: resolc-linux/
- name: Create macOS Fat Binary
run: |
lipo resolc-aarch64-apple-darwin resolc-x86_64-apple-darwin -create -output resolc-universal-apple-darwin
- name: Download revive-macos
uses: actions/download-artifact@v4
- name: Make Executable
run: |
chmod +x resolc-x86_64-unknown-linux-musl
chmod +x resolc-universal-apple-darwin
- name: Create sha-256 checksum
run: |
shasum -a 256 resolc-x86_64-unknown-linux-musl > checksums.txt
shasum -a 256 resolc-universal-apple-darwin >> checksums.txt
shasum -a 256 resolc-x86_64-pc-windows-msvc.exe >> checksums.txt
shasum -a 256 resolc.js >> checksums.txt
shasum -a 256 resolc.wasm >> checksums.txt
shasum -a 256 resolc_web.js >> checksums.txt
- uses: actions/create-github-app-token@v1
id: app-token
with:
name: resolc-macos.tar.gz
path: resolc-macos/
app-id: ${{ secrets.REVIVE_RELEASE_APP_ID }}
private-key: ${{ secrets.REVIVE_RELEASE_APP_KEY }}
- name: create-release
uses: softprops/action-gh-release@v2
with:
body: |
${{ needs.tag.outputs.RELEASE_NOTES }}
## Changelog
${{ needs.check-version-changed.outputs.RELEASE_NOTES }}
# Note for macOS Users
The macOS binary is unsigned and it needs to be made runnable using `xattr -c resolc-macos`.
tag_name: ${{ needs.tag.outputs.PKG_VER }}
name: ${{ needs.tag.outputs.PKG_VER }}
draft: true
## Note for macOS Users
The macOS binary is unsigned and it needs to be made runnable using `xattr -c resolc-universal-apple-darwin`.
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
prerelease: true
token: ${{ steps.app-token.outputs.token }}
target_commitish: ${{ github.sha }}
files: |
./resolc-linux/resolc-static-linux.tar.gz
./resolc-macos/resolc-macos.tar.gz
./resolc-wasm/resolc-wasm.tar.gz
resolc-x86_64-unknown-linux-musl
resolc-universal-apple-darwin
resolc-x86_64-pc-windows-msvc.exe
resolc.js
resolc.wasm
resolc_web.js
checksums.txt
npm-release:
needs: [create-release]
runs-on: macos-14
environment: tags
steps:
- uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- run: npm ci -w js/resolc
- name: Build
run: |
cp -f resolc.{wasm,js} js/resolc/src/resolc
npm -w js/resolc run build
- name: Set version
run: |
VERSION="${{ github.event.release.tag_name }}"
STRIPPED_VERSION="${VERSION#v}"
npm -w js/resolc version --no-git-tag-version "$STRIPPED_VERSION"
- name: npm pack
run: npm -w js/resolc pack
- uses: actions/upload-artifact@v4
with:
name: npm_package
path: "parity-resolc-*.tgz"
- uses: octokit/request-action@bbedc70b1981e610d89f1f8de88311a1fc02fb83
with:
route: POST /repos/paritytech/npm_publish_automation/actions/workflows/publish.yml/dispatches
ref: main
inputs: '${{ format(''{{ "artifact_name": "npm_package", "repo": "{0}", "run_id": "{1}" }}'', github.repository, github.run_id) }}'
env:
GITHUB_TOKEN: ${{ secrets.NPM_PUBLISH_AUTOMATION_TOKEN }}
-64
View File
@@ -1,64 +0,0 @@
name: Build
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
build-ubuntu-x86:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install solc
run: |
mkdir -p solc
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/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 geth
run: |
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt update
sudo apt install -y ethereum
# Disabled for now (always install the latest version despite setting it):
# https://github.com/bnjbvr/cargo-machete/issues/156
#- name: Machete
# uses: bnjbvr/cargo-machete@v0.7.0
- name: Format
run: make format
- name: Clippy
run: make clippy
- name: Test cargo workspace
run: make test-workspace
- name: Test CLI
run: make test-cli
- uses: actions/upload-artifact@v4
with:
name: ${{ github.job }}-resolc
path: ./target/release/resolc
retention-days: 1
@@ -1,43 +1,45 @@
name: Test LLVM Builder
on:
pull_request:
types: [assigned, opened, synchronize, reopened]
branches: ["main"]
types: [opened, synchronize]
paths:
- 'LLVM.lock'
- 'crates/llvm-builder/**'
- '.github/workflows/revive-llvm-test.yml'
- '.github/workflows/test-llvm-builder.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
test:
strategy:
matrix:
runner: [parity-large, macos-14, macos-13]
runner: [parity-large, macos-14, windows-2022]
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
# without this it will override our rust flags
rustflags: ""
cache-key: ${{ matrix.runner }}
- name: Install apt dependencies
- name: Install Dependencies
if: matrix.runner == 'parity-large'
run: |
sudo apt update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl
- name: Install macos dependencies
if: matrix.runner == 'macos-14' || matrix.runner == 'macos-13'
- name: Install Dependencies
if: matrix.runner == 'macos-14'
run: |
brew install ninja
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
components: rust-src
rustflags: ""
- run: |
rustup show
cargo --version
cmake --version
bash --version
- name: Test llvm-builder
- name: Test
run: make test-llvm-builder
env:
RUST_LOG: trace
@@ -1,10 +1,10 @@
name: Build revive-wasm
name: Test Wasm Version
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
workflow_dispatch:
types: [opened, synchronize]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -15,48 +15,38 @@ env:
REVIVE_WASM_INSTALL_DIR: ${{ github.workspace }}/target/wasm32-unknown-emscripten/release
jobs:
build-revive-wasm:
build:
runs-on: ubuntu-24.04
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- name: Install Rust stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
components: rust-src
target: wasm32-unknown-emscripten
# without this it will override our rust flags
rustflags: ""
- name: get llvm gnu
- name: Download Host LLVM
uses: ./.github/actions/get-llvm
with:
artifactArch: x86_64-linux-gnu
- name: get llvm emscripten
uses: ./.github/actions/get-llvm
with:
artifactArch: emscripten
target: x86_64-unknown-linux-gnu
- name: install emsdk
- name: Download Wasm LLVM
uses: ./.github/actions/get-llvm
with:
target: wasm32-unknown-emscripten
- name: Install emsdk
uses: ./.github/actions/get-emsdk
- name: Setup revive environment variables
- name: Set LLVM 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
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
echo "REVIVE_LLVM_TARGET_PREFIX=$(pwd)/llvm-wasm32-unknown-emscripten" >> $GITHUB_ENV
- run: |
rustup show
cargo --version
rustup +nightly show
cargo +nightly --version
cmake --version
bash --version
- name: Build revive
- name: Build Revive
run: |
source emsdk/emsdk_env.sh
make install-wasm
@@ -70,8 +60,8 @@ jobs:
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc_web.js
retention-days: 1
test-revive-wasm:
needs: build-revive-wasm
test:
needs: build
strategy:
matrix:
os: ["ubuntu-24.04", "macos-14", "windows-2022"]
@@ -93,16 +83,21 @@ jobs:
with:
node-version: "20"
- name: Install packages
- name: Install Node Packages
run: npm install
- name: Run Playwright tests
run: |
cd js
npx playwright install --with-deps
npx playwright test
- name: Test revive
- name: Test emscripten
run: |
echo "Running tests for ${{ matrix.os }}"
npm run test:wasm
- name: Test @parity/resolc
run: |
echo "Running tests for ${{ matrix.os }}"
npm run -w js/resolc test
- name: Run Playwright tests
run: |
cd js/emscripten
npx playwright install --with-deps
npx playwright test
+57
View File
@@ -0,0 +1,57 @@
name: Test
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
types: [opened, synchronize]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
# without this it will override our rust flags
rustflags: ""
- name: Install Solc
uses: ./.github/actions/get-solc
- name: Download LLVM
uses: ./.github/actions/get-llvm
with:
target: x86_64-unknown-linux-gnu
- name: Set LLVM Environment Variables
run: |
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
- 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@v0.7.1
- name: Format
run: make format
- name: Clippy
run: make clippy
- name: Test cargo workspace
run: make test-workspace
- name: Test CLI
run: make test-cli
+1 -1
View File
@@ -1,4 +1,5 @@
/target
/js/resolc/dist
target-llvm
*.dot
.vscode/
@@ -11,7 +12,6 @@ target-llvm
node_modules
artifacts
tmp
package-lock.json
/*.html
/build
soljson.js
+6
View File
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
+48
View File
@@ -6,6 +6,54 @@ This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
## v0.1.0
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
### Changed
- By default, heavy size optimizations are applied.
### Fixed
## v0.1.0-dev.14
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
- The `revive-runner` helper utility binary which helps to run contracts locally without a blockchain node.
- Allow configuration of the EVM heap memory size and stack size via CLI flags and JSON input settings.
### Changed
- The default PVM stack memory size was increased from 16kb to 32kb.
### Fixed
- Constructors avoid storing zero sized immutable data on exit.
## v0.1.0-dev.13
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
- Support for solc v0.8.29
- Decouples the solc JSON-input-output type definitions from the Solidity fronted and expose them via a dedicated crate.
- `--supported-solc-versions` for `resolc` binary to return a `semver` range of supported `solc` versions.
- Support for passing LLVM command line options via the prcoess input or providing one or more `--llvm-arg='..'` resolc CLI flag. This allows more fine-grained control over the LLVM backend configuration.
### Changed
- Storage keys and values are big endian. This was a pre-mature optimization because for the contract itself it this is a no-op and thus not observable. However we should consider the storage layout as part of the contract ABI. The endianness of transient storage values are still kept as-is.
- Running `resolc` using webkit is no longer supported.
### Fixed
- A missing byte swap for the create2 salt value.
## v0.1.0-dev.12
This is a development pre-release.
Generated
+39 -20
View File
@@ -4553,7 +4553,7 @@ checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
[[package]]
name = "lld-sys"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"cc",
"libc",
@@ -4965,9 +4965,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl"
version = "0.10.71"
version = "0.10.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
dependencies = [
"bitflags 2.8.0",
"cfg-if",
@@ -4997,9 +4997,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
version = "0.9.106"
version = "0.9.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
dependencies = [
"cc",
"libc",
@@ -8266,7 +8266,7 @@ dependencies = [
[[package]]
name = "revive-benchmarks"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"alloy-primitives",
"criterion",
@@ -8278,18 +8278,18 @@ dependencies = [
[[package]]
name = "revive-build-utils"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
[[package]]
name = "revive-builtins"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"revive-build-utils",
]
[[package]]
name = "revive-common"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"anyhow",
"serde",
@@ -8299,7 +8299,7 @@ dependencies = [
[[package]]
name = "revive-differential"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"alloy-genesis",
"alloy-primitives",
@@ -8312,7 +8312,7 @@ dependencies = [
[[package]]
name = "revive-integration"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"alloy-primitives",
"alloy-sol-types",
@@ -8328,7 +8328,7 @@ dependencies = [
[[package]]
name = "revive-linker"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"anyhow",
"libc",
@@ -8340,7 +8340,7 @@ dependencies = [
[[package]]
name = "revive-llvm-builder"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"anyhow",
"assert_cmd",
@@ -8357,22 +8357,25 @@ dependencies = [
"serde",
"tar",
"toml 0.8.20",
"which",
]
[[package]]
name = "revive-llvm-context"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"anyhow",
"hex",
"inkwell",
"itertools 0.14.0",
"libc",
"num",
"polkavm-common 0.21.0",
"polkavm-disassembler",
"revive-common",
"revive-linker",
"revive-runtime-api",
"revive-solc-json-interface",
"revive-stdlib",
"semver 1.0.25",
"serde",
@@ -8381,9 +8384,12 @@ dependencies = [
[[package]]
name = "revive-runner"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"alloy-primitives",
"anyhow",
"clap",
"env_logger 0.11.6",
"hex",
"parity-scale-codec",
"polkadot-sdk 0.1.0",
@@ -8397,7 +8403,7 @@ dependencies = [
[[package]]
name = "revive-runtime-api"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"anyhow",
"inkwell",
@@ -8405,9 +8411,21 @@ dependencies = [
"revive-common",
]
[[package]]
name = "revive-solc-json-interface"
version = "0.1.0-dev.14"
dependencies = [
"anyhow",
"rayon",
"revive-common",
"semver 1.0.25",
"serde",
"serde_json",
]
[[package]]
name = "revive-solidity"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"anyhow",
"clap",
@@ -8423,6 +8441,7 @@ dependencies = [
"regex",
"revive-common",
"revive-llvm-context",
"revive-solc-json-interface",
"semver 1.0.25",
"serde",
"serde_json",
@@ -8433,7 +8452,7 @@ dependencies = [
[[package]]
name = "revive-stdlib"
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
dependencies = [
"inkwell",
"revive-build-utils",
@@ -11101,9 +11120,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.43.0"
version = "1.44.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
dependencies = [
"backtrace",
"bytes",
+15 -14
View File
@@ -3,7 +3,7 @@ resolver = "2"
members = ["crates/*"]
[workspace.package]
version = "0.1.0-dev.12"
version = "0.1.0-dev.14"
authors = [
"Cyrill Leutwiler <cyrill@parity.io>",
"Parity Technologies <admin@parity.io>",
@@ -14,19 +14,20 @@ repository = "https://github.com/paritytech/revive"
rust-version = "1.81.0"
[workspace.dependencies]
revive-benchmarks = { version = "0.1.0-dev.12", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0-dev.12", path = "crates/builtins" }
revive-common = { version = "0.1.0-dev.12", path = "crates/common" }
revive-differential = { version = "0.1.0-dev.12", path = "crates/differential" }
revive-integration = { version = "0.1.0-dev.12", path = "crates/integration" }
revive-linker = { version = "0.1.0-dev.12", path = "crates/linker" }
lld-sys = { version = "0.1.0-dev.12", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0-dev.12", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0-dev.12", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0-dev.12", path = "crates/runner" }
revive-solidity = { version = "0.1.0-dev.12", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0-dev.12", path = "crates/stdlib" }
revive-build-utils = { version = "0.1.0-dev.12", path = "crates/build-utils" }
revive-benchmarks = { version = "0.1.0-dev.14", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0-dev.14", path = "crates/builtins" }
revive-common = { version = "0.1.0-dev.14", path = "crates/common" }
revive-differential = { version = "0.1.0-dev.14", path = "crates/differential" }
revive-integration = { version = "0.1.0-dev.14", path = "crates/integration" }
revive-linker = { version = "0.1.0-dev.14", path = "crates/linker" }
lld-sys = { version = "0.1.0-dev.14", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0-dev.14", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0-dev.14", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0-dev.14", path = "crates/runner" }
revive-solc-json-interface = { version = "0.1.0-dev.14", path = "crates/solc-json-interface" }
revive-solidity = { version = "0.1.0-dev.14", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0-dev.14", path = "crates/stdlib" }
revive-build-utils = { version = "0.1.0-dev.14", path = "crates/build-utils" }
hex = "0.4.3"
cc = "1.2"
+1 -1
View File
@@ -11,7 +11,7 @@ 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
FROM messense/rust-musl-cross@sha256:68b86bc7cb2867259e6b233415a665ff4469c28b57763e78c3bfea1c68091561 AS resolc-builder
WORKDIR /opt/revive
RUN apt update && \
+7 -6
View File
@@ -5,6 +5,7 @@
install-wasm \
install-llvm-builder \
install-llvm \
install-revive-runner \
format \
clippy \
machete \
@@ -23,7 +24,7 @@
install: install-bin install-npm
install-bin:
cargo install --path crates/solidity
cargo install --locked --path crates/solidity
install-npm:
npm install && npm fund
@@ -39,6 +40,9 @@ install-llvm: install-llvm-builder
revive-llvm clone
revive-llvm build --llvm-projects lld --llvm-projects clang
install-revive-runner:
cargo install --path crates/runner --no-default-features --locked
format:
cargo fmt --all --check
@@ -49,7 +53,7 @@ machete:
cargo install cargo-machete
cargo machete
test: format clippy machete test-cli test-workspace
test: format clippy machete test-cli test-workspace install-revive-runner
test-integration: install-bin
cargo test --package revive-integration
@@ -88,7 +92,4 @@ clean:
rm -rf node_modules ; \
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
cargo uninstall revive-solidity ; \
cargo uninstall revive-llvm-builder ; \
rm -f package-lock.json ; \
rm -rf js/dist ; \
rm -f js/src/resolc.{wasm,js}
cargo uninstall revive-llvm-builder ;
+1 -1
View File
@@ -1,4 +1,4 @@
![CI](https://github.com/paritytech/revive/actions/workflows/rust.yml/badge.svg)
![CI](https://github.com/paritytech/revive/actions/workflows/test.yml/badge.svg)
[![Docs](https://img.shields.io/badge/Docs-contracts.polkadot.io-brightgreen.svg)](https://contracts.polkadot.io/revive_compiler/)
# revive
+8 -5
View File
@@ -4,11 +4,14 @@ Prior to the first stable release we neither have formal release processes nor d
To create a new pre-release:
1. Create a release PR which updates the `-dev.X` versions in the workspace `Cargo.toml` and updates the `CHANGELOG.md` accordingly. Add the `release-test` label to trigger the release workflows.
2. If the CI passes, merge the release PR. The release workflow will attempt to build and publish a new release whenever the latest git tag does not match the cargo package version.
3. 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).
4. 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)
5. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly
1. Create a release PR which updates the `-dev.X` versions in the workspace `Cargo.toml` and updates the `CHANGELOG.md` accordingly.
2. If the CI passes, merge the release PR.
3. Push a tag that has the same `-dev.X` version as in `Cargo.toml`
4. The release workflow will attempt to build and publish a new pre-release if the latest tag does match the cargo package version.
5. Wait for the `Release` workflow to finish. It should create the pre-release with the same `-dev.X` name.
6. Check that pre-release was created on the [Releases page](https://github.com/paritytech/revive/releases) with all artifacts.
7. After the release is published, another workflow should start automatically and update json files in https://github.com/paritytech/resolc-bin. Check the changes.
8. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly
# LLVM release
+24 -24
View File
@@ -15,58 +15,58 @@
### Baseline
| | `EVM` | `PVMInterpreter` |
|:--------|:------------------------|:-------------------------------- |
| **`0`** | `3.36 us` (✅ **1.00x**) | `11.84 us` (*3.52x slower*) |
| | `EVM` | `PVMInterpreter` |
|:--------|:-------------------------|:-------------------------------- |
| **`0`** | `10.08 us` (✅ **1.00x**) | `10.32 us` (**1.02x 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**) |
| | `EVM` | `PVMInterpreter` |
|:-------------|:--------------------------|:-------------------------------- |
| **`10000`** | `3.60 ms` (✅ **1.00x**) | `1.57 ms` (🚀 **2.28x faster**) |
| **`100000`** | `34.72 ms` (✅ **1.00x**) | `14.82 ms` (🚀 **2.34x faster**) |
| **`300000`** | `105.01 ms` (✅ **1.00x**) | `44.11 ms` (🚀 **2.38x 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**) |
| **`10000`** | `2.43 ms` (✅ **1.00x**) | `1.12 ms` (🚀 **2.17x faster**) |
| **`100000`** | `24.20 ms` (✅ **1.00x**) | `10.86 ms` (🚀 **2.23x faster**) |
| **`360000`** | `88.69 ms` (✅ **1.00x**) | `38.46 ms` (🚀 **2.31x 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**) |
| **`12`** | `144.17 us` (✅ **1.00x**) | `150.85 us` (✅ **1.05x slower**) |
| **`16`** | `938.71 us` (✅ **1.00x**) | `922.11 us` (✅ **1.02x faster**) |
| **`20`** | `6.54 ms` (✅ **1.00x**) | `6.20 ms` (✅ **1.05x faster**) |
| **`24`** | `45.73 ms` (✅ **1.00x**) | `41.98 ms` (✅ **1.09x 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*) |
| **`64`** | `23.00 us` (✅ **1.00x**) | `31.88 us` (❌ *1.39x slower*) |
| **`128`** | `35.28 us` (✅ **1.00x**) | `42.43 us` (❌ *1.20x slower*) |
| **`256`** | `60.12 us` (✅ **1.00x**) | `61.20 us` (**1.02x 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*) |
| **`64`** | `23.01 us` (✅ **1.00x**) | `47.74 us` (❌ *2.07x slower*) |
| **`128`** | `25.44 us` (✅ **1.00x**) | `49.67 us` (❌ *1.95x slower*) |
| **`256`** | `28.66 us` (✅ **1.00x**) | `53.01 us` (❌ *1.85x 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**) |
| **`1`** | `135.87 us` (✅ **1.00x**) | `243.75 us` (❌ *1.79x slower*) |
| **`64`** | `258.45 us` (✅ **1.00x**) | `355.70 us` (❌ *1.38x slower*) |
| **`512`** | `1.10 ms` (✅ **1.00x**) | `1.09 ms` (✅ **1.01x faster**) |
---
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
+8 -8
View File
@@ -1,10 +1,10 @@
{
"Baseline": 1443,
"Computation": 2788,
"DivisionArithmetics": 9748,
"ERC20": 19203,
"Events": 2201,
"FibonacciIterative": 2041,
"Flipper": 2632,
"SHA1": 8958
"Baseline": 939,
"Computation": 2282,
"DivisionArithmetics": 8849,
"ERC20": 18308,
"Events": 1640,
"FibonacciIterative": 1497,
"Flipper": 2099,
"SHA1": 8243
}
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
contract Predicted {
uint public salt;
constructor(uint _salt) {
salt = _salt;
}
}
contract AddressPredictor {
constructor(uint _salt, bytes memory _bytecode) payable {
address deployed = address(new Predicted{salt: bytes32(_salt)}(_salt));
address predicted = predictAddress(_salt, _bytecode);
assert(deployed == predicted);
}
function predictAddress(
uint _foo,
bytes memory _bytecode
) public view returns (address predicted) {
bytes32 addr = keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
bytes32(_foo),
keccak256(abi.encodePacked(_bytecode, abi.encode(_foo)))
)
);
predicted = address(uint160(uint(addr)));
}
}
+52
View File
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.29;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "LayoutAt"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "a7a0d537"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "15393349"
}
}
]
}
*/
contract LayoutAt layout at 0xDEADBEEF + 0xCAFEBABE {
uint[3] public something;
constructor() payable {
something[0] = 1337;
something[1] = 42;
something[2] = 69;
}
function slotOfSomething() public pure returns (uint ret) {
assembly {
ret := something.slot
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ pragma solidity ^0.8;
"Instantiated": 0
},
"key": "0000000000000000000000000000000000000000000000000000000000000000",
"expected": "0100000000000000000000000000000000000000000000000000000000000000"
"expected": "0000000000000000000000000000000000000000000000000000000000000001"
}
},
{
+11
View File
@@ -250,6 +250,17 @@ sol!(
);
case!("Storage.sol", Storage, transientCall, storage_transient, value: U256);
sol!(
contract Predicted {
constructor(uint _foo);
}
contract AddressPredictor {
constructor(uint _foo, bytes memory _bytecode) payable;
}
);
case!("AddressPredictor.sol", Predicted, constructorCall, predicted_constructor, salt: U256);
case!("AddressPredictor.sol", AddressPredictor, constructorCall, address_predictor_constructor, salt: U256, bytecode: Bytes);
impl Contract {
pub fn build(calldata: Vec<u8>, name: &'static str, code: &str) -> Self {
Self {
+29
View File
@@ -59,6 +59,7 @@ test_spec!(function_pointer, "FunctionPointer", "FunctionPointer.sol");
test_spec!(mload, "MLoad", "MLoad.sol");
test_spec!(delegate_no_contract, "DelegateCaller", "DelegateCaller.sol");
test_spec!(function_type, "FunctionType", "FunctionType.sol");
test_spec!(layout_at, "LayoutAt", "LayoutAt.sol");
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
vec![Instantiate {
@@ -485,3 +486,31 @@ fn transfer_denies_reentrancy() {
}
.run();
}
#[test]
fn create2_salt() {
let salt = U256::from(777);
let predicted = Contract::predicted_constructor(salt).pvm_runtime;
let predictor = Contract::address_predictor_constructor(salt, predicted.clone().into());
Specs {
actions: vec![
Upload {
origin: TestAddress::Alice,
code: Code::Bytes(predicted),
storage_deposit_limit: None,
},
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Bytes(predictor.pvm_runtime),
data: predictor.calldata,
salt: OptionalHex::default(),
},
],
differential: false,
..Default::default()
}
.run();
}
+1 -1
View File
@@ -96,7 +96,7 @@ fn main() {
revive_build_utils::llvm_cxx_flags()
.split_whitespace()
.fold(&mut cc::Build::new(), |builder, flag| builder.flag(flag))
.flag("-Wno-unused-parameter")
.warnings(false)
.cpp(true)
.file("src/linker.cpp")
.compile("liblinker.a");
+1
View File
@@ -32,6 +32,7 @@ tar = { workspace = true }
flate2 = { workspace = true }
env_logger = { workspace = true }
log = { workspace = true }
which = { workspace = true }
[dev-dependencies]
assert_cmd = { workspace = true }
+33 -7
View File
@@ -1,5 +1,8 @@
//! Utilities for compiling the LLVM compiler-rt builtins.
use crate::utils::path_windows_to_unix as to_unix;
use std::{env::consts::EXE_EXTENSION, process::Command};
/// Static CFLAGS variable passed to the compiler building the compiler-rt builtins.
const C_FLAGS: [&str; 6] = [
"--target=riscv64",
@@ -44,24 +47,31 @@ fn cmake_dynamic_args(
let mut clang_path = llvm_target_host.to_path_buf();
clang_path.push("bin/clang");
clang_path.set_extension(EXE_EXTENSION);
let mut clangxx_path = llvm_target_host.to_path_buf();
clangxx_path.push("bin/clang++");
clangxx_path.set_extension(EXE_EXTENSION);
let mut llvm_config_path = llvm_target_host.to_path_buf();
llvm_config_path.push("bin/llvm-config");
llvm_config_path.set_extension(EXE_EXTENSION);
let mut ar_path = llvm_target_host.to_path_buf();
ar_path.push("bin/llvm-ar");
ar_path.set_extension(EXE_EXTENSION);
let mut nm_path = llvm_target_host.to_path_buf();
nm_path.push("bin/llvm-nm");
nm_path.set_extension(EXE_EXTENSION);
let mut ranlib_path = llvm_target_host.to_path_buf();
ranlib_path.push("bin/llvm-ranlib");
ranlib_path.set_extension(EXE_EXTENSION);
let mut linker_path = llvm_target_host.to_path_buf();
linker_path.push("bin/ld.lld");
linker_path.set_extension(EXE_EXTENSION);
Ok([
format!(
@@ -76,12 +86,18 @@ fn cmake_dynamic_args(
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!(
"-DCMAKE_C_COMPILER='{}'",
to_unix(clang_path.clone())?.display()
),
format!("-DCMAKE_ASM_COMPILER='{}'", to_unix(clang_path)?.display()),
format!(
"-DCMAKE_CXX_COMPILER='{}'",
to_unix(clangxx_path)?.display()
),
format!("-DCMAKE_AR='{}'", to_unix(ar_path)?.display()),
format!("-DCMAKE_NM='{}'", to_unix(nm_path)?.display()),
format!("-DCMAKE_RANLIB='{}'", to_unix(ranlib_path)?.display()),
format!(
"-DLLVM_CONFIG_PATH='{}'",
llvm_config_path.to_string_lossy()
@@ -131,7 +147,17 @@ pub fn build(
"LLVM compiler-rt building cmake",
)?;
crate::utils::ninja(&llvm_compiler_rt_build)?;
crate::utils::command(
Command::new("cmake").args([
"--build",
llvm_compiler_rt_build.to_string_lossy().as_ref(),
"--target",
"install",
"--config",
build_type.to_string().as_str(),
]),
"Building",
)?;
Ok(())
}
+1 -1
View File
@@ -214,7 +214,7 @@ pub fn build(
sanitizer,
)?;
} else if cfg!(target_os = "windows") {
platforms::x86_64_windows_gnu::build(
platforms::x86_64_windows_msvc::build(
build_type,
targets,
llvm_projects,
+1 -1
View File
@@ -8,7 +8,7 @@ pub mod wasm32_emscripten;
pub mod x86_64_linux_gnu;
pub mod x86_64_linux_musl;
pub mod x86_64_macos;
pub mod x86_64_windows_gnu;
pub mod x86_64_windows_msvc;
use std::str::FromStr;
+3 -1
View File
@@ -8,7 +8,7 @@ use std::path::Path;
use std::process::Command;
/// The build options shared by all platforms.
pub const SHARED_BUILD_OPTS: [&str; 19] = [
pub const SHARED_BUILD_OPTS: [&str; 21] = [
"-DPACKAGE_VENDOR='Parity Technologies'",
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
"-DLLVM_BUILD_DOCS='Off'",
@@ -28,6 +28,8 @@ pub const SHARED_BUILD_OPTS: [&str; 19] = [
"-DCMAKE_EXPORT_COMPILE_COMMANDS='On'",
"-DPython3_FIND_REGISTRY='LAST'", // Use Python version from $PATH, not from registry
"-DBUG_REPORT_URL='https://github.com/paritytech/contract-issues/issues/'",
"-DCLANG_ENABLE_ARCMT='Off'",
"-DCLANG_ENABLE_STATIC_ANALYZER='Off'",
];
/// The build options shared by all platforms except MUSL.
@@ -1,7 +1,6 @@
//! The revive LLVM amd64 `windows-gnu` builder.
use std::collections::HashSet;
use std::path::PathBuf;
use std::process::Command;
use crate::build_type::BuildType;
@@ -28,10 +27,6 @@ pub fn build(
sanitizer: Option<Sanitizer>,
) -> anyhow::Result<()> {
crate::utils::check_presence("cmake")?;
crate::utils::check_presence("clang")?;
crate::utils::check_presence("clang++")?;
crate::utils::check_presence("lld")?;
crate::utils::check_presence("ninja")?;
let llvm_module_llvm =
LLVMPath::llvm_module_llvm().and_then(crate::utils::path_windows_to_unix)?;
@@ -48,15 +43,12 @@ pub fn build(
"-B",
llvm_build_final.to_string_lossy().as_ref(),
"-G",
"Ninja",
"Visual Studio 17 2022",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
llvm_target_final.to_string_lossy().as_ref(),
)
.as_str(),
format!("-DCMAKE_BUILD_TYPE='{build_type}'").as_str(),
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
format!(
"-DLLVM_TARGETS_TO_BUILD='{}'",
targets
@@ -75,7 +67,7 @@ pub fn build(
.join(";")
)
.as_str(),
"-DLLVM_USE_LINKER='lld'",
"-DLLVM_BUILD_LLVM_C_DYLIB=Off",
])
.args(crate::platforms::shared::shared_build_opts_default_target(
default_target,
@@ -107,20 +99,16 @@ pub fn build(
"LLVM building cmake",
)?;
crate::utils::ninja(llvm_build_final.as_ref())?;
let libstdcpp_source_path = match std::env::var("LIBSTDCPP_SOURCE_PATH") {
Ok(libstdcpp_source_path) => PathBuf::from(libstdcpp_source_path),
Err(error) => anyhow::bail!(
"The `LIBSTDCPP_SOURCE_PATH` must be set to the path to the libstdc++.a static library: {}", error
),
};
let mut libstdcpp_destination_path = llvm_target_final;
libstdcpp_destination_path.push("./lib/libstdc++.a");
fs_extra::file::copy(
crate::utils::path_windows_to_unix(libstdcpp_source_path)?,
crate::utils::path_windows_to_unix(libstdcpp_destination_path)?,
&fs_extra::file::CopyOptions::default(),
crate::utils::command(
Command::new("cmake").args([
"--build",
llvm_build_final.to_string_lossy().as_ref(),
"--target",
"install",
"--config",
build_type.to_string().as_str(),
]),
"Building with msbuild",
)?;
Ok(())
+3 -5
View File
@@ -7,6 +7,7 @@ use std::process::Command;
use std::process::Stdio;
use std::time::Duration;
use anyhow::Context;
use path_slash::PathBufExt;
/// The LLVM host repository URL.
@@ -131,11 +132,8 @@ pub fn path_windows_to_unix<P: AsRef<Path> + PathBufExt>(path: P) -> anyhow::Res
/// Checks if the tool exists in the system.
pub fn check_presence(name: &str) -> anyhow::Result<()> {
let description = &format!("checking the `{name}` executable");
log::info!("{description}");
command(Command::new("which").arg(name), description)
.map_err(|_| anyhow::anyhow!("Tool `{}` is missing. Please install", name))
which::which(name).with_context(|| format!("Tool `{name}` is missing. Please install"))?;
Ok(())
}
/// Identify XCode version using `pkgutil`.
+2
View File
@@ -22,6 +22,7 @@ num = { workspace = true }
hex = { workspace = true }
sha3 = { workspace = true }
inkwell = { workspace = true }
libc = { workspace = true }
polkavm-disassembler = { workspace = true }
polkavm-common = { workspace = true }
@@ -29,3 +30,4 @@ revive-common = { workspace = true }
revive-runtime-api = { workspace = true }
revive-linker = { workspace = true }
revive-stdlib = { workspace = true }
revive-solc-json-interface = { workspace = true }
+42 -9
View File
@@ -1,12 +1,11 @@
//! The LLVM context library.
pub(crate) mod debug_config;
pub(crate) mod optimizer;
pub(crate) mod polkavm;
pub(crate) mod target_machine;
use std::ffi::CString;
use std::sync::OnceLock;
pub use self::debug_config::ir_type::IRType as DebugConfigIR;
pub use self::debug_config::DebugConfig;
pub use self::memory::MemoryConfig;
pub use self::optimizer::settings::size_level::SizeLevel as OptimizerSettingsSizeLevel;
pub use self::optimizer::settings::Settings as OptimizerSettings;
pub use self::optimizer::Optimizer;
@@ -30,6 +29,7 @@ pub use self::polkavm::context::function::runtime::entry::Entry as PolkaVMEntryF
pub use self::polkavm::context::function::runtime::revive::Exit as PolkaVMExitFunction;
pub use self::polkavm::context::function::runtime::revive::WordToPointer as PolkaVMWordToPointerFunction;
pub use self::polkavm::context::function::runtime::runtime_code::RuntimeCode as PolkaVMRuntimeCodeFunction;
pub use self::polkavm::context::function::runtime::sbrk::Sbrk as PolkaVMSbrkFunction;
pub use self::polkavm::context::function::runtime::FUNCTION_DEPLOY_CODE as PolkaVMFunctionDeployCode;
pub use self::polkavm::context::function::runtime::FUNCTION_ENTRY as PolkaVMFunctionEntry;
pub use self::polkavm::context::function::runtime::FUNCTION_RUNTIME_CODE as PolkaVMFunctionRuntimeCode;
@@ -38,7 +38,9 @@ pub use self::polkavm::context::function::Function as PolkaVMFunction;
pub use self::polkavm::context::global::Global as PolkaVMGlobal;
pub use self::polkavm::context::pointer::heap::LoadWord as PolkaVMLoadHeapWordFunction;
pub use self::polkavm::context::pointer::heap::StoreWord as PolkaVMStoreHeapWordFunction;
pub use self::polkavm::context::pointer::storage::LoadTransientWord as PolkaVMLoadTransientStorageWordFunction;
pub use self::polkavm::context::pointer::storage::LoadWord as PolkaVMLoadStorageWordFunction;
pub use self::polkavm::context::pointer::storage::StoreTransientWord as PolkaVMStoreTransientStorageWordFunction;
pub use self::polkavm::context::pointer::storage::StoreWord as PolkaVMStoreStorageWordFunction;
pub use self::polkavm::context::pointer::Pointer as PolkaVMPointer;
pub use self::polkavm::context::r#loop::Loop as PolkaVMLoop;
@@ -60,13 +62,11 @@ pub use self::polkavm::evm::ext_code as polkavm_evm_ext_code;
pub use self::polkavm::evm::immutable as polkavm_evm_immutable;
pub use self::polkavm::evm::immutable::Load as PolkaVMLoadImmutableDataFunction;
pub use self::polkavm::evm::immutable::Store as PolkaVMStoreImmutableDataFunction;
pub use self::polkavm::evm::math as polkavm_evm_math;
pub use self::polkavm::evm::memory as polkavm_evm_memory;
pub use self::polkavm::evm::r#return as polkavm_evm_return;
pub use self::polkavm::evm::return_data as polkavm_evm_return_data;
pub use self::polkavm::evm::storage as polkavm_evm_storage;
pub use self::polkavm::metadata_hash::MetadataHash as PolkaVMMetadataHash;
pub use self::polkavm::r#const as polkavm_const;
pub use self::polkavm::Dependency as PolkaVMDependency;
pub use self::polkavm::DummyDependency as PolkaVMDummyDependency;
@@ -75,9 +75,42 @@ pub use self::polkavm::WriteLLVM as PolkaVMWriteLLVM;
pub use self::target_machine::target::Target;
pub use self::target_machine::TargetMachine;
/// Initializes the target machine.
pub fn initialize_target(target: Target) {
pub(crate) mod debug_config;
pub(crate) mod memory;
pub(crate) mod optimizer;
pub(crate) mod polkavm;
pub(crate) mod target_machine;
static DID_INITIALIZE: OnceLock<()> = OnceLock::new();
/// Initializes the LLVM compiler backend.
///
/// This is a no-op if called subsequentially.
///
/// `llvm_arguments` are passed as-is to the LLVM CL options parser.
pub fn initialize_llvm(target: Target, name: &str, llvm_arguments: &[String]) {
let Ok(_) = DID_INITIALIZE.set(()) else {
return; // Tests don't go through a recursive process
};
let argv = [name.to_string()]
.iter()
.chain(llvm_arguments)
.map(|arg| CString::new(arg.as_bytes()).unwrap())
.collect::<Vec<_>>();
let argv: Vec<*const libc::c_char> = argv.iter().map(|arg| arg.as_ptr()).collect();
let overview = CString::new("").unwrap();
unsafe {
inkwell::llvm_sys::support::LLVMParseCommandLineOptions(
argv.len() as i32,
argv.as_ptr(),
overview.as_ptr(),
);
}
inkwell::support::enable_llvm_pretty_stack_trace();
match target {
Target::PVM => self::polkavm::initialize_target(),
Target::PVM => inkwell::targets::Target::initialize_riscv(&Default::default()),
}
}
+21
View File
@@ -0,0 +1,21 @@
//! The compile time PolkaVM memory configuration settings.
use serde::{Deserialize, Serialize};
/// The PolkaVM memory configuration.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct MemoryConfig {
/// The emulated EVM linear heap memory size in bytes.
pub heap_size: u32,
/// The PVM stack size in bytes.
pub stack_size: u32,
}
impl Default for MemoryConfig {
fn default() -> Self {
Self {
heap_size: 64 * 1024,
stack_size: 32 * 1024,
}
}
}
@@ -2,6 +2,7 @@
pub mod size_level;
use revive_solc_json_interface::SolcStandardJsonInputSettingsOptimizer;
use serde::Deserialize;
use serde::Serialize;
@@ -226,3 +227,18 @@ impl std::fmt::Display for Settings {
)
}
}
impl TryFrom<&SolcStandardJsonInputSettingsOptimizer> for Settings {
type Error = anyhow::Error;
fn try_from(value: &SolcStandardJsonInputSettingsOptimizer) -> Result<Self, Self::Error> {
let mut result = match value.mode {
Some(mode) => Self::try_from_cli(mode)?,
None => Self::size(),
};
if value.fallback_to_optimizing_for_size.unwrap_or_default() {
result.enable_fallback_to_size();
}
Ok(result)
}
}
@@ -9,6 +9,15 @@ pub static XLEN: usize = revive_common::BIT_LENGTH_X32;
/// The calldata size global variable name.
pub static GLOBAL_CALLDATA_SIZE: &str = "calldatasize";
/// The heap size global variable name.
pub static GLOBAL_HEAP_SIZE: &str = "__heap_size";
/// The heap memory global variable name.
pub static GLOBAL_HEAP_MEMORY: &str = "__heap_memory";
/// The spill buffer global variable name.
pub static GLOBAL_ADDRESS_SPILL_BUFFER: &str = "address_spill_buffer";
/// The deployer call header size that consists of:
/// - bytecode hash (32 bytes)
pub const DEPLOYER_CALL_HEADER_SIZE: usize = revive_common::BYTE_LENGTH_WORD;
@@ -8,10 +8,6 @@ pub enum AddressSpace {
Stack,
/// The heap memory.
Heap,
/// The generic memory page.
Storage,
/// The transient storage.
TransientStorage,
}
impl From<AddressSpace> for inkwell::AddressSpace {
@@ -19,8 +15,6 @@ impl From<AddressSpace> for inkwell::AddressSpace {
match value {
AddressSpace::Stack => Self::from(0),
AddressSpace::Heap => Self::from(1),
AddressSpace::Storage => Self::from(5),
AddressSpace::TransientStorage => Self::from(6),
}
}
}
@@ -4,61 +4,98 @@
#[derive(Debug, Clone)]
pub struct Argument<'ctx> {
/// The actual LLVM operand.
pub value: inkwell::values::BasicValueEnum<'ctx>,
pub value: Value<'ctx>,
/// The original AST value. Used mostly for string literals.
pub original: Option<String>,
/// The preserved constant value, if available.
pub constant: Option<num::BigUint>,
}
/// The function argument can be either a pointer or a integer value.
/// This disambiguation allows for lazy loading of variables.
#[derive(Clone, Debug)]
pub enum Value<'ctx> {
Register(inkwell::values::BasicValueEnum<'ctx>),
Pointer {
pointer: crate::polkavm::context::Pointer<'ctx>,
id: String,
},
}
impl<'ctx> Argument<'ctx> {
/// The calldata offset argument index.
pub const ARGUMENT_INDEX_CALLDATA_OFFSET: usize = 0;
/// The calldata length argument index.
pub const ARGUMENT_INDEX_CALLDATA_LENGTH: usize = 1;
/// A shortcut constructor.
pub fn new(value: inkwell::values::BasicValueEnum<'ctx>) -> Self {
/// A shortcut constructor for register arguments.
pub fn value(value: inkwell::values::BasicValueEnum<'ctx>) -> Self {
Self {
value,
value: Value::Register(value),
original: None,
constant: None,
}
}
/// A shortcut constructor.
pub fn new_with_original(
value: inkwell::values::BasicValueEnum<'ctx>,
original: String,
) -> Self {
/// A shortcut constructor for stack arguments.
pub fn pointer(pointer: crate::polkavm::context::Pointer<'ctx>, id: String) -> Self {
Self {
value,
original: Some(original),
value: Value::Pointer { pointer, id },
original: None,
constant: None,
}
}
/// A shortcut constructor.
pub fn new_with_constant(
value: inkwell::values::BasicValueEnum<'ctx>,
constant: num::BigUint,
) -> Self {
Self {
value,
original: None,
constant: Some(constant),
}
/// Set the original decleratation value.
pub fn with_original(mut self, original: String) -> Self {
self.original = Some(original);
self
}
/// Set the constant value.
pub fn with_constant(mut self, constant: num::BigUint) -> Self {
self.constant = Some(constant);
self
}
/// Returns the inner LLVM value.
pub fn to_llvm(&self) -> inkwell::values::BasicValueEnum<'ctx> {
self.value
///
/// Panics if `self` is a pointer argument.
pub fn _to_llvm_value(&self) -> inkwell::values::BasicValueEnum<'ctx> {
match &self.value {
Value::Register(value) => *value,
Value::Pointer { .. } => unreachable!("invalid register value access"),
}
}
/// Access the underlying value.
///
/// Will emit a stack load if `self` is a pointer argument.
pub fn access<D: crate::polkavm::Dependency + Clone>(
&self,
context: &crate::polkavm::context::Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
match &self.value {
Value::Register(value) => Ok(*value),
Value::Pointer { pointer, id } => context.build_load(*pointer, id),
}
}
/// Access the underlying value.
///
/// Will emit a stack load if `self` is a pointer argument.
pub fn as_pointer<D: crate::polkavm::Dependency + Clone>(
&self,
context: &crate::polkavm::context::Context<'ctx, D>,
) -> anyhow::Result<crate::polkavm::context::Pointer<'ctx>> {
match &self.value {
Value::Register(value) => {
let pointer = context.build_alloca_at_entry(context.word_type(), "pvm_arg");
context.build_store(pointer, *value)?;
Ok(pointer)
}
Value::Pointer { pointer, .. } => Ok(*pointer),
}
}
}
impl<'ctx> From<inkwell::values::BasicValueEnum<'ctx>> for Argument<'ctx> {
fn from(value: inkwell::values::BasicValueEnum<'ctx>) -> Self {
Self::new(value)
Self::value(value)
}
}
@@ -1,9 +1,6 @@
//! The LLVM runtime functions.
use inkwell::types::BasicType;
use crate::optimizer::Optimizer;
use crate::polkavm::context::address_space::AddressSpace;
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
use crate::polkavm::context::function::Function;
@@ -19,9 +16,6 @@ pub struct LLVMRuntime<'ctx> {
pub exp: FunctionDeclaration<'ctx>,
/// The corresponding LLVM runtime function.
pub sign_extend: FunctionDeclaration<'ctx>,
/// The corresponding LLVM runtime function.
pub sha3: FunctionDeclaration<'ctx>,
}
impl<'ctx> LLVMRuntime<'ctx> {
@@ -37,9 +31,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
/// The corresponding runtime function name.
pub const FUNCTION_SIGNEXTEND: &'static str = "__signextend";
/// The corresponding runtime function name.
pub const FUNCTION_SHA3: &'static str = "__sha3";
/// A shortcut constructor.
pub fn new(
llvm: &'ctx inkwell::context::Context,
@@ -65,43 +56,11 @@ impl<'ctx> LLVMRuntime<'ctx> {
Function::set_default_attributes(llvm, sign_extend, optimizer);
Function::set_pure_function_attributes(llvm, sign_extend);
let sha3 = Self::declare(
module,
Self::FUNCTION_SHA3,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.fn_type(
vec![
llvm.ptr_type(AddressSpace::Heap.into())
.as_basic_type_enum()
.into(),
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum()
.into(),
llvm.custom_width_int_type(revive_common::BIT_LENGTH_BOOLEAN as u32)
.as_basic_type_enum()
.into(),
]
.as_slice(),
false,
),
Some(inkwell::module::Linkage::External),
);
Function::set_default_attributes(llvm, sha3, optimizer);
Function::set_attributes(
llvm,
sha3,
//vec![Attribute::ArgMemOnly, Attribute::ReadOnly],
&[],
false,
);
Self {
add_mod,
mul_mod,
exp,
sign_extend,
sha3,
}
}
@@ -31,6 +31,31 @@ impl Entry {
context.xlen_type().get_undef(),
);
context.set_global(
crate::polkavm::GLOBAL_HEAP_SIZE,
context.xlen_type(),
AddressSpace::Stack,
context.xlen_type().const_zero(),
);
let heap_memory_type = context
.byte_type()
.array_type(context.memory_config.heap_size);
context.set_global(
crate::polkavm::GLOBAL_HEAP_MEMORY,
heap_memory_type,
AddressSpace::Stack,
heap_memory_type.const_zero(),
);
let address_type = context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS);
context.set_global(
crate::polkavm::GLOBAL_ADDRESS_SPILL_BUFFER,
address_type,
AddressSpace::Stack,
address_type.const_zero(),
);
Ok(())
}
@@ -5,6 +5,7 @@ pub mod deploy_code;
pub mod entry;
pub mod revive;
pub mod runtime_code;
pub mod sbrk;
/// The main entry function name.
pub const FUNCTION_ENTRY: &str = "__entry";
@@ -0,0 +1,144 @@
//! Emulates the linear EVM heap memory via a simulated `sbrk` system call.
use inkwell::values::BasicValue;
use crate::polkavm::context::attribute::Attribute;
use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm::WriteLLVM;
/// Simulates the `sbrk` system call, reproducing the semantics of the EVM heap memory.
///
/// Parameters:
/// - The `offset` into the emulated EVM heap memory.
/// - The `size` of the allocation emulated EVM heap memory.
///
/// Returns:
/// - A pointer to the EVM heap memory at given `offset`.
///
/// Semantics:
/// - Traps if the offset is out of bounds.
/// - Aligns the total heap memory size to the EVM word size.
/// - Traps if the memory size would be greater than the configured EVM heap memory size.
/// - Maintains the total memory size (`msize`) in global heap size value.
pub struct Sbrk;
impl<D> RuntimeFunction<D> for Sbrk
where
D: Dependency + Clone,
{
const NAME: &'static str = "__sbrk_internal";
const ATTRIBUTES: &'static [Attribute] = &[
Attribute::NoFree,
Attribute::NoRecurse,
Attribute::WillReturn,
];
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.llvm().ptr_type(Default::default()).fn_type(
&[context.xlen_type().into(), context.xlen_type().into()],
false,
)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>> {
let offset = Self::paramater(context, 0).into_int_value();
let size = Self::paramater(context, 1).into_int_value();
let trap_block = context.append_basic_block("trap");
let offset_in_bounds_block = context.append_basic_block("offset_in_bounds");
let is_offset_out_of_bounds = context.builder().build_int_compare(
inkwell::IntPredicate::UGE,
offset,
context.heap_size(),
"offset_out_of_bounds",
)?;
context.build_conditional_branch(
is_offset_out_of_bounds,
trap_block,
offset_in_bounds_block,
)?;
context.set_basic_block(trap_block);
context.build_call(context.intrinsics().trap, &[], "invalid_trap");
context.build_unreachable();
context.set_basic_block(offset_in_bounds_block);
let mask = context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64 - 1, false);
let total_size = context
.builder()
.build_int_add(offset, size, "total_size")?;
let memory_size = context.builder().build_and(
context.builder().build_int_add(total_size, mask, "mask")?,
context.builder().build_not(mask, "mask_not")?,
"memory_size",
)?;
let size_in_bounds_block = context.append_basic_block("size_in_bounds");
let is_size_out_of_bounds = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
memory_size,
context.heap_size(),
"size_out_of_bounds",
)?;
context.build_conditional_branch(
is_size_out_of_bounds,
trap_block,
size_in_bounds_block,
)?;
context.set_basic_block(size_in_bounds_block);
let return_block = context.append_basic_block("return_pointer");
let new_size_block = context.append_basic_block("new_size");
let is_new_size = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
memory_size,
context
.get_global_value(crate::polkavm::GLOBAL_HEAP_SIZE)?
.into_int_value(),
"is_new_size",
)?;
context.build_conditional_branch(is_new_size, new_size_block, return_block)?;
context.set_basic_block(new_size_block);
context.build_store(
context.get_global(crate::polkavm::GLOBAL_HEAP_SIZE)?.into(),
memory_size,
)?;
context.build_unconditional_branch(return_block);
context.set_basic_block(return_block);
Ok(Some(
context
.build_gep(
context
.get_global(crate::polkavm::GLOBAL_HEAP_MEMORY)?
.into(),
&[context.xlen_type().const_zero(), offset],
context.byte_type(),
"allocation_start_pointer",
)
.value
.as_basic_value_enum(),
))
}
}
impl<D> WriteLLVM<D> for Sbrk
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
+49 -40
View File
@@ -26,6 +26,7 @@ use inkwell::debug_info::DIScope;
use inkwell::types::BasicType;
use inkwell::values::BasicValue;
use crate::memory::MemoryConfig;
use crate::optimizer::settings::Settings as OptimizerSettings;
use crate::optimizer::Optimizer;
use crate::polkavm::DebugConfig;
@@ -33,6 +34,7 @@ use crate::polkavm::Dependency;
use crate::target_machine::target::Target;
use crate::target_machine::TargetMachine;
use crate::PolkaVMLoadHeapWordFunction;
use crate::PolkaVMSbrkFunction;
use crate::PolkaVMStoreHeapWordFunction;
use self::address_space::AddressSpace;
@@ -83,6 +85,10 @@ where
current_function: Option<Rc<RefCell<Function<'ctx>>>>,
/// The loop context stack.
loop_stack: Vec<Loop<'ctx>>,
/// The extra LLVM arguments that were used during target initialization.
llvm_arguments: &'ctx [String],
/// The PVM memory configuration.
memory_config: MemoryConfig,
/// The project dependency manager. It can be any entity implementing the trait.
/// The manager is used to get information about contracts and their dependencies during
@@ -114,9 +120,6 @@ where
/// The loop stack default capacity.
const LOOP_STACK_INITIAL_CAPACITY: usize = 16;
/// The PolkaVM minimum stack size.
const POLKAVM_STACK_SIZE: u32 = 0x4000;
/// Link in the stdlib module.
fn link_stdlib_module(
llvm: &'ctx inkwell::context::Context,
@@ -216,6 +219,7 @@ where
}
/// Initializes a new LLVM context.
#[allow(clippy::too_many_arguments)]
pub fn new(
llvm: &'ctx inkwell::context::Context,
module: inkwell::module::Module<'ctx>,
@@ -223,11 +227,13 @@ where
dependency_manager: Option<D>,
include_metadata_hash: bool,
debug_config: DebugConfig,
llvm_arguments: &'ctx [String],
memory_config: MemoryConfig,
) -> Self {
Self::set_data_layout(llvm, &module);
Self::link_stdlib_module(llvm, &module);
Self::link_polkavm_imports(llvm, &module);
Self::set_polkavm_stack_size(llvm, &module, Self::POLKAVM_STACK_SIZE);
Self::set_polkavm_stack_size(llvm, &module, memory_config.stack_size);
Self::set_module_flags(llvm, &module);
let intrinsics = Intrinsics::new(llvm, &module);
@@ -250,6 +256,8 @@ where
functions: HashMap::with_capacity(Self::FUNCTIONS_HASHMAP_INITIAL_CAPACITY),
current_function: None,
loop_stack: Vec::with_capacity(Self::LOOP_STACK_INITIAL_CAPACITY),
llvm_arguments,
memory_config,
dependency_manager,
include_metadata_hash,
@@ -639,6 +647,8 @@ where
self.optimizer.settings().to_owned(),
self.include_metadata_hash,
self.debug_config.clone(),
self.llvm_arguments,
self.memory_config,
)
})
}
@@ -745,7 +755,9 @@ where
address: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<Pointer<'ctx>> {
let address_type = self.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS);
let address_pointer = self.build_alloca_at_entry(address_type, "address_pointer");
let address_pointer = self
.get_global(crate::polkavm::GLOBAL_ADDRESS_SPILL_BUFFER)?
.into();
let address_truncated =
self.builder()
.build_int_truncate(address, address_type, "address_truncated")?;
@@ -788,9 +800,6 @@ where
panic!("revive runtime function {name} should return a value")
}))
}
AddressSpace::Storage | AddressSpace::TransientStorage => {
unreachable!("should use the runtime function")
}
AddressSpace::Stack => {
let value = self
.builder()
@@ -823,9 +832,6 @@ where
];
self.build_call(declaration, &arguments, "heap_store");
}
AddressSpace::Storage | AddressSpace::TransientStorage => {
unreachable!("should use the runtime function")
}
AddressSpace::Stack => {
let instruction = self.builder.build_store(pointer.value, value).unwrap();
instruction
@@ -870,9 +876,6 @@ where
where
T: BasicType<'ctx>,
{
assert_ne!(pointer.address_space, AddressSpace::Storage);
assert_ne!(pointer.address_space, AddressSpace::TransientStorage);
let value = unsafe {
self.builder
.build_gep(pointer.r#type, pointer.value, indexes, name)
@@ -1086,32 +1089,40 @@ where
offset: inkwell::values::IntValue<'ctx>,
size: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::PointerValue<'ctx>> {
Ok(self
.builder()
.build_call(
self.runtime_api_method(revive_runtime_api::polkavm_imports::SBRK),
&[offset.into(), size.into()],
"call_sbrk",
)?
let call_site_value = self.builder().build_call(
<PolkaVMSbrkFunction as RuntimeFunction<D>>::declaration(self).function_value(),
&[offset.into(), size.into()],
"alloc_start",
)?;
call_site_value.add_attribute(
inkwell::attributes::AttributeLoc::Return,
self.llvm
.create_enum_attribute(Attribute::NonNull as u32, 0),
);
call_site_value.add_attribute(
inkwell::attributes::AttributeLoc::Return,
self.llvm
.create_enum_attribute(Attribute::NoUndef as u32, 0),
);
Ok(call_site_value
.try_as_basic_value()
.left()
.expect("sbrk returns a pointer")
.unwrap_or_else(|| {
panic!(
"revive runtime function {} should return a value",
<PolkaVMSbrkFunction as RuntimeFunction<D>>::NAME,
)
})
.into_pointer_value())
}
/// Build a call to PolkaVM `msize` for querying the linear memory size.
pub fn build_msize(&self) -> anyhow::Result<inkwell::values::IntValue<'ctx>> {
let memory_size_pointer = self
.module()
.get_global(revive_runtime_api::polkavm_imports::MEMORY_SIZE)
.expect("the memory size symbol should have been declared")
.as_pointer_value();
let memory_size_value = self.builder().build_load(
self.xlen_type(),
memory_size_pointer,
"memory_size_value",
)?;
Ok(memory_size_value.into_int_value())
Ok(self
.get_global_value(crate::polkavm::GLOBAL_HEAP_SIZE)?
.into_int_value())
}
/// Returns a pointer to `offset` into the heap, allocating
@@ -1298,13 +1309,6 @@ where
inkwell::attributes::AttributeLoc::Param(index as u32),
self.llvm.create_enum_attribute(Attribute::NoFree as u32, 0),
);
if function == self.llvm_runtime().sha3 {
call_site_value.add_attribute(
inkwell::attributes::AttributeLoc::Param(index as u32),
self.llvm
.create_enum_attribute(Attribute::ReadOnly as u32, 0),
);
}
if Some(argument.get_type()) == function.r#type.get_return_type() {
if function
.r#type
@@ -1437,4 +1441,9 @@ where
pub fn optimizer_settings(&self) -> &OptimizerSettings {
self.optimizer.settings()
}
pub fn heap_size(&self) -> inkwell::values::IntValue<'ctx> {
self.xlen_type()
.const_int(self.memory_config.heap_size as u64, false)
}
}
@@ -17,47 +17,20 @@ where
const NAME: &'static str = "__revive_load_storage_word";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.word_type().fn_type(
&[context.xlen_type().into(), context.word_type().into()],
false,
)
context
.word_type()
.fn_type(&[context.llvm().ptr_type(Default::default()).into()], false)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
let is_transient = Self::paramater(context, 0);
let key_value = Self::paramater(context, 1);
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
let length_pointer = context.build_alloca_at_entry(context.xlen_type(), "length_pointer");
context
.builder()
.build_store(key_pointer.value, key_value)?;
context.build_store(value_pointer, context.word_const(0))?;
context.build_store(
length_pointer,
context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false),
)?;
let arguments = [
is_transient,
key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(),
length_pointer.to_int(context).into(),
];
context.build_runtime_call(revive_runtime_api::polkavm_imports::GET_STORAGE, &arguments);
// We do not to check the return value: Solidity assumes infallible loads.
// If a key doesn't exist the "zero" value is returned (ensured by above write).
Ok(Some(context.build_load(value_pointer, "storage_value")?))
Ok(Some(emit_load(
context,
Self::paramater(context, 0),
false,
)?))
}
}
@@ -74,6 +47,42 @@ where
}
}
/// Load a word size value from a transient storage pointer.
pub struct LoadTransientWord;
impl<D> RuntimeFunction<D> for LoadTransientWord
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_load_transient_storage_word";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context
.word_type()
.fn_type(&[context.llvm().ptr_type(Default::default()).into()], false)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
Ok(Some(emit_load(context, Self::paramater(context, 0), true)?))
}
}
impl<D> WriteLLVM<D> for LoadTransientWord
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
/// Store a word size value through a storage pointer.
pub struct StoreWord;
@@ -86,9 +95,8 @@ where
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.void_type().fn_type(
&[
context.xlen_type().into(),
context.word_type().into(),
context.word_type().into(),
context.llvm().ptr_type(Default::default()).into(),
context.llvm().ptr_type(Default::default()).into(),
],
false,
)
@@ -98,24 +106,12 @@ where
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
let is_transient = Self::paramater(context, 0);
let key = Self::paramater(context, 1);
let value = Self::paramater(context, 2);
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
context.build_store(key_pointer, key)?;
context.build_store(value_pointer, value)?;
let arguments = [
is_transient,
key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(),
context.integer_const(crate::polkavm::XLEN, 32).into(),
];
context.build_runtime_call(revive_runtime_api::polkavm_imports::SET_STORAGE, &arguments);
emit_store(
context,
Self::paramater(context, 0),
Self::paramater(context, 1),
false,
)?;
Ok(None)
}
@@ -133,3 +129,149 @@ where
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
/// Store a word size value through a transient storage pointer.
pub struct StoreTransientWord;
impl<D> RuntimeFunction<D> for StoreTransientWord
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_store_transient_storage_word";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.void_type().fn_type(
&[
context.llvm().ptr_type(Default::default()).into(),
context.llvm().ptr_type(Default::default()).into(),
],
false,
)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
emit_store(
context,
Self::paramater(context, 0),
Self::paramater(context, 1),
true,
)?;
Ok(None)
}
}
impl<D> WriteLLVM<D> for StoreTransientWord
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
fn emit_load<'ctx, D: Dependency + Clone>(
context: &mut Context<'ctx, D>,
key: BasicValueEnum<'ctx>,
transient: bool,
) -> anyhow::Result<BasicValueEnum<'ctx>> {
let mut key = context.build_load(
super::Pointer::new(
context.word_type(),
Default::default(),
key.into_pointer_value(),
),
"key",
)?;
if !transient {
key = context.build_byte_swap(key)?;
}
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
let length_pointer = context.build_alloca_at_entry(context.xlen_type(), "length_pointer");
context.builder().build_store(key_pointer.value, key)?;
context.build_store(value_pointer, context.word_const(0))?;
context.build_store(
length_pointer,
context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false),
)?;
let is_transient = context.xlen_type().const_int(transient as u64, false);
let arguments = [
is_transient.into(),
key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(),
length_pointer.to_int(context).into(),
];
context.build_runtime_call(revive_runtime_api::polkavm_imports::GET_STORAGE, &arguments);
// We do not to check the return value: Solidity assumes infallible loads.
// If a key doesn't exist the "zero" value is returned (ensured by above write).
let value = context.build_load(value_pointer, "storage_value")?;
Ok(if transient {
value
} else {
context.build_byte_swap(value)?
})
}
fn emit_store<'ctx, D: Dependency + Clone>(
context: &mut Context<'ctx, D>,
key: BasicValueEnum<'ctx>,
value: BasicValueEnum<'ctx>,
transient: bool,
) -> anyhow::Result<()> {
let mut key = context.build_load(
super::Pointer::new(
context.word_type(),
Default::default(),
key.into_pointer_value(),
),
"key",
)?;
let mut value = context.build_load(
super::Pointer::new(
context.word_type(),
Default::default(),
value.into_pointer_value(),
),
"key",
)?;
if !transient {
key = context.build_byte_swap(key)?;
value = context.build_byte_swap(value)?;
}
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
context.build_store(key_pointer, key)?;
context.build_store(value_pointer, value)?;
let is_transient = context.xlen_type().const_int(transient as u64, false);
let arguments = [
is_transient.into(),
key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(),
context.integer_const(crate::polkavm::XLEN, 32).into(),
];
context.build_runtime_call(revive_runtime_api::polkavm_imports::SET_STORAGE, &arguments);
Ok(())
}
@@ -10,12 +10,21 @@ pub fn create_context(
llvm: &inkwell::context::Context,
optimizer_settings: OptimizerSettings,
) -> Context<DummyDependency> {
crate::polkavm::initialize_target();
crate::initialize_llvm(crate::Target::PVM, "resolc", Default::default());
let module = llvm.create_module("test");
let optimizer = Optimizer::new(optimizer_settings);
Context::<DummyDependency>::new(llvm, module, optimizer, None, true, Default::default())
Context::<DummyDependency>::new(
llvm,
module,
optimizer,
None,
true,
Default::default(),
Default::default(),
Default::default(),
)
}
#[test]
+28 -14
View File
@@ -63,7 +63,6 @@ where
let non_overflow_block = context.append_basic_block("shift_left_non_overflow");
let join_block = context.append_basic_block("shift_left_join");
let result_pointer = context.build_alloca(context.word_type(), "shift_left_result_pointer");
let condition_is_overflow = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
shift,
@@ -73,7 +72,6 @@ where
context.build_conditional_branch(condition_is_overflow, overflow_block, non_overflow_block)?;
context.set_basic_block(overflow_block);
context.build_store(result_pointer, context.word_const(0))?;
context.build_unconditional_branch(join_block);
context.set_basic_block(non_overflow_block);
@@ -81,11 +79,17 @@ where
context
.builder()
.build_left_shift(value, shift, "shift_left_non_overflow_result")?;
context.build_store(result_pointer, value)?;
context.build_unconditional_branch(join_block);
context.set_basic_block(join_block);
context.build_load(result_pointer, "shift_left_result")
let result = context
.builder()
.build_phi(context.word_type(), "shift_left_value")?;
result.add_incoming(&[
(&value, non_overflow_block),
(&context.word_const(0), overflow_block),
]);
Ok(result.as_basic_value())
}
/// Translates the bitwise shift right.
@@ -101,7 +105,6 @@ where
let non_overflow_block = context.append_basic_block("shift_right_non_overflow");
let join_block = context.append_basic_block("shift_right_join");
let result_pointer = context.build_alloca(context.word_type(), "shift_right_result_pointer");
let condition_is_overflow = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
shift,
@@ -111,7 +114,6 @@ where
context.build_conditional_branch(condition_is_overflow, overflow_block, non_overflow_block)?;
context.set_basic_block(overflow_block);
context.build_store(result_pointer, context.word_const(0))?;
context.build_unconditional_branch(join_block);
context.set_basic_block(non_overflow_block);
@@ -121,11 +123,17 @@ where
false,
"shift_right_non_overflow_result",
)?;
context.build_store(result_pointer, value)?;
context.build_unconditional_branch(join_block);
context.set_basic_block(join_block);
context.build_load(result_pointer, "shift_right_result")
let result = context
.builder()
.build_phi(context.word_type(), "shift_right_value")?;
result.add_incoming(&[
(&value, non_overflow_block),
(&context.word_const(0), overflow_block),
]);
Ok(result.as_basic_value())
}
/// Translates the arithmetic bitwise shift right.
@@ -145,8 +153,6 @@ where
let non_overflow_block = context.append_basic_block("shift_right_arithmetic_non_overflow");
let join_block = context.append_basic_block("shift_right_arithmetic_join");
let result_pointer =
context.build_alloca(context.word_type(), "shift_right_arithmetic_result_pointer");
let condition_is_overflow = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
shift,
@@ -174,11 +180,9 @@ where
)?;
context.set_basic_block(overflow_positive_block);
context.build_store(result_pointer, context.word_const(0))?;
context.build_unconditional_branch(join_block);
context.set_basic_block(overflow_negative_block);
context.build_store(result_pointer, context.word_type().const_all_ones())?;
context.build_unconditional_branch(join_block);
context.set_basic_block(non_overflow_block);
@@ -188,11 +192,21 @@ where
true,
"shift_right_arithmetic_non_overflow_result",
)?;
context.build_store(result_pointer, value)?;
context.build_unconditional_branch(join_block);
context.set_basic_block(join_block);
context.build_load(result_pointer, "shift_right_arithmetic_result")
let result = context
.builder()
.build_phi(context.word_type(), "shift_arithmetic_right_value")?;
result.add_incoming(&[
(&value, non_overflow_block),
(
&context.word_type().const_all_ones(),
overflow_negative_block,
),
(&context.word_const(0), overflow_block),
]);
Ok(result.as_basic_value())
}
/// Translates the `byte` instruction, extracting the byte of `operand_2`
+16 -16
View File
@@ -2,6 +2,7 @@
use inkwell::values::BasicValue;
use crate::polkavm::context::pointer::Pointer;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
@@ -49,7 +50,9 @@ where
D: Dependency + Clone,
{
let address_type = context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS);
let address_pointer = context.build_alloca_at_entry(address_type, "origin_address");
let address_pointer: Pointer<'_> = context
.get_global(crate::polkavm::GLOBAL_ADDRESS_SPILL_BUFFER)?
.into();
context.build_store(address_pointer, address_type.const_zero())?;
context.build_runtime_call(
revive_runtime_api::polkavm_imports::ORIGIN,
@@ -97,13 +100,13 @@ where
D: Dependency + Clone,
{
let output_pointer = context.build_alloca_at_entry(context.word_type(), "blockhash_out_ptr");
let index_ptr = context.build_alloca_at_entry(context.word_type(), "blockhash_index_ptr");
context.build_store(index_ptr, index)?;
let index_pointer = context.build_alloca_at_entry(context.word_type(), "blockhash_index_ptr");
context.build_store(index_pointer, index)?;
context.build_runtime_call(
revive_runtime_api::polkavm_imports::BLOCK_HASH,
&[
index_ptr.to_int(context).into(),
index_pointer.to_int(context).into(),
output_pointer.to_int(context).into(),
],
);
@@ -127,10 +130,9 @@ pub fn coinbase<'ctx, D>(
where
D: Dependency + Clone,
{
let pointer = context.build_alloca_at_entry(
context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS),
"coinbase_output",
);
let pointer: Pointer<'_> = context
.get_global(crate::polkavm::GLOBAL_ADDRESS_SPILL_BUFFER)?
.into();
context.build_runtime_call(
revive_runtime_api::polkavm_imports::BLOCK_AUTHOR,
&[pointer.to_int(context).into()],
@@ -155,10 +157,9 @@ pub fn address<'ctx, D>(
where
D: Dependency + Clone,
{
let pointer = context.build_alloca_at_entry(
context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS),
"address_output",
);
let pointer: Pointer<'_> = context
.get_global(crate::polkavm::GLOBAL_ADDRESS_SPILL_BUFFER)?
.into();
context.build_runtime_call(
revive_runtime_api::polkavm_imports::ADDRESS,
&[pointer.to_int(context).into()],
@@ -173,10 +174,9 @@ pub fn caller<'ctx, D>(
where
D: Dependency + Clone,
{
let pointer = context.build_alloca_at_entry(
context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS),
"address_output",
);
let pointer: Pointer<'_> = context
.get_global(crate::polkavm::GLOBAL_ADDRESS_SPILL_BUFFER)?
.into();
context.build_runtime_call(
revive_runtime_api::polkavm_imports::CALLER,
&[pointer.to_int(context).into()],
+7 -10
View File
@@ -32,6 +32,7 @@ where
let salt_pointer = match salt {
Some(salt) => {
let salt_pointer = context.build_alloca_at_entry(context.word_type(), "salt_pointer");
let salt = context.build_byte_swap(salt.into())?;
context.build_store(salt_pointer, salt)?;
salt_pointer
}
@@ -118,10 +119,8 @@ where
_ => error,
})?;
if contract_path.as_str() == parent {
return Ok(Argument::new_with_constant(
context.word_const(0).as_basic_value_enum(),
num::BigUint::zero(),
));
return Ok(Argument::value(context.word_const(0).as_basic_value_enum())
.with_constant(num::BigUint::zero()));
} else if identifier.ends_with("_deployed") && code_type == CodeType::Runtime {
anyhow::bail!("type({}).runtimeCode is not supported", identifier);
}
@@ -130,7 +129,7 @@ where
let hash_value = context
.word_const_str_hex(hash_string.as_str())
.as_basic_value_enum();
Ok(Argument::new_with_original(hash_value, hash_string))
Ok(Argument::value(hash_value).with_original(hash_string))
}
/// Translates the deploy call header size instruction. the header consists of
@@ -159,10 +158,8 @@ where
_ => error,
})?;
if contract_path.as_str() == parent {
return Ok(Argument::new_with_constant(
context.word_const(0).as_basic_value_enum(),
num::BigUint::zero(),
));
return Ok(Argument::value(context.word_const(0).as_basic_value_enum())
.with_constant(num::BigUint::zero()));
} else if identifier.ends_with("_deployed") && code_type == CodeType::Runtime {
anyhow::bail!("type({}).runtimeCode is not supported", identifier);
}
@@ -171,5 +168,5 @@ where
let size_value = context
.word_const(crate::polkavm::DEPLOYER_CALL_HEADER_SIZE as u64)
.as_basic_value_enum();
Ok(Argument::new_with_constant(size_value, size_bigint))
Ok(Argument::value(size_value).with_constant(size_bigint))
}
@@ -28,7 +28,7 @@ pub fn value<'ctx, D>(
where
D: Dependency + Clone,
{
let output_pointer = context.build_alloca(context.value_type(), "value_transferred");
let output_pointer = context.build_alloca_at_entry(context.value_type(), "value_transferred");
context.build_store(output_pointer, context.word_const(0))?;
context.build_runtime_call(
revive_runtime_api::polkavm_imports::VALUE_TRANSFERRED,
@@ -46,8 +46,7 @@ where
D: Dependency + Clone,
{
let address_pointer = context.build_address_argument_store(address)?;
let balance_pointer = context.build_alloca(context.word_type(), "balance_pointer");
let balance_pointer = context.build_alloca_at_entry(context.word_type(), "balance_pointer");
let balance = context.builder().build_ptr_to_int(
balance_pointer.value,
context.xlen_type(),
@@ -69,7 +68,7 @@ pub fn self_balance<'ctx, D>(
where
D: Dependency + Clone,
{
let balance_pointer = context.build_alloca(context.word_type(), "balance_pointer");
let balance_pointer = context.build_alloca_at_entry(context.word_type(), "balance_pointer");
let balance = context.builder().build_ptr_to_int(
balance_pointer.value,
context.xlen_type(),
+22 -22
View File
@@ -3,20 +3,23 @@
use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::PolkaVMArgument;
use crate::PolkaVMLoadStorageWordFunction;
use crate::PolkaVMLoadTransientStorageWordFunction;
use crate::PolkaVMStoreStorageWordFunction;
use crate::PolkaVMStoreTransientStorageWordFunction;
/// Translates the storage load.
pub fn load<'ctx, D>(
context: &mut Context<'ctx, D>,
position: inkwell::values::IntValue<'ctx>,
position: &PolkaVMArgument<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let name = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::NAME;
let declaration = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::declaration(context);
let arguments = [context.xlen_type().const_zero().into(), position.into()];
let arguments = [position.as_pointer(context)?.value.into()];
Ok(context
.build_call(declaration, &arguments, "storage_load")
.unwrap_or_else(|| panic!("runtime function {name} should return a value")))
@@ -25,17 +28,16 @@ where
/// Translates the storage store.
pub fn store<'ctx, D>(
context: &mut Context<'ctx, D>,
position: inkwell::values::IntValue<'ctx>,
value: inkwell::values::IntValue<'ctx>,
position: &PolkaVMArgument<'ctx>,
value: &PolkaVMArgument<'ctx>,
) -> anyhow::Result<()>
where
D: Dependency + Clone,
{
let declaration = <PolkaVMStoreStorageWordFunction as RuntimeFunction<D>>::declaration(context);
let arguments = [
context.xlen_type().const_zero().into(),
position.into(),
value.into(),
position.as_pointer(context)?.value.into(),
value.as_pointer(context)?.value.into(),
];
context.build_call(declaration, &arguments, "storage_store");
Ok(())
@@ -44,37 +46,35 @@ where
/// Translates the transient storage load.
pub fn transient_load<'ctx, D>(
context: &mut Context<'ctx, D>,
position: inkwell::values::IntValue<'ctx>,
position: &PolkaVMArgument<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let name = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::NAME;
let declaration = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::declaration(context);
let arguments = [
context.xlen_type().const_int(1, false).into(),
position.into(),
];
let name = <PolkaVMLoadTransientStorageWordFunction as RuntimeFunction<D>>::NAME;
let arguments = [position.as_pointer(context)?.value.into()];
let declaration =
<PolkaVMLoadTransientStorageWordFunction as RuntimeFunction<D>>::declaration(context);
Ok(context
.build_call(declaration, &arguments, "storage_load")
.build_call(declaration, &arguments, "transient_storage_load")
.unwrap_or_else(|| panic!("runtime function {name} should return a value")))
}
/// Translates the transient storage store.
pub fn transient_store<'ctx, D>(
context: &mut Context<'ctx, D>,
position: inkwell::values::IntValue<'ctx>,
value: inkwell::values::IntValue<'ctx>,
position: &PolkaVMArgument<'ctx>,
value: &PolkaVMArgument<'ctx>,
) -> anyhow::Result<()>
where
D: Dependency + Clone,
{
let declaration = <PolkaVMStoreStorageWordFunction as RuntimeFunction<D>>::declaration(context);
let declaration =
<PolkaVMStoreTransientStorageWordFunction as RuntimeFunction<D>>::declaration(context);
let arguments = [
context.xlen_type().const_int(1, false).into(),
position.into(),
value.into(),
position.as_pointer(context)?.value.into(),
value.as_pointer(context)?.value.into(),
];
context.build_call(declaration, &arguments, "storage_store");
context.build_call(declaration, &arguments, "transient_storage_store");
Ok(())
}
+5 -6
View File
@@ -3,11 +3,11 @@
pub mod r#const;
pub mod context;
pub mod evm;
pub mod metadata_hash;
pub use self::r#const::*;
use crate::debug_config::DebugConfig;
use crate::memory::MemoryConfig;
use crate::optimizer::settings::Settings as OptimizerSettings;
use anyhow::Context as AnyhowContext;
@@ -18,11 +18,6 @@ use sha3::Digest;
use self::context::build::Build;
use self::context::Context;
/// Initializes the PolkaVM target machine.
pub fn initialize_target() {
inkwell::targets::Target::initialize_riscv(&Default::default());
}
/// Builds PolkaVM assembly text.
pub fn build_assembly_text(
contract_path: &str,
@@ -95,6 +90,8 @@ pub trait Dependency {
optimizer_settings: OptimizerSettings,
include_metadata_hash: bool,
debug_config: DebugConfig,
llvm_arguments: &[String],
memory_config: MemoryConfig,
) -> anyhow::Result<String>;
/// Resolves a full contract path.
@@ -115,6 +112,8 @@ impl Dependency for DummyDependency {
_optimizer_settings: OptimizerSettings,
_include_metadata_hash: bool,
_debug_config: DebugConfig,
_llvm_arguments: &[String],
_memory_config: MemoryConfig,
) -> anyhow::Result<String> {
Ok(String::new())
}
+9 -2
View File
@@ -10,12 +10,19 @@ description = "Execute revive contracts in a simulated blockchain runtime"
[package.metadata.cargo-machete]
ignored = ["codec", "scale-info"]
[[bin]]
name = "revive-runner"
path = "src/main.rs"
[features]
std = ["polkadot-sdk/std"]
default = ["solidity"]
solidity = ["revive-solidity", "revive-differential"]
solidity = ["revive-solidity", "revive-differential", "revive-llvm-context"]
[dependencies]
env_logger = { workspace = true }
clap = { workspace = true, features = ["help", "std", "derive"] }
anyhow = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
hex = { workspace = true, features = ["serde"] }
@@ -34,4 +41,4 @@ polkadot-sdk.features = [
revive-solidity = { workspace = true, optional = true }
revive-differential = { workspace = true, optional = true }
revive-llvm-context = { workspace = true }
revive-llvm-context = { workspace = true, optional = true }
+26
View File
@@ -0,0 +1,26 @@
# revive-runner
The revive runner is a helper utility aiding in contract debugging.
Given a PVM contract blob, it will upload, deploy and call that contract using a local, stand-alone un-blockchained pallet revive (which is our execution layer).
This is somewhat similar to the geth `evm` utility binary.
## Installation
The `revive-runner` does not depend on the compiler itself, hence installing this utility does not depend on LLVM, so no LLVM build is required.
Inside the root `revive` repository directory, execute:
```bash
make install-revive-runner
```
Which will install the `revive-runner` using `cargo`.
## Usage
Set the `RUST_LOG` environment varibale to the `trace` level to see the full PolkaVM execution trace. For example:
```bash
RUST_LOG=trace revive-runner -f mycontract.pvm -c a9059cbb000000000000000000000000f24ff3a9cf04c71dbc94d0b566f7a27b94566cac0000000000000000000000000000000000000000000000000000000000000000
+93
View File
@@ -0,0 +1,93 @@
use std::path::PathBuf;
use clap::Parser;
use revive_runner::{Code, OptionalHex, Specs, SpecsAction::*, TestAddress};
/// Execute revive PolkaVM contracts locally.
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Arguments {
/// The hex encoded calldata for the contract call.
#[arg(short, long)]
calldata: Option<String>,
/// The hex encoded calldata for the contract deployment.
#[arg(short, long)]
deploy_calldata: Option<String>,
/// The hex encoded contract code blob to instantiate and execute.
#[arg(short, long)]
blob: Option<String>,
/// The contract code to instantiate and execute.
#[arg(short, long)]
file: Option<PathBuf>,
/// The origin account used to initiate the deploy and call transactions.
#[arg(short, long)]
origin: Option<TestAddress>,
/// The value the call transaction is endowed with.
#[arg(short, long)]
value: Option<u128>,
/// The value the deploy transaction is endowed with.
#[arg(long)]
deploy_value: Option<u128>,
}
fn main() -> anyhow::Result<()> {
env_logger::init();
let arguments = Arguments::parse();
let code = match (arguments.blob, arguments.file) {
(Some(blob), None) => hex::decode(blob)
.map_err(|error| anyhow::anyhow!("expected hex encoded PVM blob: {error}"))?,
(None, Some(file)) => std::fs::read(&file).map_err(|error| {
anyhow::anyhow!("unable to read PVM file {}: {error}", file.display())
})?,
_ => anyhow::bail!("should either provide a PVM blob or a PVM file"),
};
let calldata = match arguments.calldata {
Some(calldata) => hex::decode(calldata)
.map_err(|error| anyhow::anyhow!("expected hex encoded calldata: {error}"))?,
None => vec![],
};
let deploy_calldata = match arguments.deploy_calldata {
Some(calldata) => hex::decode(calldata)
.map_err(|error| anyhow::anyhow!("expected hex encoded calldata: {error}"))?,
None => vec![],
};
let origin = arguments.origin.unwrap_or(TestAddress::Alice);
let actions = vec![
Instantiate {
origin: origin.clone(),
value: arguments.deploy_value.unwrap_or(0),
gas_limit: None,
storage_deposit_limit: None,
code: Code::Bytes(code),
data: deploy_calldata,
salt: OptionalHex::default(),
},
Call {
origin,
dest: TestAddress::Instantiated(0),
value: arguments.value.unwrap_or(0),
gas_limit: None,
storage_deposit_limit: None,
data: calldata,
},
];
Specs {
actions,
differential: false,
..Default::default()
}
.run();
Ok(())
}
+40 -8
View File
@@ -1,9 +1,11 @@
use std::time::Instant;
use std::{str::FromStr, time::Instant};
use serde::{Deserialize, Serialize};
use crate::*;
use alloy_primitives::{keccak256, Address};
use alloy_primitives::keccak256;
#[cfg(feature = "revive-solidity")]
use alloy_primitives::Address;
#[cfg(feature = "revive-solidity")]
use revive_differential::{Evm, EvmLog};
#[cfg(feature = "revive-solidity")]
@@ -106,14 +108,10 @@ impl SpecsAction {
};
for (key, expected) in storage {
let mut key = **key;
let mut expected = **expected;
key.reverse();
expected.reverse();
actions.push(Self::VerifyStorage {
contract: account_pvm.clone(),
key,
expected,
key: **key,
expected: **expected,
});
}
@@ -160,6 +158,39 @@ impl TestAddress {
}
}
impl FromStr for TestAddress {
type Err = &'static str;
fn from_str(value: &str) -> Result<Self, Self::Err> {
value.try_into()
}
}
impl TryFrom<&str> for TestAddress {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"alice" => Ok(Self::Alice),
"bob" => Ok(Self::Bob),
"charlie" => Ok(Self::Charlie),
value => {
if let Ok(value) = value.parse() {
return Ok(Self::Instantiated(value));
}
if let Ok(value) = hex::decode(value) {
if value.len() == 20 {
return Ok(Self::AccountId(H160(value.try_into().unwrap())));
}
}
Err("can not parse into test address")
}
}
}
}
/// Specs for a contract test
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
@@ -216,6 +247,7 @@ impl Specs {
/// Helper to allow not specifying the code bytes or path directly in the runner.json
/// - Replace `Code::Bytes(bytes)` if `bytes` are empty: read `contract_file`
/// - Replace `Code::Solidity{ path, ..}` if `path` is not provided: replace `path` with `contract_file`
#[allow(unused_variables)]
pub fn replace_empty_code(&mut self, contract_name: &str, contract_path: &str) {
for action in self.actions.iter_mut() {
let code = match action {
-28
View File
@@ -5,34 +5,6 @@
// Missing builtins
#define EVM_WORD_SIZE 32
#define ALIGN(size) ((size + EVM_WORD_SIZE - 1) & ~(EVM_WORD_SIZE - 1))
#define MAX_MEMORY_SIZE (64 * 1024)
char __memory[MAX_MEMORY_SIZE];
uint32_t __memory_size = 0;
void * __sbrk_internal(uint32_t offset, uint32_t size) {
if (offset >= MAX_MEMORY_SIZE || size > MAX_MEMORY_SIZE) {
POLKAVM_TRAP();
}
uint32_t new_size = ALIGN(offset + size);
if (new_size > MAX_MEMORY_SIZE) {
POLKAVM_TRAP();
}
if (new_size > __memory_size) {
__memory_size = new_size;
}
return (void *)&__memory[offset];
}
void * memset(void *b, int c, size_t len) {
uint8_t *dest = b;
while (len-- > 0) *dest++ = c;
return b;
}
void * memcpy(void *dst, const void *_src, size_t len) {
uint8_t *dest = dst;
const uint8_t *src = _src;
+1 -10
View File
@@ -2,14 +2,6 @@ use inkwell::{context::Context, memory_buffer::MemoryBuffer, module::Module, sup
include!(concat!(env!("OUT_DIR"), "/polkavm_imports.rs"));
/// The emulated EVM heap memory global symbol.
pub static MEMORY: &str = "__memory";
/// The emulated EVM heap memory size global symbol.
pub static MEMORY_SIZE: &str = "__memory_size";
pub static SBRK: &str = "__sbrk_internal";
pub static ADDRESS: &str = "address";
pub static BALANCE: &str = "balance";
@@ -78,8 +70,7 @@ pub static WEIGHT_TO_FEE: &str = "weight_to_fee";
/// All imported runtime API symbols.
/// Useful for configuring common attributes and linkage.
pub static IMPORTS: [&str; 34] = [
SBRK,
pub static IMPORTS: [&str; 33] = [
ADDRESS,
BALANCE,
BALANCE_OF,
+23
View File
@@ -0,0 +1,23 @@
[package]
name = "revive-solc-json-interface"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
rust-version.workspace = true
description = "Rust bindings for the solc standard JSON and combined JSON interface"
[features]
default = ["parallel"]
parallel = ["rayon"]
resolc = [] # The resolc binary adds a bunch of custom fields to the format
[dependencies]
revive-common = { workspace = true }
anyhow = { workspace = true }
rayon = { workspace = true, optional = true }
semver = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
+27
View File
@@ -0,0 +1,27 @@
//! This crates provides (de)serializable Rust types for interacting
//! `solc` via the [JSON-input-output][0] interface.
//!
//! [0]: https://docs.soliditylang.org/en/latest/using-the-compiler.html#compiler-input-and-output-json-description
pub use self::combined_json::contract::Contract as CombinedJsonContract;
pub use self::standard_json::input::language::Language as SolcStandardJsonInputLanguage;
pub use self::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
pub use self::standard_json::input::settings::metadata_hash::MetadataHash as SolcStandardJsonInputSettingsMetadataHash;
pub use self::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
pub use self::standard_json::input::settings::selection::file::flag::Flag as SolcStandardJsonInputSettingsSelectionFileFlag;
pub use self::standard_json::input::settings::selection::file::File as SolcStandardJsonInputSettingsSelectionFile;
pub use self::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
pub use self::standard_json::input::settings::Settings as SolcStandardJsonInputSettings;
pub use self::standard_json::input::source::Source as SolcStandardJsonInputSource;
pub use self::standard_json::input::Input as SolcStandardJsonInput;
pub use self::standard_json::output::contract::evm::bytecode::Bytecode as SolcStandardJsonOutputContractEVMBytecode;
pub use self::standard_json::output::contract::evm::EVM as SolcStandardJsonOutputContractEVM;
pub use self::standard_json::output::contract::Contract as SolcStandardJsonOutputContract;
pub use self::standard_json::output::Output as SolcStandardJsonOutput;
#[cfg(feature = "resolc")]
pub use self::warning::Warning as ResolcWarning;
pub mod combined_json;
pub mod standard_json;
#[cfg(feature = "resolc")]
pub mod warning;
@@ -8,14 +8,15 @@ use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::path::PathBuf;
#[cfg(feature = "parallel")]
#[cfg(all(feature = "parallel", feature = "resolc"))]
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::Deserialize;
use serde::Serialize;
use crate::solc::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
use crate::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
use crate::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
use crate::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
#[cfg(feature = "resolc")]
use crate::warning::Warning;
use self::language::Language;
@@ -33,6 +34,7 @@ pub struct Input {
/// The compiler settings.
pub settings: Settings,
/// The suppressed warnings.
#[cfg(feature = "resolc")]
#[serde(skip_serializing)]
pub suppressed_warnings: Option<Vec<Warning>>,
}
@@ -60,7 +62,7 @@ impl Input {
output_selection: SolcStandardJsonInputSettingsSelection,
optimizer: SolcStandardJsonInputSettingsOptimizer,
metadata: Option<SolcStandardJsonInputSettingsMetadata>,
suppressed_warnings: Option<Vec<Warning>>,
#[cfg(feature = "resolc")] suppressed_warnings: Option<Vec<Warning>>,
) -> anyhow::Result<Self> {
let mut paths: BTreeSet<PathBuf> = paths.iter().cloned().collect();
let libraries = Settings::parse_libraries(library_map)?;
@@ -89,12 +91,14 @@ impl Input {
optimizer,
metadata,
),
#[cfg(feature = "resolc")]
suppressed_warnings,
})
}
/// A shortcut constructor from source code.
/// Only for the integration test purposes.
#[cfg(feature = "resolc")]
#[allow(clippy::too_many_arguments)]
pub fn try_from_sources(
evm_version: Option<revive_common::EVMVersion>,
@@ -3,18 +3,20 @@
use serde::Deserialize;
use serde::Serialize;
use crate::standard_json::input::settings::metadata_hash::MetadataHash;
/// The `solc --standard-json` input settings metadata.
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Metadata {
/// The bytecode hash mode.
#[serde(skip_serializing_if = "Option::is_none")]
pub bytecode_hash: Option<revive_llvm_context::PolkaVMMetadataHash>,
pub bytecode_hash: Option<MetadataHash>,
}
impl Metadata {
/// A shortcut constructor.
pub fn new(bytecode_hash: revive_llvm_context::PolkaVMMetadataHash) -> Self {
pub fn new(bytecode_hash: MetadataHash) -> Self {
Self {
bytecode_hash: Some(bytecode_hash),
}
@@ -1,6 +1,7 @@
//! The `solc --standard-json` input settings.
pub mod metadata;
pub mod metadata_hash;
pub mod optimizer;
pub mod selection;
@@ -49,18 +49,3 @@ impl Optimizer {
};
}
}
impl TryFrom<&Optimizer> for revive_llvm_context::OptimizerSettings {
type Error = anyhow::Error;
fn try_from(value: &Optimizer) -> Result<Self, Self::Error> {
let mut result = match value.mode {
Some(mode) => Self::try_from_cli(mode)?,
None => Self::cycles(),
};
if value.fallback_to_optimizing_for_size.unwrap_or_default() {
result.enable_fallback_to_size();
}
Ok(result)
}
}
@@ -0,0 +1,4 @@
//! The `solc <input>.sol --standard-json` interface input and output.
pub mod input;
pub mod output;
@@ -0,0 +1,71 @@
//! The `solc --standard-json` output.
pub mod contract;
pub mod error;
pub mod source;
use std::collections::BTreeMap;
use serde::Deserialize;
use serde::Serialize;
#[cfg(feature = "resolc")]
use crate::warning::Warning;
use self::contract::Contract;
use self::error::Error as SolcStandardJsonOutputError;
use self::source::Source;
/// The `solc --standard-json` output.
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct Output {
/// The file-contract hashmap.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub contracts: Option<BTreeMap<String, BTreeMap<String, Contract>>>,
/// The source code mapping data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sources: Option<BTreeMap<String, Source>>,
/// The compilation errors and warnings.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub errors: Option<Vec<SolcStandardJsonOutputError>>,
/// The `solc` compiler version.
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
/// The `solc` compiler long version.
#[serde(skip_serializing_if = "Option::is_none")]
pub long_version: Option<String>,
/// The `resolc` compiler version.
#[serde(skip_serializing_if = "Option::is_none")]
pub revive_version: Option<String>,
}
impl Output {
/// Traverses the AST and returns the list of additional errors and warnings.
#[cfg(feature = "resolc")]
pub fn preprocess_ast(&mut self, suppressed_warnings: &[Warning]) -> anyhow::Result<()> {
let sources = match self.sources.as_ref() {
Some(sources) => sources,
None => return Ok(()),
};
let mut messages = Vec::new();
for (path, source) in sources.iter() {
if let Some(ast) = source.ast.as_ref() {
let mut polkavm_messages = Source::get_messages(ast, suppressed_warnings);
for message in polkavm_messages.iter_mut() {
message.push_contract_path(path.as_str());
}
messages.extend(polkavm_messages);
}
}
self.errors = match self.errors.take() {
Some(mut errors) => {
errors.extend(messages);
Some(errors)
}
None => Some(messages),
};
Ok(())
}
}
@@ -3,7 +3,8 @@
use serde::Deserialize;
use serde::Serialize;
use crate::solc::standard_json::output::error::Error as SolcStandardJsonOutputError;
use crate::standard_json::output::error::Error as SolcStandardJsonOutputError;
#[cfg(feature = "resolc")]
use crate::warning::Warning;
/// The `solc --standard-json` output source.
@@ -131,6 +132,7 @@ impl Source {
}
/// Returns the list of messages for some specific parts of the AST.
#[cfg(feature = "resolc")]
pub fn get_messages(
ast: &serde_json::Value,
suppressed_warnings: &[Warning],
@@ -194,7 +196,7 @@ impl Source {
_ => None,
},
)
.last()
.next_back()
.ok_or_else(|| anyhow::anyhow!("The last contract not found in the AST"))
}
}
@@ -1,26 +1,22 @@
//! The compiler warning.
//! `resolc` custom compiler warnings.
//!
//! The revive compiler adds warnings only applicable when compilng
//! to the revive stack on Polkadot to the output.
use std::str::FromStr;
use serde::Deserialize;
use serde::Serialize;
/// The compiler warning.
// The `resolc` custom compiler warning.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Warning {
/// The warning for eponymous feature.
EcRecover,
/// The warning for eponymous feature.
SendTransfer,
/// The warning for eponymous feature.
ExtCodeSize,
/// The warning for eponymous feature.
TxOrigin,
/// The warning for eponymous feature.
BlockTimestamp,
/// The warning for eponymous feature.
BlockNumber,
/// The warning for eponymous feature.
BlockHash,
}
+1
View File
@@ -37,6 +37,7 @@ inkwell = { workspace = true }
revive-common = { workspace = true }
revive-llvm-context = { workspace = true }
revive-solc-json-interface = { workspace = true, features = ["resolc"] }
[target.'cfg(target_env = "musl")'.dependencies]
mimalloc = { version = "*", default-features = false }
+3 -4
View File
@@ -5,12 +5,11 @@ use std::fs::File;
use std::io::Write;
use std::path::Path;
use revive_solc_json_interface::CombinedJsonContract;
use revive_solc_json_interface::SolcStandardJsonOutputContract;
use serde::Deserialize;
use serde::Serialize;
use crate::solc::combined_json::contract::Contract as CombinedJsonContract;
use crate::solc::standard_json::output::contract::Contract as StandardJsonOutputContract;
/// The Solidity contract build.
#[derive(Debug, Serialize, Deserialize)]
pub struct Contract {
@@ -131,7 +130,7 @@ impl Contract {
/// Writes the contract text assembly and bytecode to the standard JSON.
pub fn write_to_standard_json(
self,
standard_json_contract: &mut StandardJsonOutputContract,
standard_json_contract: &mut SolcStandardJsonOutputContract,
) -> anyhow::Result<()> {
standard_json_contract.metadata = Some(self.metadata_json);
+4 -3
View File
@@ -5,8 +5,9 @@ pub mod contract;
use std::collections::BTreeMap;
use std::path::Path;
use crate::solc::combined_json::CombinedJson;
use crate::solc::standard_json::output::Output as StandardJsonOutput;
use revive_solc_json_interface::combined_json::CombinedJson;
use revive_solc_json_interface::SolcStandardJsonOutput;
use crate::solc::version::Version as SolcVersion;
use crate::ResolcVersion;
@@ -66,7 +67,7 @@ impl Build {
/// Writes all contracts assembly and bytecode to the standard JSON.
pub fn write_to_standard_json(
mut self,
standard_json: &mut StandardJsonOutput,
standard_json: &mut SolcStandardJsonOutput,
solc_version: &SolcVersion,
) -> anyhow::Result<()> {
let contracts = match standard_json.contracts.as_mut() {
+69 -31
View File
@@ -7,7 +7,6 @@ pub(crate) mod process;
pub(crate) mod project;
pub(crate) mod solc;
pub(crate) mod version;
pub(crate) mod warning;
pub(crate) mod yul;
pub use self::build::contract::Contract as ContractBuild;
@@ -23,29 +22,16 @@ pub use self::process::Process;
pub use self::project::contract::Contract as ProjectContract;
pub use self::project::Project;
pub use self::r#const::*;
pub use self::solc::combined_json::contract::Contract as SolcCombinedJsonContract;
pub use self::solc::combined_json::CombinedJson as SolcCombinedJson;
#[cfg(not(target_os = "emscripten"))]
pub use self::solc::solc_compiler::SolcCompiler;
#[cfg(target_os = "emscripten")]
pub use self::solc::soljson_compiler::SoljsonCompiler;
pub use self::solc::standard_json::input::language::Language as SolcStandardJsonInputLanguage;
pub use self::solc::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
pub use self::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
pub use self::solc::standard_json::input::settings::selection::file::flag::Flag as SolcStandardJsonInputSettingsSelectionFileFlag;
pub use self::solc::standard_json::input::settings::selection::file::File as SolcStandardJsonInputSettingsSelectionFile;
pub use self::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
pub use self::solc::standard_json::input::settings::Settings as SolcStandardJsonInputSettings;
pub use self::solc::standard_json::input::source::Source as SolcStandardJsonInputSource;
pub use self::solc::standard_json::input::Input as SolcStandardJsonInput;
pub use self::solc::standard_json::output::contract::evm::bytecode::Bytecode as SolcStandardJsonOutputContractEVMBytecode;
pub use self::solc::standard_json::output::contract::evm::EVM as SolcStandardJsonOutputContractEVM;
pub use self::solc::standard_json::output::contract::Contract as SolcStandardJsonOutputContract;
pub use self::solc::standard_json::output::Output as SolcStandardJsonOutput;
pub use self::solc::version::Version as SolcVersion;
pub use self::solc::Compiler;
pub use self::solc::FIRST_SUPPORTED_VERSION as SolcFirstSupportedVersion;
pub use self::solc::LAST_SUPPORTED_VERSION as SolcLastSupportedVersion;
pub use self::version::Version as ResolcVersion;
pub use self::warning::Warning;
#[cfg(not(target_os = "emscripten"))]
pub mod test_utils;
pub mod tests;
@@ -54,6 +40,13 @@ use std::collections::BTreeSet;
use std::io::Write;
use std::path::PathBuf;
use revive_solc_json_interface::standard_json::input::settings::metadata_hash::MetadataHash;
use revive_solc_json_interface::ResolcWarning;
use revive_solc_json_interface::SolcStandardJsonInput;
use revive_solc_json_interface::SolcStandardJsonInputLanguage;
use revive_solc_json_interface::SolcStandardJsonInputSettingsOptimizer;
use revive_solc_json_interface::SolcStandardJsonInputSettingsSelection;
/// Runs the Yul mode.
pub fn yul<T: Compiler>(
input_files: &[PathBuf],
@@ -61,6 +54,8 @@ pub fn yul<T: Compiler>(
optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<Build> {
let path = match input_files.len() {
1 => input_files.first().expect("Always exists"),
@@ -81,7 +76,13 @@ pub fn yul<T: Compiler>(
let solc_validator = Some(&*solc);
let project = Project::try_from_yul_path(path, solc_validator)?;
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?;
let build = project.compile(
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
memory_config,
)?;
Ok(build)
}
@@ -92,6 +93,8 @@ pub fn llvm_ir(
optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<Build> {
let path = match input_files.len() {
1 => input_files.first().expect("Always exists"),
@@ -104,7 +107,13 @@ pub fn llvm_ir(
let project = Project::try_from_llvm_ir_path(path)?;
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?;
let build = project.compile(
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
memory_config,
)?;
Ok(build)
}
@@ -123,8 +132,10 @@ pub fn standard_output<T: Compiler>(
include_paths: Vec<String>,
allow_paths: Option<String>,
remappings: Option<BTreeSet<String>>,
suppressed_warnings: Option<Vec<Warning>>,
suppressed_warnings: Option<Vec<ResolcWarning>>,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<Build> {
let solc_version = solc.version()?;
@@ -152,7 +163,7 @@ pub fn standard_output<T: Compiler>(
.collect();
let libraries = solc_input.settings.libraries.clone().unwrap_or_default();
let mut solc_output = solc.standard_json(solc_input, base_path, include_paths, allow_paths)?;
let solc_output = solc.standard_json(solc_input, base_path, include_paths, allow_paths)?;
if let Some(errors) = solc_output.errors.as_deref() {
let mut has_errors = false;
@@ -170,15 +181,27 @@ pub fn standard_output<T: Compiler>(
}
}
let project =
solc_output.try_to_project(source_code_files, libraries, &solc_version, &debug_config)?;
let project = Project::try_from_standard_json_output(
&solc_output,
source_code_files,
libraries,
&solc_version,
&debug_config,
)?;
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?;
let build = project.compile(
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
memory_config,
)?;
Ok(build)
}
/// Runs the standard JSON mode.
#[allow(clippy::too_many_arguments)]
pub fn standard_json<T: Compiler>(
solc: &mut T,
detect_missing_libraries: bool,
@@ -186,6 +209,8 @@ pub fn standard_json<T: Compiler>(
include_paths: Vec<String>,
allow_paths: Option<String>,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<()> {
let solc_version = solc.version()?;
@@ -200,9 +225,7 @@ pub fn standard_json<T: Compiler>(
revive_llvm_context::OptimizerSettings::try_from(&solc_input.settings.optimizer)?;
let include_metadata_hash = match solc_input.settings.metadata {
Some(ref metadata) => {
metadata.bytecode_hash != Some(revive_llvm_context::PolkaVMMetadataHash::None)
}
Some(ref metadata) => metadata.bytecode_hash != Some(MetadataHash::None),
None => true,
};
@@ -218,14 +241,25 @@ pub fn standard_json<T: Compiler>(
}
}
let project =
solc_output.try_to_project(source_code_files, libraries, &solc_version, &debug_config)?;
let project = Project::try_from_standard_json_output(
&solc_output,
source_code_files,
libraries,
&solc_version,
&debug_config,
)?;
if detect_missing_libraries {
let missing_libraries = project.get_missing_libraries();
missing_libraries.write_to_standard_json(&mut solc_output, &solc_version)?;
} else {
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?;
let build = project.compile(
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
memory_config,
)?;
build.write_to_standard_json(&mut solc_output, &solc_version)?;
}
serde_json::to_writer(std::io::stdout(), &solc_output)?;
@@ -247,10 +281,12 @@ pub fn combined_json<T: Compiler>(
include_paths: Vec<String>,
allow_paths: Option<String>,
remappings: Option<BTreeSet<String>>,
suppressed_warnings: Option<Vec<Warning>>,
suppressed_warnings: Option<Vec<ResolcWarning>>,
debug_config: revive_llvm_context::DebugConfig,
output_directory: Option<PathBuf>,
overwrite: bool,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<()> {
let build = standard_output(
input_files,
@@ -266,6 +302,8 @@ pub fn combined_json<T: Compiler>(
remappings,
suppressed_warnings,
debug_config,
llvm_arguments,
memory_config,
)?;
let mut combined_json = solc.combined_json(input_files, format.as_str())?;
+3 -2
View File
@@ -3,7 +3,8 @@
use std::collections::BTreeMap;
use std::collections::HashSet;
use crate::solc::standard_json::output::Output as StandardJsonOutput;
use revive_solc_json_interface::SolcStandardJsonOutput;
use crate::solc::version::Version as SolcVersion;
use crate::ResolcVersion;
@@ -22,7 +23,7 @@ impl MissingLibraries {
/// Writes the missing libraries to the standard JSON.
pub fn write_to_standard_json(
mut self,
standard_json: &mut StandardJsonOutput,
standard_json: &mut SolcStandardJsonOutput,
solc_version: &SolcVersion,
) -> anyhow::Result<()> {
let contracts = match standard_json.contracts.as_mut() {
+8
View File
@@ -20,6 +20,10 @@ pub struct Input {
pub optimizer_settings: revive_llvm_context::OptimizerSettings,
/// The debug output config.
pub debug_config: revive_llvm_context::DebugConfig,
/// The extra LLVM arguments give used for manual control.
pub llvm_arguments: Vec<String>,
/// The PVM memory configuration.
pub memory_config: revive_llvm_context::MemoryConfig,
}
impl Input {
@@ -30,6 +34,8 @@ impl Input {
include_metadata_hash: bool,
optimizer_settings: revive_llvm_context::OptimizerSettings,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: Vec<String>,
memory_config: revive_llvm_context::MemoryConfig,
) -> Self {
Self {
contract,
@@ -37,6 +43,8 @@ impl Input {
include_metadata_hash,
optimizer_settings,
debug_config,
llvm_arguments,
memory_config,
}
}
}
+9
View File
@@ -37,11 +37,20 @@ pub trait Process {
}
let input: Input = revive_common::deserialize_from_slice(buffer.as_slice())?;
revive_llvm_context::initialize_llvm(
revive_llvm_context::Target::PVM,
crate::DEFAULT_EXECUTABLE_NAME,
&input.llvm_arguments,
);
let result = input.contract.compile(
input.project,
input.optimizer_settings,
input.include_metadata_hash,
input.debug_config,
&input.llvm_arguments,
input.memory_config,
);
match result {
@@ -18,6 +18,8 @@ pub struct Metadata {
pub revive_version: String,
/// The PolkaVM compiler optimizer settings.
pub optimizer_settings: revive_llvm_context::OptimizerSettings,
/// The extra LLVM arguments give used for manual control.
pub llvm_arguments: Vec<String>,
}
impl Metadata {
@@ -27,6 +29,7 @@ impl Metadata {
solc_version: String,
revive_pallet_version: Option<semver::Version>,
optimizer_settings: revive_llvm_context::OptimizerSettings,
llvm_arguments: Vec<String>,
) -> Self {
Self {
solc_metadata,
@@ -34,6 +37,7 @@ impl Metadata {
revive_pallet_version,
revive_version: ResolcVersion::default().long,
optimizer_settings,
llvm_arguments,
}
}
}
@@ -77,6 +77,8 @@ impl Contract {
optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<ContractBuild> {
let llvm = inkwell::context::Context::create();
let optimizer = revive_llvm_context::Optimizer::new(optimizer_settings);
@@ -89,6 +91,7 @@ impl Contract {
version.long.clone(),
version.l2_revision.clone(),
optimizer.settings().to_owned(),
llvm_arguments.to_vec(),
);
let metadata_json = serde_json::to_value(&metadata).expect("Always valid");
let metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_WORD]> = if include_metadata_hash
@@ -120,6 +123,8 @@ impl Contract {
Some(project),
include_metadata_hash,
debug_config,
llvm_arguments,
memory_config,
);
context.set_solidity_data(revive_llvm_context::PolkaVMContextSolidityData::default());
match self.ir {
+72
View File
@@ -9,6 +9,7 @@ use std::path::Path;
#[cfg(feature = "parallel")]
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use revive_solc_json_interface::SolcStandardJsonOutput;
use serde::Deserialize;
use serde::Serialize;
use sha3::Digest;
@@ -65,6 +66,8 @@ impl Project {
optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<Build> {
let project = self.clone();
#[cfg(feature = "parallel")]
@@ -80,6 +83,8 @@ impl Project {
include_metadata_hash,
optimizer_settings.clone(),
debug_config.clone(),
llvm_arguments.to_vec(),
memory_config,
);
let process_output = {
#[cfg(target_os = "emscripten")]
@@ -243,6 +248,69 @@ impl Project {
BTreeMap::new(),
))
}
/// Converts the `solc` JSON output into a convenient project.
pub fn try_from_standard_json_output(
output: &SolcStandardJsonOutput,
source_code_files: BTreeMap<String, String>,
libraries: BTreeMap<String, BTreeMap<String, String>>,
solc_version: &SolcVersion,
debug_config: &revive_llvm_context::DebugConfig,
) -> anyhow::Result<Self> {
let files = match output.contracts.as_ref() {
Some(files) => files,
None => match &output.errors {
Some(errors) if errors.iter().any(|e| e.severity == "error") => {
anyhow::bail!(serde_json::to_string_pretty(errors).expect("Always valid"));
}
_ => &BTreeMap::new(),
},
};
let mut project_contracts = BTreeMap::new();
for (path, contracts) in files.iter() {
for (name, contract) in contracts.iter() {
let full_path = format!("{path}:{name}");
let ir_optimized = match contract.ir_optimized.to_owned() {
Some(ir_optimized) => ir_optimized,
None => continue,
};
if ir_optimized.is_empty() {
continue;
}
debug_config.dump_yul(full_path.as_str(), ir_optimized.as_str())?;
let mut lexer = Lexer::new(ir_optimized.to_owned());
let object = Object::parse(&mut lexer, None).map_err(|error| {
anyhow::anyhow!("Contract `{}` parsing error: {:?}", full_path, error)
})?;
let source = IR::new_yul(ir_optimized.to_owned(), object);
let source_code = source_code_files
.get(path.as_str())
.ok_or_else(|| anyhow::anyhow!("Source code for path `{}` not found", path))?;
let source_hash = sha3::Keccak256::digest(source_code.as_bytes()).into();
let project_contract = Contract::new(
full_path.clone(),
source_hash,
solc_version.to_owned(),
source,
contract.metadata.to_owned(),
);
project_contracts.insert(full_path, project_contract);
}
}
Ok(Project::new(
solc_version.to_owned(),
project_contracts,
libraries,
))
}
}
impl revive_llvm_context::PolkaVMDependency for Project {
@@ -252,6 +320,8 @@ impl revive_llvm_context::PolkaVMDependency for Project {
optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<String> {
let contract_path = project.resolve_path(identifier)?;
let contract = project
@@ -271,6 +341,8 @@ impl revive_llvm_context::PolkaVMDependency for Project {
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
memory_config,
)
.map_err(|error| {
anyhow::anyhow!(
+46
View File
@@ -19,6 +19,10 @@ pub struct Arguments {
#[arg(long = "version")]
pub version: bool,
/// Print supported `solc` versions and exit.
#[arg(long = "supported-solc-versions")]
pub supported_solc_versions: bool,
/// Print the licence and exit.
#[arg(long = "license")]
pub license: bool,
@@ -162,6 +166,42 @@ pub struct Arguments {
#[cfg(debug_assertions)]
#[arg(long = "recursive-process-input")]
pub recursive_process_input: Option<String>,
/// These are passed to LLVM as the command line to allow manual control.
#[arg(long = "llvm-arg")]
pub llvm_arguments: Vec<String>,
/// The emulated EVM linear heap memory static buffer size in bytes.
///
/// Unlike the EVM, due to the lack of dynamic memory metering, PVM contracts emulate
/// the EVM heap memory with a static buffer. Consequentially, instead of infinite
/// memory with exponentially growing gas costs, PVM contracts have a finite amount
/// of memory with constant gas costs available.
///
/// If the contract uses more heap memory than configured, it will compile fine but
/// eventually revert execution at runtime!
///
/// You are incentiviced to keep this value as small as possible:
/// 1.Increasing the heap size will increase startup costs.
/// 2.The heap size contributes to the total memory size a contract can use,
/// which includes the contracts code size
#[arg(long = "heap-size", default_value = "65536")]
pub heap_size: u32,
/// The contracts total stack size in bytes.
///
/// PVM is a register machine with a traditional stack memory space for local
/// variables. This controls the total amount of stack space the contract can use.
///
/// If the contract uses more stack memory than configured, it will compile fine but
/// eventually revert execution at runtime!
///
/// You are incentiviced to keep this value as small as possible:
/// 1.Increasing the heap size will increase startup costs.
/// 2.The stack size contributes to the total memory size a contract can use,
/// which includes the contracts code size
#[arg(long = "stack-size", default_value = "32768")]
pub stack_size: u32,
}
impl Arguments {
@@ -171,6 +211,12 @@ impl Arguments {
anyhow::bail!("No other options are allowed while getting the compiler version.");
}
if self.supported_solc_versions && std::env::args().count() > 2 {
anyhow::bail!(
"No other options are allowed while getting the supported `solc` versions."
);
}
#[cfg(debug_assertions)]
if self.recursive_process_input.is_some() && !self.recursive_process {
anyhow::bail!("--process-input can be only used when --recursive-process is given");
+31 -6
View File
@@ -41,6 +41,16 @@ fn main_inner() -> anyhow::Result<()> {
return Ok(());
}
if arguments.supported_solc_versions {
writeln!(
std::io::stdout(),
">={},<={}",
revive_solidity::SolcFirstSupportedVersion,
revive_solidity::SolcLastSupportedVersion,
)?;
return Ok(());
}
if arguments.license {
let license_mit = include_str!("../../../../LICENSE-MIT");
let license_apache = include_str!("../../../../LICENSE-APACHE");
@@ -54,8 +64,6 @@ fn main_inner() -> anyhow::Result<()> {
.stack_size(RAYON_WORKER_STACK_SIZE)
.build_global()
.expect("Thread pool configuration failure");
inkwell::support::enable_llvm_pretty_stack_trace();
revive_llvm_context::initialize_target(revive_llvm_context::Target::PVM); // TODO: pass from CLI
if arguments.recursive_process {
#[cfg(debug_assertions)]
@@ -94,7 +102,7 @@ fn main_inner() -> anyhow::Result<()> {
let (input_files, remappings) = arguments.split_input_files_and_remappings()?;
let suppressed_warnings = match arguments.suppress_warnings {
Some(warnings) => Some(revive_solidity::Warning::try_from_strings(
Some(warnings) => Some(revive_solc_json_interface::ResolcWarning::try_from_strings(
warnings.as_slice(),
)?),
None => None,
@@ -121,7 +129,7 @@ fn main_inner() -> anyhow::Result<()> {
let mut optimizer_settings = match arguments.optimization {
Some(mode) => revive_llvm_context::OptimizerSettings::try_from_cli(mode)?,
None => revive_llvm_context::OptimizerSettings::cycles(),
None => revive_llvm_context::OptimizerSettings::size(),
};
if arguments.fallback_to_optimizing_for_size {
optimizer_settings.enable_fallback_to_size();
@@ -132,12 +140,19 @@ fn main_inner() -> anyhow::Result<()> {
let include_metadata_hash = match arguments.metadata_hash {
Some(metadata_hash) => {
let metadata =
revive_llvm_context::PolkaVMMetadataHash::from_str(metadata_hash.as_str())?;
metadata != revive_llvm_context::PolkaVMMetadataHash::None
revive_solc_json_interface::SolcStandardJsonInputSettingsMetadataHash::from_str(
metadata_hash.as_str(),
)?;
metadata != revive_solc_json_interface::SolcStandardJsonInputSettingsMetadataHash::None
}
None => true,
};
let memory_config = revive_llvm_context::MemoryConfig {
heap_size: arguments.heap_size,
stack_size: arguments.stack_size,
};
let build = if arguments.yul {
revive_solidity::yul(
input_files.as_slice(),
@@ -145,6 +160,8 @@ fn main_inner() -> anyhow::Result<()> {
optimizer_settings,
include_metadata_hash,
debug_config,
&arguments.llvm_arguments,
memory_config,
)
} else if arguments.llvm_ir {
revive_solidity::llvm_ir(
@@ -152,6 +169,8 @@ fn main_inner() -> anyhow::Result<()> {
optimizer_settings,
include_metadata_hash,
debug_config,
&arguments.llvm_arguments,
memory_config,
)
} else if arguments.standard_json {
revive_solidity::standard_json(
@@ -161,6 +180,8 @@ fn main_inner() -> anyhow::Result<()> {
arguments.include_paths,
arguments.allow_paths,
debug_config,
&arguments.llvm_arguments,
memory_config,
)?;
return Ok(());
} else if let Some(format) = arguments.combined_json {
@@ -181,6 +202,8 @@ fn main_inner() -> anyhow::Result<()> {
debug_config,
arguments.output_directory,
arguments.overwrite,
&arguments.llvm_arguments,
memory_config,
)?;
return Ok(());
} else {
@@ -198,6 +221,8 @@ fn main_inner() -> anyhow::Result<()> {
remappings,
suppressed_warnings,
debug_config,
&arguments.llvm_arguments,
memory_config,
)
}?;
+7 -8
View File
@@ -1,26 +1,25 @@
//! The Solidity compiler.
pub mod combined_json;
#[cfg(not(target_os = "emscripten"))]
pub mod solc_compiler;
#[cfg(target_os = "emscripten")]
pub mod soljson_compiler;
pub mod standard_json;
pub mod version;
use std::path::Path;
use std::path::PathBuf;
use self::combined_json::CombinedJson;
use self::standard_json::input::Input as StandardJsonInput;
use self::standard_json::output::Output as StandardJsonOutput;
use revive_solc_json_interface::combined_json::CombinedJson;
use revive_solc_json_interface::SolcStandardJsonInput;
use revive_solc_json_interface::SolcStandardJsonOutput;
use self::version::Version;
/// The first version of `solc` with the support of standard JSON interface.
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0);
/// The last supported version of `solc`.
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 28);
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 29);
/// `--include-path` was introduced in solc `0.8.8` <https://github.com/ethereum/solidity/releases/tag/v0.8.8>
pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8);
@@ -30,11 +29,11 @@ pub trait Compiler {
/// Compiles the Solidity `--standard-json` input into Yul IR.
fn standard_json(
&mut self,
input: StandardJsonInput,
input: SolcStandardJsonInput,
base_path: Option<String>,
include_paths: Vec<String>,
allow_paths: Option<String>,
) -> anyhow::Result<StandardJsonOutput>;
) -> anyhow::Result<SolcStandardJsonOutput>;
/// The `solc --combined-json abi,hashes...` mirror.
fn combined_json(
+7 -6
View File
@@ -4,9 +4,10 @@ use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use crate::solc::combined_json::CombinedJson;
use crate::solc::standard_json::input::Input as StandardJsonInput;
use crate::solc::standard_json::output::Output as StandardJsonOutput;
use revive_solc_json_interface::combined_json::CombinedJson;
use revive_solc_json_interface::SolcStandardJsonInput;
use revive_solc_json_interface::SolcStandardJsonOutput;
use crate::solc::version::Version;
use super::Compiler;
@@ -39,11 +40,11 @@ impl Compiler for SolcCompiler {
/// Compiles the Solidity `--standard-json` input into Yul IR.
fn standard_json(
&mut self,
mut input: StandardJsonInput,
mut input: SolcStandardJsonInput,
base_path: Option<String>,
include_paths: Vec<String>,
allow_paths: Option<String>,
) -> anyhow::Result<StandardJsonOutput> {
) -> anyhow::Result<SolcStandardJsonOutput> {
let version = self.version()?.validate(&include_paths)?.default;
let mut command = std::process::Command::new(self.executable.as_str());
@@ -93,7 +94,7 @@ impl Compiler for SolcCompiler {
);
}
let mut output: StandardJsonOutput =
let mut output: SolcStandardJsonOutput =
revive_common::deserialize_from_slice(output.stdout.as_slice()).map_err(|error| {
anyhow::anyhow!(
"{} subprocess output parsing error: {}\n{}",

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