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

[DRAFT] CoreAccess #411

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions cmd/celestia/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ func init() {
cmdnode.P2PFlags(),
cmdnode.HeadersFlags(),
cmdnode.MiscFlags(),
// NOTE: for now, state-related queries can only be accessed
// over an RPC connection with a celestia-core node.
cmdnode.CoreFlags(),
),
cmdnode.Start(
cmdnode.NodeFlags(node.Light),
cmdnode.P2PFlags(),
cmdnode.HeadersFlags(),
cmdnode.MiscFlags(),
// NOTE: for now, state-related queries can only be accessed
// over an RPC connection with a celestia-core node.
cmdnode.CoreFlags(),
),
)
}
Expand Down Expand Up @@ -58,6 +64,11 @@ var lightCmd = &cobra.Command{
return err
}

err = cmdnode.ParseCoreFlags(cmd, env)
if err != nil {
return err
}

return nil
},
}
2 changes: 1 addition & 1 deletion core/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func StartRemoteClient() (*node.Node, Client, error) {
return remote, client, err
}

// StartRemoteCore starts a remote core and returns it's protocol and address
// StartRemoteCore starts a remote core and returns its protocol and address
func StartRemoteCore() (*node.Node, string, string) {
remote := StartMockNode(CreateKvStore(defaultRetainBlocks))
protocol, ip := getRemoteEndpoint(remote)
Expand Down
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ require (
github.com/celestiaorg/go-libp2p-messenger v0.1.0
github.com/celestiaorg/nmt v0.8.0
github.com/celestiaorg/rsmt2d v0.3.0
github.com/gogo/protobuf v1.3.2
github.com/cosmos/cosmos-sdk v0.45.1
github.com/gogo/protobuf v1.3.3
github.com/hashicorp/go-retryablehttp v0.7.1-0.20211018174820-ff6d014e72d9
github.com/hashicorp/golang-lru v0.5.4
github.com/ipfs/go-bitswap v0.4.0
Expand Down Expand Up @@ -39,10 +40,15 @@ require (
github.com/multiformats/go-multihash v0.1.0
github.com/spf13/cobra v1.3.0
github.com/spf13/pflag v1.0.5
github.com/strangelove-ventures/lens v0.2.1
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942
github.com/tendermint/tendermint v0.34.14
go.uber.org/fx v1.16.0
go.uber.org/zap v1.20.0
)

replace github.com/tendermint/tendermint v0.34.14 => github.com/celestiaorg/celestia-core v0.34.14-celestia

replace github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v0.44.2-0.20220117152225-998142f4eef9

replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
385 changes: 359 additions & 26 deletions go.sum

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion node/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,35 @@ package node
import (
"context"

lens "github.com/strangelove-ventures/lens/client"

nodecore "github.com/celestiaorg/celestia-node/node/core"
"github.com/celestiaorg/celestia-node/node/fxutil"
"github.com/celestiaorg/celestia-node/node/p2p"
"github.com/celestiaorg/celestia-node/node/services"
statecomponents "github.com/celestiaorg/celestia-node/node/state"
"github.com/celestiaorg/celestia-node/service/header"
"github.com/celestiaorg/celestia-node/service/state"
)

// lightComponents keeps all the components as DI options required to built a Light Node.
func lightComponents(cfg *Config, store Store) fxutil.Option {
return fxutil.Options(
// condition for adding state-related components
opts := fxutil.Options(
fxutil.Supply(Light),
baseComponents(cfg, store),
fxutil.Provide(services.DASer),
fxutil.Provide(services.HeaderExchangeP2P(cfg.Services)),
// state components
fxutil.ProvideIf(cfg.Core.Remote, state.NewService),
fxutil.ProvideIf(cfg.Core.Remote, func() (*lens.ChainClient, error) {
return statecomponents.ChainClient(cfg.Core, store.Path())
}),
fxutil.ProvideIf(cfg.Core.Remote, func(cc *lens.ChainClient) state.Accessor {
return state.NewCoreAccessor(cc)
}),
)
return opts
}

// bridgeComponents keeps all the components as DI options required to build a Bridge Node.
Expand Down
20 changes: 20 additions & 0 deletions node/light_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/celestiaorg/celestia-node/core"
)

func TestNewLight(t *testing.T) {
Expand All @@ -19,6 +21,8 @@ func TestNewLight(t *testing.T) {
require.NotNil(t, nd.Config)
require.NotNil(t, nd.HeaderServ)
assert.NotZero(t, nd.Type)
// ensure that state service is not constructed if TrustedCore is not provided
require.Nil(t, nd.StateServ)
}

func TestLightLifecycle(t *testing.T) {
Expand Down Expand Up @@ -88,3 +92,19 @@ func TestLight_WithBootstrapPeers(t *testing.T) {

assert.Equal(t, node.Config.P2P.BootstrapPeers, peers)
}

func TestLight_WithStateServiceOverCore(t *testing.T) {
// start a remote mock core node
nd, protocol, endpoint := core.StartRemoteCore()
defer nd.Stop() // nolint:errcheck
// create Light config and add remote as trusted peer
conf := DefaultConfig(Light)
// create store for node
repo := MockStore(t, conf)
// create light node
node, err := New(Light, repo, WithRemoteCore(protocol, endpoint))
require.NoError(t, err)
defer node.Stop(context.Background()) // nolint:errcheck
// check to ensure node's state service is not nil
require.NotNil(t, node.StateServ)
}
2 changes: 2 additions & 0 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/celestiaorg/celestia-node/service/block"
"github.com/celestiaorg/celestia-node/service/header"
"github.com/celestiaorg/celestia-node/service/share"
"github.com/celestiaorg/celestia-node/service/state"
)

const Timeout = time.Second * 15
Expand Down Expand Up @@ -56,6 +57,7 @@ type Node struct {
BlockServ *block.Service `optional:"true"`
ShareServ share.Service // not optional
HeaderServ *header.Service // not optional
StateServ *state.Service `optional:"true"`

DASer *das.DASer `optional:"true"`

Expand Down
6 changes: 3 additions & 3 deletions node/services/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ type Config struct {
// TrustedHash is the Block/Header hash that Nodes use as starting point for header synchronization.
// Only affects the node once on initial sync.
TrustedHash string
// TrustedPeer is the peer we trust to fetch headers from.
// Note: The trusted does *not* imply Headers are not verified, but trusted as reliable to fetch headers
// at any moment.
// TrustedPeer is the multiaddr of the peer we trust to fetch headers from.
// Note: The trusted does *not* imply Headers are not verified, but trusted
// as reliable to fetch headers at any moment.
TrustedPeer string
}

Expand Down
32 changes: 32 additions & 0 deletions node/state/core.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package state

import (
"fmt"
"os"

lens "github.com/strangelove-ventures/lens/client"

"github.com/celestiaorg/celestia-node/node/core"
)

// ChainClient constructs a new `lens.ChainClient` that can be used
// to access state-related information over the active celestia-core
// connection.
func ChainClient(cfg core.Config, storePath string) (*lens.ChainClient, error) {
// TODO @renaynay: eventually handle for bridge nodes so that CC constructor can
// take a Client interface https://github.com/strangelove-ventures/lens/pull/94
conf := DefaultCelestiaChainClientConfig(cfg, fmt.Sprintf("%s/keys", storePath))
return lens.NewChainClient(conf, storePath, os.Stdin, os.Stdout)
}

func DefaultCelestiaChainClientConfig(cfg core.Config, keyDir string) *lens.ChainClientConfig {
return &lens.ChainClientConfig{
Key: "default", // TODO @renaynay idk about this
ChainID: "celestia-1", // TODO @renaynay should be hardcoded somewhere as a var
RPCAddr: fmt.Sprintf("%s://%s", cfg.RemoteConfig.Protocol, cfg.RemoteConfig.RemoteAddr),
KeyDirectory: keyDir,
Timeout: "20s",
OutputFormat: "json",
KeyringBackend: "test", // TODO @renaynay: fix this
}
}
36 changes: 36 additions & 0 deletions node/state/core_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package state

import (
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/celestiaorg/celestia-node/core"
core_components "github.com/celestiaorg/celestia-node/node/core"
)

func TestChainClient(t *testing.T) {
nd, _, ip := core.StartRemoteCore()
//nolint:errcheck
defer nd.Stop()

cfg := core_components.DefaultConfig()
cfg.RemoteConfig.RemoteAddr = ip
cfg.RemoteConfig.Protocol = "http"
cfg.Remote = true

dir, err := ioutil.TempDir("", "prefix")
require.NoError(t, err)
defer os.RemoveAll(dir)

cc, err := ChainClient(cfg, dir)
require.NoError(t, err)
require.NotNil(t, cc)

latestHeight, err := cc.QueryLatestHeight()
require.NoError(t, err)
assert.Equal(t, int64(0), latestHeight)
}
52 changes: 52 additions & 0 deletions service/state/core_access.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package state

import (
"context"
"fmt"
lens "github.com/strangelove-ventures/lens/client"
)

// CoreAccessor implements Accessor over an RPC connection
// with a celestia-core node.
type CoreAccessor struct {
client *lens.ChainClient
}

// NewCoreAccessor returns a new CoreAccessor with the
// given ChainClient.
func NewCoreAccessor(cc *lens.ChainClient) *CoreAccessor {
return &CoreAccessor{
client: cc,
}
}

// CurrentBalance gets current balance of the node's account.
func (ca *CoreAccessor) CurrentBalance() (Balance, error) {
acc, err := ca.client.AccountFromKeyOrAddress(ca.client.Key())
if err != nil {
return Balance{}, err
}

balances, err := ca.client.QueryBalanceWithAddress(acc.String())
if err != nil {
return Balance{}, err
}

// TODO @renaynay: will `celestia` balance always be first?
return balances[0], nil
}

func (ca *CoreAccessor) AccountBalance(account Account) (Balance, error) {
coins, err := ca.client.QueryBalanceWithAddress(account.GetAddress().String())
if err != nil {
return Balance{}, err
}
if len(coins) == 0 {
return Balance{}, fmt.Errorf("no balance returned for account: %s", account.GetAddress().String())
}
return coins[0], nil
}

func (ca *CoreAccessor) SubmitTx(ctx context.Context, tx Msg) (*TxResponse, error) {
return ca.client.SendMsg(ctx, tx)
}
67 changes: 67 additions & 0 deletions service/state/core_access_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package state

import (
"context"
"fmt"
"os"
"testing"

lens "github.com/strangelove-ventures/lens/client"
"github.com/stretchr/testify/require"

"github.com/celestiaorg/celestia-node/core"
)

func TestCoreAccessor_CurrentBalance(t *testing.T) {
// construct a chain client
cc := constructChainClient(t)

// construct a core accessor
accessor := NewCoreAccessor(cc)
bal, err := accessor.CurrentBalance(context.Background())
require.NoError(t, err)
t.Log("BAL: ", bal)
}

func constructChainClient(t *testing.T) *lens.ChainClient {
// start remote core node
nd, _, endpoint := core.StartRemoteCore()
t.Cleanup(func() {
//nolint:errcheck
nd.Stop()
})

tmpDir := t.TempDir()
conf := &lens.ChainClientConfig{
Key: "default",
ChainID: "",
RPCAddr: fmt.Sprintf("http://%s", endpoint),
AccountPrefix: "celes",
KeyringBackend: "test",
GasAdjustment: 1.2,
GasPrices: "0.01uosmo",
KeyDirectory: tmpDir,
Debug: true,
Timeout: "20s",
OutputFormat: "json",
SignModeStr: "direct",
Modules: lens.ModuleBasics,
}
// conf := &lens.ChainClientConfig{
// ChainID: "celestia",
// AccountPrefix: "celes",
// Key: "default",
// KeyringBackend: keyring.BackendTest,
// KeyDirectory: tmpDir,
// Debug: false,
// RPCAddr: fmt.Sprintf("http://%s", endpoint),
// }

cc, err := lens.NewChainClient(conf, tmpDir, os.Stdin, os.Stderr)
require.NoError(t, err)

err = cc.Init()
require.NoError(t, err)

return cc
}
21 changes: 21 additions & 0 deletions service/state/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package state

import "context"

var Token = "celestia"

// Accessor represents the behaviors necessary for a user to
// query for state-related information and submit transactions/
// messages to the celestia network.
type Accessor interface {
// CurrentBalance retrieves the Celestia coin balance
// for the node's Account.
CurrentBalance() (Balance, error)
// AccountBalance retrieves the Celestia coin balance
// for the given Account.
AccountBalance(Account) (Balance, error)
// SubmitTx submits the given transaction/message to the
// Celestia network.
// TODO @renaynay @wondertan: do we call this SubmitTx or SubmitMsg?
SubmitTx(context.Context, Msg) (*TxResponse, error)
}
Loading