use crate::{
chain_core::builtin_func_names::UPGRADE_CONTRACT_FUNC_NAME,
host::context::{BlockchainUpdate, CallType, TxCache, TxFunctionName, TxInput, TxResult},
host::execution,
host::runtime::{RuntimeInstanceCallLambda, RuntimeRef},
types::VMCodeMetadata,
};
use super::super::builtin_func_trait::BuiltinFunction;
pub struct UpgradeContract;
impl BuiltinFunction for UpgradeContract {
fn name(&self) -> &str {
UPGRADE_CONTRACT_FUNC_NAME
}
fn execute<F>(
&self,
tx_input: TxInput,
tx_cache: TxCache,
runtime: &RuntimeRef,
f: F,
) -> (TxResult, BlockchainUpdate)
where
F: RuntimeInstanceCallLambda,
{
if tx_input.args.len() < 2 {
return (
TxResult::from_vm_error("upgradeContract expects at least 2 arguments"),
BlockchainUpdate::empty(),
);
}
let new_code = tx_input.args[0].clone();
let code_metadata = VMCodeMetadata::from(&tx_input.args[1]);
let args = if tx_input.args.len() > 2 {
tx_input.args[2..].to_vec()
} else {
Vec::new()
};
tx_cache.with_account_mut(&tx_input.to, |account| {
account.contract_path = Some(new_code);
account.code_metadata = code_metadata;
});
let transfer_value_log =
execution::create_transfer_value_log(&tx_input, CallType::UpgradeFromSource);
let exec_input = TxInput {
from: tx_input.from,
to: tx_input.to,
egld_value: tx_input.egld_value,
esdt_values: Vec::new(),
func_name: TxFunctionName::UPGRADE,
args,
gas_limit: tx_input.gas_limit,
gas_price: tx_input.gas_price,
tx_hash: tx_input.tx_hash,
call_type: CallType::UpgradeFromSource,
..Default::default()
};
let (mut tx_result, blockchain_updates) =
execution::execute_default(exec_input, tx_cache, runtime, f);
adjust_upgrade_log_endpoint(&mut tx_result);
tx_result.result_logs.insert(0, transfer_value_log);
(tx_result, blockchain_updates)
}
}
fn adjust_upgrade_log_endpoint(tx_result: &mut TxResult) {
for log in &mut tx_result.result_logs {
if log.endpoint == TxFunctionName::UPGRADE {
log.endpoint = UPGRADE_CONTRACT_FUNC_NAME.into();
}
}
}