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  }