mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-22 02:07:55 +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`
|
||||
|
||||
### Added
|
||||
- Support for `selfdestruct`.
|
||||
|
||||
### Changed
|
||||
- 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!(add_mod_mul_mod, "AddModMulModTester", "AddModMulMod.sol");
|
||||
test_spec!(memory_bounds, "MemoryBounds", "MemoryBounds.sol");
|
||||
test_spec!(selfdestruct, "Selfdestruct", "Selfdestruct.sol");
|
||||
|
||||
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
||||
vec![Instantiate {
|
||||
|
||||
@@ -60,3 +60,16 @@ pub fn invalid(context: &mut Context) -> anyhow::Result<()> {
|
||||
context.build_call(context.intrinsics().trap, &[], "invalid_trap");
|
||||
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();
|
||||
}
|
||||
|
||||
#[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(void, terminate, 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 TERMINATE: &str = "terminate";
|
||||
|
||||
pub static VALUE_TRANSFERRED: &str = "value_transferred";
|
||||
|
||||
/// All imported runtime API symbols.
|
||||
/// Useful for configuring common attributes and linkage.
|
||||
pub static IMPORTS: [&str; 32] = [
|
||||
pub static IMPORTS: [&str; 33] = [
|
||||
ADDRESS,
|
||||
BALANCE,
|
||||
BALANCE_OF,
|
||||
@@ -100,6 +102,7 @@ pub static IMPORTS: [&str; 32] = [
|
||||
RETURNDATASIZE,
|
||||
SET_IMMUTABLE_DATA,
|
||||
SET_STORAGE,
|
||||
TERMINATE,
|
||||
VALUE_TRANSFERRED,
|
||||
];
|
||||
|
||||
|
||||
@@ -661,6 +661,14 @@ impl FunctionCall {
|
||||
Name::Invalid => {
|
||||
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 => {
|
||||
let arguments = self.pop_arguments_llvm::<2>(context)?;
|
||||
@@ -962,13 +970,6 @@ impl FunctionCall {
|
||||
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