mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-17 21:41:03 +00:00
initial SELFDESTRUCT support (#400)
Note: - The unstable interface in `v2509.0.0` of `polkadot-sdk` is required. - The differential test fails against EVM in `v2509.0.0` of `polkadot-sdk`. --------- Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
@@ -6,6 +6,9 @@ This is a development pre-release.
|
|||||||
|
|
||||||
Supported `polkadot-sdk` rev: `2509.0.0`
|
Supported `polkadot-sdk` rev: `2509.0.0`
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Support for `selfdestruct`.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Emulated EVM heap memory accesses of zero length are never out of bounds.
|
- Emulated EVM heap memory accesses of zero length are never out of bounds.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity ^0.8;
|
||||||
|
|
||||||
|
// TODO: This currently fails the differential test.
|
||||||
|
// The pallet doesn't send the correct balance back.
|
||||||
|
|
||||||
|
/* runner.json
|
||||||
|
{
|
||||||
|
"differential": false,
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"Upload": {
|
||||||
|
"code": {
|
||||||
|
"Solidity": {
|
||||||
|
"contract": "SelfdestructTester"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Instantiate": {
|
||||||
|
"code": {
|
||||||
|
"Solidity": {
|
||||||
|
"contract": "Selfdestruct"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value": 123456789
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Call": {
|
||||||
|
"dest": {
|
||||||
|
"Instantiated": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
contract Selfdestruct {
|
||||||
|
address tester;
|
||||||
|
uint value;
|
||||||
|
|
||||||
|
constructor() payable {
|
||||||
|
require(msg.value > 0, "the test should have value");
|
||||||
|
value = msg.value;
|
||||||
|
|
||||||
|
SelfdestructTester s = new SelfdestructTester{value: msg.value}();
|
||||||
|
tester = address(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
fallback() external {
|
||||||
|
(bool success, ) = tester.call(hex"");
|
||||||
|
require(success, "the call to the self destructing contract should succeed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract SelfdestructTester {
|
||||||
|
constructor() payable {}
|
||||||
|
|
||||||
|
fallback() external {
|
||||||
|
selfdestruct(payable(msg.sender));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,6 +63,7 @@ test_spec!(layout_at, "LayoutAt", "LayoutAt.sol");
|
|||||||
test_spec!(shift_arithmetic_right, "SAR", "SAR.sol");
|
test_spec!(shift_arithmetic_right, "SAR", "SAR.sol");
|
||||||
test_spec!(add_mod_mul_mod, "AddModMulModTester", "AddModMulMod.sol");
|
test_spec!(add_mod_mul_mod, "AddModMulModTester", "AddModMulMod.sol");
|
||||||
test_spec!(memory_bounds, "MemoryBounds", "MemoryBounds.sol");
|
test_spec!(memory_bounds, "MemoryBounds", "MemoryBounds.sol");
|
||||||
|
test_spec!(selfdestruct, "Selfdestruct", "Selfdestruct.sol");
|
||||||
|
|
||||||
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
||||||
vec![Instantiate {
|
vec![Instantiate {
|
||||||
|
|||||||
@@ -60,3 +60,16 @@ pub fn invalid(context: &mut Context) -> anyhow::Result<()> {
|
|||||||
context.build_call(context.intrinsics().trap, &[], "invalid_trap");
|
context.build_call(context.intrinsics().trap, &[], "invalid_trap");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Translates the `selfdestruct` instruction.
|
||||||
|
pub fn selfdestruct<'ctx>(
|
||||||
|
context: &mut Context<'ctx>,
|
||||||
|
address: inkwell::values::IntValue<'ctx>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let address_pointer = context.build_address_argument_store(address)?;
|
||||||
|
context.build_runtime_call(
|
||||||
|
revive_runtime_api::polkavm_imports::TERMINATE,
|
||||||
|
&[address_pointer.to_int(context).into()],
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -98,26 +98,3 @@ contract ExternalCodeCopy {
|
|||||||
|
|
||||||
build_solidity(sources(&[("test.sol", code)])).unwrap();
|
build_solidity(sources(&[("test.sol", code)])).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "The `SELFDESTRUCT` instruction is not supported")]
|
|
||||||
fn selfdestruct_yul() {
|
|
||||||
let solidity = r#"
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
contract MinimalDestructible {
|
|
||||||
address payable public owner;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
owner = payable(msg.sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroy() public {
|
|
||||||
require(msg.sender == owner, "Only the owner can call this function.");
|
|
||||||
selfdestruct(owner);
|
|
||||||
}
|
|
||||||
}"#;
|
|
||||||
|
|
||||||
build_solidity(sources(&[("test.sol", solidity)])).unwrap();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -101,4 +101,6 @@ POLKAVM_IMPORT(void, set_immutable_data, uint32_t, uint32_t);
|
|||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, set_storage_or_clear, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(uint32_t, set_storage_or_clear, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
|
POLKAVM_IMPORT(void, terminate, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, value_transferred, uint32_t)
|
POLKAVM_IMPORT(void, value_transferred, uint32_t)
|
||||||
|
|||||||
@@ -64,11 +64,13 @@ pub static SET_IMMUTABLE_DATA: &str = "set_immutable_data";
|
|||||||
|
|
||||||
pub static SET_STORAGE: &str = "set_storage_or_clear";
|
pub static SET_STORAGE: &str = "set_storage_or_clear";
|
||||||
|
|
||||||
|
pub static TERMINATE: &str = "terminate";
|
||||||
|
|
||||||
pub static VALUE_TRANSFERRED: &str = "value_transferred";
|
pub static VALUE_TRANSFERRED: &str = "value_transferred";
|
||||||
|
|
||||||
/// 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; 32] = [
|
pub static IMPORTS: [&str; 33] = [
|
||||||
ADDRESS,
|
ADDRESS,
|
||||||
BALANCE,
|
BALANCE,
|
||||||
BALANCE_OF,
|
BALANCE_OF,
|
||||||
@@ -100,6 +102,7 @@ pub static IMPORTS: [&str; 32] = [
|
|||||||
RETURNDATASIZE,
|
RETURNDATASIZE,
|
||||||
SET_IMMUTABLE_DATA,
|
SET_IMMUTABLE_DATA,
|
||||||
SET_STORAGE,
|
SET_STORAGE,
|
||||||
|
TERMINATE,
|
||||||
VALUE_TRANSFERRED,
|
VALUE_TRANSFERRED,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -661,6 +661,14 @@ impl FunctionCall {
|
|||||||
Name::Invalid => {
|
Name::Invalid => {
|
||||||
revive_llvm_context::polkavm_evm_return::invalid(context).map(|_| None)
|
revive_llvm_context::polkavm_evm_return::invalid(context).map(|_| None)
|
||||||
}
|
}
|
||||||
|
Name::SelfDestruct => {
|
||||||
|
let arguments = self.pop_arguments_llvm::<1>(context)?;
|
||||||
|
revive_llvm_context::polkavm_evm_return::selfdestruct(
|
||||||
|
context,
|
||||||
|
arguments[0].into_int_value(),
|
||||||
|
)
|
||||||
|
.map(|_| None)
|
||||||
|
}
|
||||||
|
|
||||||
Name::Log0 => {
|
Name::Log0 => {
|
||||||
let arguments = self.pop_arguments_llvm::<2>(context)?;
|
let arguments = self.pop_arguments_llvm::<2>(context)?;
|
||||||
@@ -962,13 +970,6 @@ impl FunctionCall {
|
|||||||
location
|
location
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Name::SelfDestruct => {
|
|
||||||
let _arguments = self.pop_arguments_llvm::<1>(context)?;
|
|
||||||
anyhow::bail!(
|
|
||||||
"{} The `SELFDESTRUCT` instruction is not supported",
|
|
||||||
location
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user