Skip to content

Commit

Permalink
feat: check agglayer certificate and use as initial if db is empty (#192
Browse files Browse the repository at this point in the history
)

- integration `interop_getLatestKnownCertificateHeader` end-point (aggsender and e2e tests)
- Check agglayer and aggsender are on the same page
- Fix wrong DBPath on default config
- Fix colors on script `local_config`
- Changes on config file: new fields `aggsender.MaxRetriesStoreCertificate` and `aggsender.DelayBeetweenRetries`
- Partial solution to bug CDK-603 on PreviousLER (just fix initial case that first cert fails)

---------

Co-authored-by: Goran Rojovic <[email protected]>
  • Loading branch information
joanestebanr and goran-ethernal authored Nov 25, 2024
1 parent 46a6789 commit e93e1b2
Show file tree
Hide file tree
Showing 19 changed files with 864 additions and 183 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ jobs:
env:
KURTOSIS_FOLDER: ${{ github.workspace }}/kurtosis-cdk
BATS_LIB_PATH: /usr/lib/
agglayer_prover_sp1_key: ${{ secrets.SP1_PRIVATE_KEY }}

- name: Dump enclave logs
if: failure()
Expand Down
22 changes: 22 additions & 0 deletions agglayer/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type AgglayerClientInterface interface {
WaitTxToBeMined(hash common.Hash, ctx context.Context) error
SendCertificate(certificate *SignedCertificate) (common.Hash, error)
GetCertificateHeader(certificateHash common.Hash) (*CertificateHeader, error)
GetLatestKnownCertificateHeader(networkID uint32) (*CertificateHeader, error)
AggLayerClientGetEpochConfiguration
}

Expand Down Expand Up @@ -158,3 +159,24 @@ func (c *AggLayerClient) GetEpochConfiguration() (*ClockConfiguration, error) {

return result, nil
}

// GetLatestKnownCertificateHeader returns the last certificate header submitted by networkID
func (c *AggLayerClient) GetLatestKnownCertificateHeader(networkID uint32) (*CertificateHeader, error) {
response, err := jSONRPCCall(c.url, "interop_getLatestKnownCertificateHeader", networkID)
if err != nil {
return nil, fmt.Errorf("GetLatestKnownCertificateHeader error jSONRPCCall. Err: %w", err)
}

if response.Error != nil {
return nil, fmt.Errorf("GetLatestKnownCertificateHeader rpc returns an error: code=%d msg=%s",
response.Error.Code, response.Error.Message)
}

var result *CertificateHeader
err = json.Unmarshal(response.Result, &result)
if err != nil {
return nil, fmt.Errorf("GetLatestKnownCertificateHeader error Unmashal. Err: %w", err)
}

return result, nil
}
71 changes: 70 additions & 1 deletion agglayer/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/0xPolygon/cdk-rpc/rpc"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)

Expand All @@ -14,11 +15,40 @@ const (

func TestExploratoryClient(t *testing.T) {
t.Skip("This test is for exploratory purposes only")
sut := NewAggLayerClient("http://127.0.0.1:32853")
sut := NewAggLayerClient("http://127.0.0.1:32781")
config, err := sut.GetEpochConfiguration()
require.NoError(t, err)
require.NotNil(t, config)
fmt.Printf("Config: %s", config.String())

lastCert, err := sut.GetLatestKnownCertificateHeader(1)
require.NoError(t, err)
require.NotNil(t, lastCert)
fmt.Printf("LastCert: %s", lastCert.String())
}

func TestExploratoryGetCertificateHeader(t *testing.T) {
t.Skip("This test is exploratory and should be skipped")
aggLayerClient := NewAggLayerClient("http://localhost:32796")
certificateID := common.HexToHash("0xf153e75e24591432ac5deafaeaafba3fec0fd851261c86051b9c0d540b38c369")
certificateHeader, err := aggLayerClient.GetCertificateHeader(certificateID)
require.NoError(t, err)
fmt.Print(certificateHeader)
}
func TestExploratoryGetEpochConfiguration(t *testing.T) {
t.Skip("This test is exploratory and should be skipped")
aggLayerClient := NewAggLayerClient("http://localhost:32796")
clockConfig, err := aggLayerClient.GetEpochConfiguration()
require.NoError(t, err)
fmt.Print(clockConfig)
}

func TestExploratoryGetLatestKnownCertificateHeader(t *testing.T) {
t.Skip("This test is exploratory and should be skipped")
aggLayerClient := NewAggLayerClient("http://localhost:32781")
cert, err := aggLayerClient.GetLatestKnownCertificateHeader(1)
require.NoError(t, err)
fmt.Print(cert)
}

func TestGetEpochConfigurationResponseWithError(t *testing.T) {
Expand Down Expand Up @@ -74,3 +104,42 @@ func TestGetEpochConfigurationOkResponse(t *testing.T) {
GenesisBlock: 1,
}, *clockConfig)
}

