github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/modules/vm/wasmtime/instance_exports.go (about) 1 package wasmtime 2 3 import ( 4 "context" 5 "encoding/binary" 6 "encoding/hex" 7 "encoding/json" 8 "fmt" 9 "math/rand" 10 "runtime/debug" 11 "strconv" 12 "strings" 13 "sync/atomic" 14 "time" 15 "unicode/utf8" 16 17 "github.com/ethereum/go-ethereum/crypto" 18 "github.com/google/uuid" 19 "github.com/pkg/errors" 20 "github.com/tidwall/gjson" 21 "golang.org/x/text/encoding/unicode" 22 23 base "github.com/machinefi/w3bstream/pkg/depends/base/types" 24 confid "github.com/machinefi/w3bstream/pkg/depends/conf/id" 25 conflog "github.com/machinefi/w3bstream/pkg/depends/conf/log" 26 confmqtt "github.com/machinefi/w3bstream/pkg/depends/conf/mqtt" 27 "github.com/machinefi/w3bstream/pkg/depends/kit/sqlx/datatypes" 28 "github.com/machinefi/w3bstream/pkg/depends/x/mapx" 29 "github.com/machinefi/w3bstream/pkg/enums" 30 "github.com/machinefi/w3bstream/pkg/models" 31 "github.com/machinefi/w3bstream/pkg/modules/metrics" 32 "github.com/machinefi/w3bstream/pkg/modules/operator" 33 optypes "github.com/machinefi/w3bstream/pkg/modules/operator/pool/types" 34 wasmapi "github.com/machinefi/w3bstream/pkg/modules/vm/wasmapi/types" 35 "github.com/machinefi/w3bstream/pkg/types" 36 "github.com/machinefi/w3bstream/pkg/types/wasm" 37 "github.com/machinefi/w3bstream/pkg/types/wasm/sql_util" 38 ) 39 40 type ( 41 Import func(module, name string, f interface{}) error 42 43 ABILinker interface { 44 LinkABI(Import) error 45 } 46 47 ExportFuncs struct { 48 rt *Runtime 49 prj *models.Project 50 app *models.Applet 51 ins *models.Instance 52 ctxID *atomic.Value 53 logs []*models.WasmLog 54 res *mapx.Map[uint32, []byte] 55 evs *mapx.Map[uint32, []byte] 56 env *wasm.Env 57 kvs wasm.KVStore 58 db *wasm.Database 59 logger conflog.Logger 60 cl *wasm.ChainClient 61 cf *types.ChainConfig 62 ctx context.Context 63 mq *confmqtt.Client 64 metrics metrics.CustomMetrics 65 srv wasmapi.Server 66 opPool optypes.Pool 67 } 68 ) 69 70 func NewExportFuncs(ctx context.Context, rt *Runtime) (*ExportFuncs, error) { 71 ef := &ExportFuncs{ 72 prj: types.MustProjectFromContext(ctx), 73 app: types.MustAppletFromContext(ctx), 74 ins: types.MustInstanceFromContext(ctx), 75 ctxID: &atomic.Value{}, 76 res: wasm.MustRuntimeResourceFromContext(ctx), 77 evs: wasm.MustRuntimeEventTypesFromContext(ctx), 78 kvs: wasm.MustKVStoreFromContext(ctx), 79 logger: wasm.MustLoggerFromContext(ctx), 80 srv: types.MustWasmApiServerFromContext(ctx), 81 opPool: types.MustOperatorPoolFromContext(ctx), 82 cl: wasm.MustChainClientFromContext(ctx), 83 cf: types.MustChainConfigFromContext(ctx), 84 db: wasm.MustSQLStoreFromContext(ctx), 85 env: wasm.MustEnvFromContext(ctx), 86 mq: wasm.MustMQTTClientFromContext(ctx), 87 metrics: wasm.MustCustomMetricsFromContext(ctx), 88 rt: rt, 89 ctx: ctx, 90 } 91 ef.ctxID.Store("") 92 93 return ef, nil 94 } 95 96 var ( 97 _ wasm.ABI = (*ExportFuncs)(nil) 98 _rand = rand.New(rand.NewSource(time.Now().UnixNano())) 99 ) 100 101 func (ef *ExportFuncs) LinkABI(impt Import) error { 102 for name, ff := range map[string]interface{}{ 103 "abort": ef.Abort, 104 "trace": ef.Trace, 105 "seed": ef.Seed, 106 "ws_log": ef.Log, 107 "ws_get_data": ef.GetData, 108 "ws_set_data": ef.SetData, 109 "ws_get_db": ef.GetDB, 110 "ws_set_db": ef.SetDB, 111 "ws_send_tx": ef.SendTX, 112 "ws_send_tx_with_operator": ef.SendTXWithOperator, 113 "ws_call_contract": ef.CallContract, 114 "ws_set_sql_db": ef.SetSQLDB, 115 "ws_get_sql_db": ef.GetSQLDB, 116 "ws_get_env": ef.GetEnv, 117 "ws_send_mqtt_msg": ef.SendMqttMsg, 118 "ws_api_call": ef.ApiCall, 119 } { 120 if err := impt("env", name, ff); err != nil { 121 return err 122 } 123 } 124 125 for name, ff := range map[string]interface{}{ 126 "ws_submit_metrics": ef.StatSubmit, 127 } { 128 if err := impt("stat", name, ff); err != nil { 129 return err 130 } 131 } 132 133 return nil 134 } 135 136 func (ef *ExportFuncs) _log(level conflog.Level, src string, msg any) { 137 l := ef.logger.WithValues("@src", src) 138 switch level { 139 case conflog.DebugLevel: 140 l.Debug(msg.(string)) 141 case conflog.InfoLevel: 142 l.Info(msg.(string)) 143 case conflog.WarnLevel: 144 l.Warn(msg.(error)) 145 case conflog.ErrorLevel: 146 l.Error(msg.(error)) 147 default: 148 l.Trace(msg.(string)) 149 } 150 _msg := subStringWithLength(fmt.Sprint(msg), enums.WasmLogMaxLength) 151 ef.logs = append(ef.logs, &models.WasmLog{ 152 WasmLogInfo: models.WasmLogInfo{ 153 ProjectName: ef.prj.Name, 154 AppletName: ef.app.Name, 155 InstanceID: ef.ins.InstanceID, 156 EventID: ef.ContextID(), 157 Src: src, 158 Level: level.String(), 159 LogTime: time.Now().UnixNano(), 160 Msg: _msg, 161 }, 162 OperationTimes: datatypes.OperationTimes{ 163 CreatedAt: base.Timestamp{Time: time.Now()}, 164 UpdatedAt: base.Timestamp{Time: time.Now()}, 165 }, 166 }) 167 } 168 169 func (ef *ExportFuncs) WasmLog(lv conflog.Level, msg any) { 170 ef._log(lv, "wasm", msg) 171 } 172 173 func (ef *ExportFuncs) HostLog(lv conflog.Level, msg any) { 174 ef._log(lv, "host", msg) 175 } 176 177 func (ef *ExportFuncs) EntryContext(ctx context.Context, ctxID string, tpe, data []byte) (uint32, bool) { 178 if ef.ctxID.CompareAndSwap("", ctxID) { 179 rid := uuid.New().ID() % uint32(maxInt) 180 ef.evs.Store(rid, tpe) 181 ef.res.Store(rid, data) 182 return rid, true 183 } 184 return 0, false 185 } 186 187 func (ef *ExportFuncs) LeaveContext(ctx context.Context, ctxID string, rid uint32) bool { 188 if ef.ctxID.Load().(string) == ctxID { 189 idg := confid.MustSFIDGeneratorFromContext(ctx) 190 ids := idg.MustGenSFIDs(len(ef.logs)) 191 d := types.MustMgrDBExecutorFromContext(ctx) 192 193 for i, l := range ef.logs { 194 l.WasmLogID = ids[i] 195 } 196 err := models.BatchCreateWasmLogs(d, ef.logs...) 197 if err != nil { 198 ef.HostLog(conflog.WarnLevel, err) 199 } 200 ef.logs = ef.logs[:0] 201 ef.evs.Remove(rid) 202 ef.res.Remove(rid) 203 return ef.ctxID.CompareAndSwap(ctxID, "") 204 } 205 return false 206 } 207 208 func (ef *ExportFuncs) ContextID() string { 209 return ef.ctxID.Load().(string) 210 } 211 212 func (ef *ExportFuncs) Log(level, ptr, size int32) int32 { 213 buf, err := ef.rt.Read(ptr, size) 214 if err != nil { 215 ef.HostLog(conflog.ErrorLevel, err) 216 return wasm.ResultStatusCode_Failed 217 } 218 ef.WasmLog(conflog.Level(level), string(buf)) 219 return int32(wasm.ResultStatusCode_OK) 220 } 221 222 func (ef *ExportFuncs) ApiCall(kAddr, kSize, vmAddrPtr, vmSizePtr int32) int32 { 223 buf, err := ef.rt.Read(kAddr, kSize) 224 if err != nil { 225 ef.HostLog(conflog.ErrorLevel, err) 226 return int32(wasm.ResultStatusCode_TransDataFromVMFailed) 227 } 228 229 resp := ef.srv.Call(ef.ctx, buf) 230 231 respJson, err := json.Marshal(resp) 232 if err != nil { 233 ef.HostLog(conflog.ErrorLevel, err) 234 return int32(wasm.ResultStatusCode_HostInternal) 235 } 236 237 if err = ef.rt.Copy(respJson, vmAddrPtr, vmSizePtr); err != nil { 238 ef.HostLog(conflog.ErrorLevel, err) 239 return int32(wasm.ResultStatusCode_TransDataToVMFailed) 240 } 241 242 return int32(wasm.ResultStatusCode_OK) 243 } 244 245 // Abort is reserved for imported func env.abort() which is auto-generated by assemblyScript 246 func (ef *ExportFuncs) Abort(msgPtr int32, fileNamePtr int32, line int32, col int32) { 247 msg, err := ef.readString(msgPtr) 248 if err != nil { 249 ef.HostLog(conflog.ErrorLevel, errors.Wrap(err, "fail to decode arguments in env.abort")) 250 return 251 } 252 fileName, err := ef.readString(fileNamePtr) 253 if err != nil { 254 ef.HostLog(conflog.ErrorLevel, errors.Wrap(err, "fail to decode arguments in env.abort")) 255 return 256 } 257 ef.HostLog(conflog.ErrorLevel, errors.Errorf("abort: %s at %s:%d:%d", msg, fileName, line, col)) 258 } 259 260 func (ef *ExportFuncs) readString(ptr int32) (string, error) { 261 if ptr < 4 { 262 return "", errors.Errorf("the pointer address %d is invalid", ptr) 263 } 264 265 decoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder() 266 267 lenData, err := ef.rt.Read(ptr-4, 4) // sizeof(uint32) is 4 268 if err != nil { 269 return "", err 270 } 271 len := binary.LittleEndian.Uint32(lenData) 272 data, err := ef.rt.Read(ptr, int32(len)) 273 if err != nil { 274 return "", err 275 } 276 utf8bytes, err := decoder.Bytes(data) 277 if err != nil { 278 return "", err 279 } 280 return string(utf8bytes), nil 281 } 282 283 // Trace is reserved for imported func env.trace() which is auto-generated by assemblyScript 284 func (ef *ExportFuncs) Trace(msgPtr int32, _ int32, arr ...float64) { 285 msg, err := ef.readString(msgPtr) 286 if err != nil { 287 ef.HostLog(conflog.ErrorLevel, errors.Wrap(err, "fail to decode arguments in env.abort")) 288 return 289 } 290 291 str := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(arr)), ", "), "[]") 292 if len(str) > 0 { 293 str = " " + str 294 } 295 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("trace: %s%s", msg, str)) 296 } 297 298 // Seed is reserved for imported func env.seed() which is auto-generated by assemblyScript 299 func (ef *ExportFuncs) Seed() float64 { 300 return _rand.Float64() * float64(time.Now().UnixNano()) 301 } 302 303 func (ef *ExportFuncs) GetData(rid, vmAddrPtr, vmSizePtr int32) int32 { 304 data, ok := ef.res.Load(uint32(rid)) 305 if !ok { 306 return int32(wasm.ResultStatusCode_ResourceNotFound) 307 } 308 309 if err := ef.rt.Copy(data, vmAddrPtr, vmSizePtr); err != nil { 310 ef.HostLog(conflog.ErrorLevel, err) 311 return int32(wasm.ResultStatusCode_TransDataToVMFailed) 312 } 313 314 return int32(wasm.ResultStatusCode_OK) 315 } 316 317 // TODO SetData if rid not exist, should be assigned by wasm? 318 func (ef *ExportFuncs) SetData(rid, addr, size int32) int32 { 319 buf, err := ef.rt.Read(addr, size) 320 if err != nil { 321 ef.HostLog(conflog.ErrorLevel, err) 322 return int32(wasm.ResultStatusCode_TransDataToVMFailed) 323 } 324 ef.res.Store(uint32(rid), buf) 325 return int32(wasm.ResultStatusCode_OK) 326 } 327 328 func (ef *ExportFuncs) GetDB(kAddr, kSize int32, vmAddrPtr, vmSizePtr int32) int32 { 329 key, err := ef.rt.Read(kAddr, kSize) 330 if err != nil { 331 ef.HostLog(conflog.ErrorLevel, err) 332 return int32(wasm.ResultStatusCode_ResourceNotFound) 333 } 334 335 val, exist := ef.kvs.Get(string(key)) 336 if exist != nil || val == nil { 337 return int32(wasm.ResultStatusCode_ResourceNotFound) 338 } 339 340 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("host.GetDB %s:%s", string(key), strconv.Quote(string(val)))) 341 342 if err = ef.rt.Copy(val, vmAddrPtr, vmSizePtr); err != nil { 343 ef.HostLog(conflog.ErrorLevel, err) 344 return int32(wasm.ResultStatusCode_TransDataToVMFailed) 345 } 346 347 return int32(wasm.ResultStatusCode_OK) 348 } 349 350 func (ef *ExportFuncs) SetDB(kAddr, kSize, vAddr, vSize int32) int32 { 351 key, err := ef.rt.Read(kAddr, kSize) 352 if err != nil { 353 ef.HostLog(conflog.ErrorLevel, err) 354 return int32(wasm.ResultStatusCode_ResourceNotFound) 355 } 356 val, err := ef.rt.Read(vAddr, vSize) 357 if err != nil { 358 ef.HostLog(conflog.ErrorLevel, err) 359 return int32(wasm.ResultStatusCode_ResourceNotFound) 360 } 361 362 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("host.SetDB %s:%s", string(key), strconv.Quote(string(val)))) 363 364 err = ef.kvs.Set(string(key), val) 365 if err != nil { 366 ef.HostLog(conflog.ErrorLevel, err) 367 return int32(wasm.ResultStatusCode_Failed) 368 } 369 return int32(wasm.ResultStatusCode_OK) 370 } 371 372 func (ef *ExportFuncs) SetSQLDB(addr, size int32) int32 { 373 if ef.db == nil { 374 return int32(wasm.ResultStatusCode_NoDBContext) 375 } 376 data, err := ef.rt.Read(addr, size) 377 if err != nil { 378 ef.HostLog(conflog.ErrorLevel, err) 379 return int32(wasm.ResultStatusCode_ResourceNotFound) 380 } 381 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("GetSQLDB: [query: %s]", string(data))) 382 383 prestate, params, err := sql_util.ParseQuery(data) 384 if err != nil { 385 ef.HostLog(conflog.ErrorLevel, err) 386 return wasm.ResultStatusCode_Failed 387 } 388 389 db, err := ef.db.WithDefaultSchema() 390 if err != nil { 391 ef.HostLog(conflog.ErrorLevel, err) 392 return wasm.ResultStatusCode_Failed 393 } 394 _, err = db.ExecContext(context.Background(), prestate, params...) 395 if err != nil { 396 ef.HostLog(conflog.ErrorLevel, err) 397 return wasm.ResultStatusCode_Failed 398 } 399 400 return int32(wasm.ResultStatusCode_OK) 401 } 402 403 func (ef *ExportFuncs) GetSQLDB(addr, size int32, vmAddrPtr, vmSizePtr int32) int32 { 404 if ef.db == nil { 405 return int32(wasm.ResultStatusCode_NoDBContext) 406 } 407 data, err := ef.rt.Read(addr, size) 408 if err != nil { 409 ef.HostLog(conflog.ErrorLevel, err) 410 return int32(wasm.ResultStatusCode_ResourceNotFound) 411 } 412 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("GetSQLDB: [query: %s]", string(data))) 413 414 prestate, params, err := sql_util.ParseQuery(data) 415 if err != nil { 416 ef.HostLog(conflog.ErrorLevel, err) 417 return wasm.ResultStatusCode_Failed 418 } 419 420 db, err := ef.db.WithDefaultSchema() 421 if err != nil { 422 ef.HostLog(conflog.ErrorLevel, err) 423 return wasm.ResultStatusCode_Failed 424 } 425 rows, err := db.QueryContext(context.Background(), prestate, params...) 426 if err != nil { 427 ef.HostLog(conflog.ErrorLevel, err) 428 return wasm.ResultStatusCode_Failed 429 } 430 431 ret, err := sql_util.JsonifyRows(rows) 432 if err != nil { 433 ef.HostLog(conflog.ErrorLevel, err) 434 return wasm.ResultStatusCode_Failed 435 } 436 437 if err = ef.rt.Copy(ret, vmAddrPtr, vmSizePtr); err != nil { 438 ef.HostLog(conflog.ErrorLevel, err) 439 return int32(wasm.ResultStatusCode_TransDataToVMFailed) 440 } 441 442 return int32(wasm.ResultStatusCode_OK) 443 } 444 445 // TODO: make sendTX async, and add callback if possible 446 func (ef *ExportFuncs) SendTX(chainID int32, offset, size, vmAddrPtr, vmSizePtr int32) (result int32) { 447 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("offset %d size %d vmAddrPtr %d vmSizePtr %d", offset, size, vmAddrPtr, vmSizePtr)) 448 if ef.cl == nil { 449 ef.HostLog(conflog.ErrorLevel, errors.New("eth client doesn't exist")) 450 return wasm.ResultStatusCode_Failed 451 } 452 buf, err := ef.rt.Read(offset, size) 453 if err != nil { 454 ef.HostLog(conflog.ErrorLevel, err) 455 return wasm.ResultStatusCode_Failed 456 } 457 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("input data: %s", string(buf))) 458 ret := gjson.Parse(string(buf)) 459 to := ret.Get("to").String() 460 value := ret.Get("value").String() 461 data := ret.Get("data").String() 462 463 op, err := ef.opPool.Get(ef.prj.AccountID, operator.DefaultOperatorName) 464 if err != nil { 465 ef.HostLog(conflog.ErrorLevel, fmt.Sprintf("failed to get operator [account: %s] [operator: %s]", ef.prj.AccountID, operator.DefaultOperatorName)) 466 } 467 prvkey, err := crypto.HexToECDSA(op.Op.PrivateKey) 468 if err != nil { 469 ef.HostLog(conflog.ErrorLevel, fmt.Sprintf("failed to parse private key [account: %s] [operator: %s]", ef.prj.AccountID, operator.DefaultOperatorName)) 470 } 471 from := crypto.PubkeyToAddress(prvkey.PublicKey) 472 473 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("send tx: [from %s] [to %s] [value %s] [data %s] [prj: %v]", from, to, value, data, ef.prj.Name)) 474 defer func() { 475 if err := recover(); err != nil { 476 fmt.Printf("panic: %s; calltrace:%s\n", fmt.Sprint(err), string(debug.Stack())) 477 result = -1 478 return 479 } 480 }() 481 txHash, err := ef.cl.SendTX(ef.cf, uint64(chainID), "", to, value, data, ef.opPool, ef.prj) 482 if err != nil { 483 ef.HostLog(conflog.ErrorLevel, err) 484 return wasm.ResultStatusCode_Failed 485 } 486 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("send tx [hash %s]", txHash)) 487 if err := ef.rt.Copy([]byte(txHash), vmAddrPtr, vmSizePtr); err != nil { 488 ef.HostLog(conflog.ErrorLevel, err) 489 return wasm.ResultStatusCode_Failed 490 } 491 ef.HostLog(conflog.InfoLevel, "send tx done") 492 return int32(wasm.ResultStatusCode_OK) 493 } 494 495 func (ef *ExportFuncs) SendTXWithOperator(chainID int32, offset, size, vmAddrPtr, vmSizePtr int32) int32 { 496 if ef.cl == nil { 497 ef.HostLog(conflog.ErrorLevel, errors.New("eth client doesn't exist")) 498 return wasm.ResultStatusCode_Failed 499 } 500 buf, err := ef.rt.Read(offset, size) 501 if err != nil { 502 ef.HostLog(conflog.ErrorLevel, err) 503 return wasm.ResultStatusCode_Failed 504 } 505 ret := gjson.Parse(string(buf)) 506 507 to := ret.Get("to").String() 508 value := ret.Get("value").String() 509 data := ret.Get("data").String() 510 operatorName := ret.Get("operatorName").String() 511 512 op, err := ef.opPool.Get(ef.prj.AccountID, operatorName) 513 if err != nil { 514 ef.HostLog(conflog.ErrorLevel, fmt.Sprintf("failed to get operator [account: %s] [operator: %s]", ef.prj.AccountID, operator.DefaultOperatorName)) 515 } 516 prvkey, err := crypto.HexToECDSA(op.Op.PrivateKey) 517 if err != nil { 518 ef.HostLog(conflog.ErrorLevel, fmt.Sprintf("failed to parse private key [account: %s] [operator: %s]", ef.prj.AccountID, operator.DefaultOperatorName)) 519 } 520 from := crypto.PubkeyToAddress(prvkey.PublicKey) 521 522 ef.HostLog(conflog.InfoLevel, fmt.Sprintf("send tx: [from %s] [to %s] [value %s] [data %s] [prj: %v]", from, to, value, data, ef.prj.Name)) 523 524 txResp, err := ef.cl.SendTXWithOperator(ef.cf, uint64(chainID), "", to, value, data, operatorName, ef.opPool, ef.prj) 525 if err != nil { 526 ef.HostLog(conflog.ErrorLevel, err) 527 return wasm.ResultStatusCode_Failed 528 } 529 if err := ef.rt.Copy([]byte(txResp.Hash), vmAddrPtr, vmSizePtr); err != nil { 530 ef.HostLog(conflog.ErrorLevel, err) 531 return wasm.ResultStatusCode_Failed 532 } 533 return int32(wasm.ResultStatusCode_OK) 534 } 535 536 func (ef *ExportFuncs) SendMqttMsg(topicAddr, topicSize, msgAddr, msgSize int32) int32 { 537 if ef.mq == nil { 538 ef.HostLog(conflog.ErrorLevel, errors.New("mq client doesn't exist")) 539 return wasm.ResultStatusCode_Failed 540 } 541 542 var ( 543 topicBuf []byte 544 msgBuf []byte 545 err error 546 ) 547 548 topicBuf, err = ef.rt.Read(topicAddr, topicSize) 549 if err != nil { 550 ef.HostLog(conflog.ErrorLevel, err) 551 return wasm.ResultStatusCode_Failed 552 } 553 msgBuf, err = ef.rt.Read(msgAddr, msgSize) 554 if err != nil { 555 ef.HostLog(conflog.ErrorLevel, err) 556 return wasm.ResultStatusCode_Failed 557 } 558 err = ef.mq.WithTopic(string(topicBuf)).Publish(string(msgBuf)) 559 if err != nil { 560 ef.HostLog(conflog.ErrorLevel, err) 561 return wasm.ResultStatusCode_Failed 562 } 563 return int32(wasm.ResultStatusCode_OK) 564 } 565 566 func (ef *ExportFuncs) CallContract(chainID int32, offset, size int32, vmAddrPtr, vmSizePtr int32) int32 { 567 if ef.cl == nil { 568 ef.HostLog(conflog.ErrorLevel, errors.New("eth client doesn't exist")) 569 return wasm.ResultStatusCode_Failed 570 } 571 buf, err := ef.rt.Read(offset, size) 572 if err != nil { 573 ef.HostLog(conflog.ErrorLevel, err) 574 return wasm.ResultStatusCode_Failed 575 } 576 ret := gjson.Parse(string(buf)) 577 data, err := ef.cl.CallContract(ef.cf, uint64(chainID), "", ret.Get("to").String(), ret.Get("data").String()) 578 if err != nil { 579 ef.HostLog(conflog.ErrorLevel, err) 580 return wasm.ResultStatusCode_Failed 581 } 582 if err = ef.rt.Copy(data, vmAddrPtr, vmSizePtr); err != nil { 583 ef.HostLog(conflog.ErrorLevel, err) 584 return wasm.ResultStatusCode_Failed 585 } 586 return int32(wasm.ResultStatusCode_OK) 587 } 588 589 func (ef *ExportFuncs) GetEnv(kAddr, kSize int32, vmAddrPtr, vmSizePtr int32) int32 { 590 if ef.env == nil { 591 return int32(wasm.ResultStatusCode_EnvKeyNotFound) 592 } 593 key, err := ef.rt.Read(kAddr, kSize) 594 if err != nil { 595 ef.HostLog(conflog.ErrorLevel, err) 596 return int32(wasm.ResultStatusCode_TransDataToVMFailed) 597 } 598 599 val, ok := ef.env.Get(string(key)) 600 if !ok { 601 return int32(wasm.ResultStatusCode_EnvKeyNotFound) 602 } 603 604 if err = ef.rt.Copy([]byte(val), vmAddrPtr, vmSizePtr); err != nil { 605 ef.HostLog(conflog.ErrorLevel, err) 606 return int32(wasm.ResultStatusCode_TransDataToVMFailed) 607 } 608 return int32(wasm.ResultStatusCode_OK) 609 } 610 611 func (ef *ExportFuncs) GetEventType(rid, vmAddrPtr, vmSizePtr int32) int32 { 612 data, ok := ef.res.Load(uint32(rid)) 613 if !ok { 614 return int32(wasm.ResultStatusCode_ResourceNotFound) 615 } 616 617 if err := ef.rt.Copy(data, vmAddrPtr, vmSizePtr); err != nil { 618 ef.HostLog(conflog.ErrorLevel, err) 619 return int32(wasm.ResultStatusCode_TransDataToVMFailed) 620 } 621 return int32(wasm.ResultStatusCode_OK) 622 } 623 624 func (ef *ExportFuncs) StatSubmit(vmAddrPtr, vmSizePtr int32) int32 { 625 buf, err := ef.rt.Read(vmAddrPtr, vmSizePtr) 626 if err != nil { 627 ef.HostLog(conflog.ErrorLevel, err) 628 return wasm.ResultStatusCode_Failed 629 } 630 str := string(buf) 631 if !gjson.Valid(str) { 632 err = errors.New("invalid json") 633 ef.HostLog(conflog.ErrorLevel, err) 634 return wasm.ResultStatusCode_Failed 635 } 636 object := gjson.Parse(str) 637 if object.IsArray() { 638 err = errors.New("json object should not be an array") 639 ef.HostLog(conflog.ErrorLevel, err) 640 return wasm.ResultStatusCode_Failed 641 } 642 643 if err = ef.metrics.Submit(object); err != nil { 644 ef.HostLog(conflog.ErrorLevel, err) 645 return wasm.ResultStatusCode_Failed 646 } 647 return int32(wasm.ResultStatusCode_OK) 648 } 649 650 func subStringWithLength(str string, length int) string { 651 if !utf8.ValidString(str) { 652 str = hex.EncodeToString([]byte(str)) 653 } 654 if length < 0 { 655 return "" 656 } 657 rs := []rune(str) 658 strLen := len(rs) 659 660 if length > strLen { 661 return str 662 } 663 return string(rs[0:length]) 664 }