Skip to content

Commit 6800405

Browse files
Merge branch 'main' into security-update
2 parents dfc268b + 3ab9d9a commit 6800405

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+7371
-304
lines changed

client/client.go

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ type Factory interface {
1717

1818
// Client is the interface that defines the implementation of all the endpoints
1919
type Client interface {
20+
GetStatus(ctx context.Context) (*types.DACStatus, error)
2021
GetOffChainData(ctx context.Context, hash common.Hash) ([]byte, error)
21-
SignSequence(signedSequence types.SignedSequence) ([]byte, error)
22+
ListOffChainData(ctx context.Context, hashes []common.Hash) (map[common.Hash][]byte, error)
23+
SignSequence(ctx context.Context, signedSequence types.SignedSequence) ([]byte, error)
2224
}
2325

2426
// factory is the implementation of the data committee client factory
@@ -46,10 +48,29 @@ func New(url string) Client {
4648
}
4749
}
4850

51+
// GetStatus returns DAC status
52+
func (c *client) GetStatus(ctx context.Context) (*types.DACStatus, error) {
53+
response, err := rpc.JSONRPCCallWithContext(ctx, c.url, "status_getStatus")
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
if response.Error != nil {
59+
return nil, fmt.Errorf("%v %v", response.Error.Code, response.Error.Message)
60+
}
61+
62+
var result types.DACStatus
63+
if err = json.Unmarshal(response.Result, &result); err != nil {
64+
return nil, err
65+
}
66+
67+
return &result, nil
68+
}
69+
4970
// SignSequence sends a request to sign the given sequence by the data committee member
5071
// if successful returns the signature. The signature should be validated after using this method!
51-
func (c *client) SignSequence(signedSequence types.SignedSequence) ([]byte, error) {
52-
response, err := rpc.JSONRPCCall(c.url, "datacom_signSequence", signedSequence)
72+
func (c *client) SignSequence(ctx context.Context, signedSequence types.SignedSequence) ([]byte, error) {
73+
response, err := rpc.JSONRPCCallWithContext(ctx, c.url, "datacom_signSequence", signedSequence)
5374
if err != nil {
5475
return nil, err
5576
}
@@ -84,3 +105,27 @@ func (c *client) GetOffChainData(ctx context.Context, hash common.Hash) ([]byte,
84105

85106
return result, nil
86107
}
108+
109+
// ListOffChainData returns data based on the given hashes
110+
func (c *client) ListOffChainData(ctx context.Context, hashes []common.Hash) (map[common.Hash][]byte, error) {
111+
response, err := rpc.JSONRPCCallWithContext(ctx, c.url, "sync_listOffChainData", hashes)
112+
if err != nil {
113+
return nil, err
114+
}
115+
116+
if response.Error != nil {
117+
return nil, fmt.Errorf("%v %v", response.Error.Code, response.Error.Message)
118+
}
119+
120+
result := make(map[common.Hash]types.ArgBytes)
121+
if err = json.Unmarshal(response.Result, &result); err != nil {
122+
return nil, err
123+
}
124+
125+
preparedResult := make(map[common.Hash][]byte)
126+
for key, val := range result {
127+
preparedResult[key] = val
128+
}
129+
130+
return preparedResult, nil
131+
}

client/client_test.go

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,69 @@ import (
1616
"github.com/stretchr/testify/require"
1717
)
1818

19+
func TestClient_GetStatus(t *testing.T) {
20+
tests := []struct {
21+
name string
22+
result string
23+
status *types.DACStatus
24+
statusCode int
25+
err error
26+
}{
27+
{
28+
name: "successfully got status",
29+
result: `{"result":{"version":"v1.0.0","uptime":"123","key_count":2,"backfill_progress":5}}`,
30+
status: &types.DACStatus{
31+
Uptime: "123",
32+
Version: "v1.0.0",
33+
KeyCount: 2,
34+
BackfillProgress: 5,
35+
},
36+
},
37+
{
38+
name: "error returned by server",
39+
result: `{"error":{"code":123,"message":"test error"}}`,
40+
err: errors.New("123 test error"),
41+
},
42+
{
43+
name: "unsuccessful status code returned by server",
44+
statusCode: http.StatusInternalServerError,
45+
err: errors.New("invalid status code, expected: 200, found: 500"),
46+
},
47+
}
48+
for _, tt := range tests {
49+
tt := tt
50+
51+
t.Run(tt.name, func(t *testing.T) {
52+
t.Parallel()
53+
54+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
55+
var res rpc.Request
56+
require.NoError(t, json.NewDecoder(r.Body).Decode(&res))
57+
require.Equal(t, "status_getStatus", res.Method)
58+
59+
if tt.statusCode > 0 {
60+
w.WriteHeader(tt.statusCode)
61+
}
62+
63+
_, err := fmt.Fprint(w, tt.result)
64+
require.NoError(t, err)
65+
}))
66+
defer srv.Close()
67+
68+
client := New(srv.URL)
69+
70+
got, err := client.GetStatus(context.Background())
71+
if tt.err != nil {
72+
require.Error(t, err)
73+
require.EqualError(t, tt.err, err.Error())
74+
} else {
75+
require.NoError(t, err)
76+
require.Equal(t, tt.status, got)
77+
}
78+
})
79+
}
80+
}
81+
1982
func TestClient_SignSequence(t *testing.T) {
2083
tests := []struct {
2184
name string
@@ -87,7 +150,7 @@ func TestClient_SignSequence(t *testing.T) {
87150

88151
client := New(srv.URL)
89152

90-
got, err := client.SignSequence(tt.ss)
153+
got, err := client.SignSequence(context.Background(), tt.ss)
91154
if tt.err != nil {
92155
require.Error(t, err)
93156
require.EqualError(t, tt.err, err.Error())
@@ -169,3 +232,81 @@ func TestClient_GetOffChainData(t *testing.T) {
169232
})
170233
}
171234
}
235+
236+
func TestClient_ListOffChainData(t *testing.T) {
237+
tests := []struct {
238+
name string
239+
hashes []common.Hash
240+
result string
241+
data map[common.Hash][]byte
242+
statusCode int
243+
err error
244+
}{
245+
{
246+
name: "successfully got offhcain data",
247+
hashes: []common.Hash{common.BytesToHash([]byte("hash"))},
248+
result: fmt.Sprintf(`{"result":{"%s":"%s"}}`,
249+
common.BytesToHash([]byte("hash")).Hex(), hex.EncodeToString([]byte("offchaindata"))),
250+
data: map[common.Hash][]byte{
251+
common.BytesToHash([]byte("hash")): []byte("offchaindata"),
252+
},
253+
},
254+
{
255+
name: "error returned by server",
256+
hashes: []common.Hash{common.BytesToHash([]byte("hash"))},
257+
result: `{"error":{"code":123,"message":"test error"}}`,
258+
err: errors.New("123 test error"),
259+
},
260+
{
261+
name: "invalid offchain data returned by server",
262+
hashes: []common.Hash{common.BytesToHash([]byte("hash"))},
263+
result: fmt.Sprintf(`{"result":{"%s":"invalid-signature"}}`,
264+
common.BytesToHash([]byte("hash")).Hex()),
265+
data: map[common.Hash][]byte{
266+
common.BytesToHash([]byte("hash")): nil,
267+
},
268+
},
269+
{
270+
name: "unsuccessful status code returned by server",
271+
hashes: []common.Hash{common.BytesToHash([]byte("hash"))},
272+
statusCode: http.StatusUnauthorized,
273+
err: errors.New("invalid status code, expected: 200, found: 401"),
274+
},
275+
}
276+
for _, tt := range tests {
277+
tt := tt
278+
279+
t.Run(tt.name, func(t *testing.T) {
280+
t.Parallel()
281+
282+
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
283+
var res rpc.Request
284+
require.NoError(t, json.NewDecoder(r.Body).Decode(&res))
285+
require.Equal(t, "sync_listOffChainData", res.Method)
286+
287+
var params [][]common.Hash
288+
require.NoError(t, json.Unmarshal(res.Params, &params))
289+
require.Equal(t, tt.hashes, params[0])
290+
291+
if tt.statusCode > 0 {
292+
w.WriteHeader(tt.statusCode)
293+
}
294+
295+
_, err := fmt.Fprint(w, tt.result)
296+
require.NoError(t, err)
297+
}))
298+
defer svr.Close()
299+
300+
c := &client{url: svr.URL}
301+
302+
got, err := c.ListOffChainData(context.Background(), tt.hashes)
303+
if tt.err != nil {
304+
require.Error(t, err)
305+
require.EqualError(t, tt.err, err.Error())
306+
} else {
307+
require.NoError(t, err)
308+
require.Equal(t, tt.data, got)
309+
}
310+
})
311+
}
312+
}

