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

service/state: Provide simple scaffold for StateService and implement CoreAccess #420

Merged
merged 33 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
59880d7
CoreAccessor
renaynay Jan 31, 2022
04bb0a9
update ADR with changes made to CoreAccess design
renaynay Feb 11, 2022
f33cb0e
cleanup
renaynay Feb 13, 2022
3003997
use new insecure.NewCredentials w grpc cli
renaynay Feb 13, 2022
dc16c61
keyconf documentation
renaynay Feb 13, 2022
6f025ed
add doc.go
renaynay Feb 15, 2022
5079afe
document service struct
renaynay Feb 15, 2022
9399b27
remove unnecessary type aliases
renaynay Feb 15, 2022
edd0a48
add lifecycle hooks
renaynay Feb 15, 2022
615d018
test: failing due to cel-app panic with InitChain
renaynay Feb 16, 2022
d8d27fa
chore|refactor: go mod tidy & change grpc dial to DialContext
renaynay Feb 25, 2022
be0add8
fix: add watchdog dep
renaynay Feb 25, 2022
07e7ae4
chore: lint
renaynay Mar 1, 2022
54be1dd
refactor: dont return err with constructor
renaynay Mar 1, 2022
2065fc3
docs: update state ADR to remove mentions of lens
renaynay Mar 7, 2022
cf976ac
fix: remove unused encCfg field from CoreAccess
renaynay Mar 7, 2022
2ebf8ce
refactor: remove KeyConfig and use "default" as KeyringAccName by def…
renaynay Mar 8, 2022
acea07c
chore: mod tidy
renaynay Mar 8, 2022
e35079f
refactor: setup queryClient in Start of CoreAccess
renaynay Mar 8, 2022
edaa05f
docs: fix typo in lightComponents doc
renaynay Mar 8, 2022
a6ff606
comment out test
renaynay Mar 10, 2022
8149dfe
chore: lint
renaynay Mar 11, 2022
5b8334f
bug: grpc needs insecure credentials
renaynay Mar 22, 2022
1904ecb
refactor: BalanceForAddress takes types.AccAddress instead of string,…
renaynay Mar 25, 2022
c704661
refactor: use BroadcastMode_BROADCAST_MODE_BLOCK as default for tx su…
renaynay Mar 25, 2022
c73a978
feat: add SubmitTxWithBroadcastMode but dont add to StateAccessor int…
renaynay Mar 26, 2022
9a9b18c
refactor: pass keystore to constructor instead of string to path and …
renaynay Mar 26, 2022
97148ea
chore: update celestia-core dep to prevent weird lint error
renaynay Mar 29, 2022
a68e0a9
refactor: add state serv to baseComponents
renaynay Mar 29, 2022
3741929
refactor: BalanceForAddress takes a types.Address from cosmos sdk ins…
renaynay Mar 29, 2022
3858b80
doc: fix typo
renaynay Mar 29, 2022
db90c98
test: delete unit test for core access as it doesnt work in favour of…
renaynay Mar 30, 2022
2fa5545
refactor: add params.Network after rebase
renaynay Mar 30, 2022
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
},
}
13 changes: 7 additions & 6 deletions core/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,21 @@ func MockEmbeddedClient() Client {
// mock Core Client.
func StartRemoteClient() (*node.Node, Client, error) {
remote := StartMockNode(CreateKvStore(defaultRetainBlocks))
protocol, ip := getRemoteEndpoint(remote)
protocol, ip := GetRemoteEndpoint(remote)
client, err := NewRemote(protocol, ip)
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)
app := CreateKvStore(defaultRetainBlocks)
remote := StartMockNode(app)
protocol, ip := GetRemoteEndpoint(remote)
return remote, protocol, ip
}

