-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First pass API for introspection of edges and assertions (#371)
- Loading branch information
1 parent
ff3a977
commit 7a2277e
Showing
21 changed files
with
807 additions
and
2 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,43 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") | ||
|
||
go_library( | ||
name = "api", | ||
srcs = [ | ||
"data.go", | ||
"edges.go", | ||
"log.go", | ||
"method_assertions.go", | ||
"method_edges.go", | ||
"method_healthz.go", | ||
"server.go", | ||
], | ||
importpath = "github.com/OffchainLabs/challenge-protocol-v2/api", | ||
visibility = ["//visibility:public"], | ||
deps = [ | ||
"//chain-abstraction:protocol", | ||
"@com_github_ethereum_go_ethereum//common", | ||
"@com_github_ethereum_go_ethereum//log", | ||
"@com_github_gorilla_mux//:mux", | ||
"@org_golang_x_sync//errgroup", | ||
], | ||
) | ||
|
||
go_test( | ||
name = "api_test", | ||
srcs = [ | ||
"data_test.go", | ||
"edges_test.go", | ||
"method_assertions_test.go", | ||
"method_edges_test.go", | ||
"method_healthz_test.go", | ||
"server_helper_test.go", | ||
"server_test.go", | ||
], | ||
embed = [":api"], | ||
deps = [ | ||
"//chain-abstraction:protocol", | ||
"//challenge-manager/challenge-tree/mock", | ||
"@com_github_gorilla_mux//:mux", | ||
"@in_gopkg_d4l3k_messagediff_v1//:messagediff_v1", | ||
], | ||
) |
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,9 @@ | ||
package api | ||
|
||
import ( | ||
protocol "github.com/OffchainLabs/challenge-protocol-v2/chain-abstraction" | ||
) | ||
|
||
type DataAccessor interface { | ||
GetEdges() []protocol.SpecEdge | ||
} |
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,16 @@ | ||
package api_test | ||
|
||
import ( | ||
"github.com/OffchainLabs/challenge-protocol-v2/api" | ||
protocol "github.com/OffchainLabs/challenge-protocol-v2/chain-abstraction" | ||
) | ||
|
||
var _ = api.DataAccessor(&FakeDataAccessor{}) | ||
|
||
type FakeDataAccessor struct { | ||
Edges []protocol.SpecEdge | ||
} | ||
|
||
func (f *FakeDataAccessor) GetEdges() []protocol.SpecEdge { | ||
return f.Edges | ||
} |
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,186 @@ | ||
package api | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
protocol "github.com/OffchainLabs/challenge-protocol-v2/chain-abstraction" | ||
"github.com/ethereum/go-ethereum/common" | ||
"golang.org/x/sync/errgroup" | ||
) | ||
|
||
type Edge struct { | ||
ID common.Hash `json:"id"` | ||
Type string `json:"type"` | ||
StartCommitment *Commitment `json:"startCommitment"` | ||
EndCommitment *Commitment `json:"endCommitment"` | ||
CreatedAtBlock uint64 `json:"createdAtBlock"` | ||
MutualID common.Hash `json:"mutualId"` | ||
OriginID common.Hash `json:"originId"` | ||
ClaimID common.Hash `json:"claimId"` | ||
HasChildren bool `json:"hasChildren"` | ||
LowerChildID common.Hash `json:"lowerChildId"` | ||
UpperChildID common.Hash `json:"upperChildId"` | ||
MiniStaker common.Address `json:"miniStaker"` | ||
AssertionHash common.Hash `json:"assertionHash"` | ||
TimeUnrivaled uint64 `json:"timeUnrivaled"` | ||
HasRival bool `json:"hasRival"` | ||
Status string `json:"status"` | ||
HasLengthOneRival bool `json:"hasLengthOneRival"` | ||
TopLevelClaimHeight protocol.OriginHeights `json:"topLevelClaimHeight"` | ||
|
||
// Validator's point of view | ||
// IsHonest bool `json:"isHonest"` | ||
// AgreesWithStartCommitment `json:"agreesWithStartCommitment"` | ||
} | ||
|
||
type Commitment struct { | ||
Height uint64 `json:"height"` | ||
Hash common.Hash `json:"hash"` | ||
} | ||
|
||
func convertSpecEdgeEdgesToEdges(ctx context.Context, e []protocol.SpecEdge) ([]*Edge, error) { | ||
// Convert concurrently as some of the underlying methods are API calls. | ||
eg, ctx := errgroup.WithContext(ctx) | ||
|
||
edges := make([]*Edge, len(e)) | ||
for i, edge := range e { | ||
index := i | ||
ee := edge | ||
|
||
eg.Go(func() (err error) { | ||
edges[index], err = convertSpecEdgeEdgeToEdge(ctx, ee) | ||
return | ||
}) | ||
} | ||
return edges, eg.Wait() | ||
} | ||
|
||
func convertSpecEdgeEdgeToEdge(ctx context.Context, e protocol.SpecEdge) (*Edge, error) { | ||
edge := &Edge{ | ||
ID: common.Hash(e.Id()), | ||
Type: e.GetType().String(), | ||
StartCommitment: toCommitment(e.StartCommitment), | ||
EndCommitment: toCommitment(e.EndCommitment), | ||
MutualID: common.Hash(e.MutualId()), | ||
OriginID: common.Hash(e.OriginId()), | ||
ClaimID: func() common.Hash { | ||
if !e.ClaimId().IsNone() { | ||
return common.Hash(e.ClaimId().Unwrap()) | ||
} | ||
return common.Hash{} | ||
}(), | ||
MiniStaker: func() common.Address { | ||
if !e.MiniStaker().IsNone() { | ||
return common.Address(e.MiniStaker().Unwrap()) | ||
} | ||
return common.Address{} | ||
}(), | ||
CreatedAtBlock: func() uint64 { | ||
cab, err := e.CreatedAtBlock() | ||
if err != nil { | ||
return 0 | ||
} | ||
return cab | ||
}(), | ||
} | ||
|
||
// The following methods include calls to the backend, so we run them concurrently. | ||
// Note: No rate limiting currently in place. | ||
eg, ctx := errgroup.WithContext(ctx) | ||
|
||
eg.Go(func() error { | ||
hasChildren, err := e.HasChildren(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge children: %w", err) | ||
} | ||
edge.HasChildren = hasChildren | ||
return nil | ||
}) | ||
|
||
eg.Go(func() error { | ||
lowerChild, err := e.LowerChild(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge lower child: %w", err) | ||
} | ||
if !lowerChild.IsNone() { | ||
edge.LowerChildID = common.Hash(lowerChild.Unwrap()) | ||
} | ||
return nil | ||
}) | ||
|
||
eg.Go(func() error { | ||
upperChild, err := e.UpperChild(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge upper child: %w", err) | ||
} | ||
if !upperChild.IsNone() { | ||
edge.UpperChildID = common.Hash(upperChild.Unwrap()) | ||
} | ||
return nil | ||
}) | ||
|
||
eg.Go(func() error { | ||
ah, err := e.AssertionHash(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge assertion hash: %w", err) | ||
} | ||
edge.AssertionHash = common.Hash(ah) | ||
Check failure on line 128 in api/edges.go GitHub Actions / Gosec scan
Check failure on line 128 in api/edges.go GitHub Actions / Build and Test
Check failure on line 128 in api/edges.go GitHub Actions / Lint
Check failure on line 128 in api/edges.go GitHub Actions / Lint
|
||
return nil | ||
}) | ||
|
||
eg.Go(func() error { | ||
timeUnrivaled, err := e.TimeUnrivaled(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge time unrivaled: %w", err) | ||
} | ||
edge.TimeUnrivaled = timeUnrivaled | ||
return nil | ||
}) | ||
|
||
eg.Go(func() error { | ||
hasRival, err := e.HasRival(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge has rival: %w", err) | ||
} | ||
edge.HasRival = hasRival | ||
return nil | ||
}) | ||
|
||
eg.Go(func() error { | ||
status, err := e.Status(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge status: %w", err) | ||
} | ||
edge.Status = status.String() | ||
return nil | ||
}) | ||
|
||
eg.Go(func() error { | ||
hasLengthOneRival, err := e.HasLengthOneRival(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge has length one rival: %w", err) | ||
} | ||
edge.HasLengthOneRival = hasLengthOneRival | ||
return nil | ||
}) | ||
|
||
eg.Go(func() error { | ||
topLevelClaimHeight, err := e.TopLevelClaimHeight(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get edge top level claim height: %w", err) | ||
} | ||
edge.TopLevelClaimHeight = topLevelClaimHeight | ||
return nil | ||
}) | ||
|
||
return edge, eg.Wait() | ||
} | ||
|
||
func toCommitment(fn func() (protocol.Height, common.Hash)) *Commitment { | ||
h, hs := fn() | ||
return &Commitment{ | ||
Height: uint64(h), | ||
Hash: hs, | ||
} | ||
} |
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,37 @@ | ||
package api_test | ||
|
||
import ( | ||
"github.com/OffchainLabs/challenge-protocol-v2/api" | ||
protocol "github.com/OffchainLabs/challenge-protocol-v2/chain-abstraction" | ||
"github.com/OffchainLabs/challenge-protocol-v2/challenge-manager/challenge-tree/mock" | ||
) | ||
|
||
func edgesToMockEdges(e []*api.Edge) []*mock.Edge { | ||
me := make([]*mock.Edge, len(e)) | ||
for i, ee := range e { | ||
me[i] = edgeToMockEdge(ee) | ||
} | ||
return me | ||
} | ||
|
||
func edgeToMockEdge(e *api.Edge) *mock.Edge { | ||
return &mock.Edge{ | ||
ID: mock.EdgeId(e.ID.Bytes()), | ||
EdgeType: func() protocol.EdgeType { | ||
et, err := protocol.EdgeTypeFromString(e.Type) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return et | ||
}(), | ||
StartHeight: e.StartCommitment.Height, | ||
StartCommit: mock.Commit(e.StartCommitment.Hash.Bytes()), | ||
EndHeight: e.EndCommitment.Height, | ||
EndCommit: mock.Commit(e.EndCommitment.Hash.Bytes()), | ||
OriginID: mock.OriginId(e.OriginID.Bytes()), | ||
ClaimID: string(e.ClaimID.Bytes()), | ||
LowerChildID: mock.EdgeId(e.LowerChildID.Bytes()), | ||
UpperChildID: mock.EdgeId(e.UpperChildID.Bytes()), | ||
CreationBlock: e.CreatedAtBlock, | ||
} | ||
} |
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,7 @@ | ||
package api | ||
|
||
import gethLog "github.com/ethereum/go-ethereum/log" | ||
|
||
var ( | ||
log = gethLog.New("service", "api") | ||
) |
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 api | ||
|
||
import "net/http" | ||
|
||
func listAssertionsHandler(w http.ResponseWriter, r *http.Request) { | ||
w.WriteHeader(http.StatusNotImplemented) | ||
if _, err := w.Write([]byte("not implemented")); err != nil { | ||
log.Error("failed to write response body", "err", err) | ||
} | ||
} | ||
|
||
func getAssertionHandler(w http.ResponseWriter, r *http.Request) { | ||
w.WriteHeader(http.StatusNotImplemented) | ||
if _, err := w.Write([]byte("not implemented")); err != nil { | ||
log.Error("failed to write response body", "err", err) | ||
} | ||
} |
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,49 @@ | ||
package api_test | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
) | ||
|
||
func TestListAssertions(t *testing.T) { | ||
s, _ := NewTestServer(t) | ||
|
||
req, err := http.NewRequest("GET", "/assertions", nil) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. | ||
rr := httptest.NewRecorder() | ||
|
||
// Serve the request with the http recorder. | ||
s.Router().ServeHTTP(rr, req) | ||
|
||
// Check the status code is what we expect. | ||
if status := rr.Code; status != http.StatusNotImplemented { | ||
t.Errorf("handler returned wrong status code: got %v want %v", | ||
status, http.StatusNotImplemented) | ||
} | ||
} | ||
|
||
func TestGetAssertion(t *testing.T) { | ||
s, _ := NewTestServer(t) | ||
|
||
req, err := http.NewRequest("GET", "/assertions/foo", nil) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. | ||
rr := httptest.NewRecorder() | ||
|
||
// Serve the request with the http recorder. | ||
s.Router().ServeHTTP(rr, req) | ||
|
||
// Check the status code is what we expect. | ||
if status := rr.Code; status != http.StatusNotImplemented { | ||
t.Errorf("handler returned wrong status code: got %v want %v", | ||
status, http.StatusNotImplemented) | ||
} | ||
} |
Oops, something went wrong.