pchain_runtime/execution/
internal.rs1use pchain_types::cryptography::PublicAddress;
9use pchain_world_state::storage::WorldStateStorage;
10use std::sync::{Arc, Mutex};
11
12use crate::{
13 contract::{self, FuncError},
14 cost::CostChange,
15 transition::TransitionContext,
16 types::CallTx,
17 BlockchainParams,
18};
19
20use super::contract::ContractModule;
21
22#[derive(Default)]
23pub(crate) struct InternalCallResult {
24 pub exec_gas: u64,
25 pub non_wasmer_gas: CostChange,
26 pub error: Option<FuncError>,
27}
28
29pub(crate) fn call_from_contract<S>(
31 mut tx_from_contract: CallTx,
32 bd: BlockchainParams,
33 txn_in_env: Arc<Mutex<TransitionContext<S>>>,
34 call_counter: u32,
35 is_view: bool,
36) -> InternalCallResult
37where
38 S: WorldStateStorage + Send + Sync + Clone + 'static,
39{
40 let mut ctx_locked = txn_in_env.lock().unwrap();
41 let mut internal_call_result = InternalCallResult::default();
42
43 if let Some(value) = tx_from_contract.amount {
45 let (from_balance, cost_change) = ctx_locked.balance(tx_from_contract.signer);
46 internal_call_result.non_wasmer_gas += cost_change;
47 if from_balance < value {
48 internal_call_result.error = Some(contract::FuncError::InsufficientBalance);
49 return internal_call_result;
50 }
51
52 let from_address_new_balance = from_balance - value;
53 let cost_change = ctx_locked.set_balance(tx_from_contract.signer, from_address_new_balance);
54 internal_call_result.non_wasmer_gas += cost_change;
55
56 let (to_address_prev_balance, cost_change) = ctx_locked.balance(tx_from_contract.target);
58 internal_call_result.non_wasmer_gas += cost_change;
59 let to_address_new_balance = to_address_prev_balance.saturating_add(value);
60 let cost_change = ctx_locked.set_balance(tx_from_contract.target, to_address_new_balance);
61 internal_call_result.non_wasmer_gas += cost_change;
62 }
63
64 let contract_module = match ContractModule::build_contract(
66 tx_from_contract.target,
67 &ctx_locked.sc_context,
68 &ctx_locked.rw_set,
69 ) {
70 Ok(module) => module,
71 Err(_) => {
72 internal_call_result.error = Some(contract::FuncError::ContractNotFound);
73 return internal_call_result;
74 }
75 };
76 internal_call_result.non_wasmer_gas += contract_module.gas_cost;
77 drop(ctx_locked);
78
79 tx_from_contract.gas_limit = tx_from_contract
81 .gas_limit
82 .saturating_sub(internal_call_result.non_wasmer_gas.values().0);
83
84 let instance = match contract_module.instantiate(
85 txn_in_env,
86 call_counter,
87 is_view,
88 tx_from_contract,
89 bd,
90 ) {
91 Ok(instance) => instance,
92 Err(_) => {
93 internal_call_result.error = Some(contract::FuncError::ContractNotFound);
94 return internal_call_result;
95 }
96 };
97
98 let (_, gas_consumed, call_error) = instance.call();
100 internal_call_result.exec_gas = gas_consumed;
101
102 if let Some(call_error) = call_error {
103 internal_call_result.error = Some(contract::FuncError::MethodCallError(call_error));
104 }
105 internal_call_result
106}
107
108pub(crate) fn transfer_from_contract<S>(
110 signer: PublicAddress,
111 amount: u64,
112 recipient: PublicAddress,
113 txn_in_env: Arc<Mutex<TransitionContext<S>>>,
114) -> InternalCallResult
115where
116 S: WorldStateStorage + Send + Sync + Clone,
117{
118 let mut ctx_locked = txn_in_env.lock().unwrap();
119 let mut internal_call_result = InternalCallResult::default();
120
121 let (from_balance, cost_change) = ctx_locked.balance(signer);
123 internal_call_result.non_wasmer_gas += cost_change;
124
125 if from_balance < amount {
126 internal_call_result.error = Some(contract::FuncError::InsufficientBalance);
127 return internal_call_result;
128 }
129
130 let from_address_new_balance = from_balance - amount;
132 let cost_change = ctx_locked.set_balance(signer, from_address_new_balance);
133 internal_call_result.non_wasmer_gas += cost_change;
134
135 let (to_address_prev_balance, cost_change) = ctx_locked.balance(recipient);
137 internal_call_result.non_wasmer_gas += cost_change;
138 let to_address_new_balance = to_address_prev_balance.saturating_add(amount);
139 let cost_change = ctx_locked.set_balance(recipient, to_address_new_balance);
140 internal_call_result.non_wasmer_gas += cost_change;
141
142 internal_call_result
143}