Browse Source

Generate code for when account metas are specified

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 3 years ago
parent
commit
02858636dd

+ 8 - 1
src/codegen/cfg.rs

@@ -116,6 +116,7 @@ pub enum Instr {
     ExternalCall {
         success: Option<usize>,
         address: Option<Expression>,
+        accounts: Option<Expression>,
         payload: Expression,
         value: Expression,
         gas: Expression,
@@ -857,11 +858,12 @@ impl ControlFlowGraph {
                 address,
                 payload,
                 value,
+                accounts,
                 gas,
                 callty,
             } => {
                 format!(
-                    "{} = external call::{} address:{} payload:{} value:{} gas:{}",
+                    "{} = external call::{} address:{} payload:{} value:{} gas:{} accounts:{}",
                     match success {
                         Some(i) => format!("%{}", self.vars[i].id.name),
                         None => "_".to_string(),
@@ -875,6 +877,11 @@ impl ControlFlowGraph {
                     self.expr_to_string(contract, ns, payload),
                     self.expr_to_string(contract, ns, value),
                     self.expr_to_string(contract, ns, gas),
+                    if let Some(accounts) = accounts {
+                        self.expr_to_string(contract, ns, accounts)
+                    } else {
+                        String::new()
+                    },
                 )
             }
             Instr::ValueTransfer {

+ 5 - 0
src/codegen/constant_folding.rs

@@ -223,6 +223,7 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, ns: &mut Namespace) {
                     payload,
                     value,
                     gas,
+                    accounts,
                     callty,
                 } => {
                     let value = expression(value, Some(&vars), cfg, ns).0;
@@ -231,10 +232,14 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, ns: &mut Namespace) {
                     let address = address
                         .as_ref()
                         .map(|expr| expression(expr, Some(&vars), cfg, ns).0);
+                    let accounts = accounts
+                        .as_ref()
+                        .map(|expr| expression(expr, Some(&vars), cfg, ns).0);
 
                     cfg.blocks[block_no].instr[instr_no] = Instr::ExternalCall {
                         success: *success,
                         address,
+                        accounts,
                         payload,
                         value,
                         gas,

+ 11 - 1
src/codegen/expression.rs

@@ -1161,6 +1161,7 @@ fn payable_send(
             Instr::ExternalCall {
                 success: Some(success),
                 address: Some(address),
+                accounts: None,
                 payload: Expression::AllocDynamicArray(
                     *loc,
                     Type::DynamicBytes,
@@ -1207,6 +1208,7 @@ fn payable_transfer(
             vartab,
             Instr::ExternalCall {
                 success: None,
+                accounts: None,
                 address: Some(address),
                 payload: Expression::AllocDynamicArray(
                     *loc,
@@ -2083,10 +2085,15 @@ pub fn emit_function_call(
             } else {
                 Expression::NumberLiteral(pt::Loc::Codegen, Type::Value, BigInt::zero())
             };
+            let accounts = call_args
+                .accounts
+                .as_ref()
+                .map(|expr| expression(expr, cfg, callee_contract_no, func, ns, vartab, opt));
 
             let success = vartab.temp_name("success", &Type::Bool);
 
-            let (payload, address) = if ns.target == Target::Solana {
+            let (payload, address) = if ns.target == Target::Solana && call_args.accounts.is_none()
+            {
                 (
                     Expression::AbiEncode {
                         loc: *loc,
@@ -2126,6 +2133,7 @@ pub fn emit_function_call(
                     address,
                     payload,
                     value,
+                    accounts,
                     gas,
                     callty: ty.clone(),
                 },
@@ -2224,6 +2232,7 @@ pub fn emit_function_call(
                     vartab,
                     Instr::ExternalCall {
                         success: None,
+                        accounts: None,
                         address,
                         payload,
                         value,
@@ -2310,6 +2319,7 @@ pub fn emit_function_call(
                     vartab,
                     Instr::ExternalCall {
                         success: None,
+                        accounts: None,
                         address: Some(address),
                         payload,
                         value,

+ 1 - 0
src/codegen/statements.rs

@@ -1092,6 +1092,7 @@ fn try_catch(
                     Instr::ExternalCall {
                         success: Some(success),
                         address: Some(address),
+                        accounts: None,
                         payload,
                         value,
                         gas,

+ 6 - 0
src/codegen/subexpression_elimination/instruction.rs

@@ -307,6 +307,7 @@ impl AvailableExpressionSet {
             Instr::ExternalCall {
                 success,
                 address,
+                accounts,
                 payload,
                 value,
                 gas,
@@ -316,9 +317,14 @@ impl AvailableExpressionSet {
                     .as_ref()
                     .map(|expr| self.regenerate_expression(expr, ave, cst).1);
 
+                let new_accounts = accounts
+                    .as_ref()
+                    .map(|expr| self.regenerate_expression(expr, ave, cst).1);
+
                 Instr::ExternalCall {
                     success: *success,
                     address: new_address,
+                    accounts: new_accounts,
                     payload: self.regenerate_expression(payload, ave, cst).1,
                     value: self.regenerate_expression(value, ave, cst).1,
                     gas: self.regenerate_expression(gas, ave, cst).1,

+ 2 - 1
src/emit/ewasm.rs

@@ -1406,13 +1406,14 @@ impl<'a> TargetRuntime<'a> for EwasmTarget {
     fn external_call<'b>(
         &self,
         binary: &Binary<'b>,
-        function: FunctionValue,
+        function: FunctionValue<'b>,
         success: Option<&mut BasicValueEnum<'b>>,
         payload: PointerValue<'b>,
         payload_len: IntValue<'b>,
         address: Option<PointerValue<'b>>,
         gas: IntValue<'b>,
         value: IntValue<'b>,
+        _accounts: Option<(PointerValue<'b>, IntValue<'b>)>,
         callty: ast::CallTy,
         ns: &ast::Namespace,
     ) {

+ 24 - 1
src/emit/mod.rs

@@ -270,13 +270,14 @@ pub trait TargetRuntime<'a> {
     fn external_call<'b>(
         &self,
         bin: &Binary<'b>,
-        function: FunctionValue,
+        function: FunctionValue<'b>,
         success: Option<&mut BasicValueEnum<'b>>,
         payload: PointerValue<'b>,
         payload_len: IntValue<'b>,
         address: Option<PointerValue<'b>>,
         gas: IntValue<'b>,
         value: IntValue<'b>,
+        accounts: Option<(PointerValue<'b>, IntValue<'b>)>,
         ty: CallTy,
         ns: &Namespace,
     );
@@ -4121,6 +4122,7 @@ pub trait TargetRuntime<'a> {
                         value,
                         gas,
                         callty,
+                        accounts,
                     } => {
                         let gas = self
                             .expression(bin, gas, &w.vars, function, ns)
@@ -4155,6 +4157,26 @@ pub trait TargetRuntime<'a> {
                             None
                         };
 
+                        let accounts = if let Some(accounts) = accounts {
+                            let ty = accounts.ty();
+
+                            let expr = self.expression(bin, accounts, &w.vars, function, ns);
+
+                            if let Some(n) = ty.array_length() {
+                                let accounts = expr.into_pointer_value();
+                                let len =
+                                    bin.context.i32_type().const_int(n.to_u64().unwrap(), false);
+
+                                Some((accounts, len))
+                            } else {
+                                let addr = bin.vector_bytes(expr);
+                                let len = bin.vector_len(expr);
+                                Some((addr, len))
+                            }
+                        } else {
+                            None
+                        };
+
                         let success = match success {
                             Some(n) => Some(&mut w.vars.get_mut(n).unwrap().value),
                             None => None,
@@ -4169,6 +4191,7 @@ pub trait TargetRuntime<'a> {
                             address,
                             gas,
                             value,
+                            accounts,
                             callty.clone(),
                             ns,
                         );

+ 112 - 19
src/emit/solana.rs

@@ -2955,39 +2955,132 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
     fn external_call<'b>(
         &self,
         binary: &Binary<'b>,
-        function: FunctionValue,
+        function: FunctionValue<'b>,
         success: Option<&mut BasicValueEnum<'b>>,
         payload: PointerValue<'b>,
         payload_len: IntValue<'b>,
         address: Option<PointerValue<'b>>,
         _gas: IntValue<'b>,
         _value: IntValue<'b>,
+        accounts: Option<(PointerValue<'b>, IntValue<'b>)>,
         _ty: ast::CallTy,
         _ns: &ast::Namespace,
     ) {
-        debug_assert!(address.is_none());
+        let ret = if let Some(address) = address {
+            // build instruction
+            let instruction_ty: BasicTypeEnum = binary
+                .module
+                .get_struct_type("struct.SolInstruction")
+                .unwrap()
+                .into();
 
-        let parameters = self.sol_parameters(binary);
+            let instruction = binary.build_alloca(function, instruction_ty, "instruction");
 
-        let external_call = binary.module.get_function("external_call").unwrap();
+            binary.builder.build_store(
+                binary
+                    .builder
+                    .build_struct_gep(instruction, 0, "program_id")
+                    .unwrap(),
+                address,
+            );
 
-        let arg2 = binary.builder.build_pointer_cast(
-            parameters,
-            external_call.get_type().get_param_types()[2].into_pointer_type(),
-            "",
-        );
+            let (accounts, accounts_len) = accounts.unwrap();
 
-        let ret = binary
-            .builder
-            .build_call(
-                external_call,
-                &[payload.into(), payload_len.into(), arg2.into()],
+            binary.builder.build_store(
+                binary
+                    .builder
+                    .build_struct_gep(instruction, 1, "accounts")
+                    .unwrap(),
+                accounts,
+            );
+
+            binary.builder.build_store(
+                binary
+                    .builder
+                    .build_struct_gep(instruction, 2, "accounts_len")
+                    .unwrap(),
+                accounts_len,
+            );
+
+            binary.builder.build_store(
+                binary
+                    .builder
+                    .build_struct_gep(instruction, 3, "data")
+                    .unwrap(),
+                payload,
+            );
+
+            binary.builder.build_store(
+                binary
+                    .builder
+                    .build_struct_gep(instruction, 4, "data_len")
+                    .unwrap(),
+                payload_len,
+            );
+
+            let parameters = self.sol_parameters(binary);
+
+            let account_infos = binary.builder.build_load(
+                binary
+                    .builder
+                    .build_struct_gep(parameters, 0, "ka")
+                    .unwrap(),
+                "ka",
+            );
+
+            let account_infos_len = binary.builder.build_load(
+                binary
+                    .builder
+                    .build_struct_gep(parameters, 0, "ka")
+                    .unwrap(),
+                "ka",
+            );
+
+            let external_call = binary.module.get_function("sol_invoke_signed_c").unwrap();
+
+            let signer_seeds = external_call.get_type().get_param_types()[3].const_zero();
+            let signer_seeds_len = external_call.get_type().get_param_types()[4].const_zero();
+
+            binary
+                .builder
+                .build_call(
+                    external_call,
+                    &[
+                        instruction.into(),
+                        account_infos.into(),
+                        account_infos_len.into(),
+                        signer_seeds.into(),
+                        signer_seeds_len.into(),
+                    ],
+                    "",
+                )
+                .try_as_basic_value()
+                .left()
+                .unwrap()
+                .into_int_value()
+        } else {
+            let parameters = self.sol_parameters(binary);
+
+            let external_call = binary.module.get_function("external_call").unwrap();
+
+            let arg2 = binary.builder.build_pointer_cast(
+                parameters,
+                external_call.get_type().get_param_types()[2].into_pointer_type(),
                 "",
-            )
-            .try_as_basic_value()
-            .left()
-            .unwrap()
-            .into_int_value();
+            );
+
+            binary
+                .builder
+                .build_call(
+                    external_call,
+                    &[payload.into(), payload_len.into(), arg2.into()],
+                    "",
+                )
+                .try_as_basic_value()
+                .left()
+                .unwrap()
+                .into_int_value()
+        };
 
         let is_success = binary.builder.build_int_compare(
             IntPredicate::EQ,

+ 2 - 1
src/emit/substrate.rs

@@ -3643,13 +3643,14 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
     fn external_call<'b>(
         &self,
         binary: &Binary<'b>,
-        function: FunctionValue,
+        function: FunctionValue<'b>,
         success: Option<&mut BasicValueEnum<'b>>,
         payload: PointerValue<'b>,
         payload_len: IntValue<'b>,
         address: Option<PointerValue<'b>>,
         gas: IntValue<'b>,
         value: IntValue<'b>,
+        _accounts: Option<(PointerValue<'b>, IntValue<'b>)>,
         _ty: ast::CallTy,
         ns: &ast::Namespace,
     ) {

+ 2 - 1
src/sema/mutability.rs

@@ -270,7 +270,8 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
         | Expression::Builtin(loc, _, Builtin::TombstoneDeposit, _)
         | Expression::Builtin(loc, _, Builtin::MinimumBalance, _)
         | Expression::Builtin(loc, _, Builtin::Balance, _)
-        | Expression::Builtin(loc, _, Builtin::Random, _) => state.read(loc),
+        | Expression::Builtin(loc, _, Builtin::Random, _)
+        | Expression::Builtin(loc, _, Builtin::Accounts, _) => state.read(loc),
         Expression::Builtin(loc, _, Builtin::PayableSend, _)
         | Expression::Builtin(loc, _, Builtin::PayableTransfer, _)
         | Expression::Builtin(loc, _, Builtin::SelfDestruct, _) => state.write(loc),