Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avail DA Adapter in Rollkit #6

Merged
merged 26 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b134701
added da for avail
chandiniv1 Jul 17, 2023
64a7b9b
fix: messages and appID + dependencies
prabal-banerjee Jul 19, 2023
b0382f7
replaced substrate rpc
chandiniv1 Jul 24, 2023
d7d815f
made changes in retrieve blocks
chandiniv1 Jul 26, 2023
5cbc78e
changed naming conventions
chandiniv1 Aug 3, 2023
619de31
taken dalayerheight as blocknumber
chandiniv1 Aug 3, 2023
4ebf625
renamed mock to datasubmit
chandiniv1 Aug 3, 2023
964575d
renamed mock to datasubmit and added desired confidence to config
chandiniv1 Aug 3, 2023
ae3fc03
added baseurl and confidence to config
chandiniv1 Aug 7, 2023
eb7269b
removed size from config and handled errors
chandiniv1 Aug 7, 2023
9ea8b1c
removed rpc in dataavailabilitylayerclient
chandiniv1 Aug 7, 2023
303d5ff
return error when appID is 0
chandiniv1 Aug 9, 2023
8cb14ba
Merge branch 'vitwit/avail-da' into chandini/avail-da
murthyvitwit Aug 9, 2023
b01f342
Merge pull request #2 from chandiniv1/chandini/avail-da
murthyvitwit Aug 9, 2023
005a235
modified submitblock to submit blocks
chandiniv1 Aug 10, 2023
56a0878
removed checkblock availability method
chandiniv1 Aug 23, 2023
ce2ee0a
Merge branch 'main' of https://github.com/vitwit/rollkit into vitwit/…
chandiniv1 Aug 23, 2023
6ba5623
removed message field in retrieve blocks
chandiniv1 Aug 24, 2023
284af08
added description to structs
chandiniv1 Sep 2, 2023
e6bf78a
updated avail.go
chandiniv1 Sep 2, 2023
3ea9afc
updated avail.go
chandiniv1 Sep 2, 2023
2a3d5e3
updated avail.go
chandiniv1 Sep 4, 2023
c0c030d
updated go
chandiniv1 Sep 4, 2023
51da5c8
fix lint issues
chandiniv1 Sep 4, 2023
41d6989
lint issues fix
chandiniv1 Sep 4, 2023
f5753bb
added description
chandiniv1 Sep 4, 2023
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
219 changes: 219 additions & 0 deletions da/avail/avail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package avail

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"

ds "github.com/ipfs/go-datastore"
chandiniv1 marked this conversation as resolved.
Show resolved Hide resolved

"github.com/rollkit/rollkit/da"
"github.com/rollkit/rollkit/da/avail/datasubmit"
"github.com/rollkit/rollkit/log"
"github.com/rollkit/rollkit/types"
)

const BLOCK_NOT_FOUND = "\"Not found\""
const PROCESSING_BLOCK = "\"Processing block\""

// Config stores Avail DALC configuration parameters.
type Config struct {
chandiniv1 marked this conversation as resolved.
Show resolved Hide resolved
BaseURL string `json:"base_url"`
Seed string `json:"seed"`
ApiURL string `json:"api_url"`
AppDataURL string `json:"app_data_url"`
AppID int `json:"app_id"`
Confidence float64 `json:"confidence"`
}

// DataAvailabilityLayerClient uses Avail-Node configuration parameters
type DataAvailabilityLayerClient struct {
_ types.NamespaceID
config Config
logger log.Logger
}

// Confidence stores block params retireved from Avail Light Node Endpoint
type Confidence struct {
Block uint32 `json:"block"`
Confidence float64 `json:"confidence"`
SerialisedConfidence *string `json:"serialised_confidence,omitempty"`
}

// AppData stores Extrinsics retrieved from Avail Light Node Endpoint
type AppData struct {
Block uint32 `json:"block"`
Extrinsics []string `json:"extrinsics"`
}

