Skip to content

Commit

Permalink
feat: enable data availiability verification via vote extensions (#25)
Browse files Browse the repository at this point in the history
* feat: added transactions

* feat: implement client

* fix tx issue

* feat: pause previous code

* adding client injection

* custom txclient

* fix: client issue debug

* new chain client

* debug client init

* update create client

* import mnemonic

* docs

* Update README.md

* update docs

* execute submit tx through client

* fix keyring issue

* import key

* fix

* refactor

* update submitblob tx

* new query

* feat: changes

* handle error

* post data to da

* execute update tx after da submission

* fix

* query and tx

* update msg

* feat: fixed range errors

* feat: vote extensions

* refactor core lgic

* feat: enable vote extensions

* feat: enable vote extensions

* feat: fix vote extensions bug

* feat: fix vote extensions bug

* fix: config script for vote extension height

* fix typo

* fix client

* feat: enable vote extensions

* remove deadcode

* feat: light client data verification

* feat: enable light client verification

* fix

* refactor: review changes

* remove unused code

* refactor: review changes

* feat: review changes

---------

Co-authored-by: PrathyushaLakkireddy <[email protected]>
Co-authored-by: Prathyusha Lakkireddy <[email protected]>
  • Loading branch information
3 people authored Sep 17, 2024
1 parent 23fc678 commit da99450
Show file tree
Hide file tree
Showing 39 changed files with 2,408 additions and 2,646 deletions.
55 changes: 54 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,59 @@

CADA is a module designed to connect Cosmos sovereign chains with the Avail network, making it easier for any Cosmos chain or rollapp to use Avail as their Data Availability (DA) layer. With CADA, developers can improve the scalability and security of their decentralized applications within the Cosmos ecosystem. It enables better data handling and availability, allowing Cosmos-based chains to tap into the strengths of Avail and build a more connected and resilient blockchain network.

For detailed instructions on how to integrate the module with a Cosmos SDK application, please refer to the [integration guide](./docs/integration.md).
For example:
Let blobInterval = 10,
- At height `11`, blocks from `1` to `10` are posted.
- At height `21`, blocks from `11` to `20` are posted.

#### Relayer
The `Relayer` acts as the transport layer, responsible for handling requests from the `prepareBlocker` and facilitating transactions between the Cosmos chain and the Avail DA network. It performs key functions such as submitting block data to Avail and updating block status on the Cosmos chain. Every validator in the network is required to run the relayer process.

#### Proven Height
The `Proven Height` signifies the most recent block height of the Cosmos chain where data has been successfully transmitted to Avail and validated by the network.

## Architecture

![Screenshot from 2024-08-27 11-35-01](https://github.com/user-attachments/assets/1a8657f6-4c1b-418a-8295-05c039baa6d0)


1. **Block Interval Trigger**:
- At each block interval, a request is sent from `PrepareProposal` abci method to the relayer, specifying the range of block heights to be posted to the Avail DA network. This request should be made by the block proposer only.

2. **MsgSubmitBlobRequest Transaction**:
- The relayer submits a `MsgSubmitBlobRequest` transaction on the Cosmos chain, signaling that the block data for the specified range is pending:
```
status[range] = pending
```
- The relayer monitors the transaction to confirm its successful inclusion and processing on the chain.
3. **Data Submission to Avail DA**:
- Once the `MsgSubmitBlobRequest` transaction is confirmed, the relayer fetches the block data for the specified range and submits it to the Avail DA layer.
4. **MsgUpdateBlobStatusRequest Transaction**:
- After confirming that the data is available on Avail, the relayer submits a `MsgUpdateBlobStatusRequest` transaction on the Cosmos chain, updating the block status to pre-verification:
```
status[range] = IN_VOTING
```
5. **Validator Confirmation**:
- Within a preconfigured block limit, all validators are required to verify the data's availability on the Avail network using their Avail light clients and cast their votes.
we could use voteExtension to cast the votes
6. **Consensus and Proven Height Update**:
- If the number of votes exceeds the consensus threshold, the status of the block range is updated to success, and the `Proven Height` is advanced:
```
status[range] = success
// Update the proven height
if range.from == provenHeight + 1 {
provenHeight = range.to
}
```
7. **Failure Handling**:
- In case of any failures or expiration of the verification window, the data will be reposted following the same procedure.
---
For detailed instructions on how to integrate the module with a spawn generated application, please refer to the [integration guide](./docs/spawn.md).
90 changes: 90 additions & 0 deletions chainclient/broadcast_tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package chainclient

import (
"fmt"
"log"
"os"

cometrpc "github.com/cometbft/cometbft/rpc/client/http"
clitx "github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/vitwit/avail-da-module/types"

"path/filepath"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)

func GetBinPath() string {
homeDir, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
}

availdHomePath := filepath.Join(homeDir, ".availsdk")
return availdHomePath
}

func ExecuteTX(ctx sdk.Context, msg types.MsgUpdateBlobStatusRequest, cdc codec.BinaryCodec) error {
// Define keyring and RPC client configuration

// homePath := "/home/vitwit/.availsdk"
homePath := GetBinPath()
key := os.Getenv("KEY")
fmt.Println("get key namee.........", key)
if key == "" { //TODO : remove this later
key = "alice"
}
keyName := key
rpcAddress := "http://localhost:26657"

// Create a keyring
kr, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, homePath, os.Stdin, cdc.(codec.Codec))
if err != nil {
return fmt.Errorf("error creating keyring: %w", err)
}

info, err := kr.Key(keyName)
valAddr, err := info.GetAddress()
fmt.Println("after address................", valAddr)

// Create an RPC client
rpcClient, err := cometrpc.NewWithTimeout(rpcAddress, "/websocket", 3)
if err != nil {
return fmt.Errorf("error creating RPC client: %w", err)
}

// Create a new client context
clientCtx := NewClientCtx(kr, rpcClient, ctx.ChainID(), cdc, homePath, valAddr)

// Set the client context's from fields
clientCtx.FromName = keyName
clientCtx.FromAddress = valAddr

// Fetch account number and sequence from the blockchain
accountRetriever := authtypes.AccountRetriever{}
account, err := accountRetriever.GetAccount(clientCtx, valAddr)
if err != nil {
return fmt.Errorf("error retrieving account: %w", err)
}

fmt.Println("account details......", account.GetAccountNumber(), account.GetSequence())

// Set the correct account number and sequence
factory := NewFactory(clientCtx).
WithAccountNumber(account.GetAccountNumber()).
WithSequence(account.GetSequence())

// Create a transaction factory and set the validator address in the message
// factory := NewFactory(clientCtx)
msg.ValidatorAddress = valAddr.String()

// Generate and broadcast the transaction
if err := clitx.GenerateOrBroadcastTxWithFactory(clientCtx, factory, &msg); err != nil {
return fmt.Errorf("error broadcasting transaction: %w", err)
}

return nil
}
29 changes: 29 additions & 0 deletions chainclient/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package chainclient

