@@ -2,6 +2,7 @@ package runtime
22
33import (
44 "context"
5+ "encoding/binary"
56 "encoding/json"
67 "fmt"
78
@@ -229,7 +230,7 @@ func hostValidateAddress(ctx context.Context, mod api.Module, addrPtr, addrLen u
229230}
230231
231232// 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 ) {
233234 env := ctx .Value ("env" ).(* RuntimeEnvironment )
234235 mem := mod .Memory ()
235236
@@ -239,17 +240,25 @@ func hostScan(ctx context.Context, mod api.Module, startPtr, startLen, endPtr, e
239240 }
240241 env .GasUsed += gasCostIteratorCreate
241242
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+ }
245252 }
246253
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+ }
250259 }
251260
252- // Check iterator limits
261+ // Start a new call context for this iterator
253262 callID := env .StartCall ()
254263 if len (env .iterators [callID ]) >= maxIteratorsPerCall {
255264 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
424433 }
425434}
426435
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 ))
432450 }
451+ keyLen := binary .LittleEndian .Uint32 (lenBytes )
433452
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+ }
436458
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+ }
439463
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+ }
444470
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+ }
448477
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+ }
453482
454- hostModBuilder .NewFunctionBuilder ().
455- WithFunc (hostCanonicalizeAddress ).
456- Export ("api_canonicalize_address" )
483+ return offset
484+ }
457485
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 ()
461490
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 )
466504
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" ).
470576 Export ("db_scan" )
471577
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" ).
474584 Export ("db_next" )
475585
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" ).
478592 Export ("db_next_key" )
479593
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" )
483602
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" )
487610
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" )
493627
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 ())
495656}
496657
497658// When you instantiate a contract, you can do something like:
0 commit comments