Skip to content

Commit

Permalink
Enhance WazeroRuntime with improved debugging and analysis features
Browse files Browse the repository at this point in the history
- Added time tracking and detailed logging for host function registration and instantiation processes.
- Refactored the AnalyzeCode function to streamline the identification of IBC entry points and capabilities.
- Introduced comprehensive debug output for memory layout and error handling during contract instantiation.
- Improved clarity in printed messages, including a summary of registered host functions and analysis results.
- Enhanced error reporting with memory dumps around failure points for better troubleshooting.
  • Loading branch information
faddat committed Jan 19, 2025
1 parent e1b2010 commit 7979c15
Showing 1 changed file with 108 additions and 31 deletions.
139 changes: 108 additions & 31 deletions internal/runtime/wazeroruntime.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (
"fmt"
"strings"
"sync"
"time"
"unicode/utf8"

"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/sys"

"github.com/CosmWasm/wasmvm/v2/types"
)
Expand Down Expand Up @@ -461,14 +463,17 @@ func (w *WazeroRuntime) AnalyzeCode(checksum []byte) (*types.AnalysisReport, err
"ibc_packet_receive",
"ibc_packet_ack",
"ibc_packet_timeout",
"ibc_source_callback",
"ibc_destination_callback",
}

for _, ibcFn := range ibcFunctions {
if _, ok := exports[ibcFn]; ok {
hasIBCEntryPoints = true
break
var entrypoints []string
for name := range exports {
entrypoints = append(entrypoints, name)
for _, ibcFn := range ibcFunctions {
if name == ibcFn {
hasIBCEntryPoints = true
break
}
}
}

Expand All @@ -488,12 +493,6 @@ func (w *WazeroRuntime) AnalyzeCode(checksum []byte) (*types.AnalysisReport, err
capabilities = append(capabilities, "iterator", "stargate")
}

// Get all exported functions for analysis
var entrypoints []string
for name := range exports {
entrypoints = append(entrypoints, name)
}

return &types.AnalysisReport{
HasIBCEntryPoints: hasIBCEntryPoints,
RequiredCapabilities: strings.Join(capabilities, ","),
Expand Down Expand Up @@ -562,18 +561,34 @@ func (w *WazeroRuntime) Instantiate(checksum []byte, env []byte, info []byte, ms
fmt.Printf("Runtime environment initialized\n")

// Register all required host functions that the contract can call
fmt.Printf("Registering host functions...\n")
fmt.Printf("\n=== Starting Host Function Registration ===\n\n")
fmt.Printf("Registering Memory Management Functions...\n")
hostModule, err := RegisterHostFunctions(w.runtime, runtimeEnv)
if err != nil {
fmt.Printf("Host function registration failed: %v\n", err)
return nil, types.GasReport{}, fmt.Errorf("failed to register host functions: %w", err)
}
defer hostModule.Close(ctx)
fmt.Printf("Host functions registered successfully\n")

// Print registered functions for debugging
fmt.Printf("\n=== Checking Required Host Functions ===\n")
start := time.Now()
if printDebug {
fmt.Printf("\n=== Registration Summary ===\n")
fmt.Printf("Registered host functions in %v\n", time.Since(start))
fmt.Printf("Memory model: wazero with 64KB pages\n")
fmt.Printf("Gas metering: enabled\n")
fmt.Printf("===================================\n\n")

fmt.Printf("Host functions registered successfully\n")
}

// Create module config and instantiate the environment module
fmt.Printf("Instantiating environment module...\n")
moduleConfig := wazero.NewModuleConfig().WithName("env")
moduleConfig := wazero.NewModuleConfig().
WithName("env").
WithStartFunctions() // Don't auto-start, we want to control this

envModule, err := w.runtime.InstantiateModule(ctx, hostModule, moduleConfig)
if err != nil {
fmt.Printf("Environment module instantiation failed: %v\n", err)
Expand All @@ -585,18 +600,37 @@ func (w *WazeroRuntime) Instantiate(checksum []byte, env []byte, info []byte, ms
// Get the contract module from our cache using the checksum
fmt.Printf("Loading contract module from cache...\n")
w.mu.Lock()
compiledModule, ok := w.compiledModules[hex.EncodeToString(checksum)]
csHex := hex.EncodeToString(checksum)
compiledModule, ok := w.compiledModules[csHex]
if !ok {
w.mu.Unlock()
return nil, types.GasReport{}, fmt.Errorf("module not found for checksum: %x", checksum)
}
w.mu.Unlock()
fmt.Printf("Contract module loaded successfully\n")

// Instantiate the contract module
// Analyze the code to get exported functions
analysis, err := w.AnalyzeCode(checksum)
if err != nil {
return nil, types.GasReport{}, fmt.Errorf("failed to analyze code: %w", err)
}

fmt.Printf("\n=== Analysis Results ===\n")
fmt.Printf("Has IBC entry points: %v\n", analysis.HasIBCEntryPoints)
fmt.Printf("Required capabilities: %v\n", analysis.RequiredCapabilities)
if analysis.ContractMigrateVersion != nil {
fmt.Printf("Contract migrate version: %v\n", *analysis.ContractMigrateVersion)
}
fmt.Printf("Entrypoints: %v\n", analysis.Entrypoints)
fmt.Printf("===================================\n\n")

// Instantiate the contract module with detailed debugging
fmt.Printf("Instantiating contract module...\n")
contractModule, err := w.runtime.InstantiateModule(ctx, compiledModule,
wazero.NewModuleConfig().WithName("contract"))
contractConfig := wazero.NewModuleConfig().
WithName("contract").
WithStartFunctions() // Don't auto-start, we want to control this

contractModule, err := w.runtime.InstantiateModule(ctx, compiledModule, contractConfig)
if err != nil {
fmt.Printf("Contract module instantiation failed: %v\n", err)
return nil, types.GasReport{}, fmt.Errorf("failed to instantiate contract module: %w", err)
Expand Down Expand Up @@ -711,29 +745,72 @@ func (w *WazeroRuntime) Instantiate(checksum []byte, env []byte, info []byte, ms
fmt.Printf("- Info: 0x%x\n", infoRegionPtr)
fmt.Printf("- Message: 0x%x\n", msgRegionPtr)

// Get the instantiate function from the contract
fmt.Printf("Calling contract instantiate function...\n")
// Add detailed debugging before calling instantiate
fmt.Printf("\n=== Preparing to Call instantiate ===\n")
fmt.Printf("Memory layout before function call:\n")
fmt.Printf(" env region ptr: %d\n", envRegion.Offset)
fmt.Printf(" info region ptr: %d\n", infoRegion.Offset)
fmt.Printf(" msg region ptr: %d\n", msgRegion.Offset)
fmt.Printf(" env data ptr: %d, size: %d\n", envPtr, len(env))
fmt.Printf(" info data ptr: %d, size: %d\n", infoPtr, len(info))
fmt.Printf(" msg data ptr: %d, size: %d\n", msgPtr, len(msg))

// Dump some memory around key regions for debugging
dumpMemory(memory, envRegion.Offset, 12)
dumpMemory(memory, infoRegion.Offset, 12)
dumpMemory(memory, msgRegion.Offset, 12)

instantiate := contractModule.ExportedFunction("instantiate")
if instantiate == nil {
return nil, types.GasReport{}, fmt.Errorf("instantiate function not found")
return nil, types.GasReport{}, fmt.Errorf("instantiate function not exported by contract")
}

// Call the contract's instantiate function with our Region pointers
results, err := instantiate.Call(ctx, uint64(envRegionPtr), uint64(infoRegionPtr),
uint64(msgRegionPtr))
fmt.Printf("\nCalling contract instantiate function...\n")
ret, err := instantiate.Call(ctx, uint64(envRegion.Offset), uint64(infoRegion.Offset), uint64(msgRegion.Offset))
if err != nil {
// On error, dump memory around the regions for debugging
if printDebug {
fmt.Printf("\nMemory dump around error:\n")
dumpMemory(memory, envRegionPtr, 64)
dumpMemory(memory, infoRegionPtr, 64)
dumpMemory(memory, msgRegionPtr, 64)
fmt.Printf("\n===================== [ WASM CONTRACT ABORT ] =====================\n")
fmt.Printf("Abort code: %d (0x%x)\n", err.Error(), err.Error())

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / lint

printf: fmt.Printf format %d has arg err.Error() of wrong type string (govet)

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-analyze-code (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-analyze-code (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-env (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-get-metrics (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-happy-path (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc-handshake (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc-packet-dispatch (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc-msg-get-channel (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc-msg-get-counter-version (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-env (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-get-metrics (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-remove-code (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-simulate-store-code (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-store-code (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-store-code-and-get (ubuntu-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-happy-path (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc-handshake (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc-msg-get-counter-version (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc-msg-get-channel (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-ibc-packet-dispatch (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-remove-code (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-simulate-store-code (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-store-code-and-get (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string

Check failure on line 772 in internal/runtime/wazeroruntime.go

View workflow job for this annotation

GitHub Actions / test-store-code (macos-latest)

fmt.Printf format %d has arg err.Error() of wrong type string
fmt.Printf("Module name: %q\n", contractModule.Name())
fmt.Printf("Memory size (pages): %d\n", memory.Size()/65536)
fmt.Printf("Approx. memory size (bytes): %d\n", memory.Size())

// Dump memory around error location if possible
if abortErr, ok := err.(*sys.ExitError); ok {
code := abortErr.ExitCode()
fmt.Printf("\n[range 0] Reading 200 bytes around the code pointer (code - 100..code+100) at offset=%d:\n", code-100)
dumpMemory(memory, uint32(code-100), 200)
}

// Also dump first 256 bytes of memory
fmt.Printf("\n[range 1] Reading 256 bytes first 256 bytes of memory at offset=0:\n")
dumpMemory(memory, 0, 256)

// And dump around the lower 16 bits of the error code
if abortErr, ok := err.(*sys.ExitError); ok {
code := abortErr.ExitCode()
offset := code & 0xFFFF
fmt.Printf("\n[range 2] Reading 256 bytes lower 16 bits offset at offset=%d:\n", offset)
dumpMemory(memory, uint32(offset), 256)
}

fmt.Printf("\n=== Runtime Environment Debug Info ===\n")
fmt.Printf(" - Gas used: %d\n", runtimeEnv.gasUsed)
fmt.Printf(" - Gas limit: %d\n", runtimeEnv.gasLimit)
fmt.Printf(" - open iterators callID->(iterID->Iterator) map size: %d\n", len(runtimeEnv.iterators))

fmt.Printf("\nMemory dump around error:\n")
fmt.Printf("Memory at 0x%x:\n", envRegion.Offset)
dumpMemory(memory, envRegion.Offset, 64)
fmt.Printf("Memory at 0x%x:\n", infoRegion.Offset)
dumpMemory(memory, infoRegion.Offset, 64)
fmt.Printf("Memory at 0x%x:\n", msgRegion.Offset)
dumpMemory(memory, msgRegion.Offset, 64)

return nil, types.GasReport{}, fmt.Errorf("failed to call instantiate: %w", err)
}

// Get the result pointer from the contract
resultPtr := uint32(results[0])
resultPtr := uint32(ret[0])

// Read the Region struct for the result
resultRegionData, err := readMemory(memory, resultPtr, 12)
Expand Down

0 comments on commit 7979c15

Please sign in to comment.