cmd/main.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/0xPolygon/cdk-data-availability/rpc"
1717
"github.com/0xPolygon/cdk-data-availability/sequencer"
1818
"github.com/0xPolygon/cdk-data-availability/services/datacom"
19+
"github.com/0xPolygon/cdk-data-availability/services/status"
1920
"github.com/0xPolygon/cdk-data-availability/services/sync"
2021
"github.com/0xPolygon/cdk-data-availability/synchronizer"
2122
"github.com/0xPolygon/cdk-data-availability/types"
@@ -140,17 +141,17 @@ func start(cliCtx *cli.Context) error {
140141
server := rpc.NewServer(
141142
c.RPC,
142143
[]rpc.Service{
144+
{
145+
Name: status.APISTATUS,
146+
Service: status.NewEndpoints(storage),
147+
},
143148
{
144149
Name: sync.APISYNC,
145-
Service: sync.NewSyncEndpoints(storage),
150+
Service: sync.NewEndpoints(storage),
146151
},
147152
{
148-
Name: datacom.APIDATACOM,
149-
Service: datacom.NewDataComEndpoints(
150-
storage,
151-
pk,
152-
sequencerTracker,
153-
),
153+
Name: datacom.APIDATACOM,
154+
Service: datacom.NewEndpoints(storage, pk, sequencerTracker),
154155
},
155156
},
156157
)

config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type L1Config struct {
3939
Timeout types.Duration `mapstructure:"Timeout"`
4040
RetryPeriod types.Duration `mapstructure:"RetryPeriod"`
4141
BlockBatchSize uint `mapstructure:"BlockBatchSize"`
42+
TrackSequencer bool `mapstructure:"TrackSequencer"`
4243

4344
// GenesisBlock represents the block number where PolygonValidium contract is deployed on L1
4445
GenesisBlock uint64 `mapstructure:"GenesisBlock"`

config/default.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Timeout = "1m"
2020
RetryPeriod = "5s"
2121
BlockBatchSize = "64"
2222
GenesisBlock = "0"
23+
TrackSequencer = true
2324
2425
[Log]
2526
Environment = "development" # "production" or "development"

db/db.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ type DB interface {
2929

3030
Exists(ctx context.Context, key common.Hash) bool
3131
GetOffChainData(ctx context.Context, key common.Hash, dbTx sqlx.QueryerContext) (types.ArgBytes, error)
32+
ListOffChainData(ctx context.Context, keys []common.Hash, dbTx sqlx.QueryerContext) (map[common.Hash]types.ArgBytes, error)
3233
StoreOffChainData(ctx context.Context, od []types.OffChainData, dbTx sqlx.ExecerContext) error
34+
35+
CountOffchainData(ctx context.Context) (uint64, error)
3336
}
3437

3538
// Tx is the interface that defines functions a db tx has to implement
@@ -218,6 +221,66 @@ func (db *pgDB) GetOffChainData(ctx context.Context, key common.Hash, dbTx sqlx.
218221
return common.FromHex(hexValue), nil
219222
}
220223

224+
// ListOffChainData returns values identified by the given keys
225+
func (db *pgDB) ListOffChainData(ctx context.Context, keys []common.Hash, dbTx sqlx.QueryerContext) (map[common.Hash]types.ArgBytes, error) {
226+
if len(keys) == 0 {
227+
return nil, nil
228+
}
229+
230+
const listOffchainDataSQL = `
231+
SELECT key, value
232+
FROM data_node.offchain_data
233+
WHERE key IN (?);
234+
`
235+
236+
preparedKeys := make([]string, len(keys))
237+
for i, key := range keys {
238+
preparedKeys[i] = key.Hex()
239+
}
240+
241+
query, args, err := sqlx.In(listOffchainDataSQL, preparedKeys)
242+
if err != nil {
243+
return nil, err
244+
}
245+
246+
// sqlx.In returns queries with the `?` bindvar, we can rebind it for our backend
247+
query = db.pg.Rebind(query)
248+
249+
rows, err := db.querier(dbTx).QueryxContext(ctx, query, args...)
250+
if err != nil {
251+
return nil, err
252+
}
253+
254+
defer rows.Close()
255+
256+
list := make(map[common.Hash]types.ArgBytes)
257+
for rows.Next() {
258+
data := struct {
259+
Key string `db:"key"`
260+
Value string `db:"value"`
261+
}{}
262+
if err = rows.StructScan(&data); err != nil {
263+
return nil, err
264+
}
265+
266+
list[common.HexToHash(data.Key)] = common.FromHex(data.Value)
267+
}
268+
269+
return list, nil
270+
}
271+
272+
// CountOffchainData returns the count of rows in the offchain_data table
273+
func (db *pgDB) CountOffchainData(ctx context.Context) (uint64, error) {
274+
const countQuery = "SELECT COUNT(*) FROM data_node.offchain_data;"
275+
276+
var count uint64
277+
if err := db.pg.QueryRowContext(ctx, countQuery).Scan(&count); err != nil {
278+
return 0, err
279+
}
280+
281+
return count, nil
282+
}
283+
221284
func (db *pgDB) execer(dbTx sqlx.ExecerContext) sqlx.ExecerContext {
222285
if dbTx != nil {
223286
return dbTx

0 commit comments

Comments
 (0)