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

feat: decouple avail light client #41

Merged
merged 11 commits into from
Sep 19, 2024
2 changes: 1 addition & 1 deletion keeper/vote_extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (h *VoteExtHandler) ExtendVoteHandler() sdk.ExtendVoteHandler {
return abciResponseVoteExt, nil
}

ok, err := h.Keeper.relayer.IsDataAvailable(ctx, from, end, availHeight, h.Keeper.relayer.AvailConfig.LightClientURL) // TODO: read light client url from config
ok, err := h.Keeper.relayer.IsDataAvailable(ctx, from, end, availHeight)
if ok {
h.logger.Info("submitted data to Avail verified successfully at",
"block_height", availHeight,
Expand Down
8 changes: 8 additions & 0 deletions relayer/avail/da.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package avail

// implement this interface to interact with avail chain
type DA interface {
Submit(data []byte) (BlockMetaData, error)
Teja2045 marked this conversation as resolved.
Show resolved Hide resolved
IsDataAvailable(data []byte, availBlockHeight int) (bool, error)
GetBlock(availBlockHeight int) (Block, error)
}
93 changes: 93 additions & 0 deletions relayer/avail/light_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package avail

import (
"encoding/base64"
"encoding/json"
"fmt"

http_client "github.com/vitwit/avail-da-module/relayer/http"
)

// AvailLightClient is a concrete implementation of the availDA interface.
// It facilitates interaction with the Avail Network by utilizing the Avail light client.
//
// Fields:
// - HttpClient: An HTTP client handler used for making requests to the Avail light client.
// - LightClientURL: The URL of the Avail light client that this module communicates with.
type LightClient struct {
HTTPClient *http_client.Handler
LightClientURL string
}

func NewLightClient(lightClientURL string, httpClient *http_client.Handler) *LightClient {
return &LightClient{
HTTPClient: httpClient,
LightClientURL: lightClientURL,
}
}

func (lc *LightClient) IsDataAvailable(data []byte, availBlockHeight int) (bool, error) {
availBlock, err := lc.GetBlock(availBlockHeight)
if err != nil {
return false, err
}

base64CosmosBlockData := base64.StdEncoding.EncodeToString(data)

// TODO: any better / optimized way to check if data is really available?
return isDataIncludedInBlock(availBlock, base64CosmosBlockData), nil
}

func (lc *LightClient) GetBlock(availBlockHeight int) (Block, error) {
// Construct the URL with the block number
url := fmt.Sprintf("%s/v2/blocks/%v/data?fields=data", lc.LightClientURL, availBlockHeight)

// Perform the GET request, returning the body directly
body, err := lc.HTTPClient.Get(url)
if err != nil {
return Block{}, fmt.Errorf("failed to fetch data from the avail: %w", err)
}

// Decode the response body into the AvailBlock struct
var block Block
err = json.Unmarshal(body, &block)
if err != nil {
return Block{}, fmt.Errorf("failed to decode block response: %w", err)
}

return block, nil
}

func (lc *LightClient) Submit(data []byte) (BlockMetaData, error) {
var blockInfo BlockMetaData

datab := base64.StdEncoding.EncodeToString(data)
jsonData := []byte(fmt.Sprintf(`{"data":"%s"}`, datab))
url := fmt.Sprintf("%s/v2/submit", lc.LightClientURL)

// Make the POST request
responseBody, err := lc.HTTPClient.Post(url, jsonData)
if err != nil {
fmt.Printf("Error: %v\n", err)
return blockInfo, err
}

// Unmarshal the JSON data into the struct
err = json.Unmarshal(responseBody, &blockInfo)
if err != nil {
return BlockMetaData{}, err
}

return blockInfo, nil
}

// bruteforce comparison check
func isDataIncludedInBlock(availBlock Block, base64cosmosData string) bool {
for _, data := range availBlock.Extrinsics {
if data.Data == base64cosmosData {
return true
}
}

return false
}
17 changes: 17 additions & 0 deletions relayer/avail/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package avail

type BlockMetaData struct {
BlockNumber int `json:"block_number"`
BlockHash string `json:"block_hash"`
Hash string `json:"hash"`
Index int `json:"index"`
}

type Block struct {
Block int64 `json:"block_number"`
Extrinsics []Extrinsics `json:"data_transactions"`
}

type Extrinsics struct {
Data string `json:"data"`
}
25 changes: 6 additions & 19 deletions relayer/http_client.go → relayer/http/http_client_handler.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package relayer
package httpclient

import (
"bytes"
Expand All @@ -9,21 +9,21 @@ import (
)

// HTTPClientHandler struct
type HTTPClientHandler struct {
type Handler struct {
client *http.Client
}

// NewHTTPClientHandler creates a new HTTPClientHandler with default settings
func NewHTTPClientHandler() *HTTPClientHandler {
return &HTTPClientHandler{
func NewHandler() *Handler {
return &Handler{
client: &http.Client{
Timeout: 100 * time.Second,
},
}
}

// Get method
func (h *HTTPClientHandler) Get(url string) ([]byte, error) {
func (h *Handler) Get(url string) ([]byte, error) {
resp, err := h.client.Get(url)
if err != nil {
return nil, fmt.Errorf("GET request error: %v", err)
Expand All @@ -38,7 +38,7 @@ func (h *HTTPClientHandler) Get(url string) ([]byte, error) {
}

// Post method
func (h *HTTPClientHandler) Post(url string, jsonData []byte) ([]byte, error) {
func (h *Handler) Post(url string, jsonData []byte) ([]byte, error) {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("error creating request: %v", err)
Expand All @@ -58,16 +58,3 @@ func (h *HTTPClientHandler) Post(url string, jsonData []byte) ([]byte, error) {
}
return body, nil
}

// RequestData struct for the POST request payload
type RequestData struct {
Data []byte `json:"data,omitempty"`
Extrinsic string `json:"extrinsic,omitempty"`
}

type BlockInfo struct {
BlockNumber int `json:"block_number"`
BlockHash string `json:"block_hash"`
Hash string `json:"hash"`
Index int `json:"index"`
}
5 changes: 3 additions & 2 deletions relayer/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ import (
cada "github.com/vitwit/avail-da-module"
module "github.com/vitwit/avail-da-module/module"
relayer "github.com/vitwit/avail-da-module/relayer"
httpclient "github.com/vitwit/avail-da-module/relayer/http"
)

type RelayerTestSuite struct {
suite.Suite

ctx sdk.Context
httpHandler relayer.HTTPClientHandler
httpHandler *httpclient.Handler
addrs []sdk.AccAddress
encCfg moduletestutil.TestEncodingConfig
addressCodec addresstypes.Codec
Expand Down Expand Up @@ -54,7 +55,7 @@ func (s *RelayerTestSuite) SetupTest() {
s.baseApp.SetInterfaceRegistry(s.encCfg.InterfaceRegistry)
s.addrs = simtestutil.CreateIncrementalAccounts(7)

s.httpHandler = *relayer.NewHTTPClientHandler()
s.httpHandler = httpclient.NewHandler()

s.relayer = &relayer.Relayer{}
}
4 changes: 2 additions & 2 deletions relayer/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ func (r *Relayer) postBlocks(ctx sdk.Context, blocks []int64, cdc codec.BinaryCo

bb := r.GetBlocksDataFromLocal(ctx, blocks)

blockInfo, err := r.SubmitDataToAvailClient(r.AvailConfig.Seed, r.AvailConfig.AppID, bb, blocks, r.AvailConfig.LightClientURL)
blockInfo, err := r.SubmitDataToAvailClient(bb, blocks)
if err != nil {
r.logger.Error("Error while submitting block(s) to Avail DA",
"height_start", blocks[0],
"height_end", blocks[len(blocks)-1],
"appID", strconv.Itoa(r.AvailConfig.AppID),
"appID", strconv.Itoa(r.AvailConfig.AppID), err,
)

// execute tx about failure submission
Expand Down
9 changes: 5 additions & 4 deletions relayer/relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/vitwit/avail-da-module/relayer/avail"
"github.com/vitwit/avail-da-module/relayer/local"
"github.com/vitwit/avail-da-module/types"
)
Expand All @@ -31,6 +31,7 @@ type Relayer struct {
submittedBlocksCache map[int64]bool

localProvider *local.CosmosProvider
availDAClient avail.DA
clientCtx client.Context

availChainID string
Expand All @@ -42,11 +43,10 @@ type Relayer struct {
func NewRelayer(
logger log.Logger,
cdc codec.BinaryCodec,
appOpts servertypes.AppOptions,
cfg types.AvailConfiguration,
nodeDir string,
daClient avail.DA,
) (*Relayer, error) {
cfg := types.AvailConfigFromAppOpts(appOpts)

// local sdk-based chain provider
localProvider, err := local.NewProvider(cdc, cfg.CosmosNodeRPC)
if err != nil {
Expand All @@ -64,6 +64,7 @@ func NewRelayer(
submittedBlocksCache: make(map[int64]bool),
NodeDir: nodeDir,
AvailConfig: cfg,
availDAClient: daClient,
}, nil
}

Expand Down
Loading
Loading