@@ -2,6 +2,7 @@ package runtime
2
2
3
3
import (
4
4
"context"
5
+ "encoding/binary"
5
6
"encoding/json"
6
7
"fmt"
7
8
@@ -229,7 +230,7 @@ func hostValidateAddress(ctx context.Context, mod api.Module, addrPtr, addrLen u
229
230
}
230
231
231
232
// hostScan implements db_scan
232
- func hostScan (ctx context.Context , mod api.Module , startPtr , startLen , endPtr , endLen uint32 , order uint32 ) (uint64 , uint64 , uint32 ) {
233
+ func hostScan (ctx context.Context , mod api.Module , startPtr , startLen , endPtr , endLen , order uint32 ) (uint64 , uint64 , uint32 ) {
233
234
env := ctx .Value ("env" ).(* RuntimeEnvironment )
234
235
mem := mod .Memory ()
235
236
@@ -239,17 +240,25 @@ func hostScan(ctx context.Context, mod api.Module, startPtr, startLen, endPtr, e
239
240
}
240
241
env .GasUsed += gasCostIteratorCreate
241
242
242
- start , err := ReadMemory (mem , startPtr , startLen )
243
- if err != nil {
244
- panic (fmt .Sprintf ("failed to read start key from memory: %v" , err ))
243
+ // Read start and end keys
244
+ var start , end []byte
245
+ var err error
246
+
247
+ if startPtr != 0 {
248
+ start , err = ReadMemory (mem , startPtr , startLen )
249
+ if err != nil {
250
+ panic (fmt .Sprintf ("failed to read start key from memory: %v" , err ))
251
+ }
245
252
}
246
253
247
- end , err := ReadMemory (mem , endPtr , endLen )
248
- if err != nil {
249
- panic (fmt .Sprintf ("failed to read end key from memory: %v" , err ))
254
+ if endPtr != 0 {
255
+ end , err = ReadMemory (mem , endPtr , endLen )
256
+ if err != nil {
257
+ panic (fmt .Sprintf ("failed to read end key from memory: %v" , err ))
258
+ }
250
259
}
251
260
252
- // Check iterator limits
261
+ // Start a new call context for this iterator
253
262
callID := env .StartCall ()
254
263
if len (env .iterators [callID ]) >= maxIteratorsPerCall {
255
264
return 0 , 0 , 2 // Return error code 2 for too many iterators
@@ -424,74 +433,226 @@ func hostCloseIterator(ctx context.Context, mod api.Module, callID, iterID uint6
424
433
}
425
434
}
426
435
427
- // RegisterHostFunctions registers all host functions into a module named "env"
428
- func RegisterHostFunctions (r wazero.Runtime , env * RuntimeEnvironment ) (wazero.CompiledModule , error ) {
429
- // Initialize memory allocator if not already done
430
- if env .Memory == nil {
431
- env .Memory = NewMemoryAllocator (65536 ) // Start at 64KB offset
436
+ // hostAbort implements the abort function required by Wasm modules
437
+ func hostAbort (ctx context.Context , mod api.Module , code uint32 ) {
438
+ panic (fmt .Sprintf ("Wasm contract aborted with code: %d" , code ))
439
+ }
440
+
441
+ // hostDbRead implements db_read
442
+ func hostDbRead (ctx context.Context , mod api.Module , keyPtr uint32 ) uint32 {
443
+ env := ctx .Value ("env" ).(* RuntimeEnvironment )
444
+ mem := mod .Memory ()
445
+
446
+ // Read length prefix (4 bytes) from the key pointer
447
+ lenBytes , err := ReadMemory (mem , keyPtr , 4 )
448
+ if err != nil {
449
+ panic (fmt .Sprintf ("failed to read key length from memory: %v" , err ))
432
450
}
451
+ keyLen := binary .LittleEndian .Uint32 (lenBytes )
433
452
434
- // Build a module that exports these functions
435
- hostModBuilder := r .NewHostModuleBuilder ("env" )
453
+ // Read the actual key
454
+ key , err := ReadMemory (mem , keyPtr + 4 , keyLen )
455
+ if err != nil {
456
+ panic (fmt .Sprintf ("failed to read key from memory: %v" , err ))
457
+ }
436
458
437
- // Register memory management functions
438
- RegisterMemoryManagement (hostModBuilder , env .Memory )
459
+ value := env .DB .Get (key )
460
+ if len (value ) == 0 {
461
+ return 0
462
+ }
439
463
440
- // Register DB functions
441
- hostModBuilder .NewFunctionBuilder ().
442
- WithFunc (hostGet ).
443
- Export ("db_get" )
464
+ // Allocate memory for the result: 4 bytes for length + actual value
465
+ totalLen := 4 + len (value )
466
+ offset , err := env .Memory .Allocate (mem , uint32 (totalLen ))
467
+ if err != nil {
468
+ panic (fmt .Sprintf ("failed to allocate memory: %v" , err ))
469
+ }
444
470
445
- hostModBuilder .NewFunctionBuilder ().
446
- WithFunc (hostSet ).
447
- Export ("db_set" )
471
+ // Write length prefix
472
+ lenData := make ([]byte , 4 )
473
+ binary .LittleEndian .PutUint32 (lenData , uint32 (len (value )))
474
+ if err := WriteMemory (mem , offset , lenData ); err != nil {
475
+ panic (fmt .Sprintf ("failed to write value length to memory: %v" , err ))
476
+ }
448
477
449
- // Register API functions
450
- hostModBuilder . NewFunctionBuilder ().
451
- WithFunc ( hostHumanizeAddress ).
452
- Export ( "api_humanize_address" )
478
+ // Write value
479
+ if err := WriteMemory ( mem , offset + 4 , value ); err != nil {
480
+ panic ( fmt . Sprintf ( "failed to write value to memory: %v" , err ))
481
+ }
453
482
454
- hostModBuilder .NewFunctionBuilder ().
455
- WithFunc (hostCanonicalizeAddress ).
456
- Export ("api_canonicalize_address" )
483
+ return offset
484
+ }
457
485
458
- hostModBuilder .NewFunctionBuilder ().
459
- WithFunc (hostValidateAddress ).
460
- Export ("api_validate_address" )
486
+ // hostDbWrite implements db_write
487
+ func hostDbWrite (ctx context.Context , mod api.Module , keyPtr , valuePtr uint32 ) {
488
+ env := ctx .Value ("env" ).(* RuntimeEnvironment )
489
+ mem := mod .Memory ()
461
490
462
- // Register Query functions
463
- hostModBuilder .NewFunctionBuilder ().
464
- WithFunc (hostQueryExternal ).
465
- Export ("querier_query" )
491
+ // Read key length prefix (4 bytes)
492
+ keyLenBytes , err := ReadMemory (mem , keyPtr , 4 )
493
+ if err != nil {
494
+ panic (fmt .Sprintf ("failed to read key length from memory: %v" , err ))
495
+ }
496
+ keyLen := binary .LittleEndian .Uint32 (keyLenBytes )
497
+
498
+ // Read value length prefix (4 bytes)
499
+ valLenBytes , err := ReadMemory (mem , valuePtr , 4 )
500
+ if err != nil {
501
+ panic (fmt .Sprintf ("failed to read value length from memory: %v" , err ))
502
+ }
503
+ valLen := binary .LittleEndian .Uint32 (valLenBytes )
466
504
467
- // Register Iterator functions
468
- hostModBuilder .NewFunctionBuilder ().
469
- WithFunc (hostScan ).
505
+ // Read the actual key and value
506
+ key , err := ReadMemory (mem , keyPtr + 4 , keyLen )
507
+ if err != nil {
508
+ panic (fmt .Sprintf ("failed to read key from memory: %v" , err ))
509
+ }
510
+
511
+ value , err := ReadMemory (mem , valuePtr + 4 , valLen )
512
+ if err != nil {
513
+ panic (fmt .Sprintf ("failed to read value from memory: %v" , err ))
514
+ }
515
+
516
+ env .DB .Set (key , value )
517
+ }
518
+
519
+ // hostDbRemove implements db_remove
520
+ func hostDbRemove (ctx context.Context , mod api.Module , keyPtr uint32 ) {
521
+ env := ctx .Value ("env" ).(* RuntimeEnvironment )
522
+ mem := mod .Memory ()
523
+
524
+ // Read length prefix (4 bytes) from the key pointer
525
+ lenBytes , err := ReadMemory (mem , keyPtr , 4 )
526
+ if err != nil {
527
+ panic (fmt .Sprintf ("failed to read key length from memory: %v" , err ))
528
+ }
529
+ keyLen := binary .LittleEndian .Uint32 (lenBytes )
530
+
531
+ // Read the actual key
532
+ key , err := ReadMemory (mem , keyPtr + 4 , keyLen )
533
+ if err != nil {
534
+ panic (fmt .Sprintf ("failed to read key from memory: %v" , err ))
535
+ }
536
+
537
+ env .DB .Delete (key )
538
+ }
539
+
540
+ // RegisterHostFunctions registers all host functions with the wazero runtime
541
+ func RegisterHostFunctions (runtime wazero.Runtime , env * RuntimeEnvironment ) (wazero.CompiledModule , error ) {
542
+ builder := runtime .NewHostModuleBuilder ("env" )
543
+
544
+ // Register abort function
545
+ builder .NewFunctionBuilder ().
546
+ WithFunc (func (ctx context.Context , m api.Module , code uint32 ) {
547
+ ctx = context .WithValue (ctx , "env" , env )
548
+ hostAbort (ctx , m , code )
549
+ }).
550
+ WithParameterNames ("code" ).
551
+ Export ("abort" )
552
+
553
+ // Register DB functions
554
+ builder .NewFunctionBuilder ().
555
+ WithFunc (func (ctx context.Context , m api.Module , keyPtr , keyLen uint32 ) (uint32 , uint32 ) {
556
+ ctx = context .WithValue (ctx , "env" , env )
557
+ return hostGet (ctx , m , keyPtr , keyLen )
558
+ }).
559
+ WithParameterNames ("key_ptr" , "key_len" ).
560
+ Export ("db_get" )
561
+
562
+ builder .NewFunctionBuilder ().
563
+ WithFunc (func (ctx context.Context , m api.Module , keyPtr , keyLen , valPtr , valLen uint32 ) {
564
+ ctx = context .WithValue (ctx , "env" , env )
565
+ hostSet (ctx , m , keyPtr , keyLen , valPtr , valLen )
566
+ }).
567
+ WithParameterNames ("key_ptr" , "key_len" , "val_ptr" , "val_len" ).
568
+ Export ("db_set" )
569
+
570
+ builder .NewFunctionBuilder ().
571
+ WithFunc (func (ctx context.Context , m api.Module , startPtr , startLen , endPtr , endLen , order uint32 ) (uint64 , uint64 , uint32 ) {
572
+ ctx = context .WithValue (ctx , "env" , env )
573
+ return hostScan (ctx , m , startPtr , startLen , endPtr , endLen , order )
574
+ }).
575
+ WithParameterNames ("start_ptr" , "start_len" , "end_ptr" , "end_len" , "order" ).
470
576
Export ("db_scan" )
471
577
472
- hostModBuilder .NewFunctionBuilder ().
473
- WithFunc (hostNext ).
578
+ builder .NewFunctionBuilder ().
579
+ WithFunc (func (ctx context.Context , m api.Module , callID , iterID uint64 ) (uint32 , uint32 , uint32 , uint32 , uint32 ) {
580
+ ctx = context .WithValue (ctx , "env" , env )
581
+ return hostNext (ctx , m , callID , iterID )
582
+ }).
583
+ WithParameterNames ("call_id" , "iter_id" ).
474
584
Export ("db_next" )
475
585
476
- hostModBuilder .NewFunctionBuilder ().
477
- WithFunc (hostNextKey ).
586
+ builder .NewFunctionBuilder ().
587
+ WithFunc (func (ctx context.Context , m api.Module , callID , iterID uint64 ) (uint32 , uint32 , uint32 ) {
588
+ ctx = context .WithValue (ctx , "env" , env )
589
+ return hostNextKey (ctx , m , callID , iterID )
590
+ }).
591
+ WithParameterNames ("call_id" , "iter_id" ).
478
592
Export ("db_next_key" )
479
593
480
- hostModBuilder .NewFunctionBuilder ().
481
- WithFunc (hostNextValue ).
482
- Export ("db_next_value" )
594
+ // Register API functions
595
+ builder .NewFunctionBuilder ().
596
+ WithFunc (func (ctx context.Context , m api.Module , addrPtr , addrLen uint32 ) (uint32 , uint32 ) {
597
+ ctx = context .WithValue (ctx , "env" , env )
598
+ return hostHumanizeAddress (ctx , m , addrPtr , addrLen )
599
+ }).
600
+ WithParameterNames ("addr_ptr" , "addr_len" ).
601
+ Export ("api_humanize_address" )
483
602
484
- hostModBuilder .NewFunctionBuilder ().
485
- WithFunc (hostCloseIterator ).
486
- Export ("db_close_iterator" )
603
+ builder .NewFunctionBuilder ().
604
+ WithFunc (func (ctx context.Context , m api.Module , addrPtr , addrLen uint32 ) (uint32 , uint32 ) {
605
+ ctx = context .WithValue (ctx , "env" , env )
606
+ return hostCanonicalizeAddress (ctx , m , addrPtr , addrLen )
607
+ }).
608
+ WithParameterNames ("addr_ptr" , "addr_len" ).
609
+ Export ("api_canonicalize_address" )
487
610
488
- // Compile the host module
489
- compiled , err := hostModBuilder .Compile (context .Background ())
490
- if err != nil {
491
- return nil , fmt .Errorf ("failed to compile host module: %w" , err )
492
- }
611
+ builder .NewFunctionBuilder ().
612
+ WithFunc (func (ctx context.Context , m api.Module , addrPtr , addrLen uint32 ) uint32 {
613
+ ctx = context .WithValue (ctx , "env" , env )
614
+ return hostValidateAddress (ctx , m , addrPtr , addrLen )
615
+ }).
616
+ WithParameterNames ("addr_ptr" , "addr_len" ).
617
+ Export ("api_validate_address" )
618
+
619
+ // Register Query functions
620
+ builder .NewFunctionBuilder ().
621
+ WithFunc (func (ctx context.Context , m api.Module , reqPtr , reqLen , gasLimit uint32 ) (uint32 , uint32 ) {
622
+ ctx = context .WithValue (ctx , "env" , env )
623
+ return hostQueryExternal (ctx , m , reqPtr , reqLen , gasLimit )
624
+ }).
625
+ WithParameterNames ("req_ptr" , "req_len" , "gas_limit" ).
626
+ Export ("querier_query" )
493
627
494
- return compiled , nil
628
+ // Register DB read function
629
+ builder .NewFunctionBuilder ().
630
+ WithFunc (func (ctx context.Context , m api.Module , keyPtr uint32 ) uint32 {
631
+ ctx = context .WithValue (ctx , "env" , env )
632
+ return hostDbRead (ctx , m , keyPtr )
633
+ }).
634
+ WithParameterNames ("key_ptr" ).
635
+ Export ("db_read" )
636
+
637
+ // Register DB write function
638
+ builder .NewFunctionBuilder ().
639
+ WithFunc (func (ctx context.Context , m api.Module , keyPtr , valuePtr uint32 ) {
640
+ ctx = context .WithValue (ctx , "env" , env )
641
+ hostDbWrite (ctx , m , keyPtr , valuePtr )
642
+ }).
643
+ WithParameterNames ("key_ptr" , "value_ptr" ).
644
+ Export ("db_write" )
645
+
646
+ // Register DB remove function
647
+ builder .NewFunctionBuilder ().
648
+ WithFunc (func (ctx context.Context , m api.Module , keyPtr uint32 ) {
649
+ ctx = context .WithValue (ctx , "env" , env )
650
+ hostDbRemove (ctx , m , keyPtr )
651
+ }).
652
+ WithParameterNames ("key_ptr" ).
653
+ Export ("db_remove" )
654
+
655
+ return builder .Compile (context .Background ())
495
656
}
496
657
497
658
// When you instantiate a contract, you can do something like:
0 commit comments