mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-15 03:21:06 +00:00
Contract calls (#19)
This commit is contained in:
@@ -3,17 +3,104 @@
|
||||
use inkwell::values::BasicValue;
|
||||
|
||||
use crate::polkavm::context::argument::Argument;
|
||||
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::Dependency;
|
||||
use crate::polkavm_const::runtime_api;
|
||||
|
||||
static STATIC_CALL_FLAG: u32 = 0b0001_0000;
|
||||
|
||||
/// Translates a contract call.
|
||||
/// If the `simulation_address` is specified, the call is substituted with another instruction
|
||||
/// according to the specification.
|
||||
///
|
||||
/// If the `simulation_address` is specified, the call is
|
||||
/// substituted with another instruction according to the specification.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn default<'ctx, D>(
|
||||
pub fn call<'ctx, D>(
|
||||
context: &mut Context<'ctx, D>,
|
||||
gas: inkwell::values::IntValue<'ctx>,
|
||||
address: inkwell::values::IntValue<'ctx>,
|
||||
value: Option<inkwell::values::IntValue<'ctx>>,
|
||||
input_offset: inkwell::values::IntValue<'ctx>,
|
||||
input_length: inkwell::values::IntValue<'ctx>,
|
||||
output_offset: inkwell::values::IntValue<'ctx>,
|
||||
output_length: inkwell::values::IntValue<'ctx>,
|
||||
_constants: Vec<Option<num::BigUint>>,
|
||||
static_call: bool,
|
||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
let address_pointer = context.build_alloca(context.word_type(), "address_ptr");
|
||||
context.build_store(address_pointer, address)?;
|
||||
|
||||
let value_pointer = if let Some(value) = value {
|
||||
let value_pointer = context.build_alloca(context.value_type(), "value");
|
||||
context.build_store(value_pointer, value)?;
|
||||
value_pointer.value
|
||||
} else {
|
||||
context.sentinel_pointer()
|
||||
};
|
||||
|
||||
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)?;
|
||||
|
||||
let gas = context
|
||||
.builder()
|
||||
.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 output_pointer = context.build_heap_gep(output_offset, output_length)?;
|
||||
|
||||
let output_length_pointer = context.get_global(crate::polkavm::GLOBAL_RETURN_DATA_SIZE)?;
|
||||
context.build_store(output_length_pointer.into(), output_length)?;
|
||||
|
||||
let argument_pointer = pallet_contracts_pvm_llapi::calling_convention::Spill::new(
|
||||
context.builder(),
|
||||
pallet_contracts_pvm_llapi::calling_convention::call(context.llvm()),
|
||||
"call_arguments",
|
||||
)?
|
||||
.next(context.xlen_type().const_int(flags as u64, false))?
|
||||
.next(address_pointer.value)?
|
||||
.next(gas)?
|
||||
.skip()
|
||||
.next(context.sentinel_pointer())?
|
||||
.next(value_pointer)?
|
||||
.next(input_pointer.value)?
|
||||
.next(input_length)?
|
||||
.next(output_pointer.value)?
|
||||
.next(output_length_pointer.value)?
|
||||
.done();
|
||||
|
||||
let name = runtime_api::imports::CALL;
|
||||
let arguments = context.builder().build_ptr_to_int(
|
||||
argument_pointer,
|
||||
context.xlen_type(),
|
||||
"argument_pointer",
|
||||
)?;
|
||||
let success = context
|
||||
.build_runtime_call(name, &[arguments.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())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn delegate_call<'ctx, D>(
|
||||
_context: &mut Context<'ctx, D>,
|
||||
_function: FunctionDeclaration<'ctx>,
|
||||
_gas: inkwell::values::IntValue<'ctx>,
|
||||
_address: inkwell::values::IntValue<'ctx>,
|
||||
_value: Option<inkwell::values::IntValue<'ctx>>,
|
||||
@@ -26,68 +113,7 @@ pub fn default<'ctx, D>(
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
todo!();
|
||||
|
||||
/*
|
||||
let ordinary_block = context.append_basic_block("contract_call_ordinary_block");
|
||||
let join_block = context.append_basic_block("contract_call_join_block");
|
||||
|
||||
let result_pointer = context.build_alloca(context.field_type(), "contract_call_result_pointer");
|
||||
context.build_store(result_pointer, context.field_const(0));
|
||||
|
||||
context.builder().build_switch(
|
||||
address,
|
||||
ordinary_block,
|
||||
&[(
|
||||
context.field_const(zkevm_opcode_defs::ADDRESS_IDENTITY.into()),
|
||||
identity_block,
|
||||
)],
|
||||
)?;
|
||||
|
||||
{
|
||||
context.set_basic_block(identity_block);
|
||||
let result = identity(context, output_offset, input_offset, output_length)?;
|
||||
context.build_store(result_pointer, result);
|
||||
context.build_unconditional_branch(join_block);
|
||||
}
|
||||
|
||||
context.set_basic_block(ordinary_block);
|
||||
let result = if let Some(value) = value {
|
||||
default_wrapped(
|
||||
context,
|
||||
function,
|
||||
gas,
|
||||
value,
|
||||
address,
|
||||
input_offset,
|
||||
input_length,
|
||||
output_offset,
|
||||
output_length,
|
||||
)?
|
||||
} else {
|
||||
let function = Runtime::default_call(context, function);
|
||||
context
|
||||
.build_call(
|
||||
function,
|
||||
&[
|
||||
gas.as_basic_value_enum(),
|
||||
address.as_basic_value_enum(),
|
||||
input_offset.as_basic_value_enum(),
|
||||
input_length.as_basic_value_enum(),
|
||||
output_offset.as_basic_value_enum(),
|
||||
output_length.as_basic_value_enum(),
|
||||
],
|
||||
"default_call",
|
||||
)
|
||||
.expect("Always exists")
|
||||
};
|
||||
context.build_store(result_pointer, result);
|
||||
context.build_unconditional_branch(join_block);
|
||||
|
||||
context.set_basic_block(join_block);
|
||||
let result = context.build_load(result_pointer, "contract_call_result");
|
||||
Ok(result)
|
||||
*/
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Translates the Yul `linkersymbol` instruction.
|
||||
|
||||
@@ -58,7 +58,7 @@ where
|
||||
"block_timestamp_output",
|
||||
);
|
||||
context.build_runtime_call(
|
||||
runtime_api::BLOCK_NUMBER,
|
||||
runtime_api::imports::BLOCK_NUMBER,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
@@ -83,7 +83,7 @@ where
|
||||
"block_timestamp_output",
|
||||
);
|
||||
context.build_runtime_call(
|
||||
runtime_api::NOW,
|
||||
runtime_api::imports::NOW,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
@@ -174,7 +174,7 @@ where
|
||||
let (output_pointer, output_length_pointer) =
|
||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_output");
|
||||
context.build_runtime_call(
|
||||
runtime_api::ADDRESS,
|
||||
runtime_api::imports::ADDRESS,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
@@ -197,7 +197,7 @@ where
|
||||
let (output_pointer, output_length_pointer) =
|
||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "caller_output");
|
||||
context.build_runtime_call(
|
||||
runtime_api::CALLER,
|
||||
runtime_api::imports::CALLER,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
|
||||
@@ -56,11 +56,7 @@ where
|
||||
|
||||
let (address_pointer, address_length_pointer) =
|
||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_pointer");
|
||||
|
||||
let sentinel = context
|
||||
.xlen_type()
|
||||
.const_all_ones()
|
||||
.const_to_pointer(context.llvm().ptr_type(Default::default()));
|
||||
context.build_store(address_pointer, context.word_const(0))?;
|
||||
|
||||
let argument_pointer = pallet_contracts_pvm_llapi::calling_convention::Spill::new(
|
||||
context.builder(),
|
||||
@@ -70,14 +66,14 @@ where
|
||||
.next(code_hash_pointer.value)?
|
||||
.skip()
|
||||
.skip()
|
||||
.next(sentinel)?
|
||||
.next(context.sentinel_pointer())?
|
||||
.next(value_pointer.value)?
|
||||
.next(input_data_pointer.value)?
|
||||
.next(input_length)?
|
||||
.next(address_pointer.value)?
|
||||
.next(address_length_pointer.value)?
|
||||
.next(sentinel)?
|
||||
.next(sentinel)?
|
||||
.next(context.sentinel_pointer())?
|
||||
.next(context.sentinel_pointer())?
|
||||
.next(salt_pointer.value)?
|
||||
.next(
|
||||
context
|
||||
@@ -86,14 +82,13 @@ where
|
||||
)?
|
||||
.done();
|
||||
|
||||
context.builder().build_direct_call(
|
||||
context.runtime_api_method(runtime_api::INSTANTIATE),
|
||||
context.build_runtime_call(
|
||||
runtime_api::imports::INSTANTIATE,
|
||||
&[context
|
||||
.builder()
|
||||
.build_ptr_to_int(argument_pointer, context.xlen_type(), "argument_pointer")?
|
||||
.into()],
|
||||
"create2",
|
||||
)?;
|
||||
);
|
||||
|
||||
context.build_load_word(
|
||||
address_pointer,
|
||||
|
||||
@@ -19,7 +19,7 @@ where
|
||||
let output_pointer = context.build_alloca(context.word_type(), "output_pointer");
|
||||
|
||||
context.build_runtime_call(
|
||||
runtime_api::HASH_KECCAK_256,
|
||||
runtime_api::imports::HASH_KECCAK_256,
|
||||
&[
|
||||
input_pointer.to_int(context).into(),
|
||||
length_casted.into(),
|
||||
|
||||
@@ -26,7 +26,7 @@ where
|
||||
let (output_pointer, output_length_pointer) =
|
||||
context.build_stack_parameter(revive_common::BIT_LENGTH_VALUE, "value_transferred_output");
|
||||
context.build_runtime_call(
|
||||
runtime_api::VALUE_TRANSFERRED,
|
||||
runtime_api::imports::VALUE_TRANSFERRED,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
|
||||
@@ -75,7 +75,7 @@ where
|
||||
]
|
||||
};
|
||||
|
||||
let _ = context.build_runtime_call(runtime_api::DEPOSIT_EVENT, &arguments);
|
||||
let _ = context.build_runtime_call(runtime_api::imports::DEPOSIT_EVENT, &arguments);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -23,8 +23,11 @@ where
|
||||
"address_pointer",
|
||||
)?;
|
||||
let value = context
|
||||
.build_runtime_call(runtime_api::CODE_SIZE, &[address_pointer_casted.into()])
|
||||
.unwrap_or_else(|| panic!("{} should return a value", runtime_api::CODE_SIZE))
|
||||
.build_runtime_call(
|
||||
runtime_api::imports::CODE_SIZE,
|
||||
&[address_pointer_casted.into()],
|
||||
)
|
||||
.unwrap_or_else(|| panic!("{} should return a value", runtime_api::imports::CODE_SIZE))
|
||||
.into_int_value();
|
||||
|
||||
Ok(context
|
||||
|
||||
@@ -4,6 +4,7 @@ use inkwell::values::BasicValue;
|
||||
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::Dependency;
|
||||
use crate::polkavm_const::runtime_api;
|
||||
|
||||
/// Translates the return data size.
|
||||
pub fn size<'ctx, D>(
|
||||
@@ -38,54 +39,16 @@ where
|
||||
let destination_offset = context.safe_truncate_int_to_xlen(destination_offset)?;
|
||||
let size = context.safe_truncate_int_to_xlen(size)?;
|
||||
|
||||
let block_copy = context.append_basic_block("copy_block");
|
||||
let block_trap = context.append_basic_block("trap_block");
|
||||
let block_check_out_of_bounds = context.append_basic_block("check_out_of_bounds_block");
|
||||
let is_overflow = context.builder().build_int_compare(
|
||||
inkwell::IntPredicate::UGT,
|
||||
source_offset,
|
||||
context.builder().build_int_sub(
|
||||
context.xlen_type().const_all_ones(),
|
||||
size,
|
||||
"offset_plus_size_max_value",
|
||||
)?,
|
||||
"is_returndata_size_out_of_bounds",
|
||||
let destination_offset = context.builder().build_ptr_to_int(
|
||||
context.build_heap_gep(destination_offset, size)?.value,
|
||||
context.xlen_type(),
|
||||
"destination_offset",
|
||||
)?;
|
||||
context.build_conditional_branch(is_overflow, block_trap, block_check_out_of_bounds)?;
|
||||
|
||||
context.set_basic_block(block_check_out_of_bounds);
|
||||
let is_out_of_bounds = context.builder().build_int_compare(
|
||||
inkwell::IntPredicate::UGT,
|
||||
context.builder().build_int_add(
|
||||
source_offset,
|
||||
context
|
||||
.get_global_value(crate::polkavm::GLOBAL_RETURN_DATA_SIZE)?
|
||||
.into_int_value(),
|
||||
"returndata_end_pointer",
|
||||
)?,
|
||||
context
|
||||
.xlen_type()
|
||||
.const_int(crate::PolkaVMEntryFunction::MAX_CALLDATA_SIZE as u64, false),
|
||||
"is_return_data_copy_overflow",
|
||||
)?;
|
||||
context.build_conditional_branch(is_out_of_bounds, block_trap, block_copy)?;
|
||||
context.build_runtime_call(
|
||||
runtime_api::imports::RETURNDATACOPY,
|
||||
&[destination_offset.into(), source_offset.into(), size.into()],
|
||||
);
|
||||
|
||||
context.set_basic_block(block_trap);
|
||||
context.build_call(context.intrinsics().trap, &[], "invalid_returndata_copy");
|
||||
context.build_unreachable();
|
||||
|
||||
context.set_basic_block(block_copy);
|
||||
context.build_memcpy(
|
||||
context.build_heap_gep(destination_offset, size)?,
|
||||
context.build_gep(
|
||||
context
|
||||
.get_global(crate::polkavm::GLOBAL_RETURN_DATA_POINTER)?
|
||||
.into(),
|
||||
&[context.xlen_type().const_zero(), source_offset],
|
||||
context.byte_type(),
|
||||
"source_offset_gep",
|
||||
),
|
||||
size,
|
||||
"return_data_copy_memcpy_from_return_data",
|
||||
)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user