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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Raw native functions for tests to use
//!
//! Native functions give tests the ability to execute shell commands,
//! read files, create block chains, push transactions to those chains,
//! and control block production on those chains.
//!
//! This is the set of raw native functions (wasm imports) exposed by `psitest`.
//! They are available for test cases to use directly, but we recommend using
//! [Wrapped Native Functions](crate::tester) instead.
extern "C" {
/// Execute a shell command
///
/// Returns the process exit code
pub fn testerExecute(command: *const u8, command_size: usize) -> i32;
}
#[link(wasm_import_module = "psibase")]
extern "C" {
/// Create a new chain and make it active for database native functions.
///
/// Returns a chain handle
pub fn createChain(hot_bytes: u64, warm_bytes: u64, cool_bytes: u64, cold_bytes: u64) -> u32;
/// Destroy chain
///
/// This destroys the chain and deletes its database from the filesystem.
pub fn destroyChain(chain_handle: u32);
/// Finish a block
///
/// This does nothing if a block isn't currently being produced.
pub fn finishBlock(chain_handle: u32);
/// Get filesystem path of chain's database
///
/// Stores up to `dest_size` bytes if the chain's path into `dest`. Returns
/// the path size. The path is UTF8.
///
/// It is safe to copy the files to another location on the filesystem. However,
/// modifying the original files or launching `psinode` on the original files
/// will corrupt the database and likely crash the `psitest` process running this wasm.
pub fn getChainPath(chain_handle: u32, dest: *mut u8, dest_size: usize) -> usize;
/// Push a transaction
///
/// `chain_handle` identifies the chain to push to. `transaction/transaction_size`
/// contains a fracpacked [`SignedTransaction`](crate::SignedTransaction).
///
/// Stores the transaction trace into result and returns the result size
pub fn pushTransaction(
chain_handle: u32,
transaction: *const u8,
transaction_size: usize,
) -> u32;
/// Shutdown chain without deleting database
///
/// This shuts down a chain, but doesn't destroy it or remove the
/// database. `chain_handle` still exists, but isn't usable except
/// with [`getChainPath`] and [`destroyChain`].
///
/// TODO: `shutdownChain` probably isn't useful anymore; it might go away.
pub fn shutdownChain(chain_handle: u32);
/// Start a new block
///
/// Starts a new block at time `time_us` (unix time). If
/// time_seconds is 0, then starts a new block 1 second after
/// the most recent.
pub fn startBlock(chain_handle: u32, time_us: i64, producer: u64, term: u32, commit_num: u32);
/// Runs an action
///
/// Stores the transaction trace into result and returns the result size
pub fn runAction(
chain_index: u32,
mode: crate::RunMode,
head: bool,
args_packed: *const u8,
args_packed_size: usize,
) -> u32;
/// Runs an HttpRequest and returns a socket
pub fn httpRequest(
chain_handle: u32,
request_packed: *const u8,
request_packed_size: usize,
) -> i32;
/// Reads a message from a socket
pub fn socketRecv(fd: i32, size: *mut u32) -> u32;
}
#[cfg(target_family = "wasm")]
#[link(wasm_import_module = "psibase")]
extern "C" {
pub fn getResult(dest: *mut u8, dest_size: u32, offset: u32) -> u32;
pub fn getKey(dest: *mut u8, dest_size: u32) -> u32;
pub fn abortMessage(message: *const u8, len: u32) -> !;
pub fn kvGet(chain_handle: u32, db: crate::DbId, key: *const u8, key_len: u32) -> u32;
pub fn getSequential(chain_handle: u32, db: crate::DbId, id: u64) -> u32;
pub fn kvGreaterEqual(
chain_handle: u32,
db: crate::DbId,
key: *const u8,
key_len: u32,
match_key_size: u32,
) -> u32;
pub fn kvLessThan(
chain_handle: u32,
db: crate::DbId,
key: *const u8,
key_len: u32,
match_key_size: u32,
) -> u32;
pub fn kvMax(chain_handle: u32, db: crate::DbId, key: *const u8, key_len: u32) -> u32;
pub fn kvPut(
chain_handle: u32,
db: crate::DbId,
key: *const u8,
key_len: u32,
value: *const u8,
value_len: u32,
);
pub fn checkoutSubjective(chain_handle: u32);
pub fn commitSubjective(chain_handle: u32) -> bool;
pub fn abortSubjective(chain_handle: u32);
}
thread_local! {
static SELECTED_CHAIN: std::cell::Cell<Option<u32>> = std::cell::Cell::new(None);
}
pub fn get_selected_chain() -> u32 {
SELECTED_CHAIN.with(|c| c.get().unwrap())
}
/// Select chain for database native functions
///
/// After you call `tester_select_chain_for_db`, the following functions will use
/// this chain's database:
///
/// * [`raw::kvGet`](crate::native_raw::kvGet)
/// * [`raw::getSequential`](crate::native_raw::getSequential)
/// * [`raw::kvGreaterEqual`](crate::native_raw::kvGreaterEqual)
/// * [`raw::kvLessThan`](crate::native_raw::kvLessThan)
/// * [`raw::kvMax`](crate::native_raw::kvMax)
pub fn tester_select_chain_for_db(chain_handle: u32) {
SELECTED_CHAIN.with(|c| c.set(Some(chain_handle)));
}
pub fn tester_clear_chain_for_db(chain_handle: u32) {
SELECTED_CHAIN.with(|c| {
if let Some(current) = c.get() {
if chain_handle == current {
c.set(None)
}
}
});
}