-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add HTTP client for EthProofs API (#5)
* ✨ Add HTTP client for EthProofs API * 🚸 Add example
- Loading branch information
Showing
14 changed files
with
1,076 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
# EthProofs Client | ||
|
||
The **EthProofs Client** is a Go package that provides a clean interface for interacting with the EthProofs API, enabling management of proving operations, clusters, and proof submissions. | ||
|
||
## Overview | ||
|
||
This package provides: | ||
- A strongly-typed client interface for all EthProofs API endpoints | ||
- HTTP implementation using Azure's autorest for robust HTTP client management | ||
- Mock implementation for testing using uber-go/mock | ||
- Comprehensive example usage and tests | ||
|
||
## Installation | ||
|
||
```sh | ||
go get github.com/kkrt-labs/go-utils/ethproofs | ||
``` | ||
|
||
## Authentication | ||
|
||
All API endpoints require authentication using an API key. You can obtain one by: | ||
1. Joining the EthProofs Slack workspace | ||
2. Requesting an API key from the team (contact Elias) | ||
|
||
## Usage | ||
|
||
### Creating a Client | ||
|
||
```go | ||
import ( | ||
"github.com/kkrt-labs/kakarot-controller/go-utils/ethproofs" | ||
ethproofshttp "github.com/kkrt-labs/kakarot-controller/go-utils/ethproofs/client/http" | ||
) | ||
|
||
// Create client with configuration | ||
client, err := ethproofshttp.NewClient(ðproofshttp.Config{ | ||
Addr: "https://staging--ethproofs.netlify.app/api/v0", | ||
APIKey: "your-api-key", | ||
}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
``` | ||
|
||
### Managing Clusters | ||
|
||
```go | ||
// Create a cluster | ||
cluster, err := client.CreateCluster(context.Background(), ðproofs.CreateClusterRequest{ | ||
Nickname: "test-cluster", | ||
Description: "Test cluster for proving operations", | ||
Hardware: "RISC-V Prover", | ||
CycleType: "SP1", | ||
ProofType: "Groth16", | ||
Configuration: []ethproofs.ClusterConfig{ | ||
{ | ||
InstanceType: "t3.small", | ||
InstanceCount: 1, | ||
}, | ||
}, | ||
}) | ||
|
||
// List all clusters | ||
clusters, err := client.ListClusters(context.Background()) | ||
``` | ||
|
||
### Managing Single Machines | ||
|
||
```go | ||
// Create a single machine | ||
machine, err := client.CreateMachine(context.Background(), ðproofs.CreateMachineRequest{ | ||
Nickname: "test-machine", | ||
Description: "Single machine for proving", | ||
Hardware: "RISC-V Prover", | ||
CycleType: "SP1", | ||
ProofType: "Groth16", | ||
InstanceType: "t3.small", | ||
}) | ||
``` | ||
|
||
### Proof Lifecycle | ||
|
||
```go | ||
// 1. Queue a proof | ||
queuedProof, err := client.QueueProof(context.Background(), ðproofs.QueueProofRequest{ | ||
BlockNumber: 12345, | ||
ClusterID: cluster.ID, | ||
}) | ||
|
||
// 2. Start proving | ||
startedProof, err := client.StartProving(context.Background(), ðproofs.StartProvingRequest{ | ||
BlockNumber: 12345, | ||
ClusterID: cluster.ID, | ||
}) | ||
|
||
// 3. Submit completed proof | ||
provingCycles := int64(1000000) | ||
submittedProof, err := client.SubmitProof(context.Background(), ðproofs.SubmitProofRequest{ | ||
BlockNumber: 12345, | ||
ClusterID: cluster.ID, | ||
ProvingTime: 60000, // milliseconds | ||
ProvingCycles: &provingCycles, | ||
Proof: "base64_encoded_proof_data", | ||
VerifierID: "test-verifier", | ||
}) | ||
``` | ||
|
||
## Testing | ||
|
||
### Prerequisites | ||
|
||
1. Install required tools: | ||
```bash | ||
# Install uber-go/mock | ||
make mockgen-install | ||
``` | ||
|
||
### Running Tests | ||
|
||
```bash | ||
# Run all tests | ||
go test ./ethproofs/... | ||
|
||
# Run with verbose output | ||
go test -v ./ethproofs/... | ||
|
||
# Run with coverage | ||
go test -cover ./ethproofs/... | ||
|
||
# Generate coverage report | ||
go test -coverprofile=coverage.out ./ethproofs/... | ||
go tool cover -html=coverage.out | ||
|
||
# Run specific domain tests | ||
go test -v ./ethproofs/... -run TestCreateCluster | ||
go test -v ./ethproofs/... -run TestListAWSPricing | ||
``` | ||
|
||
### Using Mock Client in Tests | ||
|
||
```go | ||
import ( | ||
"testing" | ||
"go.uber.org/mock/gomock" | ||
"github.com/kkrt-labs/kakarot-controller/ethproofs/mock" | ||
) | ||
|
||
func TestYourFunction(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
|
||
mockClient := mock.NewMockClient(ctrl) | ||
|
||
// Set up expectations | ||
mockClient.EXPECT(). | ||
CreateCluster(gomock.Any(), gomock.Any()). | ||
Return(ðproofs.CreateClusterResponse{ID: 123}, nil) | ||
|
||
// Use mockClient in your tests | ||
} | ||
``` | ||
|
||
## Directory Structure | ||
|
||
``` | ||
src/ethproofs/ | ||
└── client/ | ||
├── README.md # This file | ||
├── client.go # Main interface definition | ||
├── http/ | ||
│ ├── client.go # HTTP implementation using autorest | ||
│ ├── config.go # Client configuration | ||
│ ├── clusters.go # Clusters endpoint implementation | ||
│ ├── clusters_test.go | ||
│ ├── proofs.go # Proofs endpoint implementation | ||
│ ├── proofs_test.go | ||
│ ├── machine.go # Single machine endpoint implementation | ||
│ ├── machine_test.go | ||
│ ├── aws.go # AWS pricing endpoint implementation | ||
│ └── aws_test.go | ||
└── mock/ | ||
└── client.go # Generated mock client | ||
``` | ||
|
||
## API Documentation | ||
|
||
For detailed API documentation, visit: | ||
- [EthProofs API Documentation](https://staging--ethproofs.netlify.app/api.html) | ||
- [EthProofs App Preview](https://staging--ethproofs.netlify.app/) | ||
- [EthProofs Repository](https://github.com/ethproofs/ethproofs) | ||
|
||
## Contributing | ||
|
||
Interested in contributing? Check out our [Contributing Guidelines](../../CONTRIBUTING.md) to get started! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package ethproofs | ||
|
||
import ( | ||
"context" | ||
) | ||
|
||
// Package ethproofs provides a Go client for the EthProofs API. | ||
// | ||
// For more information about EthProofs, visit: | ||
// - API Documentation: https://staging--ethproofs.netlify.app/api.html | ||
// - App Preview: https://staging--ethproofs.netlify.app/ | ||
// - Repository: https://github.com/ethproofs/ethproofs | ||
// | ||
//go:generate mockgen -source client.go -destination mock/client.go -package mock Client | ||
|
||
// Client defines the interface for interacting with the EthProofs API | ||
type Client interface { | ||
// Clusters | ||
CreateCluster(ctx context.Context, req *CreateClusterRequest) (*CreateClusterResponse, error) | ||
ListClusters(ctx context.Context) ([]Cluster, error) | ||
|
||
// Single Machine | ||
CreateMachine(ctx context.Context, req *CreateMachineRequest) (*CreateMachineResponse, error) | ||
|
||
// Proofs | ||
QueueProof(ctx context.Context, req *QueueProofRequest) (*ProofResponse, error) | ||
StartProving(ctx context.Context, req *StartProvingRequest) (*ProofResponse, error) | ||
SubmitProof(ctx context.Context, req *SubmitProofRequest) (*ProofResponse, error) | ||
|
||
// AWS Pricing | ||
ListAWSPricing(ctx context.Context) ([]AWSInstance, error) | ||
} | ||
|
||
// Request/Response types for Clusters | ||
type CreateClusterRequest struct { | ||
Nickname string `json:"nickname"` | ||
Description string `json:"description,omitempty"` | ||
Hardware string `json:"hardware,omitempty"` | ||
CycleType string `json:"cycle_type,omitempty"` | ||
ProofType string `json:"proof_type,omitempty"` | ||
Configuration []ClusterConfig `json:"configuration"` | ||
} | ||
|
||
type ClusterConfig struct { | ||
InstanceType string `json:"instance_type"` | ||
InstanceCount int64 `json:"instance_count"` | ||
} | ||
|
||
type CreateClusterResponse struct { | ||
ID int64 `json:"id"` | ||
} | ||
|
||
type ListClustersResponse []Cluster | ||
|
||
type Cluster struct { | ||
ID int64 `json:"id"` | ||
Nickname string `json:"nickname"` | ||
Description string `json:"description"` | ||
Hardware string `json:"hardware"` | ||
CycleType string `json:"cycle_type"` | ||
ProofType string `json:"proof_type"` | ||
ClusterConfiguration []ClusterConfig `json:"cluster_configuration"` | ||
} | ||
|
||
// Request/Response types for Single Machine | ||
type CreateMachineRequest struct { | ||
Nickname string `json:"nickname"` | ||
Description string `json:"description,omitempty"` | ||
Hardware string `json:"hardware,omitempty"` | ||
CycleType string `json:"cycle_type,omitempty"` | ||
ProofType string `json:"proof_type,omitempty"` | ||
InstanceType string `json:"instance_type"` | ||
} | ||
|
||
type CreateMachineResponse struct { | ||
ID int64 `json:"id"` | ||
} | ||
|
||
// Request/Response types for Proofs | ||
type QueueProofRequest struct { | ||
BlockNumber int64 `json:"block_number"` | ||
ClusterID int64 `json:"cluster_id"` | ||
} | ||
|
||
type StartProvingRequest struct { | ||
BlockNumber int64 `json:"block_number"` | ||
ClusterID int64 `json:"cluster_id"` | ||
} | ||
|
||
type SubmitProofRequest struct { | ||
BlockNumber int64 `json:"block_number"` | ||
ClusterID int64 `json:"cluster_id"` | ||
ProvingTime int64 `json:"proving_time"` | ||
ProvingCycles *int64 `json:"proving_cycles,omitempty"` | ||
Proof string `json:"proof"` | ||
VerifierID string `json:"verifier_id,omitempty"` | ||
} | ||
|
||
type ProofResponse struct { | ||
ProofID int64 `json:"proof_id"` | ||
} | ||
|
||
// Request/Response types for AWS Pricing | ||
type ListAWSPricingResponse = []AWSInstance | ||
|
||
type AWSInstance struct { | ||
ID int64 `json:"id"` | ||
InstanceType string `json:"instance_type"` | ||
Region string `json:"region"` | ||
HourlyPrice float64 `json:"hourly_price"` | ||
InstanceMemory float64 `json:"instance_memory"` | ||
VCPU int64 `json:"vcpu"` | ||
InstanceStorage string `json:"instance_storage"` | ||
CreatedAt string `json:"created_at"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package http | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
|
||
ethproofs "github.com/kkrt-labs/go-utils/ethproofs/client" | ||
) | ||
|
||
func (c *Client) ListAWSPricing(ctx context.Context) ([]ethproofs.AWSInstance, error) { | ||
var resp []ethproofs.AWSInstance | ||
if err := c.do(ctx, http.MethodGet, "/aws-pricing-list", nil, &resp); err != nil { | ||
return nil, err | ||
} | ||
|
||
return resp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package http | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
ethproofs "github.com/kkrt-labs/go-utils/ethproofs/client" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestListAWSPricing(t *testing.T) { | ||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
assert.Equal(t, "/aws-pricing-list", r.URL.Path) | ||
assert.Equal(t, "Bearer test-key", r.Header.Get("Authorization")) | ||
|
||
instances := []ethproofs.AWSInstance{ | ||
{ | ||
ID: 1, | ||
InstanceType: "t3.small", | ||
HourlyPrice: 0.5, | ||
InstanceMemory: 2.0, | ||
VCPU: 2, | ||
}, | ||
} | ||
err := json.NewEncoder(w).Encode(instances) | ||
require.NoError(t, err) | ||
})) | ||
defer server.Close() | ||
|
||
client, err := NewClient(&Config{ | ||
Addr: server.URL, | ||
APIKey: "test-key", | ||
}) | ||
require.NoError(t, err) | ||
|
||
resp, err := client.ListAWSPricing(context.Background()) | ||
require.NoError(t, err) | ||
require.Len(t, resp, 1) | ||
assert.Equal(t, "t3.small", resp[0].InstanceType) | ||
} |
Oops, something went wrong.