github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/modules/wasm/host/host.go (about) 1 package host 2 3 import ( 4 "fmt" 5 "runtime" 6 "strings" 7 8 "github.com/pkg/errors" 9 10 "github.com/machinefi/w3bstream/pkg/modules/wasm/abi/types" 11 "github.com/machinefi/w3bstream/pkg/modules/wasm/consts" 12 ) 13 14 var ( 15 errFailedToGetImportsHandler = errors.New("failed to get imports handler") 16 ) 17 18 func NewImportFunc(ns string, f interface{}) *ImportFuncInfo { 19 return &ImportFuncInfo{ 20 Namespace: ns, 21 Func: f, 22 } 23 } 24 25 type ImportFuncInfo struct { 26 Namespace string 27 Func interface{} 28 } 29 30 func newHost(i types.Instance) (*host, error) { 31 imports := GetImportsHandler(i) 32 if imports == nil { 33 return nil, errFailedToGetImportsHandler 34 } 35 36 return &host{ 37 instance: i, 38 imports: imports, 39 }, nil 40 } 41 42 func HostFunctions(i types.Instance) (map[string]*ImportFuncInfo, error) { 43 fns := make(map[string]*ImportFuncInfo) 44 h, err := newHost(i) 45 if err != nil { 46 return nil, err 47 } 48 49 fns["abort"] = NewImportFunc("env", h.Abort) 50 fns["trace"] = NewImportFunc("env", h.Trace) 51 fns["seed"] = NewImportFunc("env", h.Seed) 52 fns["ws_log"] = NewImportFunc("env", h.Log) 53 fns["ws_get_data"] = NewImportFunc("env", h.GetResourceData) 54 fns["ws_set_data"] = NewImportFunc("env", h.SetResourceData) 55 fns["ws_get_event_type"] = NewImportFunc("env", h.GetEventType) 56 fns["ws_get_db"] = NewImportFunc("env", h.GetKVData) 57 fns["ws_set_db"] = NewImportFunc("env", h.SetKVData) 58 fns["ws_set_sql_db"] = NewImportFunc("env", h.ExecSQL) 59 fns["ws_get_sql_db"] = NewImportFunc("env", h.QuerySQL) 60 fns["ws_send_tx"] = NewImportFunc("env", h.SendTX) 61 fns["ws_send_tx_with_operator"] = NewImportFunc("env", h.SendTXWithOperator) 62 fns["ws_call_contract"] = NewImportFunc("env", h.CallContract) 63 fns["ws_get_env"] = NewImportFunc("env", h.Env) 64 fns["ws_send_mqtt_msg"] = NewImportFunc("env", h.PubMQTT) 65 fns["ws_submit_metrics"] = NewImportFunc("stat", h.SubmitMetrics) 66 fns["ws_api_call"] = NewImportFunc("env", h.AsyncAPICall) 67 68 return fns, nil 69 } 70 71 type host struct { 72 instance types.Instance 73 imports types.ImportsHandler 74 } 75 76 func (h *host) Log(level, msgaddr, msgsize int32) int32 { 77 msg, err := h.instance.GetMemory(msgaddr, msgsize) 78 if err != nil { 79 h.error(errors.Wrap(err, "Log::GetMemory"), "addr", msgaddr, "size", msgsize) 80 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 81 } 82 h.info("Log::GetMemory", "message", string(msg)) 83 84 h.imports.Log(consts.LogLevel(level), string(msg)) 85 return consts.RESULT_OK.Int32() 86 } 87 88 func (h *host) Env(keyaddr, keysize, varaddrptr, varsizeptr int32) int32 { 89 key, err := h.instance.GetMemory(keyaddr, keysize) 90 if err != nil { 91 h.error(errors.Wrap(err, "Env::GetMemory"), "addr", keyaddr, "size", keysize) 92 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 93 } 94 h.info("Env::GetMemory", "key", string(key)) 95 96 val, ok := h.imports.Env(string(key)) 97 if !ok { 98 h.error(consts.RESULT__ENV_NOT_FOUND, "key", string(key)) 99 return consts.RESULT__ENV_NOT_FOUND.Int32() 100 } 101 102 h.info("Env::GetMemory", "val", val) 103 if err = CopyHostDataToWasm(h.instance, []byte(val), varaddrptr, varsizeptr); err != nil { 104 h.error(errors.Wrap(err, "Env::CopyHostDataToWasm"), "addr", varaddrptr, "size", varsizeptr) 105 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 106 } 107 h.info("succeed", "key", key, "val", val) 108 return consts.RESULT_OK.Int32() 109 } 110 111 func (h *host) Abort(msgaddr, filenameaddr, line, col int32) { 112 msg, err := ReadStringFromAddr(h.instance, msgaddr) 113 if err != nil { 114 h.error(errors.Wrap(err, "Abort::ReadStringFromAddr1"), "addr", msgaddr) 115 return 116 } 117 h.info("Abort::ReadStringFromAddr", "message", msg) 118 119 filename, err := ReadStringFromAddr(h.instance, filenameaddr) 120 if err != nil { 121 h.error(errors.Wrap(err, "Abort::ReadStringFromAddr2"), "addr", filenameaddr) 122 return 123 } 124 h.info("Abort::ReadStringFromAddr", "filename", filename) 125 126 h.imports.Abort(msg, filename, line, col) 127 } 128 129 func (h *host) Trace(msgaddr, _ int32, arr ...float64) { 130 msg, err := ReadStringFromAddr(h.instance, msgaddr) 131 if err != nil { 132 h.error(errors.Wrap(err, "Trace::ReadStringFromAddr"), "addr", msgaddr) 133 return 134 } 135 h.info("Trace::ReadStringFromAddr", "message", msg) 136 137 str := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(arr)), ", "), "[]") 138 if len(str) > 0 { 139 str = " " + str 140 } 141 h.imports.Trace(msg, str) 142 } 143 144 func (h *host) Seed() float64 { 145 val := h.imports.Seed() 146 h.info("succeed", "rand_value", val) 147 return val 148 } 149 150 func (h *host) GetResourceData(rid, retaddrptr, retsizeptr int32) int32 { 151 data, ok := h.imports.GetResourceData(uint32(rid)) 152 if !ok { 153 h.error(consts.RESULT__RESOURCE_NOT_FOUND, "rid", rid) 154 return consts.RESULT__RESOURCE_NOT_FOUND.Int32() 155 } 156 157 h.info("GetResourceData", "data", string(data)) 158 if err := CopyHostDataToWasm(h.instance, data, retaddrptr, retsizeptr); err != nil { 159 h.error(errors.Wrap(err, "GetResourceData::CopyHostDataToWasm"), "addr", retaddrptr, "size", retsizeptr) 160 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 161 } 162 h.info("succeed", "rid", rid, "data", string(data)) 163 return consts.RESULT_OK.Int32() 164 } 165 166 func (h *host) SetResourceData(rid, dataaddr, datasize int32) int32 { 167 data, err := h.instance.GetMemory(dataaddr, datasize) 168 if err != nil { 169 h.error(errors.Wrap(err, "SetResourceData::GetMemory"), "addr", dataaddr, "size", datasize) 170 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 171 } 172 if err = h.imports.SetResourceData(uint32(rid), data); err != nil { 173 h.error(err, "rid", rid) 174 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 175 } 176 h.info("succeed", "rid", rid, "data", string(data)) 177 return consts.RESULT_OK.Int32() 178 } 179 180 func (h *host) GetEventType(rid, retaddrptr, retsizeptr int32) int32 { 181 data, ok := h.imports.GetEventType(uint32(rid)) 182 if !ok { 183 h.error(consts.RESULT__RESOURCE_EVENT_NOT_FOUND, "rid", rid) 184 return consts.RESULT__RESOURCE_EVENT_NOT_FOUND.Int32() 185 } 186 187 h.info("GetEventType", "event_type", data) 188 if err := CopyHostDataToWasm(h.instance, []byte(data), retaddrptr, retsizeptr); err != nil { 189 h.error(errors.Wrap(err, "GetEventType::CopyHostDataToWasm"), "addr", retaddrptr, "size", retsizeptr) 190 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 191 } 192 h.info("succeed", "rid", rid, "event_type", data) 193 return consts.RESULT_OK.Int32() 194 } 195 196 func (h *host) GetKVData(keyaddr, keysize, retaddrptr, retsizeptr int32) int32 { 197 key, err := h.instance.GetMemory(keyaddr, keysize) 198 if err != nil { 199 h.error(errors.Wrap(err, "GetKVData::GetMemory"), "addr", keyaddr, "size", keysize) 200 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 201 } 202 h.info("GetKVData::GetMemory", "key", string(key)) 203 204 val, err := h.imports.GetKVData(string(key)) 205 if err != nil { 206 h.error(err) 207 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 208 } 209 if val == nil { 210 return consts.RESULT__KV_DATA_NOT_FOUND.Int32() 211 } 212 213 h.info("GetKVData", "val", string(val)) 214 if err = CopyHostDataToWasm(h.instance, val, retaddrptr, retsizeptr); err != nil { 215 h.error(errors.Wrap(err, "GetKVData::CopyHostDataToWasm"), "addr", retaddrptr, "size", retsizeptr) 216 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 217 } 218 h.info("succeed", "key", string(key), "val", string(val)) 219 return consts.RESULT_OK.Int32() 220 } 221 222 func (h *host) SetKVData(keyaddr, keysize, dataaddr, datasize int32) int32 { 223 key, err := h.instance.GetMemory(keyaddr, keysize) 224 if err != nil { 225 h.error(errors.Wrap(err, "SetKVData::GetMemory1"), "addr", keyaddr, "size", keysize) 226 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 227 } 228 h.info("SetKVData1", "key", string(key)) 229 230 data, err := h.instance.GetMemory(dataaddr, datasize) 231 if err != nil { 232 h.error(errors.Wrap(err, "SetKVData::GetMemory2"), "addr", dataaddr, "size", datasize) 233 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 234 } 235 h.info("SetKVData1", "val", string(data)) 236 237 if err = h.imports.SetKVData(string(key), data); err != nil { 238 h.error(err) 239 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 240 } 241 h.info("succeed", "key", string(key), "val", string(data)) 242 return consts.RESULT_OK.Int32() 243 } 244 245 func (h *host) ExecSQL(queryaddr, querysize int32) int32 { 246 query, err := h.instance.GetMemory(queryaddr, querysize) 247 if err != nil { 248 h.error(errors.Wrap(err, "ExecSQL::GetMemory"), "addr", queryaddr, "size", querysize) 249 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 250 } 251 h.info("ExecSQL", "query", string(query)) 252 253 if err = h.imports.ExecSQL(string(query)); err != nil { 254 h.error(err) 255 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 256 } 257 h.info("succeed") 258 return consts.RESULT_OK.Int32() 259 } 260 261 func (h *host) QuerySQL(queryaddr, querysize, retaddrptr, retsizeptr int32) int32 { 262 query, err := h.instance.GetMemory(queryaddr, querysize) 263 if err != nil { 264 h.error(errors.Wrap(err, "QuerySQL::GetMemory"), "addr", queryaddr, "size", querysize) 265 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 266 } 267 h.info("QuerySQL", "query", string(query)) 268 269 res, err := h.imports.QuerySQL(string(query)) 270 if err != nil { 271 h.error(err, "query", string(query)) 272 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 273 } 274 h.info("QuerySQL", "result", string(res)) 275 276 if err = CopyHostDataToWasm(h.instance, res, retaddrptr, retsizeptr); err != nil { 277 h.error(errors.Wrap(err, "QuerySQL::CopyHostDataToWasm"), "addr", retaddrptr, "size", retsizeptr) 278 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 279 } 280 h.info("succeed") 281 return consts.RESULT_OK.Int32() 282 } 283 284 func (h *host) SendTX(chainid, dataaddr, datasize, hashaddrptr, hashsizeptr int32) int32 { 285 data, err := h.instance.GetMemory(dataaddr, datasize) 286 if err != nil { 287 h.error(errors.Wrap(err, "SendTX::GetMemory"), "addr", dataaddr, "size", datasize) 288 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 289 } 290 h.info("SendTX", "data", string(data)) 291 292 hash, err := h.imports.SendTX(uint32(chainid), data) 293 if err != nil { 294 h.error(err) 295 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 296 } 297 h.info("SendTX", "hash", hash) 298 299 if err = CopyHostDataToWasm(h.instance, []byte(hash), hashaddrptr, hashsizeptr); err != nil { 300 h.error(errors.Wrap(err, "SendTX::CopyHostDataToWasm"), "addr", hashaddrptr, "size", hashsizeptr) 301 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 302 } 303 h.info("succeed") 304 return consts.RESULT_OK.Int32() 305 } 306 307 func (h *host) SendTXWithOperator(chainid, dataaddr, datasize, hashaddrptr, hashsizeptr int32) int32 { 308 data, err := h.instance.GetMemory(dataaddr, datasize) 309 if err != nil { 310 h.error(errors.Wrap(err, "SendTXWithOperator::GetMemory"), "addr", dataaddr, "size", datasize) 311 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 312 } 313 h.info("SendTXWithOperator", "data", string(data)) 314 315 hash, err := h.imports.SendTXWithOperator(uint32(chainid), data) 316 if err != nil { 317 h.error(err, "chain", chainid, "data", string(data)) 318 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 319 } 320 321 h.info("SendTXWithOperator", "hash", hash) 322 if err = CopyHostDataToWasm(h.instance, []byte(hash), hashaddrptr, hashsizeptr); err != nil { 323 h.error(errors.Wrap(err, "SendTXWithOperator::CopyHostDataToWasm"), "addr", hashaddrptr, "size", hashsizeptr) 324 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 325 } 326 h.info("succeed") 327 return consts.RESULT_OK.Int32() 328 } 329 330 func (h *host) CallContract(chainid, dataaddr, datasize, resultaddrptr, resultsizeptr int32) int32 { 331 data, err := h.instance.GetMemory(dataaddr, datasize) 332 if err != nil { 333 h.error(errors.Wrap(err, "CallContract::GetMemory"), "addr", dataaddr, "size", datasize) 334 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 335 } 336 h.info("CallContract", "data", string(data)) 337 338 res, err := h.imports.CallContract(uint32(chainid), data) 339 if err != nil { 340 h.error(err) 341 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 342 } 343 h.info("CallContract", "result", res) 344 345 if err = CopyHostDataToWasm(h.instance, res, resultaddrptr, resultsizeptr); err != nil { 346 h.error(errors.Wrap(err, "CallContract::CopyHostDataToWasm"), "addr", resultaddrptr, "size", resultsizeptr) 347 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 348 } 349 h.info("succeed") 350 return consts.RESULT_OK.Int32() 351 } 352 353 func (h *host) PubMQTT(topicaddr, topicsize, msgaddr, msgsize int32) int32 { 354 topic, err := h.instance.GetMemory(topicaddr, topicsize) 355 if err != nil { 356 h.error(errors.Wrap(err, "PutMQTT::GetMemory1"), "addr", topicaddr, "size", topicsize) 357 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 358 } 359 h.info("PubMQTT", "topic", string(topic)) 360 361 msg, err := h.instance.GetMemory(msgaddr, msgsize) 362 if err != nil { 363 h.error(errors.Wrap(err, "PutMQTT::GetMemory2"), "addr", msgaddr, "size", msgsize) 364 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 365 } 366 h.info("PubMQTT", "message", string(msg)) 367 368 if err = h.imports.PubMQTT(string(topic), msg); err != nil { 369 h.error(err) 370 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 371 } 372 h.info("succeed") 373 return consts.RESULT_OK.Int32() 374 } 375 376 func (h *host) SubmitMetrics(dataaddr, datasize int32) int32 { 377 data, err := h.instance.GetMemory(dataaddr, datasize) 378 if err != nil { 379 h.error(errors.Wrap(err, "SubmitMetrics::GetMemory"), "dataaddr", dataaddr, "datasize", datasize) 380 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 381 } 382 h.info("SubmitMetrics", "data", string(data)) 383 384 if err = h.imports.SubmitMetrics(data); err != nil { 385 h.error(err) 386 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 387 } 388 h.info("succeed") 389 return consts.RESULT_OK.Int32() 390 } 391 392 func (h *host) AsyncAPICall(reqaddr, reqsize, rspaddrptr, rspsizeptr int32) int32 { 393 req, err := h.instance.GetMemory(reqaddr, reqsize) 394 if err != nil { 395 h.error(errors.Wrap(err, "AsyncAPICall::GetMemory"), "reqaddr", reqaddr, "reqsize", reqsize) 396 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 397 } 398 h.info("AsyncAPICall", "req", string(req)) 399 400 rsp, err := h.imports.AsyncAPICall(req) 401 if err != nil { 402 h.error(err) 403 return consts.RESULT__IMPORT_HANDLE_FAILED.Int32() 404 } 405 h.info("AsyncAPICall", "rsp", string(rsp)) 406 407 if err = CopyHostDataToWasm(h.instance, rsp, rspaddrptr, rspsizeptr); err != nil { 408 h.error(errors.Wrap(err, "AsyncAPICall::CopyHostDataToWasm"), "addr", rspaddrptr, "size", rspsizeptr) 409 return consts.RESULT__INVALID_MEM_ACCESS.Int32() 410 } 411 h.info("succeed") 412 return consts.RESULT_OK.Int32() 413 } 414 415 func (h *host) _log(lv consts.LogLevel, msg string, args ...any) { 416 var pcs [1]uintptr 417 runtime.Callers(3, pcs[:]) 418 fs := runtime.CallersFrames([]uintptr{pcs[0]}) 419 f, _ := fs.Next() 420 parts := strings.Split(f.Function, ".") 421 fn := parts[len(parts)-1] 422 h.imports.LogInternal(lv, msg, append(args, "host_func", fn, "instance_id", h.instance.ID())...) 423 } 424 425 func (h *host) info(msg string, args ...any) { 426 h._log(consts.LOG_LEVEL__INFO, msg, args...) 427 } 428 429 func (h *host) error(err error, args ...any) { 430 h._log(consts.LOG_LEVEL__ERROR, err.Error(), args...) 431 }