redgold_executor/
extism_wrapper.rs

1use extism::{Context, Plugin};
2
3use redgold_schema::helpers::easy_json::EasyJson;
4use redgold_schema::observability::errors::EnhanceErrorInfo;
5use redgold_schema::proto_serde::ProtoSerde;
6use redgold_schema::structs::{ExecutionInput, ExecutionResult, TestContractInternalState, TestContractRequest, TestContractUpdate2};
7use redgold_schema::{bytes_data, error_info, ErrorInfoContext, RgResult};
8
9pub async fn invoke_wasm(
10    wasm_bytes: &[u8],
11    function_name: impl Into<String>,
12    args: ExecutionInput
13) -> RgResult<ExecutionResult> {
14    let context = Context::new();
15    let mut plugin = Plugin::new(
16        &context,
17        wasm_bytes,
18        vec![],
19        false
20    ).map_err(|e|
21        error_info(
22            format!("Unable to build plugin while invoking wasm {}", e.to_string())))?;
23
24    let fname = function_name.into();
25    let has = plugin.has_function(fname.clone());
26    if !has {
27        return Err(error_info(format!("Function not found {}", fname.clone())))?
28    }
29    let data = plugin.call(fname.clone(), args.proto_serialize())
30        .map_err(|e|
31            error_info(
32                format!("Error calling function {}", e.to_string())))
33        .add(fname.clone())?;
34    ExecutionResult::proto_deserialize(data.to_vec())
35}
36
37pub async fn invoke_extism_wasm(
38    wasm_bytes: &[u8],
39    args: ExecutionInput
40) -> RgResult<ExecutionResult> {
41    invoke_wasm(wasm_bytes, "extism_entrypoint", args).await
42}
43
44// TODO: impl AsRef<u8>
45pub async fn invoke_extism_wasm_direct(
46    wasm_bytes: impl AsRef<[u8]>,
47    input: &Vec<u8>,
48    state: &Vec<u8>
49) -> RgResult<ExecutionResult> {
50    let mut args = ExecutionInput::default();
51    args.input = bytes_data(input.clone());
52    args.state = bytes_data(state.clone());
53    invoke_wasm(wasm_bytes.as_ref(), "extism_entrypoint", args).await
54}
55
56
57#[ignore]
58#[tokio::test]
59async fn extism_direct_test() {
60    // println!()
61    let wasm = std::fs::read("../sdk/test_contract_guest.wasm").expect("");
62
63    let res_g = invoke_wasm(
64        &*wasm, "extism_entrypoint", ExecutionInput::default()
65    ).await.unwrap();
66    let gen_state = res_g.data.expect("d").state;
67    let gen_state_deser = TestContractInternalState::proto_deserialize
68        (gen_state.clone().expect("s").value).expect("");
69    let res = gen_state_deser.json_or();
70    println!("initial result genesis: {}", res);
71
72    let mut input = ExecutionInput::default();
73    let mut req = TestContractRequest::default();
74    let mut update2 = TestContractUpdate2::default();
75    update2.value = "UPDATED".to_string();
76    req.test_contract_update2 = Some(update2);
77    input.input = bytes_data(req.proto_serialize());
78    input.state = gen_state.clone();
79
80    let res = invoke_wasm(&*wasm, "extism_entrypoint", input).await.unwrap();
81    println!("Exec result: {}", res.json_or());
82
83    let done_state = res.data.clone().expect("d").state;
84    let done_state_deser = TestContractInternalState::proto_deserialize
85        (done_state.clone().expect("s").value).expect("");
86    let resr = done_state_deser.json_or();
87    println!("final result after: {}", resr);
88
89    // let res = invoke_wasm(&*wasm, "entrypoint", input).await.unwrap();
90    assert!(res.valid);
91}
92
93
94#[ignore]
95#[tokio::test]
96async fn proto_test() {
97    // println!()
98    let wasm = std::fs::read("../sdk/test_contract_guest.wasm").expect("");
99    let input = ExecutionInput::default();
100    let res = invoke_wasm(&*wasm, "extism_entrypoint", input).await.unwrap();
101    println!("Exec result: {}", res.json_or());
102    // let res = invoke_wasm(&*wasm, "entrypoint", input).await.unwrap();
103    assert!(res.valid);
104}
105
106#[ignore]
107#[test]
108fn debug_test() {
109
110    let context = Context::new();
111    // let wasm = include_bytes!("code.wasm");
112    let wasm = std::fs::read("../../sdk/test_contract_guest.wasm").expect("");
113    // let wasm = include_bytes!("../../sdk/extism_test.wasm");
114
115    // NOTE: if you encounter an error such as:
116    // "Unable to load plugin: unknown import: wasi_snapshot_preview1::fd_write has not been defined"
117    // change `false` to `true` in the following function to provide WASI imports to your plugin.
118    let mut plugin = Plugin::new(&context, wasm, vec![], false).unwrap();
119    let has = plugin.has_function("count_vowels");
120    println!("has: {:?}", has);
121    let data = plugin.call("count_vowels", "this is a test");
122    println!("data: {:?}", data);
123    // assert_eq!(data, b"{\"count\": 4}");
124}