import (
"bytes"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
)

const (
KeyringBackendTest = "test"
)

// ChainClient is client to interact with SPN.
type ChainClient struct {
factory tx.Factory
clientCtx client.Context
out *bytes.Buffer
Address string `json:"address"`
AddressPrefix string `json:"account_address_prefix"`
RPC string `json:"rpc"`
Key string `json:"key"`
Mnemonic string `json:"mnemonic"`
KeyringServiceName string `json:"keyring_service_name"`
HDPath string `json:"hd_path"`
Enabled bool `json:"enabled"`
ChainName string `json:"chain_name"`
Denom string `json:"denom"`
}
153 changes: 153 additions & 0 deletions chainclient/create_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package chainclient

import (
"fmt"

cometrpc "github.com/cometbft/cometbft/rpc/client/http"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/std"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authTx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/go-bip39"

// "github.com/tendermint/starport/starport/pkg/xfilepath"

"github.com/cosmos/cosmos-sdk/types/module"
)

const (
defaultGasAdjustment = 1.0
defaultGasLimit = 300000
)

// var availdHomePath = xfilepath.JoinFromHome(xfilepath.Path("availsdk"))

func NewClientCtx(kr keyring.Keyring, c *cometrpc.HTTP, chainID string,
cdc codec.BinaryCodec, homepath string, fromAddress sdk.AccAddress) client.Context {
encodingConfig := MakeEncodingConfig()

broadcastMode := flags.BroadcastSync

return client.Context{}.
WithCodec(cdc.(codec.Codec)).
WithChainID(chainID).
WithFromAddress(fromAddress).
WithFromName("testkey").
WithKeyringDir(homepath).
WithBroadcastMode(broadcastMode).
WithTxConfig(authTx.NewTxConfig(cdc.(codec.Codec), authTx.DefaultSignModes)).
WithKeyring(kr).
WithAccountRetriever(authtypes.AccountRetriever{}).
WithClient(c).WithInterfaceRegistry(encodingConfig.InterfaceRegistry).
WithSkipConfirmation(true)
}