func TestGetLatestKnownCertificateHeaderOkResponse(t *testing.T) {
sut := NewAggLayerClient(testURL)
response := rpc.Response{
Result: []byte(`{"network_id":1,"height":0,"epoch_number":223,"certificate_index":0,"certificate_id":"0xf9179d2fbe535814b5a14496e2eed474f49c6131227a9dfc5d2d8caf9e212054","new_local_exit_root":"0x7ae06f4a5d0b6da7dd4973fb6ef40d82c9f2680899b3baaf9e564413b59cc160","metadata":"0x00000000000000000000000000000000000000000000000000000000000001a7","status":"Settled"}`),
}
jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) {
return response, nil
}
cert, err := sut.GetLatestKnownCertificateHeader(1)
require.NotNil(t, cert)
require.NoError(t, err)
}
func TestGetLatestKnownCertificateHeaderErrorResponse(t *testing.T) {
sut := NewAggLayerClient(testURL)
jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) {
return rpc.Response{}, fmt.Errorf("unittest error")
}

cert, err := sut.GetLatestKnownCertificateHeader(1)

require.Nil(t, cert)
require.Error(t, err)
}

func TestGetLatestKnownCertificateHeaderResponseBadJson(t *testing.T) {
sut := NewAggLayerClient(testURL)
response := rpc.Response{
Result: []byte(`{`),
}
jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) {
return response, nil
}

cert, err := sut.GetLatestKnownCertificateHeader(1)

require.Nil(t, cert)
require.Error(t, err)
}
58 changes: 58 additions & 0 deletions agglayer/mock_agglayer_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 38 additions & 1 deletion agglayer/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"math/big"
"slices"
"strings"

"github.com/0xPolygon/cdk/bridgesync"
Expand All @@ -24,11 +25,36 @@ const (
Settled
)

var (
NonSettledStatuses = []CertificateStatus{Pending, Candidate, Proven}
ClosedStatuses = []CertificateStatus{Settled, InError}
)

// String representation of the enum
func (c CertificateStatus) String() string {
return [...]string{"Pending", "Proven", "Candidate", "InError", "Settled"}[c]
}

// IsClosed returns true if the certificate is closed (settled or inError)
func (c CertificateStatus) IsClosed() bool {
return !c.IsOpen()
}

// IsSettled returns true if the certificate is settled
func (c CertificateStatus) IsSettled() bool {
return c == Settled
}

// IsInError returns true if the certificate is in error
func (c CertificateStatus) IsInError() bool {
return c == InError
}

// IsOpen returns true if the certificate is open (pending, candidate or proven)
func (c CertificateStatus) IsOpen() bool {
return slices.Contains(NonSettledStatuses, c)
}

// UnmarshalJSON is the implementation of the json.Unmarshaler interface
func (c *CertificateStatus) UnmarshalJSON(data []byte) error {
dataStr := string(data)
Expand Down Expand Up @@ -550,7 +576,18 @@ type CertificateHeader struct {
Error PPError `json:"-"`
}

func (c CertificateHeader) String() string {
// ID returns a string with the ident of this cert (height/certID)
func (c *CertificateHeader) ID() string {
if c == nil {
return "nil"
}
return fmt.Sprintf("%d/%s", c.Height, c.CertificateID.String())
}

func (c *CertificateHeader) String() string {
if c == nil {
return "nil"
}
errors := ""
if c.Error != nil {
errors = c.Error.String()
Expand Down
Loading

0 comments on commit e93e1b2

Please sign in to comment.