Skip to content
Prev Previous commit
Next Next commit
rewrite kv executor
  • Loading branch information
tac0turtle
tac0turtle committed Apr 18, 2025
commit 315230d8899fa9fe504fb601e91822af8aa7eb18
9 changes: 6 additions & 3 deletions rollups/testapp/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ var RunCmd = &cobra.Command{

logger := log.NewLogger(os.Stdout, opts...)

// Create test implementations
executor := kvexecutor.NewKVExecutor()

// Get KV endpoint flag
kvEndpoint, _ := cmd.Flags().GetString(flagKVEndpoint)
if kvEndpoint == "" {
Expand All @@ -54,6 +51,12 @@ var RunCmd = &cobra.Command{
return err
}

// Create test implementations
executor, err := kvexecutor.NewKVExecutor(nodeConfig.RootDir, nodeConfig.DBPath)
if err != nil {
return err
}

daJrpc, err := proxy.NewClient(nodeConfig.DA.Address, nodeConfig.DA.AuthToken)
if err != nil {
panic(err)
Expand Down
1 change: 1 addition & 0 deletions rollups/testapp/kv/bench/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ func runBenchmark(url string, duration, interval time.Duration, txPerInterval in
func sendTransaction(url, txData string) bool {
resp, err := http.Post(url, "text/plain", strings.NewReader(txData))
if err != nil {
fmt.Printf("Error sending transaction: %v\n", err)
return false
}
defer resp.Body.Close()
Expand Down
78 changes: 42 additions & 36 deletions rollups/testapp/kv/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package executor
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"time"

ds "github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
)

// HTTPServer wraps a KVExecutor and provides an HTTP interface for it
Expand Down Expand Up @@ -109,7 +113,7 @@ func (hs *HTTPServer) handleTx(w http.ResponseWriter, r *http.Request) {
}
}

// handleKV handles direct key-value operations (GET/POST)
// handleKV handles direct key-value operations (GET/POST) against the database
// GET /kv?key=somekey - retrieve a value
// POST /kv with JSON {"key": "somekey", "value": "somevalue"} - set a value
func (hs *HTTPServer) handleKV(w http.ResponseWriter, r *http.Request) {
Expand All @@ -121,41 +125,25 @@ func (hs *HTTPServer) handleKV(w http.ResponseWriter, r *http.Request) {
return
}

value, exists := hs.executor.GetStoreValue(key)
// Use r.Context() when calling the executor method
value, exists := hs.executor.GetStoreValue(r.Context(), key)
if !exists {
http.Error(w, "Key not found", http.StatusNotFound)
return
}

_, err := w.Write([]byte(value))
if err != nil {
fmt.Printf("Error writing response: %v\n", err)
}

case http.MethodPost:
var data struct {
Key string `json:"key"`
Value string `json:"value"`
}

if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
defer func() {
if err := r.Body.Close(); err != nil {
fmt.Printf("Error closing request body: %v\n", err)
// GetStoreValue now returns false on error too, check logs for details
// Check if the key truly doesn't exist vs a DB error occurred.
// For simplicity here, we treat both as Not Found for the client.
// A more robust implementation might check the error type.
_, err := hs.executor.db.Get(r.Context(), ds.NewKey(key))
if errors.Is(err, ds.ErrNotFound) {
http.Error(w, "Key not found", http.StatusNotFound)
} else {
// Some other DB error occurred
http.Error(w, "Failed to retrieve key", http.StatusInternalServerError)
fmt.Printf("Error retrieving key '%s' from DB: %v\n", key, err)
}
}()

if data.Key == "" {
http.Error(w, "Missing key", http.StatusBadRequest)
return
}

hs.executor.SetStoreValue(data.Key, data.Value)
w.WriteHeader(http.StatusOK)
_, err := w.Write([]byte("Value set"))
_, err := w.Write([]byte(value))
if err != nil {
fmt.Printf("Error writing response: %v\n", err)
}
Expand All @@ -165,23 +153,41 @@ func (hs *HTTPServer) handleKV(w http.ResponseWriter, r *http.Request) {
}
}

// handleStore returns all key-value pairs in the store
// handleStore returns all non-reserved key-value pairs in the store by querying the database
// GET /store
func (hs *HTTPServer) handleStore(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

hs.executor.mu.Lock()
store := make(map[string]string)
for k, v := range hs.executor.store {
store[k] = v
q := query.Query{} // Query all entries
results, err := hs.executor.db.Query(r.Context(), q)
if err != nil {
http.Error(w, "Failed to query store", http.StatusInternalServerError)
fmt.Printf("Error querying datastore: %v\n", err)
return
}
defer results.Close()

for result := range results.Next() {
if result.Error != nil {
http.Error(w, "Failed during store iteration", http.StatusInternalServerError)
fmt.Printf("Error iterating datastore results: %v\n", result.Error)
return
}
// Exclude reserved genesis keys from the output
dsKey := ds.NewKey(result.Key)
if dsKey.Equal(genesisInitializedKey) || dsKey.Equal(genesisStateRootKey) {
continue
}
store[result.Key] = string(result.Value)
}
hs.executor.mu.Unlock()

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(store); err != nil {
// Error already sent potentially, just log
fmt.Printf("Error encoding JSON response: %v\n", err)
}
}
Loading