pub(super) mod target;
use crate::sema::ast;
use std::cmp::Ordering;
use crate::codegen::{cfg::ReturnCode, Options};
use crate::sema::ast::{StructType, Type};
use inkwell::module::{Linkage, Module};
use inkwell::types::BasicType;
use inkwell::values::{
BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, UnnamedAddress,
};
use inkwell::{context::Context, types::BasicTypeEnum};
use inkwell::{AddressSpace, IntPredicate};
use num_traits::ToPrimitive;
use crate::emit::functions::emit_functions;
use crate::emit::loop_builder::LoopBuilder;
use crate::emit::{Binary, ContractArgs, TargetRuntime};
pub struct SolanaTarget();
impl SolanaTarget {
pub fn build<'a>(
context: &'a Context,
std_lib: &Module<'a>,
contract: &'a ast::Contract,
ns: &'a ast::Namespace,
opt: &'a Options,
) -> Binary<'a> {
let mut target = SolanaTarget();
let filename = ns.files[contract.loc.file_no()].file_name();
let mut bin = Binary::new(
context,
ns,
&contract.id.name,
filename.as_str(),
opt,
std_lib,
None,
);
bin.return_values
.insert(ReturnCode::Success, context.i64_type().const_zero());
bin.return_values.insert(
ReturnCode::FunctionSelectorInvalid,
context.i64_type().const_int(2u64 << 32, false),
);
bin.return_values.insert(
ReturnCode::AbiEncodingInvalid,
context.i64_type().const_int(2u64 << 32, false),
);
bin.return_values.insert(
ReturnCode::InvalidProgramId,
context.i64_type().const_int(7u64 << 32, false),
);
bin.return_values.insert(
ReturnCode::InvalidDataError,
context.i64_type().const_int(2, false),
);
bin.return_values.insert(
ReturnCode::AccountDataTooSmall,
context.i64_type().const_int(5u64 << 32, false),
);
target.declare_externals(&mut bin);
emit_functions(&mut target, &mut bin, contract);
bin.internalize(&[
"entrypoint",
"sol_log_",
"sol_log_pubkey",
"sol_invoke_signed_c",
"sol_panic_",
"sol_get_return_data",
"sol_set_return_data",
"sol_create_program_address",
"sol_try_find_program_address",
"sol_sha256",
"sol_keccak256",
"sol_log_data",
]);
bin
}
fn declare_externals(&self, bin: &mut Binary) {
let void_ty = bin.context.void_type();
let u8_ptr = bin.context.i8_type().ptr_type(AddressSpace::default());
let u64_ty = bin.context.i64_type();
let u32_ty = bin.context.i32_type();
let address = bin.address_type().ptr_type(AddressSpace::default());
let seeds = bin.llvm_type(&Type::Ref(Box::new(Type::Slice(Box::new(Type::Bytes(1))))));
let sol_bytes = bin
.context
.struct_type(&[u8_ptr.into(), u64_ty.into()], false)
.ptr_type(AddressSpace::default());
let function = bin.module.add_function(
"sol_log_",
void_ty.fn_type(&[u8_ptr.into(), u64_ty.into()], false),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let function = bin.module.add_function(
"sol_log_64_",
void_ty.fn_type(
&[
u64_ty.into(),
u64_ty.into(),
u64_ty.into(),
u64_ty.into(),
u64_ty.into(),
],
false,
),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let function = bin.module.add_function(
"sol_sha256",
void_ty.fn_type(&[sol_bytes.into(), u32_ty.into(), u8_ptr.into()], false),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let function = bin.module.add_function(
"sol_keccak256",
void_ty.fn_type(&[sol_bytes.into(), u32_ty.into(), u8_ptr.into()], false),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let function = bin.module.add_function(
"sol_set_return_data",
void_ty.fn_type(&[u8_ptr.into(), u64_ty.into()], false),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let function = bin.module.add_function(
"sol_get_return_data",
u64_ty.fn_type(&[u8_ptr.into(), u64_ty.into(), u8_ptr.into()], false),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let fields = bin.context.opaque_struct_type("SolLogDataField");
fields.set_body(&[u8_ptr.into(), u64_ty.into()], false);
let function = bin.module.add_function(
"sol_log_data",
void_ty.fn_type(
&[
fields.ptr_type(AddressSpace::default()).into(),
u64_ty.into(),
],
false,
),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let function = bin.module.add_function(
"sol_create_program_address",
u64_ty.fn_type(
&[seeds.into(), u64_ty.into(), address.into(), address.into()],
false,
),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let function = bin.module.add_function(
"sol_try_find_program_address",
u64_ty.fn_type(
&[
seeds.into(),
u64_ty.into(),
address.into(),
address.into(),
u8_ptr.into(),
],
false,
),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
let function = bin.module.add_function(
"sol_invoke_signed_c",
u64_ty.fn_type(
&[
u8_ptr.into(),
bin.module
.get_struct_type("struct.SolAccountInfo")
.unwrap()
.ptr_type(AddressSpace::default())
.into(),
bin.context.i32_type().into(),
bin.context
.i8_type()
.ptr_type(AddressSpace::default())
.into(),
bin.context.i32_type().into(),
],
false,
),
None,
);
function
.as_global_value()
.set_unnamed_address(UnnamedAddress::Local);
}
fn contract_storage_account<'b>(&self, bin: &Binary<'b>) -> PointerValue<'b> {
let parameters = self.sol_parameters(bin);
unsafe {
bin.builder
.build_gep(
bin.module.get_struct_type("struct.SolParameters").unwrap(),
parameters,
&[
bin.context.i32_type().const_int(0, false),
bin.context.i32_type().const_int(0, false),
bin.context.i32_type().const_int(0, false),
],
"account",
)
.unwrap()
}
}
fn sol_parameters<'b>(&self, bin: &Binary<'b>) -> PointerValue<'b> {
bin.builder
.get_insert_block()
.unwrap()
.get_parent()
.unwrap()
.get_last_param()
.unwrap()
.into_pointer_value()
}
fn contract_storage_data<'b>(&self, bin: &Binary<'b>) -> PointerValue<'b> {
let parameters = self.sol_parameters(bin);
bin.builder
.build_load(
bin.context.i8_type().ptr_type(AddressSpace::default()),
unsafe {
bin.builder
.build_gep(
bin.module.get_struct_type("struct.SolParameters").unwrap(),
parameters,
&[
bin.context.i32_type().const_int(0, false),
bin.context.i32_type().const_int(0, false),
bin.context.i32_type().const_int(0, false),
bin.context.i32_type().const_int(3, false),
],
"data",
)
.unwrap()
},
"data",
)
.unwrap()
.into_pointer_value()
}
fn storage_free<'b>(
&self,
bin: &Binary<'b>,
ty: &ast::Type,
data: PointerValue<'b>,
slot: IntValue<'b>,
function: FunctionValue<'b>,
zero: bool,
) {
if !zero && !ty.is_dynamic(bin.ns) {
return;
}
let member = unsafe {
bin.builder
.build_gep(bin.context.i8_type(), data, &[slot], "data")
.unwrap()
};
if *ty == ast::Type::String || *ty == ast::Type::DynamicBytes {
let offset = bin
.builder
.build_load(bin.context.i32_type(), member, "offset")
.unwrap()
.into_int_value();
bin.builder
.build_call(
bin.module.get_function("account_data_free").unwrap(),
&[data.into(), offset.into()],
"",
)
.unwrap();
let new_offset = bin.context.i32_type().const_zero();
bin.builder.build_store(member, new_offset).unwrap();
} else if let ast::Type::Array(elem_ty, dim) = ty {
let mut elem_slot = slot;
let mut free_array = None;
if elem_ty.is_dynamic(bin.ns) || zero {
let length = if let Some(ast::ArrayLength::Fixed(length)) = dim.last() {
bin.context
.i32_type()
.const_int(length.to_u64().unwrap(), false)
} else {
elem_slot = bin
.builder
.build_load(bin.context.i32_type(), member, "offset")
.unwrap()
.into_int_value();
free_array = Some(elem_slot);
self.storage_array_length(bin, function, slot, elem_ty)
};
let elem_size = elem_ty.solana_storage_size(bin.ns).to_u64().unwrap();
let mut builder = LoopBuilder::new(bin, function);
let offset_phi =
builder.add_loop_phi(bin, "offset", slot.get_type(), elem_slot.into());
let _ = builder.over(bin, bin.context.i32_type().const_zero(), length);
let offset_val = offset_phi.into_int_value();
let elem_ty = ty.array_deref();
self.storage_free(bin, elem_ty.deref_any(), data, offset_val, function, zero);
let offset_val = bin
.builder
.build_int_add(
offset_val,
bin.context.i32_type().const_int(elem_size, false),
"new_offset",
)
.unwrap();
builder.set_loop_phi_value(bin, "offset", offset_val.into());
builder.finish(bin);
}
if let Some(offset) = free_array {
bin.builder
.build_call(
bin.module.get_function("account_data_free").unwrap(),
&[data.into(), offset.into()],
"",
)
.unwrap();
if zero {
let new_offset = bin.context.i32_type().const_zero();
bin.builder.build_store(member, new_offset).unwrap();
}
}
} else if let ast::Type::Struct(struct_ty) = ty {
for (i, field) in struct_ty.definition(bin.ns).fields.iter().enumerate() {
let field_offset = struct_ty.definition(bin.ns).storage_offsets[i]
.to_u64()
.unwrap();
let offset = bin
.builder
.build_int_add(
slot,
bin.context.i32_type().const_int(field_offset, false),
"field_offset",
)
.unwrap();
self.storage_free(bin, &field.ty, data, offset, function, zero);
}
} else if matches!(ty, Type::Address(_) | Type::Contract(_)) {
let ty = bin.llvm_type(ty);
bin.builder
.build_store(member, ty.into_array_type().const_zero())
.unwrap();
} else {
let ty = bin.llvm_type(ty);
bin.builder
.build_store(member, ty.into_int_type().const_zero())
.unwrap();
}
}
fn sparse_entry<'b>(
&self,
bin: &Binary<'b>,
key_ty: &ast::Type,
value_ty: &ast::Type,
) -> BasicTypeEnum<'b> {
let key = if matches!(
key_ty,
ast::Type::String | ast::Type::DynamicBytes | ast::Type::Mapping(..)
) {
bin.context.i32_type().into()
} else {
bin.llvm_type(key_ty)
};
bin.context
.struct_type(
&[
key, bin.context.i32_type().into(), if value_ty.is_mapping() {
bin.context.i32_type().into()
} else {
bin.llvm_type(value_ty) },
],
false,
)
.into()
}
fn sparse_lookup_function<'b>(
&self,
bin: &Binary<'b>,
key_ty: &ast::Type,
value_ty: &ast::Type,
) -> FunctionValue<'b> {
let function_name = format!(
"sparse_lookup_{}_{}",
key_ty.to_llvm_string(bin.ns),
value_ty.to_llvm_string(bin.ns)
);
if let Some(function) = bin.module.get_function(&function_name) {
return function;
}
let function_ty = bin.function_type(
&[ast::Type::Uint(32), key_ty.clone()],
&[ast::Type::Uint(32)],
);
let function =
bin.module
.add_function(&function_name, function_ty, Some(Linkage::Internal));
let entry = bin.context.append_basic_block(function, "entry");
bin.builder.position_at_end(entry);
let offset = function.get_nth_param(0).unwrap().into_int_value();
let key = function.get_nth_param(1).unwrap();
let entry_ty = self.sparse_entry(bin, key_ty, value_ty);
let value_offset = unsafe {
entry_ty
.ptr_type(AddressSpace::default())
.const_null()
.const_gep(
entry_ty.as_basic_type_enum(),
&[
bin.context.i32_type().const_zero(),
bin.context.i32_type().const_int(2, false),
],
)
.const_to_int(bin.context.i32_type())
};
let data = self.contract_storage_data(bin);
let member = unsafe {
bin.builder
.build_gep(bin.context.i8_type(), data, &[offset], "data")
}
.unwrap();
let address = bin.build_alloca(function, bin.address_type(), "address");
let bucket = if matches!(key_ty, ast::Type::String | ast::Type::DynamicBytes) {
bin.builder
.build_call(
bin.module.get_function("vector_hash").unwrap(),
&[key.into()],
"hash",
)
.unwrap()
.try_as_basic_value()
.left()
.unwrap()
.into_int_value()
} else if matches!(key_ty, ast::Type::Contract(_) | ast::Type::Address(_)) {
bin.builder.build_store(address, key).unwrap();
bin.builder
.build_call(
bin.module.get_function("address_hash").unwrap(),
&[address.into()],
"hash",
)
.unwrap()
.try_as_basic_value()
.left()
.unwrap()
.into_int_value()
} else if key_ty.bits(bin.ns) > 64 {
bin.builder
.build_int_truncate(key.into_int_value(), bin.context.i64_type(), "")
.unwrap()
} else {
key.into_int_value()
};
let bucket = bin
.builder
.build_int_unsigned_rem(
bucket,
bucket
.get_type()
.const_int(crate::sema::SOLANA_BUCKET_SIZE, false),
"",
)
.unwrap();
let first_offset_ptr = unsafe {
bin.builder
.build_gep(bin.context.i32_type(), member, &[bucket], "bucket_list")
}
.unwrap();
let loop_entry = bin.context.append_basic_block(function, "loop_entry");
let end_of_bucket = bin.context.append_basic_block(function, "end_of_bucket");
let examine_bucket = bin.context.append_basic_block(function, "examine_bucket");
let found_entry = bin.context.append_basic_block(function, "found_entry");
let next_entry = bin.context.append_basic_block(function, "next_entry");
bin.builder.build_unconditional_branch(loop_entry).unwrap();
bin.builder.position_at_end(loop_entry);
let offset_ptr_phi = bin
.builder
.build_phi(
bin.context.i32_type().ptr_type(AddressSpace::default()),
"offset_ptr",
)
.unwrap();
offset_ptr_phi.add_incoming(&[(&first_offset_ptr, entry)]);
let offset = bin
.builder
.build_load(
bin.context.i32_type(),
offset_ptr_phi.as_basic_value().into_pointer_value(),
"offset",
)
.unwrap()
.into_int_value();
let is_offset_zero = bin
.builder
.build_int_compare(
IntPredicate::EQ,
offset,
offset.get_type().const_zero(),
"offset_is_zero",
)
.unwrap();
bin.builder
.build_conditional_branch(is_offset_zero, end_of_bucket, examine_bucket)
.unwrap();
bin.builder.position_at_end(examine_bucket);
let member = unsafe {
bin.builder
.build_gep(bin.context.i8_type(), data, &[offset], "data")
}
.unwrap();
let ptr = unsafe {
bin.builder
.build_gep(
entry_ty,
member,
&[
bin.context.i32_type().const_zero(),
bin.context.i32_type().const_zero(),
],
"key_ptr",
)
.unwrap()
};
let matches = if matches!(key_ty, ast::Type::String | ast::Type::DynamicBytes) {
let entry_key = bin
.builder
.build_load(bin.context.i32_type(), ptr, "key")
.unwrap();
let entry_data = unsafe {
bin.builder
.build_gep(
bin.context.i8_type(),
data,
&[entry_key.into_int_value()],
"data",
)
.unwrap()
};
let entry_length = bin
.builder
.build_call(
bin.module.get_function("account_data_len").unwrap(),
&[data.into(), entry_key.into()],
"length",
)
.unwrap()
.try_as_basic_value()
.left()
.unwrap()
.into_int_value();
bin.builder
.build_call(
bin.module.get_function("__memcmp").unwrap(),
&[
entry_data.into(),
entry_length.into(),
bin.vector_bytes(key).into(),
bin.vector_len(key).into(),
],
"",
)
.unwrap()
.try_as_basic_value()
.left()
.unwrap()
.into_int_value()
} else if matches!(key_ty, ast::Type::Address(_) | ast::Type::Contract(_)) {
bin.builder
.build_call(
bin.module.get_function("address_equal").unwrap(),
&[address.into(), ptr.into()],
"",
)
.unwrap()
.try_as_basic_value()
.left()
.unwrap()
.into_int_value()
} else {
let entry_key = bin
.builder
.build_load(bin.llvm_type(key_ty), ptr, "key")
.unwrap();
bin.builder
.build_int_compare(
IntPredicate::EQ,
key.into_int_value(),
entry_key.into_int_value(),
"matches",
)
.unwrap()
};
bin.builder
.build_conditional_branch(matches, found_entry, next_entry)
.unwrap();
bin.builder.position_at_end(found_entry);
let ret_offset = function.get_nth_param(2).unwrap().into_pointer_value();
bin.builder
.build_store(
ret_offset,
bin.builder
.build_int_add(offset, value_offset, "value_offset")
.unwrap(),
)
.unwrap();
bin.builder
.build_return(Some(&bin.context.i64_type().const_zero()))
.unwrap();
bin.builder.position_at_end(next_entry);
let offset_ptr = bin
.builder
.build_struct_gep(entry_ty, member, 1, "offset_ptr")
.unwrap();
offset_ptr_phi.add_incoming(&[(&offset_ptr, next_entry)]);
bin.builder.build_unconditional_branch(loop_entry).unwrap();
let offset_ptr = offset_ptr_phi.as_basic_value().into_pointer_value();
bin.builder.position_at_end(end_of_bucket);
let entry_length = entry_ty
.size_of()
.unwrap()
.const_cast(bin.context.i32_type(), false);
let account = self.contract_storage_account(bin);
let rc = bin
.builder
.build_call(
bin.module.get_function("account_data_alloc").unwrap(),
&[account.into(), entry_length.into(), offset_ptr.into()],
"rc",
)
.unwrap()
.try_as_basic_value()
.left()
.unwrap()
.into_int_value();
let is_rc_zero = bin
.builder
.build_int_compare(
IntPredicate::EQ,
rc,
bin.context.i64_type().const_zero(),
"is_rc_zero",
)
.unwrap();
let rc_not_zero = bin.context.append_basic_block(function, "rc_not_zero");
let rc_zero = bin.context.append_basic_block(function, "rc_zero");
bin.builder
.build_conditional_branch(is_rc_zero, rc_zero, rc_not_zero)
.unwrap();
bin.builder.position_at_end(rc_not_zero);
self.return_code(bin, rc);
bin.builder.position_at_end(rc_zero);
let offset = bin
.builder
.build_load(bin.context.i32_type(), offset_ptr, "new_offset")
.unwrap()
.into_int_value();
let member = unsafe {
bin.builder
.build_gep(bin.context.i8_type(), data, &[offset], "data")
.unwrap()
};
let length = bin
.builder
.build_int_unsigned_div(
bin.builder
.build_int_add(entry_length, bin.context.i32_type().const_int(7, false), "")
.unwrap(),
bin.context.i32_type().const_int(8, false),
"length_div_8",
)
.unwrap();
bin.builder
.build_call(
bin.module.get_function("__bzero8").unwrap(),
&[member.into(), length.into()],
"zeroed",
)
.unwrap();
if matches!(key_ty, ast::Type::String | ast::Type::DynamicBytes) {
let new_string_length = bin.vector_len(key);
let offset_ptr = bin
.builder
.build_struct_gep(entry_ty, member, 0, "key_ptr")
.unwrap();
let rc = bin
.builder
.build_call(
bin.module.get_function("account_data_alloc").unwrap(),
&[account.into(), new_string_length.into(), offset_ptr.into()],
"alloc",
)
.unwrap()
.try_as_basic_value()
.left()
.unwrap()
.into_int_value();
let is_rc_zero = bin
.builder
.build_int_compare(
IntPredicate::EQ,
rc,
bin.context.i64_type().const_zero(),
"is_rc_zero",
)
.unwrap();
let rc_not_zero = bin.context.append_basic_block(function, "rc_not_zero");
let rc_zero = bin.context.append_basic_block(function, "rc_zero");
let memcpy = bin.context.append_basic_block(function, "memcpy");
bin.builder
.build_conditional_branch(is_rc_zero, rc_zero, rc_not_zero)
.unwrap();
bin.builder.position_at_end(rc_not_zero);
self.return_code(bin, bin.context.i64_type().const_int(5u64 << 32, false));
bin.builder.position_at_end(rc_zero);
let new_offset = bin
.builder
.build_load(bin.context.i32_type(), offset_ptr, "new_offset")
.unwrap();
bin.builder.build_unconditional_branch(memcpy).unwrap();
bin.builder.position_at_end(memcpy);
let offset_phi = bin
.builder
.build_phi(bin.context.i32_type(), "offset")
.unwrap();
offset_phi.add_incoming(&[(&new_offset, rc_zero), (&offset, entry)]);
let dest_string_data = unsafe {
bin.builder
.build_gep(
bin.context.i8_type(),
data,
&[offset_phi.as_basic_value().into_int_value()],
"dest_string_data",
)
.unwrap()
};
bin.builder
.build_call(
bin.module.get_function("__memcpy").unwrap(),
&[
dest_string_data.into(),
bin.vector_bytes(key).into(),
new_string_length.into(),
],
"copied",
)
.unwrap();
} else {
let key_ptr = bin
.builder
.build_struct_gep(entry_ty, member, 0, "key_ptr")
.unwrap();
bin.builder.build_store(key_ptr, key).unwrap();
};
let ret_offset = function.get_nth_param(2).unwrap().into_pointer_value();
bin.builder
.build_store(
ret_offset,
bin.builder
.build_int_add(offset, value_offset, "value_offset")
.unwrap(),
)
.unwrap();
bin.builder
.build_return(Some(&bin.context.i64_type().const_zero()))
.unwrap();
function
}
fn sparse_lookup<'b>(
&self,
bin: &Binary<'b>,
function: FunctionValue<'b>,
key_ty: &ast::Type,
value_ty: &ast::Type,
slot: IntValue<'b>,
index: BasicValueEnum<'b>,
) -> IntValue<'b> {
let offset = bin.build_alloca(function, bin.context.i32_type(), "offset");
let current_block = bin.builder.get_insert_block().unwrap();
let lookup = self.sparse_lookup_function(bin, key_ty, value_ty);
bin.builder.position_at_end(current_block);
let parameters = self.sol_parameters(bin);
let rc = bin
.builder
.build_call(
lookup,
&[slot.into(), index.into(), offset.into(), parameters.into()],
"mapping_lookup_res",
)
.unwrap()
.try_as_basic_value()
.left()
.unwrap()
.into_int_value();
let is_rc_zero = bin
.builder
.build_int_compare(
IntPredicate::EQ,
rc,
rc.get_type().const_zero(),
"is_rc_zero",
)
.unwrap();
let rc_not_zero = bin.context.append_basic_block(function, "rc_not_zero");
let rc_zero = bin.context.append_basic_block(function, "rc_zero");
bin.builder
.build_conditional_branch(is_rc_zero, rc_zero, rc_not_zero)
.unwrap();
bin.builder.position_at_end(rc_not_zero);
self.return_code(bin, rc);
bin.builder.position_at_end(rc_zero);
bin.builder
.build_load(bin.context.i32_type(), offset, "offset")
.unwrap()
.into_int_value()
}
fn account_info_member<'b>(
&self,
bin: &Binary<'b>,
function: FunctionValue<'b>,
account_info: PointerValue<'b>,
member: usize,
) -> BasicValueEnum<'b> {
let account_info_ty = bin.module.get_struct_type("struct.SolAccountInfo").unwrap();
let gep_no = match member.cmp(&2) {
Ordering::Less => member as u32,
Ordering::Greater => (member + 1) as u32,
Ordering::Equal => {
let data_len = bin
.builder
.build_load(
bin.context.i64_type(),
bin.builder
.build_struct_gep(account_info_ty, account_info, 2, "data_len")
.unwrap(),
"data_len",
)
.unwrap()
.into_int_value();
let data = bin
.builder
.build_load(
bin.context.i8_type().ptr_type(AddressSpace::default()),
bin.builder
.build_struct_gep(account_info_ty, account_info, 3, "data")
.unwrap(),
"data",
)
.unwrap();
let slice_alloca = bin.build_alloca(
function,
bin.llvm_type(&ast::Type::Slice(Box::new(Type::Bytes(1)))),
"slice_alloca",
);
let data_elem = bin
.builder
.build_struct_gep(
bin.llvm_type(&ast::Type::Slice(Box::new(Type::Bytes(1)))),
slice_alloca,
0,
"data",
)
.unwrap();
bin.builder.build_store(data_elem, data).unwrap();
let data_len_elem = bin
.builder
.build_struct_gep(
bin.llvm_type(&ast::Type::Slice(Box::new(Type::Bytes(1)))),
slice_alloca,
1,
"data_len",
)
.unwrap();
bin.builder.build_store(data_len_elem, data_len).unwrap();
return slice_alloca.as_basic_value_enum();
}
};
bin.builder
.build_struct_gep(
account_info_ty,
account_info,
gep_no,
format!("AccountInfo_member_{}", member).as_str(),
)
.unwrap()
.as_basic_value_enum()
}
fn build_invoke_signed_c<'b>(
&self,
bin: &Binary<'b>,
function: FunctionValue<'b>,
payload: PointerValue<'b>,
payload_len: IntValue<'b>,
contract_args: ContractArgs<'b>,
) {
let instruction_ty: BasicTypeEnum = bin
.context
.struct_type(
&[
bin.module
.get_struct_type("struct.SolPubkey")
.unwrap()
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
bin.llvm_type(&Type::Struct(StructType::AccountMeta))
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
bin.context.i64_type().as_basic_type_enum(),
bin.context
.i8_type()
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
bin.context.i64_type().as_basic_type_enum(),
],
false,
)
.as_basic_type_enum();
let instruction = bin.build_alloca(function, instruction_ty, "instruction");
bin.builder
.build_store(
bin.builder
.build_struct_gep(instruction_ty, instruction, 0, "program_id")
.unwrap(),
contract_args.program_id.unwrap(),
)
.unwrap();
bin.builder
.build_store(
bin.builder
.build_struct_gep(instruction_ty, instruction, 1, "accounts")
.unwrap(),
contract_args.accounts.unwrap().0,
)
.unwrap();
bin.builder
.build_store(
bin.builder
.build_struct_gep(instruction_ty, instruction, 2, "accounts_len")
.unwrap(),
bin.builder
.build_int_z_extend(
contract_args.accounts.unwrap().1,
bin.context.i64_type(),
"accounts_len",
)
.unwrap(),
)
.unwrap();
bin.builder
.build_store(
bin.builder
.build_struct_gep(instruction_ty, instruction, 3, "data")
.unwrap(),
payload,
)
.unwrap();
bin.builder
.build_store(
bin.builder
.build_struct_gep(instruction_ty, instruction, 4, "data_len")
.unwrap(),
bin.builder
.build_int_z_extend(payload_len, bin.context.i64_type(), "payload_len")
.unwrap(),
)
.unwrap();
let parameters = self.sol_parameters(bin);
let account_infos = bin
.builder
.build_struct_gep(
bin.module.get_struct_type("struct.SolParameters").unwrap(),
parameters,
0,
"ka",
)
.unwrap();
let account_infos_len = bin
.builder
.build_int_truncate(
bin.builder
.build_load(
bin.context.i64_type(),
bin.builder
.build_struct_gep(
bin.module.get_struct_type("struct.SolParameters").unwrap(),
parameters,
1,
"ka_num",
)
.unwrap(),
"ka_num",
)
.unwrap()
.into_int_value(),
bin.context.i32_type(),
"ka_num",
)
.unwrap();
let external_call = bin.module.get_function("sol_invoke_signed_c").unwrap();
let (signer_seeds, signer_seeds_len) = if let Some((seeds, len)) = contract_args.seeds {
(
seeds,
bin.builder
.build_int_cast(
len,
external_call.get_type().get_param_types()[4].into_int_type(),
"len",
)
.unwrap(),
)
} else {
(
external_call.get_type().get_param_types()[3]
.const_zero()
.into_pointer_value(),
external_call.get_type().get_param_types()[4]
.const_zero()
.into_int_value(),
)
};
bin.builder
.build_call(
external_call,
&[
instruction.into(),
account_infos.into(),
account_infos_len.into(),
signer_seeds.into(),
signer_seeds_len.into(),
],
"",
)
.unwrap();
}
}