1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use dharitri_sc::types::heap::Address;
use num_traits::Zero;

use crate::{
    tx_mock::{BlockchainUpdate, TxCache, TxContext, TxFunctionName, TxInput, TxLog, TxResult},
    world_mock::is_smart_contract_address,
};

use super::execute_tx_context;

pub fn default_execution(tx_input: TxInput, tx_cache: TxCache) -> (TxResult, BlockchainUpdate) {
    let mut tx_context = TxContext::new(tx_input, tx_cache);

    tx_context.tx_cache.subtract_moax_balance(
        &tx_context.tx_input_box.from,
        &tx_context.tx_input_box.moax_value,
    );
    tx_context.tx_cache.increase_moax_balance(
        &tx_context.tx_input_box.to,
        &tx_context.tx_input_box.moax_value,
    );

    // skip for transactions coming directly from scenario json, which should all be coming from user wallets
    // TODO: reorg context logic
    let add_transfer_log = is_smart_contract_address(&tx_context.tx_input_box.from)
        && !tx_context.tx_input_box.moax_value.is_zero();
    let transfer_value_log = if add_transfer_log {
        Some(TxLog {
            address: Address::zero(), // TODO: figure out the real VM behavior
            endpoint: "transferValueOnly".into(),
            topics: vec![
                tx_context.tx_input_box.from.to_vec(),
                tx_context.tx_input_box.to.to_vec(),
                tx_context.tx_input_box.moax_value.to_bytes_be(),
            ],
            data: Vec::new(),
        })
    } else {
        None
    };

    // TODO: temporary, will convert to explicit builtin function first
    for dct_transfer in tx_context.tx_input_box.dct_values.iter() {
        tx_context.tx_cache.transfer_dct_balance(
            &tx_context.tx_input_box.from,
            &tx_context.tx_input_box.to,
            &dct_transfer.token_identifier,
            dct_transfer.nonce,
            &dct_transfer.value,
        );
    }

    let mut tx_result = if !is_smart_contract_address(&tx_context.tx_input_box.to)
        || tx_context.tx_input_box.func_name.is_empty()
    {
        // direct MOAX transfer
        TxResult::empty()
    } else {
        let (tx_context_modified, tx_result) = execute_tx_context(tx_context);
        tx_context = tx_context_modified;
        tx_result
    };

    if let Some(tv_log) = transfer_value_log {
        tx_result.result_logs.insert(0, tv_log);
    }

    let blockchain_updates = tx_context.into_blockchain_updates();

    (tx_result, blockchain_updates)
}

pub fn deploy_contract(
    mut tx_input: TxInput,
    contract_path: Vec<u8>,
    tx_cache: TxCache,
) -> (TxResult, Address, BlockchainUpdate) {
    let new_address = tx_cache.get_new_address(&tx_input.from);
    tx_input.to = new_address.clone();
    tx_input.func_name = TxFunctionName::INIT;
    let tx_context = TxContext::new(tx_input, tx_cache);
    let tx_input_ref = &*tx_context.tx_input_box;

    tx_context
        .tx_cache
        .subtract_moax_balance(&tx_input_ref.from, &tx_input_ref.moax_value);
    tx_context.create_new_contract(&new_address, contract_path, tx_input_ref.from.clone());
    tx_context
        .tx_cache
        .increase_moax_balance(&new_address, &tx_input_ref.moax_value);

    let (tx_context, tx_result) = execute_tx_context(tx_context);
    let blockchain_updates = tx_context.into_blockchain_updates();

    (tx_result, new_address, blockchain_updates)
}