mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 19:11:04 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 454108d1f1 | |||
| 698e4c7812 |
@@ -1,38 +0,0 @@
|
|||||||
name: Build revive-debian
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
REVIVE_DEBIAN_PACKAGE: revive-debian-x86
|
|
||||||
DEBIAN_CONTAINER: revive-builder-debian-x86
|
|
||||||
DEBIAN_CONTAINER_BUILDER: build-debian-builder.sh
|
|
||||||
DEBIAN_CONTAINER_RUNNER: run-debian-builder.sh
|
|
||||||
REVIVE_DEBIAN_INSTALL: ${{ github.workspace }}/target/release
|
|
||||||
REVIVE_DEBIAN_BINARY: resolc
|
|
||||||
RUST_VERSION: "1.80"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-revive-debian-x86:
|
|
||||||
name: debian-container-x86
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: build-container
|
|
||||||
run: |
|
|
||||||
(cd utils && ./${{ env.DEBIAN_CONTAINER_BUILDER}} --build-arg RUST_VERSION=${{ env.RUST_VERSION}} . )
|
|
||||||
|
|
||||||
- name: build-revive-debian
|
|
||||||
run: |
|
|
||||||
rustup show
|
|
||||||
cargo --version
|
|
||||||
rustup +nightly show
|
|
||||||
cargo +nightly --version
|
|
||||||
bash --version
|
|
||||||
utils/${{ env.DEBIAN_CONTAINER_RUNNER }} utils/build-revive.sh -o ${{ env.REVIVE_DEBIAN_INSTALL}}
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ env.REVIVE_DEBIAN_PACKAGE }}
|
|
||||||
path: ${{ env.REVIVE_DEBIAN_INSTALL }}/${{ env.REVIVE_DEBIAN_BINARY }}
|
|
||||||
retention-days: 1
|
|
||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
- name: Install solc
|
- name: Install solc
|
||||||
run: |
|
run: |
|
||||||
mkdir -p solc
|
mkdir -p solc
|
||||||
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.27/solc-static-linux
|
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.26/solc-static-linux
|
||||||
chmod +x solc/solc
|
chmod +x solc/solc
|
||||||
echo "$(pwd)/solc/" >> $GITHUB_PATH
|
echo "$(pwd)/solc/" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
|||||||
Generated
+673
-784
File diff suppressed because it is too large
Load Diff
+2
-3
@@ -10,8 +10,7 @@ authors = [
|
|||||||
]
|
]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/paritytech/revive"
|
repository = "https://github.com/xermicus/revive"
|
||||||
rust-version = "1.80.0"
|
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
revive-benchmarks = { version = "0.1.0", path = "crates/benchmarks" }
|
revive-benchmarks = { version = "0.1.0", path = "crates/benchmarks" }
|
||||||
@@ -67,7 +66,7 @@ log = { version = "0.4" }
|
|||||||
# polkadot-sdk and friends
|
# polkadot-sdk and friends
|
||||||
codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
|
codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
|
||||||
scale-info = { version = "2.11.1", default-features = false }
|
scale-info = { version = "2.11.1", default-features = false }
|
||||||
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c77095f51119d2eccdc54d2f3518bed0ffbd6d53" }
|
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", branch = "pg/repro" }
|
||||||
|
|
||||||
# llvm
|
# llvm
|
||||||
[workspace.dependencies.inkwell]
|
[workspace.dependencies.inkwell]
|
||||||
|
|||||||
@@ -8,13 +8,6 @@ install-bin:
|
|||||||
install-npm:
|
install-npm:
|
||||||
npm install && npm fund
|
npm install && npm fund
|
||||||
|
|
||||||
# install-revive: Build and install to the directory specified in REVIVE_INSTALL_DIR
|
|
||||||
ifeq ($(origin REVIVE_INSTALL_DIR), undefined)
|
|
||||||
REVIVE_INSTALL_DIR=`pwd`/release/revive-debian
|
|
||||||
endif
|
|
||||||
install-revive:
|
|
||||||
cargo install --path crates/solidity --root $(REVIVE_INSTALL_DIR)
|
|
||||||
|
|
||||||
format:
|
format:
|
||||||
cargo fmt --all --check
|
cargo fmt --all --check
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||

|