// getRemoteEndpoint returns the protocol and ip of the remote node.
func getRemoteEndpoint(remote *node.Node) (string, string) {
// GetRemoteEndpoint returns the protocol and ip of the remote node.
func GetRemoteEndpoint(remote *node.Node) (string, string) {
endpoint := remote.Config().RPC.ListenAddress
// protocol = "tcp"
protocol, ip := endpoint[:3], endpoint[6:]
Expand Down
113 changes: 65 additions & 48 deletions docs/adr/adr-004-state-interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
## Changelog

* 2022-01-14: initial draft
* 2022-02-11: update to interface and `CoreAccess` implementation details

<hr style="border:2px solid gray"> </hr>

Expand All @@ -19,95 +20,112 @@ and public state of others.

## Decision

Both celestia **light** and **full** nodes will run `StateService`.
Both celestia **light** and **full** nodes will run `StateService`.
`StateService` will be responsible for managing the RPC endpoints provided by `StateAccessor`.

`StateAccessor` will be an interface for interacting with celestia-core in order to retrieve account-related information
as well as submit transactions.

### `StateService`

`StateService` will expose several higher-level RPC endpoints for users to access the methods provided by the
`StateService` will expose several higher-level RPC endpoints for users to access the methods provided by the
`StateAccessor`.

```go
type StateService struct {
accessor StateAccessor
accessor StateAccessor
}
```

### `StateAccessor`

`StateAccessor` is defined by the two methods listed below and may be expanded in the future to include more methods
`StateAccessor` is defined by the two methods listed below and may be expanded in the future to include more methods
related to accounts and transactions in later iterations.

```go
type StateAccessor interface {
// AccountBalance returns the Celestia Balance for the given Account
func AccountBalance(context.Context, Account) (Balance, error)
// SubmitTx submits the given Tx, where Tx implements sdk.Msg
func SubmitTx(context.Context, Tx) error
// Balance retrieves the Celestia coin balance
// for the node's account/signer.
Balance(ctx context.Context) (*Balance, error)
// BalanceForAddress retrieves the Celestia coin balance
// for the given address (given as `types.AccAddress` from cosmos-SDK).
BalanceForAddress(ctx context.Context, addr types.AccAddress) (*Balance, error)
// SubmitTx submits the given transaction/message to the
// Celestia network and blocks until the tx is included in
// a block.
SubmitTx(ctx context.Context, tx Tx) (*TxResponse, error)
}
```

`StateAccessor` will have 3 separate implementations under the hood, the first of which will be outlined in this ADR:
`StateAccessor` will have 3 separate implementations under the hood, the first of which will be outlined in this ADR:

1. **CORE**: RPC connection with a celestia-core endpoint handed to the node upon initialisation
(*required for this iteration*)
2. **P2P**: discovery of a **bridge** node or other node that is able to provide state (*nice-to-have for this iteration*)
3. **LOCAL**: eventually, **full** nodes will be able to provide state to the network, and can therefore execute and
respond to the queries without relaying queries to celestia-core (*to be scoped out and implemented in later iterations*)
(*required for this iteration*)
2. **P2P**: discovery of a **bridge** node or other node that is able to provide state (*nice-to-have for this
iteration*)
3. **LOCAL**: eventually, **full** nodes will be able to provide state to the network, and can therefore execute and
respond to the queries without relaying queries to celestia-core (*to be scoped out and implemented in later
iterations*)

### 1. Core Implementation of `StateAccessor`: `CoreAccess`

`CoreAccess` will be the direct RPC connection implementation of `StateAccessor`. It will use the [lens implementation of ChainClient](https://github.com/strangelove-ventures/lens/blob/main/client/chain_client.go#L23)
under the hood. `lens.ChainClient` provides a nice wrapper around the Cosmos-SDK APIs.
`CoreAccess` will be the direct RPC connection implementation of `StateAccessor`. It will maintain a gRPC connection
with a celestia-core node under the hood.

Upon node initialisation, the node will receive the endpoint of a trusted celestia-core node. The constructor for
`CoreAccess` will construct a new instance of `CoreAccess` with the `lens.ChainClient` pointing at the given
celestia-core endpoint.
Upon node initialisation, the node will receive the endpoint of a trusted celestia-core node. The constructor for
`CoreAccess` will create a new instance of `CoreAccess`, and the given celestia-core endpoint will only be dialed upon
start.

```go
type CoreAccess struct {
cc *lens.ChainClient
signer *apptypes.KeyringSigner
encCfg cosmoscmd.EncodingConfig

coreEndpoint string
coreConn *grpc.ClientConn
}

func NewCoreAccess(cc *lens.ChainClient) (*CoreAccess, error) {
return &CoreAccess{
cc: cc,
}, nil
func (ca *CoreAccessor) BalanceForAddress(ctx context.Context, addr string) (*Balance, error) {
queryCli := banktypes.NewQueryClient(ca.coreConn)

balReq := &banktypes.QueryBalanceRequest{
Address: addr,
Denom: app.DisplayDenom,
}

balResp, err := queryCli.Balance(ctx, balReq)
if err != nil {
return nil, err
}

return balResp.Balance, nil
}

// where Account wraps account information and Balance
func (ca *CoreAccess) AccountBalance(ctx context.Context, acct Account) (Balance, error) {
coins, err := da.cc.QueryBalanceWithAddress(acct.Address)
if err != nil {
return err
}
// returning first index as we only care for account's balance on celestia chain
return coins[0], nil
func (ca *CoreAccessor) SubmitTx(ctx context.Context, tx Tx) (*TxResponse, error) {
txResp, err := apptypes.BroadcastTx(ctx, ca.coreConn, sdk_tx.BroadcastMode_BROADCAST_MODE_SYNC, tx)
if err != nil {
return nil, err
}
return txResp.TxResponse, nil
}

// where Tx implements sdk.Msg
func (ca *CoreAccess) SubmitTx(ctx context.Context, tx Tx) (TxResponse, error) {
return da.cc.SendMsg(ctx, tx)
}
```

### 2. P2P Implementation of `StateAccessor`: `P2PAccess`

While it is not necessary to detail how `P2PAccess` will be implemented in this ADR, it will still conform to the
`StateAccessor` interface, but instead of being provided a core endpoint to connect to via RPC and using `lens.ChainClient`
for state-related queries, `P2PAccess` will perform service discovery of state-providing nodes in the network and perform
the state queries via libp2p streams. More details of the p2p implementation will be described in a separate dedicated ADR.
While it is not necessary to detail how `P2PAccess` will be implemented in this ADR, it will still conform to the
`StateAccessor` interface, but instead of being provided a core endpoint to connect to via RPC, `P2PAccess` will perform
service discovery of state-providing nodes in the network and perform the state queries via libp2p streams. More details
of the p2p implementation will be described in a separate dedicated ADR.

```go
type P2PAccess struct {
// for discovery and communication
// with state-providing nodes
host host.Host
// for managing keys
keybase keyring.Keyring
keyringOptions []keyring.Option
// for discovery and communication
// with state-providing nodes
host host.Host
// for managing keys
keybase keyring.Keyring
keyringOptions []keyring.Option
}
```

Expand All @@ -116,6 +134,5 @@ type P2PAccess struct {
A **bridge** node will run a `StateProvider` (server-side of `P2PAccessor`). The `StateProvider` will be responsible for
relaying the state-related queries through to its trusted celestia-core node.

The `StateProvider` will be initialised with a `lens.ChainClient` that will be used under the hood for communication
with its already-configured celestia-core RPC connection. It will listen for inbound state-related queries from its
peers and relay the received payloads to celestia-core.
The `StateProvider` will be initialised with a celestia-core RPC connection. It will listen for inbound state-related
queries from its peers and relay the received payloads to celestia-core.
Loading