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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use super::*;
impl ExecutionContext {
/// Get gas limit
pub fn gas_limit(&self) -> u64 {
self.gas_limit
}
/// Get gas used so far
pub fn gas_used(&self) -> u64 {
self.gas_used
}
/// Get instruction count
pub fn instruction_count(&self) -> u64 {
self.instruction_count
}
/// Get pending block height override, if any.
pub fn pending_block_height(&self) -> Option<u64> {
self.pending_block_height
}
/// Get pending timestamp override, if any.
pub fn pending_timestamp(&self) -> Option<u64> {
self.pending_timestamp
}
/// Get pending caller account override bytes, if any.
pub fn pending_caller_account(&self) -> Option<&[u8]> {
self.pending_caller_account.as_deref()
}
/// Task #113 — Get pending msg.value override, if any.
pub fn pending_msg_value(&self) -> Option<u64> {
self.pending_msg_value
}
/// Task #113 — Get the active msg.value for the current execution.
/// `None` indicates no override was set (compiled `GetMsgValue`
/// syscall coalesces None → 0 at push time).
pub fn msg_value(&self) -> Option<u64> {
self.msg_value
}
/// Get the active block height for the current execution.
pub fn block_height(&self) -> Option<u64> {
self.block_height
}
/// Get the active timestamp for the current execution.
pub fn timestamp(&self) -> Option<u64> {
self.timestamp
}
/// Get the active caller account for the current execution.
pub fn caller_account(&self) -> Option<&[u8]> {
self.caller_account.as_deref()
}
/// Get the default account bytes configured for this context.
pub fn default_account_bytes(&self) -> &[u8] {
&self.default_account_bytes
}
/// Disable the bytecode-derived `default_account_bytes` behaviour.
///
/// When a test harness seeds a deterministic `default_account_bytes`
/// (for example to exercise native-contract balance tracking or an
/// explicit caller account), it can call this after construction to
/// pin the explicitly configured value. Subsequent `initialize` calls
/// will NOT overwrite `default_account_bytes` with `Hash160(bytecode)`.
///
/// This is the escape hatch that keeps pre-existing tests (which set
/// `contract_account` to a non-default value) unaffected by the
/// self-hash derivation introduced for `address(this)` support.
pub fn force_default_account_explicit_for_tests(&mut self) {
self.default_account_derived = false;
}
/// Number of contracts currently tracked by the in-memory registry.
pub fn contract_registry_len(&self) -> usize {
self.contract_registry.len()
}
/// Update counter for a registered contract (if present).
pub fn contract_update_counter(&self, hash: &[u8]) -> Option<u32> {
self.contract_registry.get(hash).map(|c| c.update_counter)
}
/// Known contract hashes (20-byte each).
pub fn contract_hashes(&self) -> Vec<[u8; 20]> {
self.contract_registry
.keys()
.filter_map(|k| {
if k.len() == 20 {
let mut arr = [0u8; 20];
arr.copy_from_slice(k);
Some(arr)
} else {
None
}
})
.collect()
}
/// Get maximum stack depth
pub fn max_stack_depth(&self) -> u32 {
self.max_stack_depth
}
/// Task #70: Install the `(method_name → (offset, arg_count))` table that
/// `handle_contract_call` uses to route `this.someFn()` self external
/// calls to compiled method offsets. Populated from `manifest.abi.methods`
/// by `NeoRuntime::call_method` before each invocation.
pub fn set_self_method_table(&mut self, table: Vec<(String, u32, u16)>) {
self.self_method_offsets.clear();
self.self_method_arg_counts.clear();
for (name, offset, arg_count) in table {
self.self_method_offsets.insert(name.clone(), offset);
self.self_method_arg_counts.insert(name, arg_count);
}
}
/// Task #70: Clear the self-method table. Called between `execute()`
/// invocations that don't run through `call_method`.
pub fn clear_self_method_table(&mut self) {
self.self_method_offsets.clear();
self.self_method_arg_counts.clear();
}
}