Skip to content

Commit

Permalink
Support call v3.
Browse files Browse the repository at this point in the history
  • Loading branch information
q-uint committed Feb 5, 2025
1 parent 604678d commit 814e768
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 24 deletions.
12 changes: 8 additions & 4 deletions agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,10 @@ func New(cfg Config) (*Agent, error) {
id = cfg.Identity
}
client := NewClient(cfg.ClientConfig...)
rootKey, _ := hex.DecodeString(certification.RootKey)
rootKey, err := hex.DecodeString(certification.RootKey)
if err != nil {
return nil, err
}
if cfg.FetchRootKey {
status, err := client.Status()
if err != nil {
Expand Down Expand Up @@ -314,9 +317,10 @@ func (a Agent) RequestStatus(ecID principal.Principal, requestID RequestID) ([]b
if err != nil {
return nil, nil, err
}
if err := certification.VerifyCertificate(*certificate, ecID, a.rootKey); err != nil {
return nil, nil, err
}
return handleStatus(path, certificate)
}

func handleStatus(path []hashtree.Label, certificate *certification.Certificate) ([]byte, hashtree.Node, error) {
status, err := certificate.Tree.Lookup(append(path, hashtree.Label("status"))...)
var lookupError hashtree.LookupError
if errors.As(err, &lookupError) && lookupError.Type == hashtree.LookupResultAbsent {
Expand Down
31 changes: 19 additions & 12 deletions call.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
package agent

import (
"fmt"

"github.com/aviate-labs/agent-go/certification"
"github.com/aviate-labs/agent-go/certification/hashtree"
"github.com/aviate-labs/agent-go/principal"
"github.com/fxamacker/cbor/v2"
"google.golang.org/protobuf/proto"
)

// Call calls a method on a canister, it does not wait for the result.
func (c APIRequest[_, _]) Call() error {
c.a.logger.Printf("[AGENT] CALL %s %s (%x)", c.effectiveCanisterID, c.methodName, c.requestID)
_, err := c.a.call(c.effectiveCanisterID, c.data)
return err
}

// CallAndWait calls a method on a canister and waits for the result.
func (c APIRequest[_, Out]) CallAndWait(out Out) error {
if err := c.Call(); err != nil {
c.a.logger.Printf("[AGENT] CALL %s %s (%x)", c.effectiveCanisterID, c.methodName, c.requestID)
rawCertificate, err := c.a.call(c.effectiveCanisterID, c.data)
if err != nil {
return err
}
return c.Wait(out)
}
if len(rawCertificate) != 0 {
var certificate certification.Certificate
if err := cbor.Unmarshal(rawCertificate, &certificate); err != nil {
return err
}
raw, err := hashtree.Lookup(certificate.Tree.Root, hashtree.Label("request_status"), c.requestID[:], hashtree.Label("reply"))
if err != nil {
return fmt.Errorf("no reply found")
}
return c.unmarshal(raw, out)
}

// Wait waits for the result of the Call and unmarshals it into the given values.
func (c APIRequest[_, Out]) Wait(out Out) error {
raw, err := c.a.poll(c.effectiveCanisterID, c.requestID)
if err != nil {
return err
Expand Down
31 changes: 25 additions & 6 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func NewClient(options ...ClientOption) Client {
}

func (c Client) Call(ctx context.Context, canisterID principal.Principal, data []byte) ([]byte, error) {
u := c.url(fmt.Sprintf("/api/v2/canister/%s/call", canisterID.Encode()))
u := c.url(fmt.Sprintf("/api/v3/canister/%s/call", canisterID.Encode()))
c.logger.Printf("[CLIENT] CALL %s", u)
req, err := c.newRequest(ctx, "POST", u, bytes.NewBuffer(data))
if err != nil {
Expand All @@ -53,19 +53,38 @@ func (c Client) Call(ctx context.Context, canisterID principal.Principal, data [
defer resp.Body.Close()
switch resp.StatusCode {
case http.StatusAccepted:
return io.ReadAll(resp.Body)
return nil, nil
case http.StatusOK:
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var pErr preprocessingError
if err := cbor.Unmarshal(body, &pErr); err != nil {
var status struct {
Status string `cbor:"status"`
}
if err := cbor.Unmarshal(body, &status); err != nil {
return nil, err
}
return nil, pErr
switch status.Status {
case "replied":
var certificate struct {
Certificate []byte `cbor:"certificate"`
}
return certificate.Certificate, cbor.Unmarshal(body, &certificate)
case "non_replicated_rejection":
var pErr preprocessingError
if err := cbor.Unmarshal(body, &pErr); err != nil {
return nil, err
}
return nil, pErr
default:
return nil, fmt.Errorf("unknown status: %s", status)
}
default:
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("(%d) %s: %s", resp.StatusCode, resp.Status, body)
}
}
Expand Down
21 changes: 20 additions & 1 deletion clients/registry/client_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package registry_test

import (
"github.com/aviate-labs/agent-go/clients/registry"
"os"
"testing"

"github.com/aviate-labs/agent-go/clients/registry"
"github.com/aviate-labs/agent-go/principal"
)

func TestClient_GetNodeListSince(t *testing.T) {
Expand All @@ -24,6 +26,23 @@ func TestClient_GetNodeListSince(t *testing.T) {
}
}

func TestClient_GetNNSSubnetID(t *testing.T) {
checkEnabled(t)

c, err := registry.New()
if err != nil {
t.Fatal(err)
}

id, err := c.GetNNSSubnetID()
if err != nil {
t.Fatal(err)
}
if !id.Equal(principal.MustDecode("tdb26-jop6k-aogll-7ltgs-eruif-6kk7m-qpktf-gdiqx-mxtrf-vb5e6-eqe")) {
t.Error(id)
}
}

func checkEnabled(t *testing.T) {
// The reason for this is that the tests are very slow.
if os.Getenv("REGISTRY_TEST_ENABLE") != "true" {
Expand Down
3 changes: 2 additions & 1 deletion clients/registry/dataprovider_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package registry_test

import (
"github.com/aviate-labs/agent-go/clients/registry"
"testing"

"github.com/aviate-labs/agent-go/clients/registry"
)

func TestDataProvider_GetLatestVersion(t *testing.T) {
Expand Down

0 comments on commit 814e768

Please sign in to comment.