Skip to content
Open
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
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,4 @@ data
*.sqlite-wal
**aggkit-001-data**
.vscode
debug
bin
debug
28 changes: 22 additions & 6 deletions aggsender/rpcclient/client.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
package rpcclient

import (
"context"
"encoding/json"
"fmt"
"time"

"github.com/0xPolygon/cdk-rpc/rpc"
agglayertypes "github.com/agglayer/aggkit/agglayer/types"
"github.com/agglayer/aggkit/aggsender/types"
)

var jSONRPCCall = rpc.JSONRPCCall
var jSONRPCCallWithContext = rpc.JSONRPCCallWithContext

const defaultRequestTimeout = 10 * time.Second

// Client wraps all the available endpoints of the data abailability committee node server
type Client struct {
url string
url string
requestTimeout time.Duration
}

func NewClient(url string) *Client {
return &Client{
url: url,
url: url,
requestTimeout: defaultRequestTimeout,
}
}

func (c *Client) GetStatus() (*types.AggsenderInfo, error) {
response, err := jSONRPCCall(c.url, "aggsender_status")
response, err := c.call("aggsender_status")
if err != nil {
return nil, err
}
Expand All @@ -41,7 +47,7 @@ func (c *Client) GetStatus() (*types.AggsenderInfo, error) {
}

func (c *Client) GetCertificateHeaderPerHeight(height *uint64) (*types.Certificate, error) {
response, err := jSONRPCCall(c.url, "aggsender_getCertificateHeaderPerHeight", height)
response, err := c.call("aggsender_getCertificateHeaderPerHeight", height)
if err != nil {
return nil, err
}
Expand All @@ -61,7 +67,7 @@ func (c *Client) GetCertificateHeaderPerHeight(height *uint64) (*types.Certifica
// GetCertificateBridgeExits returns the bridge exits for the certificate at the given height.
// If height is nil, returns the bridge exits of the last sent certificate.
func (c *Client) GetCertificateBridgeExits(height *uint64) ([]*agglayertypes.BridgeExit, error) {
response, err := jSONRPCCall(c.url, "aggsender_getCertificateBridgeExits", height)
response, err := c.call("aggsender_getCertificateBridgeExits", height)
if err != nil {
return nil, err
}
Expand All @@ -74,3 +80,13 @@ func (c *Client) GetCertificateBridgeExits(height *uint64) ([]*agglayertypes.Bri
}
return exits, nil
}

func (c *Client) call(method string, params ...interface{}) (rpc.Response, error) {
timeout := c.requestTimeout
if timeout <= 0 {
timeout = defaultRequestTimeout
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return jSONRPCCallWithContext(ctx, c.url, method, params...)
}
48 changes: 36 additions & 12 deletions aggsender/rpcclient/client_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package rpcclient

import (
"context"
"encoding/json"
"fmt"
"math/big"
"testing"
"time"

"github.com/0xPolygon/cdk-rpc/rpc"
agglayertypes "github.com/agglayer/aggkit/agglayer/types"
Expand All @@ -22,7 +24,7 @@ func TestGetCertificateHeaderPerHeight(t *testing.T) {
response := rpc.Response{
Result: responseCertJSON,
}
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return response, nil
}
cert, err := sut.GetCertificateHeaderPerHeight(&height)
Expand All @@ -47,7 +49,7 @@ func TestGetCertificateBridgeExits(t *testing.T) {
response := rpc.Response{
Result: responseExitsJSON,
}
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return response, nil
}
exits, err := sut.GetCertificateBridgeExits(&height)
Expand All @@ -65,7 +67,7 @@ func TestGetStatus(t *testing.T) {
response := rpc.Response{
Result: responseDataJSON,
}
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return response, nil
}
result, err := sut.GetStatus()
Expand All @@ -74,19 +76,41 @@ func TestGetStatus(t *testing.T) {
require.Equal(t, responseData, *result)
}

func TestClientCallUsesTimeout(t *testing.T) {
sut := NewClient("url")
sut.requestTimeout = 50 * time.Millisecond

responseData := types.AggsenderInfo{}
responseDataJSON, err := json.Marshal(responseData)
require.NoError(t, err)
response := rpc.Response{
Result: responseDataJSON,
}
jSONRPCCallWithContext = func(ctx context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
deadline, ok := ctx.Deadline()
require.True(t, ok)
require.Positive(t, time.Until(deadline))
require.LessOrEqual(t, time.Until(deadline), 50*time.Millisecond)
return response, nil
}

_, err = sut.GetStatus()
require.NoError(t, err)
}

func TestGetStatus_Errors(t *testing.T) {
sut := NewClient("url")

t.Run("rpc call error", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{}, fmt.Errorf("network error")
}
_, err := sut.GetStatus()
require.Error(t, err)
})

t.Run("response error field set", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{Error: &rpc.ErrorObject{Message: "rpc error"}}, nil
}
_, err := sut.GetStatus()
Expand All @@ -95,7 +119,7 @@ func TestGetStatus_Errors(t *testing.T) {
})

t.Run("unmarshal error", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{Result: json.RawMessage("not-json")}, nil
}
_, err := sut.GetStatus()
Expand All @@ -109,15 +133,15 @@ func TestGetCertificateHeaderPerHeight_Errors(t *testing.T) {
height := uint64(1)

t.Run("rpc call error", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{}, fmt.Errorf("network error")
}
_, err := sut.GetCertificateHeaderPerHeight(&height)
require.Error(t, err)
})

t.Run("response error field set", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{Error: &rpc.ErrorObject{Message: "rpc error"}}, nil
}
_, err := sut.GetCertificateHeaderPerHeight(&height)
Expand All @@ -126,7 +150,7 @@ func TestGetCertificateHeaderPerHeight_Errors(t *testing.T) {
})

t.Run("unmarshal error", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{Result: json.RawMessage("not-json")}, nil
}
_, err := sut.GetCertificateHeaderPerHeight(&height)
Expand All @@ -140,15 +164,15 @@ func TestGetCertificateBridgeExits_Errors(t *testing.T) {
height := uint64(5)

t.Run("rpc call error", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{}, fmt.Errorf("network error")
}
_, err := sut.GetCertificateBridgeExits(&height)
require.Error(t, err)
})

t.Run("response error field set", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{Error: &rpc.ErrorObject{Message: "rpc error"}}, nil
}
_, err := sut.GetCertificateBridgeExits(&height)
Expand All @@ -157,7 +181,7 @@ func TestGetCertificateBridgeExits_Errors(t *testing.T) {
})

t.Run("unmarshal error", func(t *testing.T) {
jSONRPCCall = func(_, _ string, _ ...interface{}) (rpc.Response, error) {
jSONRPCCallWithContext = func(_ context.Context, _, _ string, _ ...interface{}) (rpc.Response, error) {
return rpc.Response{Result: json.RawMessage("not-json")}, nil
}
_, err := sut.GetCertificateBridgeExits(&height)
Expand Down
Loading
Loading