|
|
@@ -967,46 +967,125 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
|
|
|
payload_len: IntValue<'b>,
|
|
|
address: Option<PointerValue<'b>>,
|
|
|
contract_args: ContractArgs<'b>,
|
|
|
- _ty: ast::CallTy,
|
|
|
+ call_type: ast::CallTy,
|
|
|
ns: &ast::Namespace,
|
|
|
loc: Loc,
|
|
|
) {
|
|
|
emit_context!(binary);
|
|
|
|
|
|
- // balance is a u128
|
|
|
- let value_ptr = binary
|
|
|
- .builder
|
|
|
- .build_alloca(binary.value_type(ns), "balance");
|
|
|
- binary
|
|
|
- .builder
|
|
|
- .build_store(value_ptr, contract_args.value.unwrap());
|
|
|
-
|
|
|
let (scratch_buf, scratch_len) = scratch_buf!();
|
|
|
-
|
|
|
binary
|
|
|
.builder
|
|
|
.build_store(scratch_len, i32_const!(SCRATCH_SIZE as u64));
|
|
|
|
|
|
// do the actual call
|
|
|
- let ret = call!(
|
|
|
- "seal_call",
|
|
|
- &[
|
|
|
- contract_args.flags.unwrap_or(i32_zero!()).into(),
|
|
|
- address.unwrap().into(),
|
|
|
- contract_args.gas.unwrap().into(),
|
|
|
- value_ptr.into(),
|
|
|
- payload.into(),
|
|
|
- payload_len.into(),
|
|
|
- scratch_buf.into(),
|
|
|
- scratch_len.into(),
|
|
|
- ]
|
|
|
- )
|
|
|
- .try_as_basic_value()
|
|
|
- .left()
|
|
|
- .unwrap()
|
|
|
- .into_int_value();
|
|
|
+ let ret = match call_type {
|
|
|
+ ast::CallTy::Regular => {
|
|
|
+ let value_ptr = binary
|
|
|
+ .builder
|
|
|
+ .build_alloca(binary.value_type(ns), "balance");
|
|
|
+ binary
|
|
|
+ .builder
|
|
|
+ .build_store(value_ptr, contract_args.value.unwrap());
|
|
|
+ let ret = call!(
|
|
|
+ "seal_call",
|
|
|
+ &[
|
|
|
+ contract_args.flags.unwrap_or(i32_zero!()).into(),
|
|
|
+ address.unwrap().into(),
|
|
|
+ contract_args.gas.unwrap().into(),
|
|
|
+ value_ptr.into(),
|
|
|
+ payload.into(),
|
|
|
+ payload_len.into(),
|
|
|
+ scratch_buf.into(),
|
|
|
+ scratch_len.into(),
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ .try_as_basic_value()
|
|
|
+ .left()
|
|
|
+ .unwrap()
|
|
|
+ .into_int_value();
|
|
|
+ log_return_code(binary, "seal_call", ret);
|
|
|
+ ret
|
|
|
+ }
|
|
|
+ ast::CallTy::Delegate => {
|
|
|
+ // delegate_call asks for a code hash instead of an address
|
|
|
+ let hash_len = i32_const!(32); // FIXME: This is configurable like the address length
|
|
|
+ let code_hash_out_ptr = binary.builder.build_array_alloca(
|
|
|
+ binary.context.i8_type(),
|
|
|
+ hash_len,
|
|
|
+ "code_hash_out_ptr",
|
|
|
+ );
|
|
|
+ let code_hash_out_len_ptr = binary
|
|
|
+ .builder
|
|
|
+ .build_alloca(binary.context.i32_type(), "code_hash_out_len_ptr");
|
|
|
+ binary.builder.build_store(code_hash_out_len_ptr, hash_len);
|
|
|
+ let code_hash_ret = call!(
|
|
|
+ "code_hash",
|
|
|
+ &[
|
|
|
+ address.unwrap().into(),
|
|
|
+ code_hash_out_ptr.into(),
|
|
|
+ code_hash_out_len_ptr.into(),
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ .try_as_basic_value()
|
|
|
+ .left()
|
|
|
+ .unwrap()
|
|
|
+ .into_int_value();
|
|
|
+ log_return_code(binary, "seal_code_hash", code_hash_ret);
|
|
|
+
|
|
|
+ let code_hash_found = binary.builder.build_int_compare(
|
|
|
+ IntPredicate::EQ,
|
|
|
+ code_hash_ret,
|
|
|
+ i32_zero!(),
|
|
|
+ "code_hash_found",
|
|
|
+ );
|
|
|
+ let entry = binary.builder.get_insert_block().unwrap();
|
|
|
+ let call_block = binary
|
|
|
+ .context
|
|
|
+ .append_basic_block(function, "code_hash_found");
|
|
|
+ let not_found_block = binary
|
|
|
+ .context
|
|
|
+ .append_basic_block(function, "code_hash_not_found");
|
|
|
+ let done_block = binary.context.append_basic_block(function, "done_block");
|
|
|
+ binary.builder.build_conditional_branch(
|
|
|
+ code_hash_found,
|
|
|
+ call_block,
|
|
|
+ not_found_block,
|
|
|
+ );
|
|
|
|
|
|
- log_return_code(binary, "seal_call", ret);
|
|
|
+ binary.builder.position_at_end(not_found_block);
|
|
|
+ let msg = "delegatecall callee is not a contract account";
|
|
|
+ self.log_runtime_error(binary, msg.into(), Some(loc), ns);
|
|
|
+ binary.builder.build_unconditional_branch(done_block);
|
|
|
+
|
|
|
+ binary.builder.position_at_end(call_block);
|
|
|
+ let delegate_call_ret = call!(
|
|
|
+ "delegate_call",
|
|
|
+ &[
|
|
|
+ contract_args.flags.unwrap_or(i32_zero!()).into(),
|
|
|
+ code_hash_out_ptr.into(),
|
|
|
+ payload.into(),
|
|
|
+ payload_len.into(),
|
|
|
+ scratch_buf.into(),
|
|
|
+ scratch_len.into(),
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ .try_as_basic_value()
|
|
|
+ .left()
|
|
|
+ .unwrap()
|
|
|
+ .into_int_value();
|
|
|
+ log_return_code(binary, "seal_delegate_call", delegate_call_ret);
|
|
|
+ binary.builder.build_unconditional_branch(done_block);
|
|
|
+
|
|
|
+ binary.builder.position_at_end(done_block);
|
|
|
+ let ty = binary.context.i32_type();
|
|
|
+ let ret = binary.builder.build_phi(ty, "storage_res");
|
|
|
+ ret.add_incoming(&[(&code_hash_ret, not_found_block), (&ty.const_zero(), entry)]);
|
|
|
+ ret.add_incoming(&[(&delegate_call_ret, call_block), (&ty.const_zero(), entry)]);
|
|
|
+ ret.as_basic_value().into_int_value()
|
|
|
+ }
|
|
|
+ ast::CallTy::Static => unreachable!("sema does not allow this"),
|
|
|
+ };
|
|
|
|
|
|
let is_success =
|
|
|
binary
|