// NewFactory creates a new Factory.
func NewFactory(clientCtx client.Context) tx.Factory {
return tx.Factory{}.
WithChainID(clientCtx.ChainID).
WithKeybase(clientCtx.Keyring).
WithGas(defaultGasLimit).
WithGasAdjustment(defaultGasAdjustment).
WithSignMode(signing.SignMode_SIGN_MODE_DIRECT).
WithAccountRetriever(clientCtx.AccountRetriever).
WithTxConfig(clientCtx.TxConfig)
}

// MakeEncodingConfig creates an EncodingConfig for an amino based test configuration.
func MakeEncodingConfig(modules ...module.AppModuleBasic) EncodingConfig {
aminoCodec := codec.NewLegacyAmino()
interfaceRegistry := codectypes.NewInterfaceRegistry()
codec := codec.NewProtoCodec(interfaceRegistry)
txCfg := authTx.NewTxConfig(codec, authTx.DefaultSignModes)

encCfg := EncodingConfig{
InterfaceRegistry: interfaceRegistry,
Codec: codec,
TxConfig: txCfg,
Amino: aminoCodec,
}

mb := module.NewBasicManager(modules...)

std.RegisterLegacyAminoCodec(encCfg.Amino)
std.RegisterInterfaces(encCfg.InterfaceRegistry)
mb.RegisterLegacyAminoCodec(encCfg.Amino)
mb.RegisterInterfaces(encCfg.InterfaceRegistry)

return encCfg
}

// EncodingConfig specifies the concrete encoding types to use for a given app.
// This is provided for compatibility between protobuf and amino implementations.
type EncodingConfig struct {
InterfaceRegistry codectypes.InterfaceRegistry
Codec codec.Codec
TxConfig client.TxConfig
Amino *codec.LegacyAmino
}

// ImportMnemonic is to import existing account mnemonic in keyring
func ImportMnemonic(keyName, mnemonic, hdPath string, c client.Context) (*keyring.Record, error) {
info, err := AccountCreate(keyName, mnemonic, hdPath, c) // return account also
if err != nil {
return nil, err
}

return info, nil
}

// AccountCreate creates an account by name and mnemonic (optional) in the keyring.
func AccountCreate(accountName, mnemonic, hdPath string, c client.Context) (*keyring.Record, error) {
if mnemonic == "" {
entropySeed, err := bip39.NewEntropy(256)
if err != nil {
return nil, err
}
mnemonic, err = bip39.NewMnemonic(entropySeed)
if err != nil {
return nil, err
}
}

algos, _ := c.Keyring.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(string(hd.Secp256k1Type), algos)
if err != nil {
return nil, err
}

path := hd.CreateHDPath(118, 0, 0).String()
// fmt.Println("pathhh......", path)

// record, str, err := c.Keyring.NewMnemonic("test_key1", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
// fmt.Println("recorddddd.......", err, str, record)

// k, _, err = kb.NewMnemonic("test", English, types.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
info, err := c.Keyring.NewAccount(accountName, mnemonic, keyring.DefaultBIP39Passphrase, path, algo)
fmt.Println("after creationnnn.........", info, err)
if err != nil {
return nil, err
}
// pk, err := info.GetPubKey()
// if err != nil {
// return nil, err
// }

// addr := sdk.AccAddress(pk.Address())
// fmt.Println("address hereee...", addr)

// aa, err := info.GetAddress()
// fmt.Println("here aa and err.......", aa, err)

// account := c.ToAccount(info)
// account.Mnemonic = mnemonic
return info, nil
}
34 changes: 34 additions & 0 deletions client/cli/query.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package cli

import (
"log"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"
availblob "github.com/vitwit/avail-da-module"
"github.com/vitwit/avail-da-module/types"
)

func GetQueryCmd() *cobra.Command {
Expand All @@ -13,5 +17,35 @@ func GetQueryCmd() *cobra.Command {
RunE: client.ValidateCmd,
}

cmd.AddCommand(GetLatestBlobStatusInfo())

return cmd
}

func GetLatestBlobStatusInfo() *cobra.Command {
cmd := &cobra.Command{
Use: "get-da-status",
Short: "Show what range of blocks are being submitted and thier status",
Long: `Show what range of blocks are being submitted and thier status,
`,
Example: "simd query cada get-da-status",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

req := &types.QuerySubmittedBlobStatusRequest{}
res, err := queryClient.SubmittedBlobStatus(cmd.Context(), req)
if err != nil {
log.Fatal(err)
}

return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
Loading

0 comments on commit da99450

Please sign in to comment.