|
||||||
|
|
||||||
# revive
|
# revive
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Use this template for reporting issues
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🐛 Bug Report
|
||||||
|
|
||||||
|
#### 📝 Description
|
||||||
|
|
||||||
|
Provide a clear and concise description of the bug.
|
||||||
|
|
||||||
|
#### 🔄 Reproduction Steps
|
||||||
|
|
||||||
|
Steps to reproduce the behaviour
|
||||||
|
|
||||||
|
#### 🤔 Expected Behavior
|
||||||
|
|
||||||
|
Describe what you expected to happen.
|
||||||
|
|
||||||
|
#### 😯 Current Behavior
|
||||||
|
|
||||||
|
Describe what actually happened.
|
||||||
|
|
||||||
|
#### 🖥️ Environment
|
||||||
|
|
||||||
|
Any relevant environment details.
|
||||||
|
|
||||||
|
#### 📋 Additional Context
|
||||||
|
|
||||||
|
Add any other context about the problem here. If applicable, add screenshots to help explain.
|
||||||
|
|
||||||
|
#### 📎 Log Output
|
||||||
|
|
||||||
|
```
|
||||||
|
Paste any relevant log output here.
|
||||||
|
```
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Use this template for requesting features
|
||||||
|
title: ''
|
||||||
|
labels: feat
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🌟 Feature Request
|
||||||
|
|
||||||
|
#### 📝 Description
|
||||||
|
|
||||||
|
Provide a clear and concise description of the feature you'd like to see.
|
||||||
|
|
||||||
|
#### 🤔 Rationale
|
||||||
|
|
||||||
|
Explain why this feature is important and how it benefits the project.
|
||||||
|
|
||||||
|
#### 📋 Additional Context
|
||||||
|
|
||||||
|
Add any other context or information about the feature request here.
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
# What ❔
|
||||||
|
|
||||||
|
<!-- What are the changes this PR brings about? -->
|
||||||
|
<!-- Example: This PR adds a PR template to the repo. -->
|
||||||
|
<!-- (For bigger PRs adding more context is appreciated) -->
|
||||||
|
|
||||||
|
## Why ❔
|
||||||
|
|
||||||
|
<!-- Why are these changes done? What goal do they contribute to? What are the principles behind them? -->
|
||||||
|
<!-- Example: PR templates ensure PR reviewers, observers, and future iterators are in context about the evolution of repos. -->
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!-- Check your PR fulfills the following items. -->
|
||||||
|
<!-- For draft PRs check the boxes as you complete them. -->
|
||||||
|
|
||||||
|
- [ ] PR title corresponds to the body of PR.
|
||||||
|
- [ ] Tests for the changes have been added / updated.
|
||||||
|
- [ ] Documentation comments have been added / updated.
|
||||||
|
- [ ] Code has been formatted via `cargo fmt` and checked with `cargo clippy`.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
name: Cargo license check
|
||||||
|
on: pull_request
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cargo-deny:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: EmbarkStudios/cargo-deny-action@v1
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
name: "Rust CI"
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: cargo build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
- run: cargo build --verbose
|
||||||
|
|
||||||
|
formatting:
|
||||||
|
name: cargo fmt
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
with:
|
||||||
|
components: rustfmt
|
||||||
|
- name: Rustfmt Check
|
||||||
|
uses: actions-rust-lang/rustfmt@v1
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
name: Leaked Secrets Scan
|
||||||
|
on: [pull_request]
|
||||||
|
jobs:
|
||||||
|
TruffleHog:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: TruffleHog OSS
|
||||||
|
uses: trufflesecurity/trufflehog@0c66d30c1f4075cee1aada2e1ab46dabb1b0071a
|
||||||
|
with:
|
||||||
|
path: ./
|
||||||
|
base: ${{ github.event.repository.default_branch }}
|
||||||
|
head: HEAD
|
||||||
|
extra_args: --debug --only-verified
|
||||||
@@ -20,7 +20,7 @@ pub const BIT_LENGTH_ETH_ADDRESS: usize =
|
|||||||
pub const BIT_LENGTH_WORD: usize = crate::byte_length::BYTE_LENGTH_WORD * BIT_LENGTH_BYTE;
|
pub const BIT_LENGTH_WORD: usize = crate::byte_length::BYTE_LENGTH_WORD * BIT_LENGTH_BYTE;
|
||||||
|
|
||||||
/// Bit length of the runtime value type.
|
/// Bit length of the runtime value type.
|
||||||
pub const BIT_LENGTH_VALUE: usize = BIT_LENGTH_WORD;
|
pub const BIT_LENGTH_VALUE: usize = crate::byte_length::BYTE_LENGTH_VALUE * BIT_LENGTH_BYTE;
|
||||||
|
|
||||||
/// Bit length of thre runimte block number type.
|
/// Bit length of thre runimte block number type.
|
||||||
pub const BIT_LENGTH_BLOCK_NUMBER: usize =
|
pub const BIT_LENGTH_BLOCK_NUMBER: usize =
|
||||||
|
|||||||
@@ -6,12 +6,15 @@ pub const BYTE_LENGTH_BYTE: usize = 1;
|
|||||||
/// The x86 word byte-length.
|
/// The x86 word byte-length.
|
||||||
pub const BYTE_LENGTH_X32: usize = 4;
|
pub const BYTE_LENGTH_X32: usize = 4;
|
||||||
|
|
||||||
|
/// Native stack alignment size in bytes
|
||||||
|
#[cfg(not(feature = "riscv-64"))]
|
||||||
|
pub const BYTE_LENGTH_STACK_ALIGN: usize = 4;
|
||||||
|
#[cfg(feature = "riscv-64")]
|
||||||
|
pub const BYTE_LENGTH_STACK_ALIGN: usize = 8;
|
||||||
|
|
||||||
/// The x86_64 word byte-length.
|
/// The x86_64 word byte-length.
|
||||||
pub const BYTE_LENGTH_X64: usize = 8;
|
pub const BYTE_LENGTH_X64: usize = 8;
|
||||||
|
|
||||||
/// EVM native stack alignment size in bytes
|
|
||||||
pub const BYTE_LENGTH_STACK_ALIGN: usize = 32;
|
|
||||||
|
|
||||||
/// The ETH address byte-length.
|
/// The ETH address byte-length.
|
||||||
pub const BYTE_LENGTH_ETH_ADDRESS: usize = 20;
|
pub const BYTE_LENGTH_ETH_ADDRESS: usize = 20;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
//! The revive exit code constants.
|
//!
|
||||||
|
//! The exit code constants.
|
||||||
|
//!
|
||||||
|
|
||||||
/// The common application success exit code.
|
/// The common application success exit code.
|
||||||
pub const EXIT_CODE_SUCCESS: i32 = 0;
|
pub const EXIT_CODE_SUCCESS: i32 = 0;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ pub(crate) mod byte_length;
|
|||||||
pub(crate) mod evm_version;
|
pub(crate) mod evm_version;
|
||||||
pub(crate) mod exit_code;
|
pub(crate) mod exit_code;
|
||||||
pub(crate) mod extension;
|
pub(crate) mod extension;
|
||||||
|
pub(crate) mod polkavm;
|
||||||
pub(crate) mod utils;
|
pub(crate) mod utils;
|
||||||
|
|
||||||
pub use self::base::*;
|
pub use self::base::*;
|
||||||
@@ -14,4 +15,5 @@ pub use self::byte_length::*;
|
|||||||
pub use self::evm_version::EVMVersion;
|
pub use self::evm_version::EVMVersion;
|
||||||
pub use self::exit_code::*;
|
pub use self::exit_code::*;
|
||||||
pub use self::extension::*;
|
pub use self::extension::*;
|
||||||
|
pub use self::polkavm::address::*;
|
||||||
pub use self::utils::*;
|
pub use self::utils::*;
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
//! The PolkaVM address constants.
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_TO_L1: u16 = 0xFFFF;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_PRECOMPILE: u16 = 0xFFFD;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_META: u16 = 0xFFFC;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_MIMIC_CALL: u16 = 0xFFFB;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_SYSTEM_MIMIC_CALL: u16 = 0xFFFA;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_MIMIC_CALL_BYREF: u16 = 0xFFF9;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_SYSTEM_MIMIC_CALL_BYREF: u16 = 0xFFF8;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_RAW_FAR_CALL: u16 = 0xFFF7;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_RAW_FAR_CALL_BYREF: u16 = 0xFFF6;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_SYSTEM_CALL: u16 = 0xFFF5;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_SYSTEM_CALL_BYREF: u16 = 0xFFF4;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_SET_CONTEXT_VALUE_CALL: u16 = 0xFFF3;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_SET_PUBDATA_PRICE: u16 = 0xFFF2;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_INCREMENT_TX_COUNTER: u16 = 0xFFF1;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_GET_GLOBAL_PTR_CALLDATA: u16 = 0xFFF0;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_GET_GLOBAL_CALL_FLAGS: u16 = 0xFFEF;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_GET_GLOBAL_PTR_RETURN_DATA: u16 = 0xFFEE;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_EVENT_INITIALIZE: u16 = 0xFFED;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_EVENT_WRITE: u16 = 0xFFEC;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_CALLDATA: u16 = 0xFFEB;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_RETURN_DATA: u16 = 0xFFEA;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_ADD: u16 = 0xFFE9;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_SHRINK: u16 = 0xFFE8;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_PACK: u16 = 0xFFE7;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_MULTIPLICATION_HIGH_REGISTER: u16 = 0xFFE6;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_GET_GLOBAL_EXTRA_ABI_DATA: u16 = 0xFFE5;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_LOAD: u16 = 0xFFE4;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_COPY: u16 = 0xFFE3;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_SIZE: u16 = 0xFFE2;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_CONST_ARRAY_DECLARE: u16 = 0xFFE1;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_CONST_ARRAY_SET: u16 = 0xFFE0;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_CONST_ARRAY_FINALIZE: u16 = 0xFFDF;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_CONST_ARRAY_GET: u16 = 0xFFDE;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_DECOMMIT: u16 = 0xFFDD;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_DECOMMIT: u16 = 0xFFDC;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_RETURN_FORWARD: u16 = 0xFFDB;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_REVERT_FORWARD: u16 = 0xFFDA;
|
||||||
|
|
||||||
|
/// The corresponding simulation predefined address.
|
||||||
|
pub const POLKAVM_ADDRESS_ACTIVE_PTR_SWAP: u16 = 0xFFD9;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//!
|
||||||
|
//! The PolkaVM constants.
|
||||||
|
//!
|
||||||
|
|
||||||
|
pub mod address;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"chainId": 420420420,
|
"chainId": 1,
|
||||||
"homesteadBlock": 0,
|
"homesteadBlock": 0,
|
||||||
"eip150Block": 0,
|
"eip150Block": 0,
|
||||||
"eip155Block": 0,
|
"eip155Block": 0,
|
||||||
@@ -26,15 +26,5 @@
|
|||||||
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"timestamp": "0x00",
|
"timestamp": "0x00",
|
||||||
"alloc": {
|
"alloc": {}
|
||||||
"0101010101010101010101010101010101010101": {
|
|
||||||
"balance": "1000000000"
|
|
||||||
},
|
|
||||||
"0202020202020202020202020202020202020202": {
|
|
||||||
"balance": "1000000000"
|
|
||||||
},
|
|
||||||
"0303030303030303030303030303030303030303": {
|
|
||||||
"balance": "1000000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -100,9 +100,10 @@ pub struct EvmOutput {
|
|||||||
impl EvmOutput {
|
impl EvmOutput {
|
||||||
/// Return if there was no error found.
|
/// Return if there was no error found.
|
||||||
///
|
///
|
||||||
/// Panics if the gas used is zero as this indicates nothing was run.
|
/// Panics if the gas used is zero as this indicates nothing was run, i.e.
|
||||||
|
/// there was no receiving account but still no error is reported.
|
||||||
pub fn run_success(&self) -> bool {
|
pub fn run_success(&self) -> bool {
|
||||||
assert_ne!(self.gas_used, U256::ZERO, "nothing was executed: {self:?}");
|
assert_ne!(self.gas_used, U256::ZERO, "nothing was executed");
|
||||||
self.error.is_none()
|
self.error.is_none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"Baseline": 912,
|
"Baseline": 878,
|
||||||
"Computation": 4413,
|
"Computation": 4305,
|
||||||
"DivisionArithmetics": 40689,
|
"DivisionArithmetics": 39774,
|
||||||
"ERC20": 54374,
|
"ERC20": 53405,
|
||||||
"Events": 1726,
|
"Events": 1693,
|
||||||
"FibonacciIterative": 3015,
|
"FibonacciIterative": 2917,
|
||||||
"Flipper": 3612,
|
"Flipper": 3570,
|
||||||
"SHA1": 32865
|
"SHA1": 32557
|
||||||
}
|
}
|
||||||
@@ -2,62 +2,19 @@
|
|||||||
|
|
||||||
pragma solidity ^0.8;
|
pragma solidity ^0.8;
|
||||||
|
|
||||||
/* runner.json
|
contract Call {
|
||||||
{
|
|
||||||
"differential": true,
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"Upload": {
|
|
||||||
"code": {
|
|
||||||
"Solidity": {
|
|
||||||
"contract": "Callee"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Instantiate": {
|
|
||||||
"code": {
|
|
||||||
"Solidity": {
|
|
||||||
"contract": "Caller"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
},
|
|
||||||
"value": 123,
|
|
||||||
"data": "1eb16e5b000000000000000000000000d8b934580fce35a11b58c6d73adee468a2833fa8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
},
|
|
||||||
"data": "5a6535fc00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
contract Callee {
|
|
||||||
function echo(bytes memory payload) public pure returns (bytes memory) {
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract Caller {
|
|
||||||
function value_transfer(address payable destination) public payable {
|
function value_transfer(address payable destination) public payable {
|
||||||
destination.transfer(msg.value);
|
destination.transfer(msg.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function call(bytes memory payload) public returns (bytes memory) {
|
function echo(bytes memory payload) public pure returns (bytes memory) {
|
||||||
Callee callee = new Callee();
|
return payload;
|
||||||
return callee.echo(payload);
|
}
|
||||||
|
|
||||||
|
function call(
|
||||||
|
address callee,
|
||||||
|
bytes memory payload
|
||||||
|
) public pure returns (bytes memory) {
|
||||||
|
return Call(callee).echo(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,14 +30,6 @@ pragma solidity ^0.8;
|
|||||||
},
|
},
|
||||||
"data": "fc9c8d39"
|
"data": "fc9c8d39"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
},
|
|
||||||
"data": "3af973b1"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -51,12 +43,4 @@ contract Context {
|
|||||||
function caller() public view returns (address ret) {
|
function caller() public view returns (address ret) {
|
||||||
ret = msg.sender;
|
ret = msg.sender;
|
||||||
}
|
}
|
||||||
|
|
||||||
function chain_id() public view returns (uint) {
|
|
||||||
uint256 id;
|
|
||||||
assembly {
|
|
||||||
id := chainid()
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,13 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
pragma solidity ^0.8;
|
pragma solidity ^0.8.24;
|
||||||
|
|
||||||
/* runner.json
|
|
||||||
{
|
|
||||||
"differential": true,
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"Upload": {
|
|
||||||
"code": {
|
|
||||||
"Solidity": {
|
|
||||||
"contract": "CreateA"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Instantiate": {
|
|
||||||
"code": {
|
|
||||||
"Solidity": {
|
|
||||||
"contract": "CreateB"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
},
|
|
||||||
"value": 10000
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
contract CreateA {
|
contract CreateA {
|
||||||
constructor() payable {}
|
address creator;
|
||||||
|
|
||||||
|
constructor() payable {
|
||||||
|
creator = msg.sender;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract CreateB {
|
contract CreateB {
|
||||||
|
|||||||
@@ -4,32 +4,30 @@ pragma solidity ^0.8.24;
|
|||||||
|
|
||||||
/* runner.json
|
/* runner.json
|
||||||
{
|
{
|
||||||
"differential": true,
|
"actions": [
|
||||||
"actions": [
|
|
||||||
{
|
{
|
||||||
"Instantiate": {
|
"Instantiate": {}
|
||||||
"code": {
|
|
||||||
"Solidity": {
|
|
||||||
"contract": "TestSha3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Call": {
|
"Call": {
|
||||||
"dest": {
|
"dest": {
|
||||||
"Instantiated": 0
|
"Instantiated": 0
|
||||||
},
|
},
|
||||||
"data": "f9fbd5540000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c68656c6c6f20776f726c64210000000000000000000000000000000000000000"
|
"data": "f9fbd5540000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c68656c6c6f20776f726c64210000000000000000000000000000000000000000"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"VerifyCall": {
|
||||||
|
"success": true,
|
||||||
|
"output": "57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
contract TestSha3 {
|
contract TestSha3 {
|
||||||
function test(string memory _pre) external payable returns (bytes32) {
|
function test(string memory _pre) external payable returns (bytes32 hash) {
|
||||||
bytes32 hash = keccak256(bytes(_pre));
|
hash = keccak256(bytes(_pre));
|
||||||
return bytes32(uint(hash) + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,12 @@ pragma solidity ^0.8;
|
|||||||
},
|
},
|
||||||
"data": "4d43bec90000000000000000000000000000000000000000000000000000000000000000"
|
"data": "4d43bec90000000000000000000000000000000000000000000000000000000000000000"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO when pallet_revive accepts Solidity event topics
|
||||||
{
|
{
|
||||||
"Call": {
|
"Call": {
|
||||||
"dest": {
|
"dest": {
|
||||||
@@ -31,8 +36,7 @@ pragma solidity ^0.8;
|
|||||||
"data": "4d43bec9000000000000000000000000000000000000000000000000000000000000007b"
|
"data": "4d43bec9000000000000000000000000000000000000000000000000000000000000007b"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
contract Events {
|
contract Events {
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
pragma solidity ^0.8;
|
|
||||||
|
|
||||||
/* runner.json
|
|
||||||
{
|
|
||||||
"differential": true,
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"Upload": {
|
|
||||||
"code": {
|
|
||||||
"Solidity": {
|
|
||||||
"contract": "Callee"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Instantiate": {
|
|
||||||
"code": {
|
|
||||||
"Solidity": {
|
|
||||||
"contract": "ReturnDataOob"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
contract Callee {
|
|
||||||
function echo(bytes memory payload) public pure returns (bytes memory) {
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract ReturnDataOob {
|
|
||||||
fallback() external {
|
|
||||||
new Callee().echo(hex"1234");
|
|
||||||
assembly {
|
|
||||||
let pos := mload(64)
|
|
||||||
let size := add(returndatasize(), 1)
|
|
||||||
returndatacopy(pos, 0, size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8;
|
|
||||||
|
|
||||||
/* runner.json
|
|
||||||
{
|
|
||||||
"differential": true,
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"Instantiate": {
|
|
||||||
"code": {
|
|
||||||
"Solidity": {
|
|
||||||
"contract": "Transfer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"value": 11
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
},
|
|
||||||
"data": "1c8d16b30000000000000000000000000303030303030303030303030303030303030303000000000000000000000000000000000000000000000000000000000000000a"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
},
|
|
||||||
"data": "fb9e8d0500000000000000000000000003030303030303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000001"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
contract Transfer {
|
|
||||||
constructor() payable {
|
|
||||||
transfer_self(msg.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function address_self() internal view returns (address payable) {
|
|
||||||
return payable(address(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
function transfer_self(uint _amount) public payable {
|
|
||||||
transfer_to(address_self(), _amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
function transfer_to(address payable _dest, uint _amount) public payable {
|
|
||||||
_dest.transfer(_amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ pragma solidity ^0.8;
|
|||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
"Instantiate": {
|
"Instantiate": {
|
||||||
"value": 1024,
|
|
||||||
"code": {
|
"code": {
|
||||||
"Solidity": {
|
"Solidity": {
|
||||||
"contract": "Value"
|
"contract": "Value"
|
||||||
@@ -20,33 +19,18 @@ pragma solidity ^0.8;
|
|||||||
"dest": {
|
"dest": {
|
||||||
"Instantiated": 0
|
"Instantiated": 0
|
||||||
},
|
},
|
||||||
"value": 123,
|
|
||||||
"data": "3fa4f245"
|
"data": "3fa4f245"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"Call": {
|
|
||||||
"dest": {
|
|
||||||
"Instantiated": 0
|
|
||||||
},
|
|
||||||
"data": "52da5fa0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
contract Value {
|
contract Value {
|
||||||
constructor() payable {}
|
|
||||||
|
|
||||||
function value() public payable returns (uint ret) {
|
function value() public payable returns (uint ret) {
|
||||||
ret = msg.value;
|
ret = msg.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function balance_self() public view returns (uint ret) {
|
|
||||||
ret = address(this).balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function balance_of(address _address) public view returns (uint ret) {
|
function balance_of(address _address) public view returns (uint ret) {
|
||||||
ret = _address.balance;
|
ret = _address.balance;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,11 +209,9 @@ case!("Call.sol", "Call", vec![], call_constructor);
|
|||||||
sol!(
|
sol!(
|
||||||
contract Value {
|
contract Value {
|
||||||
function balance_of(address _address) public view returns (uint ret);
|
function balance_of(address _address) public view returns (uint ret);
|
||||||
function balance_self() public view returns (uint ret);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
case!("Value.sol", Value, balance_ofCall, value_balance_of, address: Address);
|
case!("Value.sol", Value, balance_ofCall, value_balance_of, address: Address);
|
||||||
case!("Value.sol", Value, balance_selfCall, value_balance_self,);
|
|
||||||
|
|
||||||
sol!(
|
sol!(
|
||||||
contract Bitwise {
|
contract Bitwise {
|
||||||
|
|||||||
+112
-35
@@ -6,10 +6,6 @@ use SpecsAction::*;
|
|||||||
|
|
||||||
use crate::cases::Contract;
|
use crate::cases::Contract;
|
||||||
|
|
||||||
/// Parameters:
|
|
||||||
/// - The function name of the test
|
|
||||||
/// - The contract name to fill in empty code based on the file path
|
|
||||||
/// - The contract source file
|
|
||||||
macro_rules! test_spec {
|
macro_rules! test_spec {
|
||||||
($test_name:ident, $contract_name:literal, $source_file:literal) => {
|
($test_name:ident, $contract_name:literal, $source_file:literal) => {
|
||||||
#[test]
|
#[test]
|
||||||
@@ -30,6 +26,7 @@ test_spec!(hash_keccak_256, "TestSha3", "Crypto.sol");
|
|||||||
test_spec!(erc20, "ERC20", "ERC20.sol");
|
test_spec!(erc20, "ERC20", "ERC20.sol");
|
||||||
test_spec!(computation, "Computation", "Computation.sol");
|
test_spec!(computation, "Computation", "Computation.sol");
|
||||||
test_spec!(msize, "MSize", "MSize.sol");
|
test_spec!(msize, "MSize", "MSize.sol");
|
||||||
|
test_spec!(transferred_value, "Value", "Value.sol");
|
||||||
test_spec!(sha1, "SHA1", "SHA1.sol");
|
test_spec!(sha1, "SHA1", "SHA1.sol");
|
||||||
test_spec!(block, "Block", "Block.sol");
|
test_spec!(block, "Block", "Block.sol");
|
||||||
test_spec!(mcopy, "MCopy", "MCopy.sol");
|
test_spec!(mcopy, "MCopy", "MCopy.sol");
|
||||||
@@ -37,11 +34,6 @@ test_spec!(events, "Events", "Events.sol");
|
|||||||
test_spec!(storage, "Storage", "Storage.sol");
|
test_spec!(storage, "Storage", "Storage.sol");
|
||||||
test_spec!(mstore8, "MStore8", "MStore8.sol");
|
test_spec!(mstore8, "MStore8", "MStore8.sol");
|
||||||
test_spec!(address, "Context", "Context.sol");
|
test_spec!(address, "Context", "Context.sol");
|
||||||
test_spec!(balance, "Value", "Value.sol");
|
|
||||||
test_spec!(create, "CreateB", "Create.sol");
|
|
||||||
test_spec!(call, "Caller", "Call.sol");
|
|
||||||
test_spec!(transfer, "Transfer", "Transfer.sol");
|
|
||||||
test_spec!(return_data_oob, "ReturnDataOob", "ReturnDataOob.sol");
|
|
||||||
|
|
||||||
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
||||||
vec![Instantiate {
|
vec![Instantiate {
|
||||||
@@ -232,35 +224,12 @@ fn signed_remainder() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// These test were implement for the mock-runtime and need to be ported yet.
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create2_failure() {
|
fn events() {
|
||||||
let mut state = State::default();
|
assert_success(&Contract::event(U256::ZERO), true);
|
||||||
let contract_a = Contract::create_a();
|
assert_success(&Contract::event(U256::from(123)), true);
|
||||||
state.upload_code(&contract_a.pvm_runtime);
|
|
||||||
|
|
||||||
let contract = Contract::create_b();
|
|
||||||
let (state, output) = state
|
|
||||||
.transaction()
|
|
||||||
.with_default_account(&contract.pvm_runtime)
|
|
||||||
.calldata(contract.calldata.clone())
|
|
||||||
.call();
|
|
||||||
|
|
||||||
assert_eq!(output.flags, ReturnFlags::Success);
|
|
||||||
|
|
||||||
// The address already exists, which should cause the contract to revert
|
|
||||||
|
|
||||||
let (_, output) = state
|
|
||||||
.transaction()
|
|
||||||
.with_default_account(&contract.pvm_runtime)
|
|
||||||
.calldata(contract.calldata)
|
|
||||||
.call();
|
|
||||||
|
|
||||||
assert_eq!(output.flags, ReturnFlags::Revert);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn balance() {
|
fn balance() {
|
||||||
let (_, output) = assert_success(&Contract::value_balance_of(Default::default()), false);
|
let (_, output) = assert_success(&Contract::value_balance_of(Default::default()), false);
|
||||||
@@ -286,6 +255,84 @@ fn balance() {
|
|||||||
assert_eq!(expected, received)
|
assert_eq!(expected, received)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create2() {
|
||||||
|
let mut state = State::default();
|
||||||
|
let contract_a = Contract::create_a();
|
||||||
|
state.upload_code(&contract_a.pvm_runtime);
|
||||||
|
|
||||||
|
let contract = Contract::create_b();
|
||||||
|
let (state, output) = state
|
||||||
|
.transaction()
|
||||||
|
.with_default_account(&contract.pvm_runtime)
|
||||||
|
.calldata(contract.calldata)
|
||||||
|
.call();
|
||||||
|
|
||||||
|
assert_eq!(output.flags, ReturnFlags::Success);
|
||||||
|
assert_eq!(state.accounts().len(), 2);
|
||||||
|
|
||||||
|
for address in state.accounts().keys() {
|
||||||
|
if *address != Transaction::default_address() {
|
||||||
|
let derived_address = Transaction::default_address().create2(
|
||||||
|
B256::from(U256::from(1)),
|
||||||
|
keccak256(&contract_a.pvm_runtime).0,
|
||||||
|
);
|
||||||
|
assert_eq!(*address, derived_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create2_failure() {
|
||||||
|
let mut state = State::default();
|
||||||
|
let contract_a = Contract::create_a();
|
||||||
|
state.upload_code(&contract_a.pvm_runtime);
|
||||||
|
|
||||||
|
let contract = Contract::create_b();
|
||||||
|
let (state, output) = state
|
||||||
|
.transaction()
|
||||||
|
.with_default_account(&contract.pvm_runtime)
|
||||||
|
.calldata(contract.calldata.clone())
|
||||||
|
.call();
|
||||||
|
|
||||||
|
assert_eq!(output.flags, ReturnFlags::Success);
|
||||||
|
|
||||||
|
// The address already exists, which should cause the contract to revert
|
||||||
|
|
||||||
|
let (_, output) = state
|
||||||
|
.transaction()
|
||||||
|
.with_default_account(&contract.pvm_runtime)
|
||||||
|
.calldata(contract.calldata)
|
||||||
|
.call();
|
||||||
|
|
||||||
|
assert_eq!(output.flags, ReturnFlags::Revert);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_with_value() {
|
||||||
|
let mut state = State::default();
|
||||||
|
state.upload_code(&Contract::create_a().pvm_runtime);
|
||||||
|
let amount = U256::from(123);
|
||||||
|
|
||||||
|
let contract = Contract::create_b();
|
||||||
|
let (state, output) = state
|
||||||
|
.transaction()
|
||||||
|
.with_default_account(&contract.pvm_runtime)
|
||||||
|
.callvalue(amount)
|
||||||
|
.call();
|
||||||
|
|
||||||
|
assert_eq!(output.flags, ReturnFlags::Success);
|
||||||
|
assert_eq!(state.accounts().len(), 2);
|
||||||
|
|
||||||
|
for (address, account) in state.accounts() {
|
||||||
|
if *address == Transaction::default_address() {
|
||||||
|
assert_eq!(account.value, U256::ZERO);
|
||||||
|
} else {
|
||||||
|
assert_eq!(account.value, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ext_code_size() {
|
fn ext_code_size() {
|
||||||
let contract = Contract::ext_code_size(Transaction::default_address());
|
let contract = Contract::ext_code_size(Transaction::default_address());
|
||||||
@@ -309,4 +356,34 @@ fn code_size() {
|
|||||||
let received = U256::from_be_slice(&output.data);
|
let received = U256::from_be_slice(&output.data);
|
||||||
assert_eq!(expected, received);
|
assert_eq!(expected, received);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn value_transfer() {
|
||||||
|
// Succeeds in remix (shanghai) but traps the interpreter
|
||||||
|
let (state, _) = assert_success(&Contract::call_value_transfer(Default::default()), false);
|
||||||
|
|
||||||
|
assert_eq!(state.accounts().len(), 2);
|
||||||
|
assert!(state.accounts().get(&Address::default()).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn echo() {
|
||||||
|
let (state, address) = State::new_deployed(Contract::call_constructor());
|
||||||
|
|
||||||
|
let expected = vec![1, 2, 3, 4, 5];
|
||||||
|
let contract = Contract::call_call(address, expected.clone());
|
||||||
|
let (_, output) = state
|
||||||
|
.transaction()
|
||||||
|
.with_default_account(&contract.pvm_runtime)
|
||||||
|
.calldata(contract.calldata)
|
||||||
|
.call();
|
||||||
|
|
||||||
|
assert_eq!(output.flags, ReturnFlags::Success);
|
||||||
|
|
||||||
|
let received = alloy_primitives::Bytes::abi_decode(&output.data, true)
|
||||||
|
.unwrap()
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
|
assert_eq!(expected, received);
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ fn invoke_lld(cmd_args: &[&str]) -> bool {
|
|||||||
fn polkavm_linker<T: AsRef<[u8]>>(code: T) -> anyhow::Result<Vec<u8>> {
|
fn polkavm_linker<T: AsRef<[u8]>>(code: T) -> anyhow::Result<Vec<u8>> {
|
||||||
let mut config = polkavm_linker::Config::default();
|
let mut config = polkavm_linker::Config::default();
|
||||||
config.set_strip(true);
|
config.set_strip(true);
|
||||||
config.set_optimize(true);
|
|
||||||
|
|
||||||
polkavm_linker::program_from_elf(config, code.as_ref())
|
polkavm_linker::program_from_elf(config, code.as_ref())
|
||||||
.map_err(|reason| anyhow::anyhow!("polkavm linker failed: {}", reason))
|
.map_err(|reason| anyhow::anyhow!("polkavm linker failed: {}", reason))
|
||||||
|
|||||||
@@ -21,15 +21,33 @@ pub static GLOBAL_CALLDATA_POINTER: &str = "ptr_calldata";
|
|||||||
/// The calldata size global variable name.
|
/// The calldata size global variable name.
|
||||||
pub static GLOBAL_CALLDATA_SIZE: &str = "calldatasize";
|
pub static GLOBAL_CALLDATA_SIZE: &str = "calldatasize";
|
||||||
|
|
||||||
|
/// The return data pointer global variable name.
|
||||||
|
pub static GLOBAL_RETURN_DATA_POINTER: &str = "ptr_return_data";
|
||||||
|
|
||||||
|
/// The return data size pointer global variable name.
|
||||||
|
pub static GLOBAL_RETURN_DATA_SIZE: &str = "returndatasize";
|
||||||
|
|
||||||
/// The call flags global variable name.
|
/// The call flags global variable name.
|
||||||
pub static GLOBAL_CALL_FLAGS: &str = "call_flags";
|
pub static GLOBAL_CALL_FLAGS: &str = "call_flags";
|
||||||
|
|
||||||
|
/// The extra ABI data global variable name.
|
||||||
|
pub static GLOBAL_EXTRA_ABI_DATA: &str = "extra_abi_data";
|
||||||
|
|
||||||
/// The constant array global variable name prefix.
|
/// The constant array global variable name prefix.
|
||||||
pub static GLOBAL_CONST_ARRAY_PREFIX: &str = "const_array_";
|
pub static GLOBAL_CONST_ARRAY_PREFIX: &str = "const_array_";
|
||||||
|
|
||||||
/// The global verbatim getter identifier prefix.
|
/// The global verbatim getter identifier prefix.
|
||||||
pub static GLOBAL_VERBATIM_GETTER_PREFIX: &str = "get_global::";
|
pub static GLOBAL_VERBATIM_GETTER_PREFIX: &str = "get_global::";
|
||||||
|
|
||||||
|
/// The static word size.
|
||||||
|
pub static GLOBAL_I256_SIZE: &str = "i256_size";
|
||||||
|
|
||||||
|
/// The static value size.
|
||||||
|
pub static GLOBAL_I160_SIZE: &str = "i160_size";
|
||||||
|
|
||||||
|
/// The static i64 size.
|
||||||
|
pub static GLOBAL_I64_SIZE: &str = "i64_size";
|
||||||
|
|
||||||
/// The external call data offset in the auxiliary heap.
|
/// The external call data offset in the auxiliary heap.
|
||||||
pub const HEAP_AUX_OFFSET_EXTERNAL_CALL: u64 = 0;
|
pub const HEAP_AUX_OFFSET_EXTERNAL_CALL: u64 = 0;
|
||||||
|
|
||||||
@@ -37,6 +55,9 @@ pub const HEAP_AUX_OFFSET_EXTERNAL_CALL: u64 = 0;
|
|||||||
pub const HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA: u64 =
|
pub const HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA: u64 =
|
||||||
8 * (revive_common::BYTE_LENGTH_WORD as u64);
|
8 * (revive_common::BYTE_LENGTH_WORD as u64);
|
||||||
|
|
||||||
|
/// The number of the extra ABI data arguments.
|
||||||
|
pub const EXTRA_ABI_DATA_SIZE: usize = 0;
|
||||||
|
|
||||||
/// The `create` method deployer signature.
|
/// The `create` method deployer signature.
|
||||||
pub static DEPLOYER_SIGNATURE_CREATE: &str = "create(bytes32,bytes32,bytes)";
|
pub static DEPLOYER_SIGNATURE_CREATE: &str = "create(bytes32,bytes32,bytes)";
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ pub mod imports {
|
|||||||
|
|
||||||
pub static BLOCK_NUMBER: &str = "block_number";
|
pub static BLOCK_NUMBER: &str = "block_number";
|
||||||
|
|
||||||
pub static CHAIN_ID: &str = "chain_id";
|
|
||||||
|
|
||||||
pub static CALL: &str = "call";
|
pub static CALL: &str = "call";
|
||||||
|
|
||||||
pub static CALLER: &str = "caller";
|
pub static CALLER: &str = "caller";
|
||||||
@@ -41,9 +39,7 @@ pub mod imports {
|
|||||||
|
|
||||||
pub static RETURN: &str = "seal_return";
|
pub static RETURN: &str = "seal_return";
|
||||||
|
|
||||||
pub static RETURNDATACOPY: &str = "return_data_copy";
|
pub static RETURNDATACOPY: &str = "returndatacopy";
|
||||||
|
|
||||||
pub static RETURNDATASIZE: &str = "return_data_size";
|
|
||||||
|
|
||||||
pub static SET_STORAGE: &str = "set_storage";
|
pub static SET_STORAGE: &str = "set_storage";
|
||||||
|
|
||||||
@@ -51,13 +47,12 @@ pub mod imports {
|
|||||||
|
|
||||||
/// All imported runtime API symbols.
|
/// All imported runtime API symbols.
|
||||||
/// Useful for configuring common attributes and linkage.
|
/// Useful for configuring common attributes and linkage.
|
||||||
pub static IMPORTS: [&str; 18] = [
|
pub static IMPORTS: [&str; 16] = [
|
||||||
ADDRESS,
|
ADDRESS,
|
||||||
BALANCE,
|
BALANCE,
|
||||||
BLOCK_NUMBER,
|
BLOCK_NUMBER,
|
||||||
CALL,
|
CALL,
|
||||||
CALLER,
|
CALLER,
|
||||||
CHAIN_ID,
|
|
||||||
CODE_SIZE,
|
CODE_SIZE,
|
||||||
DEPOSIT_EVENT,
|
DEPOSIT_EVENT,
|
||||||
GET_STORAGE,
|
GET_STORAGE,
|
||||||
@@ -67,7 +62,6 @@ pub mod imports {
|
|||||||
NOW,
|
NOW,
|
||||||
RETURN,
|
RETURN,
|
||||||
RETURNDATACOPY,
|
RETURNDATACOPY,
|
||||||
RETURNDATASIZE,
|
|
||||||
SET_STORAGE,
|
SET_STORAGE,
|
||||||
VALUE_TRANSFERRED,
|
VALUE_TRANSFERRED,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! The entry function.
|
//! The entry function.
|
||||||
|
|
||||||
use inkwell::types::BasicType;
|
use inkwell::types::BasicType;
|
||||||
|
use inkwell::values::BasicValue;
|
||||||
|
|
||||||
use crate::polkavm::context::address_space::AddressSpace;
|
use crate::polkavm::context::address_space::AddressSpace;
|
||||||
use crate::polkavm::context::function::runtime;
|
use crate::polkavm::context::function::runtime;
|
||||||
@@ -22,8 +23,11 @@ impl Entry {
|
|||||||
/// The number of mandatory arguments.
|
/// The number of mandatory arguments.
|
||||||
pub const MANDATORY_ARGUMENTS_COUNT: usize = 2;
|
pub const MANDATORY_ARGUMENTS_COUNT: usize = 2;
|
||||||
|
|
||||||
/// Reserve 1kb for calldata.
|
/// Reserve 1mb for calldata.
|
||||||
pub const MAX_CALLDATA_SIZE: usize = 1024;
|
pub const MAX_CALLDATA_SIZE: usize = 1024 * 1024;
|
||||||
|
|
||||||
|
/// Reserve 1mb for returndata.
|
||||||
|
pub const MAX_RETURNDATA_SIZE: usize = 1024 * 1024;
|
||||||
|
|
||||||
/// Initializes the global variables.
|
/// Initializes the global variables.
|
||||||
/// The pointers are not initialized, because it's not possible to create a null pointer.
|
/// The pointers are not initialized, because it's not possible to create a null pointer.
|
||||||
@@ -39,6 +43,14 @@ impl Entry {
|
|||||||
calldata_type.get_undef(),
|
calldata_type.get_undef(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let returndata_type = context.array_type(context.byte_type(), Self::MAX_RETURNDATA_SIZE);
|
||||||
|
context.set_global(
|
||||||
|
crate::polkavm::GLOBAL_RETURN_DATA_POINTER,
|
||||||
|
returndata_type,
|
||||||
|
AddressSpace::Stack,
|
||||||
|
returndata_type.get_undef(),
|
||||||
|
);
|
||||||
|
|
||||||
context.set_global(
|
context.set_global(
|
||||||
crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER,
|
crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER,
|
||||||
context.llvm().ptr_type(AddressSpace::Heap.into()),
|
context.llvm().ptr_type(AddressSpace::Heap.into()),
|
||||||
@@ -58,6 +70,12 @@ impl Entry {
|
|||||||
AddressSpace::Stack,
|
AddressSpace::Stack,
|
||||||
context.word_undef(),
|
context.word_undef(),
|
||||||
);
|
);
|
||||||
|
context.set_global(
|
||||||
|
crate::polkavm::GLOBAL_RETURN_DATA_SIZE,
|
||||||
|
context.xlen_type(),
|
||||||
|
AddressSpace::Stack,
|
||||||
|
context.xlen_type().const_zero().as_basic_value_enum(),
|
||||||
|
);
|
||||||
|
|
||||||
context.set_global(
|
context.set_global(
|
||||||
crate::polkavm::GLOBAL_CALL_FLAGS,
|
crate::polkavm::GLOBAL_CALL_FLAGS,
|
||||||
@@ -66,6 +84,44 @@ impl Entry {
|
|||||||
context.word_const(0),
|
context.word_const(0),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let extra_abi_data_type = context.array_type(
|
||||||
|
context.word_type().as_basic_type_enum(),
|
||||||
|
crate::polkavm::EXTRA_ABI_DATA_SIZE,
|
||||||
|
);
|
||||||
|
context.set_global(
|
||||||
|
crate::polkavm::GLOBAL_EXTRA_ABI_DATA,
|
||||||
|
extra_abi_data_type,
|
||||||
|
AddressSpace::Stack,
|
||||||
|
extra_abi_data_type.const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
context.set_global(
|
||||||
|
crate::polkavm::GLOBAL_I256_SIZE,
|
||||||
|
context.xlen_type(),
|
||||||
|
AddressSpace::Stack,
|
||||||
|
context.integer_const(
|
||||||
|
crate::polkavm::XLEN,
|
||||||
|
revive_common::BYTE_LENGTH_X64 as u64 * 4,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
context.set_global(
|
||||||
|
crate::polkavm::GLOBAL_I160_SIZE,
|
||||||
|
context.xlen_type(),
|
||||||
|
AddressSpace::Stack,
|
||||||
|
context.integer_const(
|
||||||
|
crate::polkavm::XLEN,
|
||||||
|
revive_common::BYTE_LENGTH_X64 as u64 * 2 + revive_common::BYTE_LENGTH_X32 as u64,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
context.set_global(
|
||||||
|
crate::polkavm::GLOBAL_I64_SIZE,
|
||||||
|
context.xlen_type(),
|
||||||
|
AddressSpace::Stack,
|
||||||
|
context.integer_const(crate::polkavm::XLEN, revive_common::BYTE_LENGTH_X64 as u64),
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +141,7 @@ impl Entry {
|
|||||||
"input_pointer_casted",
|
"input_pointer_casted",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let length_pointer = context.build_alloca_at_entry(context.xlen_type(), "len_ptr");
|
let length_pointer = context.build_alloca(context.xlen_type(), "len_ptr");
|
||||||
let length_pointer_casted = context.builder.build_ptr_to_int(
|
let length_pointer_casted = context.builder.build_ptr_to_int(
|
||||||
length_pointer.value,
|
length_pointer.value,
|
||||||
context.xlen_type(),
|
context.xlen_type(),
|
||||||
|
|||||||
@@ -595,53 +595,59 @@ where
|
|||||||
self.builder.get_insert_block().expect("Always exists")
|
self.builder.get_insert_block().expect("Always exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds an aligned stack allocation at the function entry.
|
/// Builds a stack allocation instruction.
|
||||||
pub fn build_alloca_at_entry<T: BasicType<'ctx> + Clone + Copy>(
|
/// Sets the alignment to 128 bits.
|
||||||
&self,
|
|
||||||
r#type: T,
|
|
||||||
name: &str,
|
|
||||||
) -> Pointer<'ctx> {
|
|
||||||
let current_block = self.basic_block();
|
|
||||||
let entry_block = self.current_function().borrow().entry_block();
|
|
||||||
|
|
||||||
match entry_block.get_first_instruction() {
|
|
||||||
Some(instruction) => self.builder().position_before(&instruction),
|
|
||||||
None => self.builder().position_at_end(entry_block),
|
|
||||||
}
|
|
||||||
|
|
||||||
let pointer = self.build_alloca(r#type, name);
|
|
||||||
self.set_basic_block(current_block);
|
|
||||||
pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds an aligned stack allocation at the current position.
|
|
||||||
/// Use this if [`build_alloca_at_entry`] might change program semantics.
|
|
||||||
/// Otherwise, alloca should always be built at the function prelude!
|
|
||||||
pub fn build_alloca<T: BasicType<'ctx> + Clone + Copy>(
|
pub fn build_alloca<T: BasicType<'ctx> + Clone + Copy>(
|
||||||
&self,
|
&self,
|
||||||
r#type: T,
|
r#type: T,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Pointer<'ctx> {
|
) -> Pointer<'ctx> {
|
||||||
let pointer = self.builder.build_alloca(r#type, name).unwrap();
|
let pointer = self.builder.build_alloca(r#type, name).unwrap();
|
||||||
pointer
|
self.basic_block()
|
||||||
.as_instruction()
|
.get_last_instruction()
|
||||||
.unwrap()
|
.expect("Always exists")
|
||||||
.set_alignment(revive_common::BYTE_LENGTH_STACK_ALIGN as u32)
|
.set_alignment(revive_common::BYTE_LENGTH_STACK_ALIGN as u32)
|
||||||
.expect("Alignment is valid");
|
.expect("Alignment is valid");
|
||||||
|
|
||||||
Pointer::new(r#type, AddressSpace::Stack, pointer)
|
Pointer::new(r#type, AddressSpace::Stack, pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load the address at given pointer and zero extend it to the VM word size.
|
/// Allocate an int of size `bit_length` on the stack.
|
||||||
pub fn build_load_address(
|
/// Returns the allocation pointer and the length pointer.
|
||||||
|
///
|
||||||
|
/// Useful helper for passing runtime API parameters on the stack.
|
||||||
|
pub fn build_stack_parameter(
|
||||||
|
&self,
|
||||||
|
bit_length: usize,
|
||||||
|
name: &str,
|
||||||
|
) -> (Pointer<'ctx>, Pointer<'ctx>) {
|
||||||
|
let buffer_pointer = self.build_alloca(self.integer_type(bit_length), name);
|
||||||
|
let symbol = match bit_length {
|
||||||
|
revive_common::BIT_LENGTH_WORD => GLOBAL_I256_SIZE,
|
||||||
|
revive_common::BIT_LENGTH_ETH_ADDRESS => GLOBAL_I160_SIZE,
|
||||||
|
revive_common::BIT_LENGTH_BLOCK_NUMBER => GLOBAL_I64_SIZE,
|
||||||
|
_ => panic!("invalid stack parameter bit width: {bit_length}"),
|
||||||
|
};
|
||||||
|
let length_pointer = self.get_global(symbol).expect("should be declared");
|
||||||
|
(buffer_pointer, length_pointer.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load the integer at given pointer and zero extend it to the VM word size.
|
||||||
|
pub fn build_load_word(
|
||||||
&self,
|
&self,
|
||||||
pointer: Pointer<'ctx>,
|
pointer: Pointer<'ctx>,
|
||||||
|
bit_length: usize,
|
||||||
|
name: &str,
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
|
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
|
||||||
let address = self.build_byte_swap(self.build_load(pointer, "address_pointer")?)?;
|
let value = self.build_load(
|
||||||
Ok(self
|
pointer.cast(self.integer_type(bit_length)),
|
||||||
.builder()
|
&format!("load_{name}"),
|
||||||
.build_int_z_extend(address.into_int_value(), self.word_type(), "address_zext")?
|
)?;
|
||||||
.into())
|
let value_extended = self.builder().build_int_z_extend(
|
||||||
|
value.into_int_value(),
|
||||||
|
self.word_type(),
|
||||||
|
&format!("zext_{name}"),
|
||||||
|
)?;
|
||||||
|
Ok(value_extended.as_basic_value_enum())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a stack load instruction.
|
/// Builds a stack load instruction.
|
||||||
@@ -922,22 +928,6 @@ where
|
|||||||
.left()
|
.left()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a call to the runtime API `import`, where `import` is a "getter" API.
|
|
||||||
/// This means that the supplied API method just writes back a single word.
|
|
||||||
/// `import` is thus expect to have a single parameter, the 32 bytes output buffer,
|
|
||||||
/// and no return value.
|
|
||||||
pub fn build_runtime_call_to_getter(
|
|
||||||
&self,
|
|
||||||
import: &'static str,
|
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
|
||||||
where
|
|
||||||
D: Dependency + Clone,
|
|
||||||
{
|
|
||||||
let pointer = self.build_alloca_at_entry(self.word_type(), &format!("{import}_output"));
|
|
||||||
self.build_runtime_call(import, &[pointer.to_int(self).into()]);
|
|
||||||
self.build_load(pointer, import)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds a call.
|
/// Builds a call.
|
||||||
pub fn build_call(
|
pub fn build_call(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -7,14 +7,16 @@ use crate::polkavm::context::Context;
|
|||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
use crate::polkavm_const::runtime_api;
|
use crate::polkavm_const::runtime_api;
|
||||||
|
|
||||||
const STATIC_CALL_FLAG: u32 = 0b0001_0000;
|
static STATIC_CALL_FLAG: u32 = 0b0001_0000;
|
||||||
const REENTRANT_CALL_FLAG: u32 = 0b0000_1000;
|
|
||||||
|
|
||||||
/// Translates a contract call.
|
/// Translates a contract call.
|
||||||
|
///
|
||||||
|
/// If the `simulation_address` is specified, the call is
|
||||||
|
/// substituted with another instruction according to the specification.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn call<'ctx, D>(
|
pub fn call<'ctx, D>(
|
||||||
context: &mut Context<'ctx, D>,
|
context: &mut Context<'ctx, D>,
|
||||||
_gas: inkwell::values::IntValue<'ctx>,
|
gas: inkwell::values::IntValue<'ctx>,
|
||||||
address: inkwell::values::IntValue<'ctx>,
|
address: inkwell::values::IntValue<'ctx>,
|
||||||
value: Option<inkwell::values::IntValue<'ctx>>,
|
value: Option<inkwell::values::IntValue<'ctx>>,
|
||||||
input_offset: inkwell::values::IntValue<'ctx>,
|
input_offset: inkwell::values::IntValue<'ctx>,
|
||||||
@@ -27,71 +29,59 @@ pub fn call<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
let address_type = context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS);
|
let address_pointer = context.build_alloca(context.word_type(), "address_ptr");
|
||||||
let address_pointer = context.build_alloca_at_entry(address_type, "address_pointer");
|
context.build_store(address_pointer, address)?;
|
||||||
let address_truncated =
|
|
||||||
context
|
|
||||||
.builder()
|
|
||||||
.build_int_truncate(address, address_type, "address_truncated")?;
|
|
||||||
let address_swapped = context.build_byte_swap(address_truncated.into())?;
|
|
||||||
context.build_store(address_pointer, address_swapped)?;
|
|
||||||
|
|
||||||
let value = value.unwrap_or_else(|| context.word_const(0));
|
let value_pointer = if let Some(value) = value {
|
||||||
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
|
let value_pointer = context.build_alloca(context.value_type(), "value");
|
||||||
context.build_store(value_pointer, value)?;
|
context.build_store(value_pointer, value)?;
|
||||||
|
value_pointer
|
||||||
|
} else {
|
||||||
|
context.sentinel_pointer()
|
||||||
|
};
|
||||||
|
|
||||||
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
|
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
|
||||||
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
|
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
|
||||||
let output_offset = context.safe_truncate_int_to_xlen(output_offset)?;
|
let output_offset = context.safe_truncate_int_to_xlen(output_offset)?;
|
||||||
let output_length = context.safe_truncate_int_to_xlen(output_length)?;
|
let output_length = context.safe_truncate_int_to_xlen(output_length)?;
|
||||||
|
|
||||||
// TODO: What to supply here? Is there a weight to gas?
|
let gas = context
|
||||||
let _gas = context
|
|
||||||
.builder()
|
.builder()
|
||||||
.build_int_truncate(_gas, context.integer_type(64), "gas")?;
|
.build_int_truncate(gas, context.integer_type(64), "gas")?;
|
||||||
|
|
||||||
|
let flags = if static_call { STATIC_CALL_FLAG } else { 0 };
|
||||||
|
|
||||||
let input_pointer = context.build_heap_gep(input_offset, input_length)?;
|
let input_pointer = context.build_heap_gep(input_offset, input_length)?;
|
||||||
let output_pointer = context.build_heap_gep(output_offset, output_length)?;
|
let output_pointer = context.build_heap_gep(output_offset, output_length)?;
|
||||||
|
|
||||||
let output_length_pointer = context.build_alloca_at_entry(context.xlen_type(), "output_length");
|
let output_length_pointer = context.get_global(crate::polkavm::GLOBAL_RETURN_DATA_SIZE)?;
|
||||||
context.build_store(output_length_pointer, output_length)?;
|
context.build_store(output_length_pointer.into(), output_length)?;
|
||||||
|
|
||||||
let flags = if static_call {
|
let argument_pointer = revive_runtime_api::calling_convention::Spill::new(
|
||||||
REENTRANT_CALL_FLAG | STATIC_CALL_FLAG
|
|
||||||
} else {
|
|
||||||
REENTRANT_CALL_FLAG
|
|
||||||
};
|
|
||||||
let flags = context.xlen_type().const_int(flags as u64, false);
|
|
||||||
|
|
||||||
let argument_type = revive_runtime_api::calling_convention::call(context.llvm());
|
|
||||||
let argument_pointer = context.build_alloca_at_entry(argument_type, "call_arguments");
|
|
||||||
let arguments = &[
|
|
||||||
flags.as_basic_value_enum(),
|
|
||||||
address_pointer.value.as_basic_value_enum(),
|
|
||||||
context.integer_const(64, 0).as_basic_value_enum(),
|
|
||||||
context.integer_const(64, 0).as_basic_value_enum(),
|
|
||||||
context.sentinel_pointer().value.as_basic_value_enum(),
|
|
||||||
value_pointer.value.as_basic_value_enum(),
|
|
||||||
input_pointer.value.as_basic_value_enum(),
|
|
||||||
input_length.as_basic_value_enum(),
|
|
||||||
output_pointer.value.as_basic_value_enum(),
|
|
||||||
output_length_pointer.value.as_basic_value_enum(),
|
|
||||||
];
|
|
||||||
revive_runtime_api::calling_convention::spill(
|
|
||||||
context.builder(),
|
context.builder(),
|
||||||
argument_pointer.value,
|
revive_runtime_api::calling_convention::call(context.llvm()),
|
||||||
argument_type,
|
"call_arguments",
|
||||||
arguments,
|
)?
|
||||||
)?;
|
.next(context.xlen_type().const_int(flags as u64, false))?
|
||||||
|
.next(address_pointer.value)?
|
||||||
|
.next(gas)?
|
||||||
|
.skip()
|
||||||
|
.next(context.sentinel_pointer().value)?
|
||||||
|
.next(value_pointer.value)?
|
||||||
|
.next(input_pointer.value)?
|
||||||
|
.next(input_length)?
|
||||||
|
.next(output_pointer.value)?
|
||||||
|
.next(output_length_pointer.value)?
|
||||||
|
.done();
|
||||||
|
|
||||||
let name = runtime_api::imports::CALL;
|
let name = runtime_api::imports::CALL;
|
||||||
let argument_pointer = context.builder().build_ptr_to_int(
|
let arguments = context.builder().build_ptr_to_int(
|
||||||
argument_pointer.value,
|
argument_pointer,
|
||||||
context.xlen_type(),
|
context.xlen_type(),
|
||||||
"call_argument_pointer",
|
"argument_pointer",
|
||||||
)?;
|
)?;
|
||||||
let success = context
|
let success = context
|
||||||
.build_runtime_call(name, &[argument_pointer.into()])
|
.build_runtime_call(name, &[arguments.into()])
|
||||||
.unwrap_or_else(|| panic!("{name} should return a value"))
|
.unwrap_or_else(|| panic!("{name} should return a value"))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ pub fn chain_id<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
context.build_runtime_call_to_getter(runtime_api::imports::CHAIN_ID)
|
Ok(context.word_const(0).as_basic_value_enum())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the `block_number` instruction.
|
/// Translates the `block_number` instruction.
|
||||||
@@ -53,7 +53,22 @@ pub fn block_number<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
context.build_runtime_call_to_getter(runtime_api::imports::BLOCK_NUMBER)
|
let (output_pointer, output_length_pointer) = context.build_stack_parameter(
|
||||||
|
revive_common::BIT_LENGTH_BLOCK_NUMBER,
|
||||||
|
"block_timestamp_output",
|
||||||
|
);
|
||||||
|
context.build_runtime_call(
|
||||||
|
runtime_api::imports::BLOCK_NUMBER,
|
||||||
|
&[
|
||||||
|
output_pointer.to_int(context).into(),
|
||||||
|
output_length_pointer.to_int(context).into(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
context.build_load_word(
|
||||||
|
output_pointer,
|
||||||
|
revive_common::BIT_LENGTH_BLOCK_NUMBER,
|
||||||
|
"block_number",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the `block_timestamp` instruction.
|
/// Translates the `block_timestamp` instruction.
|
||||||
@@ -63,7 +78,22 @@ pub fn block_timestamp<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
context.build_runtime_call_to_getter(runtime_api::imports::NOW)
|
let (output_pointer, output_length_pointer) = context.build_stack_parameter(
|
||||||
|
revive_common::BIT_LENGTH_BLOCK_TIMESTAMP,
|
||||||
|
"block_timestamp_output",
|
||||||
|
);
|
||||||
|
context.build_runtime_call(
|
||||||
|
runtime_api::imports::NOW,
|
||||||
|
&[
|
||||||
|
output_pointer.to_int(context).into(),
|
||||||
|
output_length_pointer.to_int(context).into(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
context.build_load_word(
|
||||||
|
output_pointer,
|
||||||
|
revive_common::BIT_LENGTH_BLOCK_TIMESTAMP,
|
||||||
|
"block_timestamp",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the `block_hash` instruction.
|
/// Translates the `block_hash` instruction.
|
||||||
@@ -141,15 +171,20 @@ pub fn address<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
let pointer = context.build_alloca_at_entry(
|
let (output_pointer, output_length_pointer) =
|
||||||
context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS),
|
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_output");
|
||||||
"address_output",
|
|
||||||
);
|
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::imports::ADDRESS,
|
runtime_api::imports::ADDRESS,
|
||||||
&[pointer.to_int(context).into()],
|
&[
|
||||||
|
output_pointer.to_int(context).into(),
|
||||||
|
output_length_pointer.to_int(context).into(),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
context.build_load_address(pointer)
|
let value = context.build_byte_swap(context.build_load(output_pointer, "address")?)?;
|
||||||
|
Ok(context
|
||||||
|
.builder()
|
||||||
|
.build_int_z_extend(value.into_int_value(), context.word_type(), "address_zext")?
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the `caller` instruction.
|
/// Translates the `caller` instruction.
|
||||||
@@ -159,13 +194,18 @@ pub fn caller<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
let pointer = context.build_alloca_at_entry(
|
let (output_pointer, output_length_pointer) =
|
||||||
context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS),
|
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "caller_output");
|
||||||
"address_output",
|
|
||||||
);
|
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::imports::CALLER,
|
runtime_api::imports::CALLER,
|
||||||
&[pointer.to_int(context).into()],
|
&[
|
||||||
|
output_pointer.to_int(context).into(),
|
||||||
|
output_length_pointer.to_int(context).into(),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
context.build_load_address(pointer)
|
let value = context.build_byte_swap(context.build_load(output_pointer, "caller")?)?;
|
||||||
|
Ok(context
|
||||||
|
.builder()
|
||||||
|
.build_int_z_extend(value.into_int_value(), context.word_type(), "caller_zext")?
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,26 @@ use crate::polkavm::context::Context;
|
|||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
use crate::polkavm_const::runtime_api;
|
use crate::polkavm_const::runtime_api;
|
||||||
|
|
||||||
/// Translates the contract `create` and `create2` instruction.
|
/// Translates the contract `create` instruction.
|
||||||
///
|
/// The instruction is simulated by a call to a system contract.
|
||||||
/// A `salt` value of `None` is equivalent to `create1`.
|
|
||||||
pub fn create<'ctx, D>(
|
pub fn create<'ctx, D>(
|
||||||
context: &mut Context<'ctx, D>,
|
context: &mut Context<'ctx, D>,
|
||||||
value: inkwell::values::IntValue<'ctx>,
|
value: inkwell::values::IntValue<'ctx>,
|
||||||
input_offset: inkwell::values::IntValue<'ctx>,
|
input_offset: inkwell::values::IntValue<'ctx>,
|
||||||
input_length: inkwell::values::IntValue<'ctx>,
|
input_length: inkwell::values::IntValue<'ctx>,
|
||||||
|
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
||||||
|
where
|
||||||
|
D: Dependency + Clone,
|
||||||
|
{
|
||||||
|
self::create2(context, value, input_offset, input_length, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Translates the contract `create2` instruction.
|
||||||
|
pub fn create2<'ctx, D>(
|
||||||
|
context: &mut Context<'ctx, D>,
|
||||||
|
value: inkwell::values::IntValue<'ctx>,
|
||||||
|
input_offset: inkwell::values::IntValue<'ctx>,
|
||||||
|
input_length: inkwell::values::IntValue<'ctx>,
|
||||||
salt: Option<inkwell::values::IntValue<'ctx>>,
|
salt: Option<inkwell::values::IntValue<'ctx>>,
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
||||||
where
|
where
|
||||||
@@ -25,6 +37,9 @@ where
|
|||||||
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
|
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
|
||||||
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
|
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
|
||||||
|
|
||||||
|
let value_pointer = context.build_alloca(context.value_type(), "value");
|
||||||
|
context.build_store(value_pointer, value)?;
|
||||||
|
|
||||||
let code_hash_pointer = context.build_heap_gep(input_offset, input_length)?;
|
let code_hash_pointer = context.build_heap_gep(input_offset, input_length)?;
|
||||||
|
|
||||||
let input_data_pointer = context.build_gep(
|
let input_data_pointer = context.build_gep(
|
||||||
@@ -33,68 +48,53 @@ where
|
|||||||
.xlen_type()
|
.xlen_type()
|
||||||
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false)],
|
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false)],
|
||||||
context.byte_type(),
|
context.byte_type(),
|
||||||
"input_ptr_parameter_offset",
|
"value_ptr_parameter_offset",
|
||||||
);
|
);
|
||||||
|
|
||||||
let value_pointer = context.build_alloca_at_entry(context.value_type(), "transferred_value");
|
let salt_pointer = context.build_alloca(context.word_type(), "salt");
|
||||||
context.build_store(value_pointer, value)?;
|
context.build_store(salt_pointer, salt.unwrap_or_else(|| context.word_const(0)))?;
|
||||||
|
|
||||||
let salt_pointer = match salt {
|
let (address_pointer, address_length_pointer) =
|
||||||
Some(salt) => {
|
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_pointer");
|
||||||
let salt_pointer = context.build_alloca_at_entry(context.word_type(), "salt_pointer");
|
|
||||||
context.build_store(salt_pointer, salt)?;
|
|
||||||
salt_pointer
|
|
||||||
}
|
|
||||||
None => context.sentinel_pointer(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let address_pointer = context.build_alloca_at_entry(
|
|
||||||
context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS),
|
|
||||||
"address_pointer",
|
|
||||||
);
|
|
||||||
context.build_store(address_pointer, context.word_const(0))?;
|
context.build_store(address_pointer, context.word_const(0))?;
|
||||||
|
|
||||||
let argument_type = revive_runtime_api::calling_convention::instantiate(context.llvm());
|
let argument_pointer = revive_runtime_api::calling_convention::Spill::new(
|
||||||
let argument_pointer = context.build_alloca_at_entry(argument_type, "instantiate_arguments");
|
|
||||||
let arguments = &[
|
|
||||||
code_hash_pointer.value.as_basic_value_enum(),
|
|
||||||
context.integer_const(64, 0).as_basic_value_enum(),
|
|
||||||
context.integer_const(64, 0).as_basic_value_enum(),
|
|
||||||
context.sentinel_pointer().value.as_basic_value_enum(),
|
|
||||||
value_pointer.value.as_basic_value_enum(),
|
|
||||||
input_data_pointer.value.as_basic_value_enum(),
|
|
||||||
input_length.as_basic_value_enum(),
|
|
||||||
address_pointer.value.as_basic_value_enum(),
|
|
||||||
context.sentinel_pointer().value.as_basic_value_enum(),
|
|
||||||
context.sentinel_pointer().value.as_basic_value_enum(),
|
|
||||||
salt_pointer.value.as_basic_value_enum(),
|
|
||||||
];
|
|
||||||
revive_runtime_api::calling_convention::spill(
|
|
||||||
context.builder(),
|
context.builder(),
|
||||||
argument_pointer.value,
|
revive_runtime_api::calling_convention::instantiate(context.llvm()),
|
||||||
argument_type,
|
"create2_arguments",
|
||||||
arguments,
|
)?
|
||||||
)?;
|
.next(code_hash_pointer.value)?
|
||||||
|
.skip()
|
||||||
|
.skip()
|
||||||
|
.next(context.sentinel_pointer().value)?
|
||||||
|
.next(value_pointer.value)?
|
||||||
|
.next(input_data_pointer.value)?
|
||||||
|
.next(input_length)?
|
||||||
|
.next(address_pointer.value)?
|
||||||
|
.next(address_length_pointer.value)?
|
||||||
|
.next(context.sentinel_pointer().value)?
|
||||||
|
.next(context.sentinel_pointer().value)?
|
||||||
|
.next(salt_pointer.value)?
|
||||||
|
.next(
|
||||||
|
context
|
||||||
|
.xlen_type()
|
||||||
|
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false),
|
||||||
|
)?
|
||||||
|
.done();
|
||||||
|
|
||||||
let argument_pointer = context.builder().build_ptr_to_int(
|
|
||||||
argument_pointer.value,
|
|
||||||
context.xlen_type(),
|
|
||||||
"instantiate_argument_pointer",
|
|
||||||
)?;
|
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::imports::INSTANTIATE,
|
runtime_api::imports::INSTANTIATE,
|
||||||
&[argument_pointer.into()],
|
&[context
|
||||||
|
.builder()
|
||||||
|
.build_ptr_to_int(argument_pointer, context.xlen_type(), "argument_pointer")?
|
||||||
|
.into()],
|
||||||
);
|
);
|
||||||
|
|
||||||
let address = context.build_byte_swap(context.build_load(address_pointer, "address")?)?;
|
context.build_load_word(
|
||||||
Ok(context
|
address_pointer,
|
||||||
.builder()
|
revive_common::BIT_LENGTH_ETH_ADDRESS,
|
||||||
.build_int_z_extend(
|
"address",
|
||||||
address.into_int_value(),
|
)
|
||||||
context.word_type(),
|
|
||||||
"address_zext",
|
|
||||||
)?
|
|
||||||
.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the contract hash instruction, which is actually used to set the hash of the contract
|
/// Translates the contract hash instruction, which is actually used to set the hash of the contract
|
||||||
|
|||||||
@@ -23,13 +23,20 @@ pub fn value<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
let output_pointer = context.build_alloca(context.value_type(), "value_transferred");
|
let (output_pointer, output_length_pointer) =
|
||||||
context.build_store(output_pointer, context.word_const(0))?;
|
context.build_stack_parameter(revive_common::BIT_LENGTH_VALUE, "value_transferred_output");
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::imports::VALUE_TRANSFERRED,
|
runtime_api::imports::VALUE_TRANSFERRED,
|
||||||
&[output_pointer.to_int(context).into()],
|
&[
|
||||||
|
output_pointer.to_int(context).into(),
|
||||||
|
output_length_pointer.to_int(context).into(),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
context.build_load(output_pointer, "value_transferred")
|
context.build_load_word(
|
||||||
|
output_pointer,
|
||||||
|
revive_common::BIT_LENGTH_VALUE,
|
||||||
|
"value_transferred",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the `balance` instructions.
|
/// Translates the `balance` instructions.
|
||||||
@@ -49,32 +56,16 @@ where
|
|||||||
context.xlen_type(),
|
context.xlen_type(),
|
||||||
"balance",
|
"balance",
|
||||||
)?;
|
)?;
|
||||||
let _address = context.builder().build_ptr_to_int(
|
let address = context.builder().build_ptr_to_int(
|
||||||
address_pointer.value,
|
address_pointer.value,
|
||||||
context.xlen_type(),
|
context.xlen_type(),
|
||||||
"address",
|
"address",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
context.build_runtime_call(runtime_api::imports::BALANCE, &[balance.into()]);
|
context.build_runtime_call(
|
||||||
|
runtime_api::imports::BALANCE,
|
||||||
context.build_load(balance_pointer, "balance")
|
&[address.into(), balance.into()],
|
||||||
}
|
);
|
||||||
|
|
||||||
/// Translates the `selfbalance` instructions.
|
|
||||||
pub fn self_balance<'ctx, D>(
|
|
||||||
context: &mut Context<'ctx, D>,
|
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
|
||||||
where
|
|
||||||
D: Dependency + Clone,
|
|
||||||
{
|
|
||||||
let balance_pointer = context.build_alloca(context.word_type(), "balance_pointer");
|
|
||||||
let balance = context.builder().build_ptr_to_int(
|
|
||||||
balance_pointer.value,
|
|
||||||
context.xlen_type(),
|
|
||||||
"balance",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
context.build_runtime_call(runtime_api::imports::BALANCE, &[balance.into()]);
|
|
||||||
|
|
||||||
context.build_load(balance_pointer, "balance")
|
context.build_load(balance_pointer, "balance")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ where
|
|||||||
context.byte_type().array_type(topics_buffer_size as u32),
|
context.byte_type().array_type(topics_buffer_size as u32),
|
||||||
"topics_buffer",
|
"topics_buffer",
|
||||||
);
|
);
|
||||||
|
|
||||||
for (n, topic) in topics.iter().enumerate() {
|
for (n, topic) in topics.iter().enumerate() {
|
||||||
let topic_buffer_offset = context
|
let topic_buffer_offset = context
|
||||||
.xlen_type()
|
.xlen_type()
|
||||||
@@ -58,7 +57,6 @@ where
|
|||||||
context.build_byte_swap(topic.as_basic_value_enum())?,
|
context.build_byte_swap(topic.as_basic_value_enum())?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
[
|
[
|
||||||
context
|
context
|
||||||
.builder()
|
.builder()
|
||||||
@@ -70,7 +68,7 @@ where
|
|||||||
.as_basic_value_enum(),
|
.as_basic_value_enum(),
|
||||||
context
|
context
|
||||||
.xlen_type()
|
.xlen_type()
|
||||||
.const_int(topics.len() as u64, false)
|
.const_int(topics_buffer_size as u64, false)
|
||||||
.as_basic_value_enum(),
|
.as_basic_value_enum(),
|
||||||
input_pointer.as_basic_value_enum(),
|
input_pointer.as_basic_value_enum(),
|
||||||
input_length.as_basic_value_enum(),
|
input_length.as_basic_value_enum(),
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
//! Translates the return data instructions.
|
//! Translates the return data instructions.
|
||||||
|
|
||||||
|
use inkwell::values::BasicValue;
|
||||||
|
|
||||||
use crate::polkavm::context::Context;
|
use crate::polkavm::context::Context;
|
||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
use crate::polkavm_const::runtime_api;
|
use crate::polkavm_const::runtime_api;
|
||||||
@@ -11,17 +13,13 @@ pub fn size<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
let output_pointer = context.build_alloca_at_entry(context.word_type(), "return_data_size");
|
let value = context
|
||||||
let output_pointer_parameter = context.builder().build_ptr_to_int(
|
.get_global_value(crate::polkavm::GLOBAL_RETURN_DATA_SIZE)?
|
||||||
output_pointer.value,
|
.into_int_value();
|
||||||
context.xlen_type(),
|
Ok(context
|
||||||
"return_data_copy_output_pointer",
|
.builder()
|
||||||
)?;
|
.build_int_z_extend(value, context.word_type(), "calldatasize_extended")?
|
||||||
context.build_runtime_call(
|
.as_basic_value_enum())
|
||||||
runtime_api::imports::RETURNDATASIZE,
|
|
||||||
&[output_pointer_parameter.into()],
|
|
||||||
);
|
|
||||||
context.build_load(output_pointer, "return_data_size_load")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the return data copy, trapping if
|
/// Translates the return data copy, trapping if
|
||||||
@@ -41,49 +39,16 @@ where
|
|||||||
let destination_offset = context.safe_truncate_int_to_xlen(destination_offset)?;
|
let destination_offset = context.safe_truncate_int_to_xlen(destination_offset)?;
|
||||||
let size = context.safe_truncate_int_to_xlen(size)?;
|
let size = context.safe_truncate_int_to_xlen(size)?;
|
||||||
|
|
||||||
let output_pointer = context.builder().build_ptr_to_int(
|
let destination_offset = context.builder().build_ptr_to_int(
|
||||||
context.build_heap_gep(destination_offset, size)?.value,
|
context.build_heap_gep(destination_offset, size)?.value,
|
||||||
context.xlen_type(),
|
context.xlen_type(),
|
||||||
"return_data_copy_output_pointer",
|
"destination_offset",
|
||||||
)?;
|
|
||||||
|
|
||||||
let output_length_pointer = context.build_alloca_at_entry(
|
|
||||||
context.xlen_type(),
|
|
||||||
"return_data_copy_output_length_pointer",
|
|
||||||
);
|
|
||||||
context.build_store(output_length_pointer, size)?;
|
|
||||||
let output_length_pointer_int = context.builder().build_ptr_to_int(
|
|
||||||
output_length_pointer.value,
|
|
||||||
context.xlen_type(),
|
|
||||||
"return_data_copy_output_length_pointer_int",
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::imports::RETURNDATACOPY,
|
runtime_api::imports::RETURNDATACOPY,
|
||||||
&[
|
&[destination_offset.into(), source_offset.into(), size.into()],
|
||||||
output_pointer.into(),
|
|
||||||
output_length_pointer_int.into(),
|
|
||||||
source_offset.into(),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Trap on OOB (will be different in EOF code)
|
|
||||||
let overflow_block = context.append_basic_block("return_data_overflow");
|
|
||||||
let non_overflow_block = context.append_basic_block("return_data_non_overflow");
|
|
||||||
let is_overflow = context.builder().build_int_compare(
|
|
||||||
inkwell::IntPredicate::UGT,
|
|
||||||
size,
|
|
||||||
context
|
|
||||||
.build_load(output_length_pointer, "bytes_written")?
|
|
||||||
.into_int_value(),
|
|
||||||
"is_overflow",
|
|
||||||
)?;
|
|
||||||
context.build_conditional_branch(is_overflow, overflow_block, non_overflow_block)?;
|
|
||||||
|
|
||||||
context.set_basic_block(overflow_block);
|
|
||||||
context.build_call(context.intrinsics().trap, &[], "invalid_trap");
|
|
||||||
context.build_unreachable();
|
|
||||||
|
|
||||||
context.set_basic_block(non_overflow_block);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ impl TargetMachine {
|
|||||||
|
|
||||||
/// LLVM target features.
|
/// LLVM target features.
|
||||||
#[cfg(feature = "riscv-zbb")]
|
#[cfg(feature = "riscv-zbb")]
|
||||||
pub const VM_FEATURES: &'static str = "+zbb,+e,+m,+c";
|
pub const VM_FEATURES: &'static str = "+zbb,+e,+m";
|
||||||
#[cfg(not(feature = "riscv-zbb"))]
|
#[cfg(not(feature = "riscv-zbb"))]
|
||||||
pub const VM_FEATURES: &'static str = "+e,+m,+c";
|
pub const VM_FEATURES: &'static str = "+e,+m";
|
||||||
|
|
||||||
/// A shortcut constructor.
|
/// A shortcut constructor.
|
||||||
/// A separate instance for every optimization level is created.
|
/// A separate instance for every optimization level is created.
|
||||||
|
|||||||
Binary file not shown.
@@ -75,12 +75,10 @@ impl pallet_revive::Config for Runtime {
|
|||||||
type DepositPerByte = DepositPerByte;
|
type DepositPerByte = DepositPerByte;
|
||||||
type DepositPerItem = DepositPerItem;
|
type DepositPerItem = DepositPerItem;
|
||||||
type AddressMapper = AccountId;
|
type AddressMapper = AccountId;
|
||||||
type RuntimeMemory = ConstU32<{ 512 * 1024 * 1024 }>;
|
|
||||||
type PVFMemory = ConstU32<{ 1024 * 1024 * 1024 }>;
|
|
||||||
type UnsafeUnstableInterface = UnstableInterface;
|
type UnsafeUnstableInterface = UnstableInterface;
|
||||||
type UploadOrigin = EnsureSigned<AccountId32>;
|
type UploadOrigin = EnsureSigned<AccountId32>;
|
||||||
type InstantiateOrigin = EnsureSigned<AccountId32>;
|
type InstantiateOrigin = EnsureSigned<AccountId32>;
|
||||||
|
type Migrations = ();
|
||||||
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
|
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
|
||||||
type Debug = ();
|
type Debug = ();
|
||||||
type ChainId = ConstU64<420_420_420>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-59
@@ -58,6 +58,7 @@ pub enum SpecsAction {
|
|||||||
},
|
},
|
||||||
/// Verify the result of the last call, omitting this will simply ensure the last call was successful
|
/// Verify the result of the last call, omitting this will simply ensure the last call was successful
|
||||||
VerifyCall(VerifyCallExpectation),
|
VerifyCall(VerifyCallExpectation),
|
||||||
|
|
||||||
/// Verify the balance of an account
|
/// Verify the balance of an account
|
||||||
VerifyBalance {
|
VerifyBalance {
|
||||||
origin: TestAddress,
|
origin: TestAddress,
|
||||||
@@ -178,11 +179,7 @@ impl Default for Specs {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
differential: false,
|
differential: false,
|
||||||
balances: vec![
|
balances: vec![(ALICE, 1_000_000_000)],
|
||||||
(ALICE, 1_000_000_000),
|
|
||||||
(BOB, 1_000_000_000),
|
|
||||||
(CHARLIE, 1_000_000_000),
|
|
||||||
],
|
|
||||||
actions: Default::default(),
|
actions: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,10 +272,10 @@ impl Specs {
|
|||||||
origin,
|
origin,
|
||||||
value,
|
value,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
|
storage_deposit_limit,
|
||||||
code,
|
code,
|
||||||
data,
|
data,
|
||||||
salt,
|
salt,
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
let Code::Solidity {
|
let Code::Solidity {
|
||||||
path: Some(path),
|
path: Some(path),
|
||||||
@@ -289,41 +286,21 @@ impl Specs {
|
|||||||
else {
|
else {
|
||||||
panic!("the differential runner requires Code::Solidity source");
|
panic!("the differential runner requires Code::Solidity source");
|
||||||
};
|
};
|
||||||
|
assert_ne!(solc_optimizer, Some(false), "solc_optimizer must be enabled in differntial mode");
|
||||||
assert_ne!(
|
assert_ne!(pipeline, Some(revive_solidity::SolcPipeline::EVMLA), "yul pipeline must be enabled in differntial mode");
|
||||||
solc_optimizer,
|
assert!(storage_deposit_limit.is_none(), "storage deposit limit is not supported in differential mode");
|
||||||
Some(false),
|
assert!(salt.0.is_none(), "salt is not supported in differential mode");
|
||||||
"solc_optimizer must be enabled in differntial mode"
|
assert_eq!(origin, TestAddress::default(), "configuring the origin is not supported in differential mode");
|
||||||
);
|
|
||||||
assert_ne!(
|
|
||||||
pipeline,
|
|
||||||
Some(revive_solidity::SolcPipeline::EVMLA),
|
|
||||||
"yul pipeline must be enabled in differntial mode"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
salt.0.is_none(),
|
|
||||||
"salt is not supported in differential mode"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
origin,
|
|
||||||
TestAddress::default(),
|
|
||||||
"configuring the origin is not supported in differential mode"
|
|
||||||
);
|
|
||||||
|
|
||||||
let deploy_code = match std::fs::read_to_string(&path) {
|
let deploy_code = match std::fs::read_to_string(&path) {
|
||||||
Ok(solidity_source) => {
|
Ok(solidity_source) => compile_evm_deploy_code(&contract, &solidity_source),
|
||||||
hex::encode(compile_evm_deploy_code(&contract, &solidity_source))
|
|
||||||
}
|
|
||||||
Err(err) => panic!(
|
Err(err) => panic!(
|
||||||
"failed to read solidity source\n . path: '{}'\n . error: {:?}",
|
"failed to read solidity source\n . path: '{}'\n . error: {:?}",
|
||||||
path.display(),
|
path.display(),
|
||||||
err
|
err
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
let mut vm = evm
|
let deploy_code = hex::encode(deploy_code);
|
||||||
.code_blob(deploy_code.as_bytes().to_vec())
|
let mut vm = evm.code_blob(deploy_code.as_bytes().to_vec()).sender(origin.to_eth_addr(&[]).0.into()).deploy(true);
|
||||||
.sender(origin.to_eth_addr(&[]).0.into())
|
|
||||||
.deploy(true);
|
|
||||||
if !data.is_empty() {
|
if !data.is_empty() {
|
||||||
vm = vm.input(data.into());
|
vm = vm.input(data.into());
|
||||||
}
|
}
|
||||||
@@ -338,13 +315,7 @@ impl Specs {
|
|||||||
let deployed_account = log.account_deployed.expect("no account was created");
|
let deployed_account = log.account_deployed.expect("no account was created");
|
||||||
let account_pvm = TestAddress::Instantiated(deployed_accounts.len());
|
let account_pvm = TestAddress::Instantiated(deployed_accounts.len());
|
||||||
deployed_accounts.push(deployed_account);
|
deployed_accounts.push(deployed_account);
|
||||||
derived_specs
|
derived_specs.actions.append(&mut SpecsAction::derive_verification(&log, deployed_account, account_pvm));
|
||||||
.actions
|
|
||||||
.append(&mut SpecsAction::derive_verification(
|
|
||||||
&log,
|
|
||||||
deployed_account,
|
|
||||||
account_pvm,
|
|
||||||
));
|
|
||||||
evm = Evm::from_genesis(log.state_dump.into());
|
evm = Evm::from_genesis(log.state_dump.into());
|
||||||
}
|
}
|
||||||
Call {
|
Call {
|
||||||
@@ -352,23 +323,16 @@ impl Specs {
|
|||||||
dest,
|
dest,
|
||||||
value,
|
value,
|
||||||
gas_limit,
|
gas_limit,
|
||||||
|
storage_deposit_limit,
|
||||||
data,
|
data,
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(
|
assert_eq!(origin, TestAddress::default(), "configuring the origin is not supported in differential mode");
|
||||||
origin,
|
assert!(storage_deposit_limit.is_none(), "storage deposit limit is not supported in differential mode");
|
||||||
TestAddress::default(),
|
|
||||||
"configuring the origin is not supported in differential mode"
|
|
||||||
);
|
|
||||||
let TestAddress::Instantiated(n) = dest else {
|
let TestAddress::Instantiated(n) = dest else {
|
||||||
panic!("the differential runner requires TestAccountId::Instantiated(n) as dest");
|
panic!("the differential runner requires TestAccountId::Instantiated(n) as dest");
|
||||||
};
|
};
|
||||||
let address = deployed_accounts
|
let address = deployed_accounts.get(n).unwrap_or_else(|| panic!("no account at index {n} "));
|
||||||
.get(n)
|
let mut vm = evm.receiver(*address).sender(origin.to_eth_addr(&[]).0.into());
|
||||||
.unwrap_or_else(|| panic!("no account at index {n} "));
|
|
||||||
let mut vm = evm
|
|
||||||
.receiver(*address)
|
|
||||||
.sender(origin.to_eth_addr(&[]).0.into());
|
|
||||||
if !data.is_empty() {
|
if !data.is_empty() {
|
||||||
vm = vm.input(data.into());
|
vm = vm.input(data.into());
|
||||||
}
|
}
|
||||||
@@ -380,13 +344,10 @@ impl Specs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let log = vm.run();
|
let log = vm.run();
|
||||||
derived_specs
|
derived_specs.actions.append(&mut SpecsAction::derive_verification(&log, *address, dest));
|
||||||
.actions
|
|
||||||
.append(&mut SpecsAction::derive_verification(&log, *address, dest));
|
|
||||||
evm = Evm::from_genesis(log.state_dump.into());
|
evm = Evm::from_genesis(log.state_dump.into());
|
||||||
}
|
}
|
||||||
Upload { .. } => continue,
|
_ => panic!("only instantiate and call action allowed in differential mode, got: {action:?}"),
|
||||||
other => derived_specs.actions.push(other),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,7 +402,7 @@ impl Specs {
|
|||||||
pallet_revive::Code::Existing(_) => continue,
|
pallet_revive::Code::Existing(_) => continue,
|
||||||
pallet_revive::Code::Upload(bytes) => bytes,
|
pallet_revive::Code::Upload(bytes) => bytes,
|
||||||
},
|
},
|
||||||
storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT),
|
storage_deposit_limit.unwrap_or_default(),
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|error| panic!("code upload failed: {error:?}")),
|
.unwrap_or_else(|error| panic!("code upload failed: {error:?}")),
|
||||||
Call {
|
Call {
|
||||||
@@ -481,6 +442,7 @@ impl Specs {
|
|||||||
expected,
|
expected,
|
||||||
} => {
|
} => {
|
||||||
let address = contract.to_eth_addr(&results);
|
let address = contract.to_eth_addr(&results);
|
||||||
|
dbg!(contract.to_account_id(&results));
|
||||||
let Ok(value) = Contracts::get_storage(address, key) else {
|
let Ok(value) = Contracts::get_storage(address, key) else {
|
||||||
panic!("error reading storage for address {address}");
|
panic!("error reading storage for address {address}");
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use inkwell::{
|
|||||||
context::Context,
|
context::Context,
|
||||||
module::Module,
|
module::Module,
|
||||||
types::{BasicType, StructType},
|
types::{BasicType, StructType},
|
||||||
values::{BasicValueEnum, PointerValue},
|
values::{BasicValue, PointerValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates a module that sets the PolkaVM minimum stack size to [`size`] if linked in.
|
/// Creates a module that sets the PolkaVM minimum stack size to [`size`] if linked in.
|
||||||
@@ -21,33 +21,56 @@ pub fn min_stack_size<'context>(
|
|||||||
module
|
module
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for building function calls with stack spilled arguments.
|
pub struct Spill<'a, 'ctx> {
|
||||||
/// - `pointer`: points to a struct of the packed argument struct type
|
|
||||||
/// - `type`: the packed argument struct type
|
|
||||||
/// - `arguments`: a correctly ordered list of the struct field values
|
|
||||||
pub fn spill<'ctx>(
|
|
||||||
builder: &Builder<'ctx>,
|
|
||||||
pointer: PointerValue<'ctx>,
|
pointer: PointerValue<'ctx>,
|
||||||
|
builder: &'a Builder<'ctx>,
|
||||||
r#type: StructType<'ctx>,
|
r#type: StructType<'ctx>,
|
||||||
arguments: &[BasicValueEnum<'ctx>],
|
current_field: u32,
|
||||||
) -> anyhow::Result<()> {
|
}
|
||||||
for index in 0..r#type.get_field_types().len() {
|
|
||||||
let field_pointer = builder.build_struct_gep(
|
impl<'a, 'ctx> Spill<'a, 'ctx> {
|
||||||
r#type,
|
pub fn new(
|
||||||
pointer,
|
builder: &'a Builder<'ctx>,
|
||||||
index as u32,
|
r#type: StructType<'ctx>,
|
||||||
&format!("spill_parameter_{}", index),
|
name: &str,
|
||||||
)?;
|
) -> anyhow::Result<Self> {
|
||||||
let field_value = arguments
|
Ok(Self {
|
||||||
.get(index)
|
pointer: builder.build_alloca(r#type, name)?,
|
||||||
.ok_or_else(|| anyhow::anyhow!("invalid index {index} for struct type {}", r#type))?;
|
builder,
|
||||||
builder.build_store(field_pointer, *field_value)?;
|
r#type,
|
||||||
}
|
current_field: 0,
|
||||||
|
})
|
||||||
Ok(())
|
}
|
||||||
|
|
||||||
|
pub fn next<V: BasicValue<'ctx>>(mut self, value: V) -> anyhow::Result<Self> {
|
||||||
|
let field_pointer = self.builder.build_struct_gep(
|
||||||
|
self.r#type,
|
||||||
|
self.pointer,
|
||||||
|
self.current_field,
|
||||||
|
&format!("spill_parameter_{}", self.current_field),
|
||||||
|
)?;
|
||||||
|
self.builder.build_store(field_pointer, value)?;
|
||||||
|
self.current_field += 1;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn skip(mut self) -> Self {
|
||||||
|
self.current_field += 1;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn done(self) -> PointerValue<'ctx> {
|
||||||
|
assert!(
|
||||||
|
self.r#type
|
||||||
|
.get_field_type_at_index(self.current_field)
|
||||||
|
.is_none(),
|
||||||
|
"there must not be any missing parameters"
|
||||||
|
);
|
||||||
|
|
||||||
|
self.pointer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a packed struct argument type for the `instantiate` API.
|
|
||||||
pub fn instantiate(context: &Context) -> StructType {
|
pub fn instantiate(context: &Context) -> StructType {
|
||||||
context.struct_type(
|
context.struct_type(
|
||||||
&[
|
&[
|
||||||
@@ -67,18 +90,21 @@ pub fn instantiate(context: &Context) -> StructType {
|
|||||||
context.i32_type().as_basic_type_enum(),
|
context.i32_type().as_basic_type_enum(),
|
||||||
// address_ptr: u32,
|
// address_ptr: u32,
|
||||||
context.ptr_type(Default::default()).as_basic_type_enum(),
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// address_len_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
// output_ptr: u32,
|
// output_ptr: u32,
|
||||||
context.ptr_type(Default::default()).as_basic_type_enum(),
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
// output_len_ptr: u32,
|
// output_len_ptr: u32,
|
||||||
context.ptr_type(Default::default()).as_basic_type_enum(),
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
// salt_ptr: u32,
|
// salt_ptr: u32,
|
||||||
context.ptr_type(Default::default()).as_basic_type_enum(),
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// salt_len: u32
|
||||||
|
context.i32_type().as_basic_type_enum(),
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a packed struct argument type for the `call` API.
|
|
||||||
pub fn call(context: &Context) -> StructType {
|
pub fn call(context: &Context) -> StructType {
|
||||||
context.struct_type(
|
context.struct_type(
|
||||||
&[
|
&[
|
||||||
|
|||||||
@@ -55,11 +55,9 @@ POLKAVM_IMPORT(void, input, uint32_t, uint32_t)
|
|||||||
|
|
||||||
POLKAVM_IMPORT(void, seal_return, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, seal_return, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, return_data_copy, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, returndatacopy, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, return_data_size, uint32_t)
|
POLKAVM_IMPORT(void, value_transferred, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, value_transferred, uint32_t)
|
|
||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, set_storage, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(uint32_t, set_storage, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
@@ -79,7 +77,7 @@ POLKAVM_IMPORT(uint32_t, instantiate, uint32_t)
|
|||||||
|
|
||||||
POLKAVM_IMPORT(void, terminate, uint32_t)
|
POLKAVM_IMPORT(void, terminate, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, caller, uint32_t)
|
POLKAVM_IMPORT(void, caller, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, is_contract, uint32_t)
|
POLKAVM_IMPORT(uint32_t, is_contract, uint32_t)
|
||||||
|
|
||||||
@@ -93,23 +91,21 @@ POLKAVM_IMPORT(uint32_t, caller_is_origin)
|
|||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, caller_is_root)
|
POLKAVM_IMPORT(uint32_t, caller_is_root)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, address, uint32_t)
|
POLKAVM_IMPORT(void, address, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, weight_to_fee, uint64_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, weight_to_fee, uint64_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, gas_left, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, gas_left, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, balance, uint32_t)
|
POLKAVM_IMPORT(void, balance, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, chain_id, uint32_t)
|
POLKAVM_IMPORT(void, now, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, now, uint32_t)
|
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, minimum_balance, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, minimum_balance, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, deposit_event, uint32_t, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, deposit_event, uint32_t, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, block_number, uint32_t)
|
POLKAVM_IMPORT(void, block_number, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, hash_sha2_256, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, hash_sha2_256, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
|
|||||||
@@ -1119,7 +1119,6 @@ where
|
|||||||
value,
|
value,
|
||||||
input_offset,
|
input_offset,
|
||||||
input_length,
|
input_length,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.map(Some)
|
.map(Some)
|
||||||
}
|
}
|
||||||
@@ -1131,7 +1130,7 @@ where
|
|||||||
let input_length = arguments[2].into_int_value();
|
let input_length = arguments[2].into_int_value();
|
||||||
let salt = arguments[3].into_int_value();
|
let salt = arguments[3].into_int_value();
|
||||||
|
|
||||||
revive_llvm_context::polkavm_evm_create::create(
|
revive_llvm_context::polkavm_evm_create::create2(
|
||||||
context,
|
context,
|
||||||
value,
|
value,
|
||||||
input_offset,
|
input_offset,
|
||||||
@@ -1160,9 +1159,7 @@ where
|
|||||||
let address = arguments[0].into_int_value();
|
let address = arguments[0].into_int_value();
|
||||||
revive_llvm_context::polkavm_evm_ether_gas::balance(context, address).map(Some)
|
revive_llvm_context::polkavm_evm_ether_gas::balance(context, address).map(Some)
|
||||||
}
|
}
|
||||||
InstructionName::SELFBALANCE => {
|
InstructionName::SELFBALANCE => todo!(),
|
||||||
revive_llvm_context::polkavm_evm_ether_gas::self_balance(context).map(Some)
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionName::GASLIMIT => {
|
InstructionName::GASLIMIT => {
|
||||||
revive_llvm_context::polkavm_evm_contract_context::gas_limit(context).map(Some)
|
revive_llvm_context::polkavm_evm_contract_context::gas_limit(context).map(Some)
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ pub struct Arguments {
|
|||||||
pub solc: Option<String>,
|
pub solc: Option<String>,
|
||||||
|
|
||||||
/// The EVM target version to generate IR for.
|
/// The EVM target version to generate IR for.
|
||||||
/// See https://github.com/paritytech/revive/blob/main/crates/common/src/evm_version.rs for reference.
|
/// See https://github.com/xermicus/revive/blob/main/crates/common/src/evm_version.rs for reference.
|
||||||
#[structopt(long = "evm-version")]
|
#[structopt(long = "evm-version")]
|
||||||
pub evm_version: Option<String>,
|
pub evm_version: Option<String>,
|
||||||
|
|
||||||
@@ -196,14 +196,14 @@ impl Arguments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if self.recursive_process_input.is_some() && !self.recursive_process {
|
if self.recursive_process_input.is_none() && !self.recursive_process {
|
||||||
anyhow::bail!("--process-input can be only used when --recursive-process is given");
|
anyhow::bail!("--process-input can be only used when --recursive-process is given");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if self.recursive_process
|
if self.recursive_process
|
||||||
&& ((self.recursive_process_input.is_none() && std::env::args().count() > 2)
|
&& ((self.recursive_process_input.is_none() && std::env::args().count() > 2)
|
||||||
|| (self.recursive_process_input.is_some() && std::env::args().count() > 4))
|
|| (self.recursive_process_input.is_none() && std::env::args().count() > 4))
|
||||||
{
|
{
|
||||||
anyhow::bail!("No other options are allowed in recursive mode.");
|
anyhow::bail!("No other options are allowed in recursive mode.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ impl Compiler {
|
|||||||
pub const FIRST_VIA_IR_VERSION: semver::Version = semver::Version::new(0, 8, 13);
|
pub const FIRST_VIA_IR_VERSION: semver::Version = semver::Version::new(0, 8, 13);
|
||||||
|
|
||||||
/// The last supported version of `solc`.
|
/// The last supported version of `solc`.
|
||||||
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 27);
|
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 26);
|
||||||
|
|
||||||
/// A shortcut constructor.
|
/// A shortcut constructor.
|
||||||
/// Different tools may use different `executable` names. For example, the integration tester
|
/// Different tools may use different `executable` names. For example, the integration tester
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"title": "resolc CLI Tests",
|
"title": "resolc CLI Tests",
|
||||||
"description": "Auto tests for verifying resolc CLI",
|
"description": "Auto tests for verifying resolc CLI",
|
||||||
"repository": "https://github.com/paritytech/revive",
|
"repository": "https://github.com/xermicus/revive",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -831,7 +831,6 @@ impl FunctionCall {
|
|||||||
value,
|
value,
|
||||||
input_offset,
|
input_offset,
|
||||||
input_length,
|
input_length,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.map(Some)
|
.map(Some)
|
||||||
}
|
}
|
||||||
@@ -843,7 +842,7 @@ impl FunctionCall {
|
|||||||
let input_length = arguments[2].into_int_value();
|
let input_length = arguments[2].into_int_value();
|
||||||
let salt = arguments[3].into_int_value();
|
let salt = arguments[3].into_int_value();
|
||||||
|
|
||||||
revive_llvm_context::polkavm_evm_create::create(
|
revive_llvm_context::polkavm_evm_create::create2(
|
||||||
context,
|
context,
|
||||||
value,
|
value,
|
||||||
input_offset,
|
input_offset,
|
||||||
@@ -913,9 +912,7 @@ impl FunctionCall {
|
|||||||
let address = arguments[0].into_int_value();
|
let address = arguments[0].into_int_value();
|
||||||
revive_llvm_context::polkavm_evm_ether_gas::balance(context, address).map(Some)
|
revive_llvm_context::polkavm_evm_ether_gas::balance(context, address).map(Some)
|
||||||
}
|
}
|
||||||
Name::SelfBalance => {
|
Name::SelfBalance => todo!(),
|
||||||
revive_llvm_context::polkavm_evm_ether_gas::self_balance(context).map(Some)
|
|
||||||
}
|
|
||||||
|
|
||||||
Name::GasLimit => {
|
Name::GasLimit => {
|
||||||
revive_llvm_context::polkavm_evm_contract_context::gas_limit(context).map(Some)
|
revive_llvm_context::polkavm_evm_contract_context::gas_limit(context).map(Some)
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#! /usr/bin/env bash
|
|
||||||
|
|
||||||
CONTAINER=revive-builder-debian-x86
|
|
||||||
VERSION=latest
|
|
||||||
DOCKERFILE=revive-builder-debian.dockerfile
|
|
||||||
|
|
||||||
docker build --rm -t ${CONTAINER}:${VERSION} -f ${DOCKERFILE} $@
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#! /usr/bin/env bash
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REVIVE_INSTALL_DIR=$(pwd)/target/release
|
|
||||||
while getopts "o:" option ; do
|
|
||||||
case $option in
|
|
||||||
o) # Output directory
|
|
||||||
REVIVE_INSTALL_DIR=$OPTARG
|
|
||||||
;;
|
|
||||||
\?) echo "Error: Invalid option"
|
|
||||||
exit 1;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
echo "Installing to ${REVIVE_INSTALL_DIR}"
|
|
||||||
|
|
||||||
$(pwd)/build-llvm.sh
|
|
||||||
export PATH=$(pwd)/llvm18.0/bin:$PATH
|
|
||||||
|
|
||||||
make install-revive REVIVE_INSTALL_DIR=${REVIVE_INSTALL_DIR}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:1
|
|
||||||
# Dockerfile for building revive in a Debian container.
|
|
||||||
FROM debian:12
|
|
||||||
RUN <<EOF
|
|
||||||
apt-get update
|
|
||||||
apt-get install -q -y build-essential cmake make ninja-build python3 \
|
|
||||||
libmpfr-dev libgmp-dev libmpc-dev ncurses-dev \
|
|
||||||
git curl
|
|
||||||
EOF
|
|
||||||
ARG RUST_VERSION=stable
|
|
||||||
RUN <<EOF
|
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${RUST_VERSION}
|
|
||||||
EOF
|
|
||||||
ENV PATH=/root/.cargo/bin:${PATH}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#! /usr/bin/env bash
|
|
||||||
|
|
||||||
CONTAINER=revive-builder-debian-x86
|
|
||||||
VERSION=latest
|
|
||||||
|
|
||||||
docker run --rm -v $(pwd):$(pwd) -w $(pwd) ${CONTAINER}:${VERSION} $@
|
|
||||||
Reference in New Issue
Block a user