var _ da.DataAvailabilityLayerClient = &DataAvailabilityLayerClient{}
var _ da.BlockRetriever = &DataAvailabilityLayerClient{}
aterentic-ethernal marked this conversation as resolved.
Show resolved Hide resolved

// Init initializes DataAvailabilityLayerClient instance.
func (c *DataAvailabilityLayerClient) Init(_ types.NamespaceID, config []byte, kvStore ds.Datastore, logger log.Logger) error {
c.logger = logger

if len(config) > 0 {
return json.Unmarshal(config, &c.config)
}

return nil
}

// Start prepares DataAvailabilityLayerClient to work.
func (c *DataAvailabilityLayerClient) Start() error {

c.logger.Info("starting avail data availability layer client", "baseURL", c.config.ApiURL)

return nil
}

// Stop stops DataAvailabilityLayerClient.
func (c *DataAvailabilityLayerClient) Stop() error {

c.logger.Info("stopping avail data availability layer client")

return nil
}

// SubmitBlock submits a block to DA layer.
func (c *DataAvailabilityLayerClient) SubmitBlocks(ctx context.Context, blocks []*types.Block) da.ResultSubmitBlocks {

for _, block := range blocks {
data, err := block.MarshalBinary()
if err != nil {
return da.ResultSubmitBlocks{
BaseResult: da.BaseResult{
Code: da.StatusError,
Message: err.Error(),
},
}
}
if err := datasubmit.SubmitData(c.config.ApiURL, c.config.Seed, c.config.AppID, data); err != nil {
return da.ResultSubmitBlocks{
BaseResult: da.BaseResult{
Code: da.StatusError,
Message: err.Error(),
},
}
}

}

return da.ResultSubmitBlocks{
BaseResult: da.BaseResult{
Code: da.StatusSuccess,
Message: "success",
DAHeight: 1,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this height static?

},
}

}

// RetrieveBlocks gets the block from DA layer.
func (c *DataAvailabilityLayerClient) RetrieveBlocks(ctx context.Context, dataLayerHeight uint64) da.ResultRetrieveBlocks {

blocks := []*types.Block{}

Loop:
blockNumber := dataLayerHeight

appDataURL := fmt.Sprintf(c.config.BaseURL+c.config.AppDataURL, blockNumber)

// Sanitize and validate the URL
parsedURL, err := url.Parse(appDataURL)
if err != nil {
return da.ResultRetrieveBlocks{
BaseResult: da.BaseResult{
Code: da.StatusError,
Message: err.Error(),
},
}
}

// Create an HTTP request with the sanitized URL
req, err := http.NewRequest("GET", parsedURL.String(), nil)
if err != nil {
return da.ResultRetrieveBlocks{
BaseResult: da.BaseResult{
Code: da.StatusError,
Message: err.Error(),
},
}
}

// Perform the HTTP request
client := http.DefaultClient
response, err := client.Do(req)
if err != nil {
return da.ResultRetrieveBlocks{
BaseResult: da.BaseResult{
Code: da.StatusError,
Message: err.Error(),
},
}
}
defer func() {
_ = response.Body.Close()
}()

responseData, err := io.ReadAll(response.Body)
if err != nil {
return da.ResultRetrieveBlocks{
BaseResult: da.BaseResult{
Code: da.StatusError,
Message: err.Error(),
},
}
}

var appDataObject AppData
if string(responseData) == BLOCK_NOT_FOUND {

appDataObject = AppData{Block: uint32(blockNumber), Extrinsics: []string{}}

} else if string(responseData) == PROCESSING_BLOCK {

goto Loop

} else {
if err = json.Unmarshal(responseData, &appDataObject); err != nil {
return da.ResultRetrieveBlocks{
BaseResult: da.BaseResult{
Code: da.StatusError,
Message: err.Error(),
},
}
}
}

txnsByteArray := []byte{}
for _, extrinsic := range appDataObject.Extrinsics {
txnsByteArray = append(txnsByteArray, []byte(extrinsic)...)
}

block := &types.Block{
SignedHeader: types.SignedHeader{
Header: types.Header{
BaseHeader: types.BaseHeader{
Height: blockNumber,
},
}},
Data: types.Data{
Txs: types.Txs{txnsByteArray},
},
}

blocks = append(blocks, block)

return da.ResultRetrieveBlocks{
BaseResult: da.BaseResult{
Code: da.StatusSuccess,
DAHeight: uint64(appDataObject.Block),
},
Blocks: blocks,
}
}
88 changes: 88 additions & 0 deletions da/avail/datasubmit/submitdata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package datasubmit

