Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: enhance DummyExecutor #39

Merged
merged 5 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions cmd/dummy/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package main

import (
"errors"
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"

"google.golang.org/grpc"

grpcproxy "github.com/rollkit/go-execution/proxy/grpc"
"github.com/rollkit/go-execution/test"
pb "github.com/rollkit/go-execution/types/pb/execution"
)

func main() {
listenAddress, err := parseListenAddress()
if err != nil {
log.Fatalf("Failed to parse listen address: %v\n", err)
}
listener, err := net.Listen("tcp4", listenAddress)
if err != nil {
log.Fatalf("Failed to listen on %q: %v\n", listenAddress, err)
}
defer func() {
_ = listener.Close()
}()

log.Println("Creating Dummy Executor and gRPC server")
dummy := test.NewDummyExecutor()
server := grpcproxy.NewServer(dummy, grpcproxy.DefaultConfig())
s := grpc.NewServer()
pb.RegisterExecutionServiceServer(s, server)

// Setup signal handling
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

doneChan := make(chan interface{}, 1)
go func() {
log.Printf("Serving (%s)...\n", listenAddress)
log.Println("Type Ctrl+C to shutdown")
if err := s.Serve(listener); err != nil && !errors.Is(err, grpc.ErrServerStopped) {
log.Fatalf("Server exited with error: %v\n", err)
tzdybal marked this conversation as resolved.
Show resolved Hide resolved
}
doneChan <- nil
}()

// Handle shutdown signal
go func() {
<-sigChan
log.Println("Received shutdown signal")
s.GracefulStop()
}()

<-doneChan
log.Println("Server stopped")
}

func parseListenAddress() (string, error) {
var listenAddress string
flag.StringVar(&listenAddress, "address", "127.0.0.1:40041", "gRPC server listen address")
flag.Parse()

_, port, err := net.SplitHostPort(listenAddress)
if err != nil {
return "", fmt.Errorf("invalid address format %q: %v", listenAddress, err)
}
if port == "" {
return "", errors.New("port cannot be empty")
}

return listenAddress, nil
}
46 changes: 35 additions & 11 deletions test/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,69 @@ package test

import (
"context"
"crypto/sha512"
"fmt"
"time"

"github.com/rollkit/go-execution/types"
)

// DummyExecutor is a dummy implementation of the DummyExecutor interface for testing
type DummyExecutor struct {
stateRoot types.Hash
maxBytes uint64
txs []types.Tx
stateRoot types.Hash
pendingRoots map[uint64]types.Hash
maxBytes uint64
injectedTxs []types.Tx
}

// NewDummyExecutor creates a new dummy DummyExecutor instance
func NewDummyExecutor() *DummyExecutor {
return &DummyExecutor{
stateRoot: types.Hash{1, 2, 3},
maxBytes: 1000000,
txs: make([]types.Tx, 0),
stateRoot: types.Hash{1, 2, 3},
pendingRoots: make(map[uint64]types.Hash),
maxBytes: 1000000,
}
}

// InitChain initializes the chain state with the given genesis time, initial height, and chain ID.
// It returns the state root hash, the maximum byte size, and an error if the initialization fails.
func (e *DummyExecutor) InitChain(ctx context.Context, genesisTime time.Time, initialHeight uint64, chainID string) (types.Hash, uint64, error) {
hash := sha512.New()
hash.Write(e.stateRoot)
e.stateRoot = hash.Sum(nil)
return e.stateRoot, e.maxBytes, nil
}

// GetTxs returns the list of transactions (types.Tx) within the DummyExecutor instance and an error if any.
func (e *DummyExecutor) GetTxs(context.Context) ([]types.Tx, error) {
return e.txs, nil
txs := e.injectedTxs
e.injectedTxs = nil
return txs, nil
}

// InjectTx adds a transaction to the internal list of injected transactions in the DummyExecutor instance.
func (e *DummyExecutor) InjectTx(tx types.Tx) {
e.injectedTxs = append(e.injectedTxs, tx)
tzdybal marked this conversation as resolved.
Show resolved Hide resolved
}

// ExecuteTxs simulate execution of transactions.
func (e *DummyExecutor) ExecuteTxs(ctx context.Context, txs []types.Tx, blockHeight uint64, timestamp time.Time, prevStateRoot types.Hash) (types.Hash, uint64, error) {
e.txs = append(e.txs, txs...)
return e.stateRoot, e.maxBytes, nil
hash := sha512.New()
hash.Write(prevStateRoot)
for _, tx := range txs {
hash.Write(tx)
}
pending := hash.Sum(nil)
e.pendingRoots[blockHeight] = pending
return pending, e.maxBytes, nil
}

// SetFinal marks block at given height as finalized. Currently not implemented.
// SetFinal marks block at given height as finalized.
func (e *DummyExecutor) SetFinal(ctx context.Context, blockHeight uint64) error {
return nil
if pending, ok := e.pendingRoots[blockHeight]; ok {
e.stateRoot = pending
delete(e.pendingRoots, blockHeight)
return nil
}
return fmt.Errorf("cannot set finalized block at height %d", blockHeight)
}
8 changes: 7 additions & 1 deletion test/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (s *ExecutorSuite) TestInitChain() {
func (s *ExecutorSuite) TestGetTxs() {
txs, err := s.Exec.GetTxs(context.TODO())
s.Require().NoError(err)
s.NotNil(txs)
s.Empty(txs)
}

// TestExecuteTxs tests ExecuteTxs method.
Expand All @@ -50,6 +50,12 @@ func (s *ExecutorSuite) TestExecuteTxs() {

// TestSetFinal tests SetFinal method.
func (s *ExecutorSuite) TestSetFinal() {
// finalizing invalid height must return error
err := s.Exec.SetFinal(context.TODO(), 1)
s.Require().Error(err)

_, _, err = s.Exec.ExecuteTxs(context.TODO(), nil, 2, time.Now(), types.Hash("test state"))
s.Require().NoError(err)
err = s.Exec.SetFinal(context.TODO(), 2)
s.Require().NoError(err)
}
Loading