Skip to content

Commit

Permalink
feat(da): added default config and config verification
Browse files Browse the repository at this point in the history
  • Loading branch information
keruch committed Jul 2, 2024
1 parent de0a32a commit 4bf7af9
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 24 deletions.
37 changes: 32 additions & 5 deletions da/da.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,6 @@ type DataAvailabilityLayerClient interface {
// triggers a state transition in the DA layer.
SubmitBatch(batch *types.Batch) ResultSubmitBatch

// SubmitBatchV2 is a method that supports MsgUpdateStateV2.
SubmitBatchV2(*types.Batch) ResultSubmitBatchV2

GetClientType() Client

// CheckBatchAvailability checks the availability of the blob submitted getting proofs and validating them
Expand All @@ -248,13 +245,43 @@ type DataAvailabilityLayerClient interface {
Synced() <-chan struct{}
}

// ClientV2 defines generic interface for DA layer block submission.
type ClientV2 interface {
// DataAvailabilityLayerClient closure for backward compatibility
DataAvailabilityLayerClient

// Init is called once to allow DA client to read configuration and initialize resources.
Init([]byte, *pubsub.Server, store.KV, types.Logger, ...Option) error

// Start is called once, after Init. It starts the operation of ClientV2.
Start() error

// Stop is called once, when DAClientV2 is no longer needed.
Stop() error

// SubmitBatchV2 submits the passed in block to the DA layer.
SubmitBatchV2(*types.Batch) ResultSubmitBatchV2

GetClientType() Client

Synced() <-chan struct{}
}

// BatchRetriever is additional interface that can be implemented by Data Availability Layer Client that is able to retrieve
// block data from DA layer. This gives the ability to use it for block synchronization.
type BatchRetriever interface {
// RetrieveBatches returns blocks at given data layer height from data availability layer.
RetrieveBatches(daMetaData *DASubmitMetaData) ResultRetrieveBatch
// RetrieveBatchesV2 is a method that supports MsgUpdateStateV2.
RetrieveBatchesV2(ResultSubmitBatchV2) ResultRetrieveBatchV2
// CheckBatchAvailability checks the availability of the blob received getting proofs and validating them
CheckBatchAvailability(daMetaData *DASubmitMetaData) ResultCheckBatch
}

// BatchRetrieverV2 is an additional interface implemented by the DA layer client. It allows to retrieve
// block data from the DA layer and use this interface for block synchronization.
type BatchRetrieverV2 interface {
// BatchRetriever closure for backward compatibility
BatchRetriever

// RetrieveBatchesV2 returns blocks by the given da.Path.
RetrieveBatchesV2(ResultSubmitBatchV2) ResultRetrieveBatchV2
}
80 changes: 73 additions & 7 deletions da/interchain/config.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package interchain

import (
"errors"
"os"
"path/filepath"
"time"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"

interchainda "github.com/dymensionxyz/dymint/types/pb/interchain_da"
)

Expand All @@ -25,17 +31,77 @@ type DAConfig struct {
RetryAttempts uint `mapstructure:"retry_attempts"`
}

func (c *DAConfig) Verify() error {
if c.ClientID == "" {
return errors.New("missing IBC client ID")
}

if c.ChainID == "" {
return errors.New("missing Chain ID of the DA layer")
}

if c.KeyringBackend == "" {
return errors.New("missing Keyring Backend")
}

if c.KeyringHomeDir == "" {
return errors.New("missing Keyring HomeDir")
}

if c.AddressPrefix == "" {
return errors.New("missing Address Prefix")
}

if c.AccountName == "" {
return errors.New("missing Account Name")
}

if c.NodeAddress == "" {
return errors.New("missing Node Address")
}

if c.GasLimit == 0 {
return errors.New("missing Gas Limit")
}

if c.GasPrices == "" && c.GasFees == "" {
return errors.New("either gas prices or gas_prices are required")
}

if c.GasPrices != "" && c.GasFees != "" {
return errors.New("cannot provide both fees and gas prices")
}

// DAParams are set during Init

if c.RetryMinDelay.Nanoseconds() == 0 {
return errors.New("missing Retry MinDelay")
}

if c.RetryMaxDelay.Nanoseconds() == 0 {
return errors.New("missing Retry MaxDelay")
}

if c.RetryAttempts == 0 {
return errors.New("missing Retry Attempts")
}

return nil
}

func DefaultDAConfig() DAConfig {
home, _ := os.UserHomeDir()
keyringHomeDir := filepath.Join(home, ".simapp")
return DAConfig{
ClientID: "",
ChainID: "",
KeyringBackend: "",
KeyringHomeDir: "",
AddressPrefix: "",
AccountName: "",
NodeAddress: "",
ChainID: "interchain-da-test",
KeyringBackend: keyring.BackendTest,
KeyringHomeDir: keyringHomeDir,
AddressPrefix: sdk.Bech32MainPrefix,
AccountName: "sequencer",
NodeAddress: "http://127.0.0.1:36657",
GasLimit: 0,
GasPrices: "",
GasPrices: "10stake",
GasFees: "",
DAParams: interchainda.Params{},
RetryMinDelay: 100 * time.Millisecond,
Expand Down
14 changes: 8 additions & 6 deletions da/interchain/interchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import (
)

var (
_ da.DataAvailabilityLayerClient = &DALayerClient{}
_ da.BatchRetriever = &DALayerClient{}
_ da.ClientV2 = &DALayerClient{}
_ da.BatchRetrieverV2 = &DALayerClient{}
)

type DAClient interface {
Expand All @@ -42,8 +42,6 @@ type DALayerClient struct {
cdc codec.Codec
synced chan struct{}

pubsubServer *pubsub.Server

daClient DAClient
daConfig DAConfig
}
Expand All @@ -59,6 +57,11 @@ func (c *DALayerClient) Init(rawConfig []byte, _ *pubsub.Server, _ store.KV, log
return fmt.Errorf("invalid config: %w", err)
}

err = config.Verify()
if err != nil {
return fmt.Errorf("intechain DA config verification failed: %w", err)
}

// Create cosmos client with DA layer
client, err := newDAClient(ctx, config)
if err != nil {
Expand Down Expand Up @@ -108,7 +111,6 @@ func (c *DALayerClient) Start() error {

// Stop is called once, when DALayerClient is no longer needed.
func (c *DALayerClient) Stop() error {
c.pubsubServer.Stop()
c.cancel()
return nil
}
Expand All @@ -123,5 +125,5 @@ func (c *DALayerClient) GetClientType() da.Client {
}

func (c *DALayerClient) CheckBatchAvailability(daMetaData *da.DASubmitMetaData) da.ResultCheckBatch {
panic("implement me")
panic("CheckBatchAvailability method is not supported by the interchain DA clint")
}
2 changes: 1 addition & 1 deletion da/interchain/retrieve_batches.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package interchain
import "github.com/dymensionxyz/dymint/da"

func (c *DALayerClient) RetrieveBatches(daMetaData *da.DASubmitMetaData) da.ResultRetrieveBatch {
panic("implement me")
panic("RetrieveBatches method is not supported by the interchain DA clint")
}

func (c *DALayerClient) RetrieveBatchesV2(da.ResultSubmitBatchV2) da.ResultRetrieveBatchV2 {
Expand Down
14 changes: 9 additions & 5 deletions da/interchain/submit_batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,34 +59,36 @@ func (c *DALayerClient) SubmitBatchV2(batch *types.Batch) da.ResultSubmitBatchV2
}
}

type submitBatchResult struct {
BlobID uint64
BlobHash string
}

// submitBatch is used to process and transmit batches to the interchain DA.
func (c *DALayerClient) submitBatch(batch *types.Batch) (*interchainda.Commitment, error) {
// Prepare the blob data
blob, err := batch.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("can't marshal batch: %w", err)
}

// Gzip the blob
gzipped, err := ioutils.Gzip(blob)
if err != nil {
return nil, fmt.Errorf("can't gzip batch: %w", err)
}

// Verify the size of the blob is within the limit
if len(blob) > int(c.daConfig.DAParams.MaxBlobSize) {
return nil, fmt.Errorf("blob size %d exceeds the maximum allowed size %d", len(blob), c.daConfig.DAParams.MaxBlobSize)
}

// Calculate the fees of submitting this blob
feesToPay := sdk.NewCoin(c.daConfig.DAParams.CostPerByte.Denom, c.daConfig.DAParams.CostPerByte.Amount.MulRaw(int64(len(blob))))

// Prepare the message to be sent to the DA layer
msg := interchainda.MsgSubmitBlob{
Creator: c.daConfig.AccountName,
Blob: gzipped,
Fees: feesToPay,
}

// Broadcast the message to the DA layer applying retries in case of failure
var txResp cosmosclient.Response
err = c.runWithRetry(func() error {
txResp, err = c.broadcastTx(&msg)
Expand All @@ -96,12 +98,14 @@ func (c *DALayerClient) submitBatch(batch *types.Batch) (*interchainda.Commitmen
return nil, fmt.Errorf("can't broadcast MsgSubmitBlob to DA layer: %w", err)
}

// Decode the response
var resp interchainda.MsgSubmitBlobResponse
err = txResp.Decode(&resp)
if err != nil {
return nil, fmt.Errorf("can't decode MsgSubmitBlob response: %w", err)
}

// Get Merkle proof of the blob ID inclusion
key, err := collections.EncodeKeyWithPrefix(
interchainda.BlobMetadataPrefix(),
collcodec.NewUint64Key[interchainda.BlobID](),
Expand Down

0 comments on commit 4bf7af9

Please sign in to comment.