mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-20 20:41:00 +00:00
Implement delegate_call (#80)
This commit is contained in:
Generated
+357
-357
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -67,7 +67,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 = "a77940bac783108fcae783c553528c8d5328e5b2" }
|
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "0449b214accd0f0fbf7ea3e8f3a8d8b7f99445e4" }
|
||||||
|
|
||||||
# llvm
|
# llvm
|
||||||
[workspace.dependencies.inkwell]
|
[workspace.dependencies.inkwell]
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity ^0.8;
|
||||||
|
|
||||||
|
/* runner.json
|
||||||
|
{
|
||||||
|
"differential": true,
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"Upload": {
|
||||||
|
"code": {
|
||||||
|
"Solidity": {
|
||||||
|
"contract": "Logic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Instantiate": {
|
||||||
|
"code": {
|
||||||
|
"Solidity": {
|
||||||
|
"contract": "Tester"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Call": {
|
||||||
|
"dest": {
|
||||||
|
"Instantiated": 0
|
||||||
|
},
|
||||||
|
"value": 123,
|
||||||
|
"data": "6466414b0000000000000000000000000000000000000000000000000000000000000020"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
contract Logic {
|
||||||
|
// NOTE: storage layout must be the same as contract Tester
|
||||||
|
uint256 public num;
|
||||||
|
address public sender;
|
||||||
|
uint256 public value;
|
||||||
|
|
||||||
|
uint public immutable multiplier = 4;
|
||||||
|
|
||||||
|
event DidSetVars();
|
||||||
|
|
||||||
|
function setVars(uint256 _num) public payable returns (uint256) {
|
||||||
|
num = _num * multiplier;
|
||||||
|
sender = msg.sender;
|
||||||
|
value = msg.value;
|
||||||
|
emit DidSetVars();
|
||||||
|
return _num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Tester {
|
||||||
|
uint256 public num;
|
||||||
|
address public sender;
|
||||||
|
uint256 public value;
|
||||||
|
|
||||||
|
uint public immutable multiplier = 2;
|
||||||
|
|
||||||
|
function setVars(uint256 _num) public payable returns (bool, bytes memory) {
|
||||||
|
Logic impl = new Logic();
|
||||||
|
|
||||||
|
// Tester's storage is set, Logic is not modified.
|
||||||
|
(bool success, bytes memory data) = address(impl).delegatecall(
|
||||||
|
abi.encodeWithSignature("setVars(uint256)", _num)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(success);
|
||||||
|
assert(impl.num() == 0);
|
||||||
|
assert(impl.sender() == address(0));
|
||||||
|
assert(impl.value() == 0);
|
||||||
|
assert(num == _num * 4);
|
||||||
|
assert(sender == msg.sender);
|
||||||
|
assert(value == msg.value);
|
||||||
|
|
||||||
|
return (success, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@ test_spec!(return_data_oob, "ReturnDataOob", "ReturnDataOob.sol");
|
|||||||
test_spec!(immutables, "Immutables", "Immutables.sol");
|
test_spec!(immutables, "Immutables", "Immutables.sol");
|
||||||
test_spec!(transaction, "Transaction", "Transaction.sol");
|
test_spec!(transaction, "Transaction", "Transaction.sol");
|
||||||
test_spec!(block_hash, "BlockHash", "BlockHash.sol");
|
test_spec!(block_hash, "BlockHash", "BlockHash.sol");
|
||||||
|
test_spec!(delegate, "Delegate", "Delegate.sol");
|
||||||
|
|
||||||
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
|
||||||
vec![Instantiate {
|
vec![Instantiate {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const REENTRANT_CALL_FLAG: u32 = 0b0000_1000;
|
|||||||
#[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>,
|
||||||
@@ -40,7 +40,7 @@ where
|
|||||||
// TODO: What to supply here? Is there a weight to gas?
|
// 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 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)?;
|
||||||
@@ -102,20 +102,80 @@ where
|
|||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn delegate_call<'ctx, D>(
|
pub fn delegate_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>>,
|
input_offset: inkwell::values::IntValue<'ctx>,
|
||||||
_input_offset: inkwell::values::IntValue<'ctx>,
|
input_length: inkwell::values::IntValue<'ctx>,
|
||||||
_input_length: inkwell::values::IntValue<'ctx>,
|
output_offset: inkwell::values::IntValue<'ctx>,
|
||||||
_output_offset: inkwell::values::IntValue<'ctx>,
|
output_length: inkwell::values::IntValue<'ctx>,
|
||||||
_output_length: inkwell::values::IntValue<'ctx>,
|
|
||||||
_constants: Vec<Option<num::BigUint>>,
|
_constants: Vec<Option<num::BigUint>>,
|
||||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
todo!()
|
let address_pointer = context.build_address_argument_store(address)?;
|
||||||
|
|
||||||
|
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
|
||||||
|
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
|
||||||
|
let output_offset = context.safe_truncate_int_to_xlen(output_offset)?;
|
||||||
|
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
|
||||||
|
.builder()
|
||||||
|
.build_int_truncate(gas, context.integer_type(64), "gas")?;
|
||||||
|
|
||||||
|
let input_pointer = context.build_heap_gep(input_offset, input_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");
|
||||||
|
context.build_store(output_length_pointer, output_length)?;
|
||||||
|
|
||||||
|
let flags = context.xlen_type().const_int(0u64, false);
|
||||||
|
|
||||||
|
let argument_type = revive_runtime_api::calling_convention::delegate_call(context.llvm());
|
||||||
|
let argument_pointer = context.build_alloca_at_entry(argument_type, "delegate_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(),
|
||||||
|
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(),
|
||||||
|
argument_pointer.value,
|
||||||
|
argument_type,
|
||||||
|
arguments,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let name = revive_runtime_api::polkavm_imports::DELEGATE_CALL;
|
||||||
|
let argument_pointer = context.builder().build_ptr_to_int(
|
||||||
|
argument_pointer.value,
|
||||||
|
context.xlen_type(),
|
||||||
|
"delegate_call_argument_pointer",
|
||||||
|
)?;
|
||||||
|
let success = context
|
||||||
|
.build_runtime_call(name, &[argument_pointer.into()])
|
||||||
|
.unwrap_or_else(|| panic!("{name} should return a value"))
|
||||||
|
.into_int_value();
|
||||||
|
|
||||||
|
let is_success = context.builder().build_int_compare(
|
||||||
|
inkwell::IntPredicate::EQ,
|
||||||
|
success,
|
||||||
|
context.xlen_type().const_zero(),
|
||||||
|
"is_success",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(context
|
||||||
|
.builder()
|
||||||
|
.build_int_z_extend(is_success, context.word_type(), "success")?
|
||||||
|
.as_basic_value_enum())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the Yul `linkersymbol` instruction.
|
/// Translates the Yul `linkersymbol` instruction.
|
||||||
|
|||||||
@@ -106,3 +106,30 @@ pub fn call(context: &Context) -> StructType {
|
|||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a packed struct argument type for the `delegate_call` API.
|
||||||
|
pub fn delegate_call(context: &Context) -> StructType {
|
||||||
|
context.struct_type(
|
||||||
|
&[
|
||||||
|
// flags: u32,
|
||||||
|
context.i32_type().as_basic_type_enum(),
|
||||||
|
// address_ptr:
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// ref_time_limit: u64,
|
||||||
|
context.i64_type().as_basic_type_enum(),
|
||||||
|
// proof_size_limit: u64,
|
||||||
|
context.i64_type().as_basic_type_enum(),
|
||||||
|
// deposit_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// input_data_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// input_data_len: u32,
|
||||||
|
context.i32_type().as_basic_type_enum(),
|
||||||
|
// output_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// output_len_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ POLKAVM_IMPORT(void, block_number, uint32_t)
|
|||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, call, uint32_t)
|
POLKAVM_IMPORT(uint32_t, call, uint32_t)
|
||||||
|
|
||||||
|
POLKAVM_IMPORT(uint32_t, delegate_call, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, caller, uint32_t)
|
POLKAVM_IMPORT(void, caller, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, chain_id, uint32_t)
|
POLKAVM_IMPORT(void, chain_id, uint32_t)
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ pub static BLOCK_NUMBER: &str = "block_number";
|
|||||||
|
|
||||||
pub static CALL: &str = "call";
|
pub static CALL: &str = "call";
|
||||||
|
|
||||||
|
pub static DELEGATE_CALL: &str = "delegate_call";
|
||||||
|
|
||||||
pub static CALLER: &str = "caller";
|
pub static CALLER: &str = "caller";
|
||||||
|
|
||||||
pub static CHAIN_ID: &str = "chain_id";
|
pub static CHAIN_ID: &str = "chain_id";
|
||||||
@@ -64,7 +66,7 @@ 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; 26] = [
|
pub static IMPORTS: [&str; 27] = [
|
||||||
SBRK,
|
SBRK,
|
||||||
MEMORY_SIZE,
|
MEMORY_SIZE,
|
||||||
ADDRESS,
|
ADDRESS,
|
||||||
@@ -73,6 +75,7 @@ pub static IMPORTS: [&str; 26] = [
|
|||||||
BLOCK_HASH,
|
BLOCK_HASH,
|
||||||
BLOCK_NUMBER,
|
BLOCK_NUMBER,
|
||||||
CALL,
|
CALL,
|
||||||
|
DELEGATE_CALL,
|
||||||
CALLER,
|
CALLER,
|
||||||
CHAIN_ID,
|
CHAIN_ID,
|
||||||
CODE_SIZE,
|
CODE_SIZE,
|
||||||
|
|||||||
@@ -1096,7 +1096,6 @@ where
|
|||||||
context,
|
context,
|
||||||
gas,
|
gas,
|
||||||
address,
|
address,
|
||||||
None,
|
|
||||||
input_offset,
|
input_offset,
|
||||||
input_size,
|
input_size,
|
||||||
output_offset,
|
output_offset,
|
||||||
|
|||||||
@@ -807,7 +807,6 @@ impl FunctionCall {
|
|||||||
context,
|
context,
|
||||||
gas,
|
gas,
|
||||||
address,
|
address,
|
||||||
None,
|
|
||||||
input_offset,
|
input_offset,
|
||||||
input_size,
|
input_size,
|
||||||
output_offset,
|
output_offset,
|
||||||
|
|||||||
Reference in New Issue
Block a user