import (
"errors"

gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4"
"github.com/centrifuge/go-substrate-rpc-client/v4/signature"
"github.com/centrifuge/go-substrate-rpc-client/v4/types"
)

// submit data submits the extrinsic through substrate api
func SubmitData(apiURL string, seed string, appID int, data []byte) error {

// if app id is greater than 0 then it must be created before submitting data
if appID < 1 {
return errors.New("AppID cant be 0")
}

api, err := gsrpc.NewSubstrateAPI(apiURL)
if err != nil {
return err
}

meta, err := api.RPC.State.GetMetadataLatest()
if err != nil {
return err
}

c, err := types.NewCall(meta, "DataAvailability.submit_data", data)
if err != nil {
return err
}

// Create the extrinsic
ext := types.NewExtrinsic(c)

genesisHash, err := api.RPC.Chain.GetBlockHash(0)
if err != nil {
return err
}

rv, err := api.RPC.State.GetRuntimeVersionLatest()
if err != nil {
return err
}

keyringPair, err := signature.KeyringPairFromSecret(seed, 42)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a secure way of doing it. Did you check other cosmos implementations on how this is being handled?

if err != nil {
return err
}

key, err := types.CreateStorageKey(meta, "System", "Account", keyringPair.PublicKey)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to create storate key everytime we are trying to submit the data?

if err != nil {
return err
}

var accountInfo types.AccountInfo
ok, err := api.RPC.State.GetStorageLatest(key, &accountInfo)
if err != nil || !ok {
return errors.New("failed to get the latest storage")
}

nonce := uint32(accountInfo.Nonce)
signOptions := types.SignatureOptions{
BlockHash: genesisHash,
Era: types.ExtrinsicEra{IsMortalEra: false},
GenesisHash: genesisHash,
Nonce: types.NewUCompactFromUInt(uint64(nonce)),
SpecVersion: rv.SpecVersion,
Tip: types.NewUCompactFromUInt(0),
AppID: types.NewUCompactFromUInt(uint64(appID)),
TransactionVersion: rv.TransactionVersion,
}

// Sign the transaction
err = ext.Sign(keyringPair, signOptions)
if err != nil {
return err
}

// Send the extrinsic
_, err = api.RPC.Author.SubmitExtrinsic(ext)
if err != nil {
return err
}

return nil
}
3 changes: 3 additions & 0 deletions da/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"fmt"

"github.com/rollkit/rollkit/da"
"github.com/rollkit/rollkit/da/avail"
"github.com/rollkit/rollkit/da/celestia"

"github.com/rollkit/rollkit/da/grpc"
"github.com/rollkit/rollkit/da/mock"
)
Expand All @@ -23,6 +25,7 @@ var clients = map[string]func() da.DataAvailabilityLayerClient{
"mock": func() da.DataAvailabilityLayerClient { return &mock.DataAvailabilityLayerClient{} },
"grpc": func() da.DataAvailabilityLayerClient { return &grpc.DataAvailabilityLayerClient{} },
"celestia": func() da.DataAvailabilityLayerClient { return &celestia.DataAvailabilityLayerClient{} },
"avail": func() da.DataAvailabilityLayerClient { return &avail.DataAvailabilityLayerClient{} },
}

// GetClient returns client identified by name.
Expand Down
Loading
Loading