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(rpc): chain RPCs #1147

Merged
merged 7 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
7 changes: 6 additions & 1 deletion app/node/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (

rpcserver "github.com/kwilteam/kwil-db/node/services/jsonrpc"
"github.com/kwilteam/kwil-db/node/services/jsonrpc/adminsvc"
"github.com/kwilteam/kwil-db/node/services/jsonrpc/chainsvc"
"github.com/kwilteam/kwil-db/node/services/jsonrpc/funcsvc"
"github.com/kwilteam/kwil-db/node/services/jsonrpc/usersvc"
)
Expand Down Expand Up @@ -94,7 +95,7 @@ func buildServer(ctx context.Context, d *coreDependencies) *server {
usersvc.WithPrivateMode(d.cfg.RPC.Private),
usersvc.WithChallengeExpiry(d.cfg.RPC.ChallengeExpiry),
usersvc.WithChallengeRateLimit(d.cfg.RPC.ChallengeRateLimit),
// usersvc.WithBlockAgeHealth(6*totalConsensusTimeouts.Dur()),
// usersvc.WithBlockAgeHealth(6*totalConsensusTimeouts.Dur()),
)

rpcServerLogger := d.logger.New("RPC")
Expand Down Expand Up @@ -125,6 +126,10 @@ func buildServer(ctx context.Context, d *coreDependencies) *server {
jsonRPCAdminServer.RegisterSvc(&funcsvc.Service{})
}

chainRpcSvcLogger := d.logger.New("CHAIN")
jsonChainSvc := chainsvc.NewService(chainRpcSvcLogger, node, vs, d.genesisCfg)
jsonRPCServer.RegisterSvc(jsonChainSvc)

s := &server{
cfg: d.cfg,
closers: closers,
Expand Down
7 changes: 3 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import (
"time"

"github.com/kwilteam/kwil-db/core/log"
ktypes "github.com/kwilteam/kwil-db/core/types"
"github.com/kwilteam/kwil-db/node/types"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be simplify to just use core types

"github.com/kwilteam/kwil-db/core/types"

"github.com/pelletier/go-toml/v2"
)
Expand Down Expand Up @@ -41,7 +40,7 @@ type GenesisConfig struct {
// Leader is the leader's public key.
Leader types.HexBytes `json:"leader"`
// Validators is the list of genesis validators (including the leader).
Validators []*ktypes.Validator `json:"validators"`
Validators []*types.Validator `json:"validators"`

// MaxBlockSize is the maximum size of a block in bytes.
MaxBlockSize int64 `json:"max_block_size"`
Expand Down Expand Up @@ -89,7 +88,7 @@ func DefaultGenesisConfig() *GenesisConfig {
ChainID: "kwil-test-chain",
InitialHeight: 0,
Leader: types.HexBytes{},
Validators: []*ktypes.Validator{},
Validators: []*types.Validator{},
DisabledGasCosts: true,
JoinExpiry: 14400,
VoteExpiry: 108000,
Expand Down
3 changes: 2 additions & 1 deletion contrib/docker/compose/postgres/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ services:
# POSTGRES_USER: kwild
# POSTGRES_PASSWORD: kwild
# POSTGRES_DB: kwild
volumes:
volumes:
- kwildb:/var/lib/postgresql/data

volumes:
kwildb:
driver: local

21 changes: 21 additions & 0 deletions core/rpc/client/chain/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package chain

import (
"context"

"github.com/kwilteam/kwil-db/core/types"
chaintypes "github.com/kwilteam/kwil-db/core/types/chain"
)

type Client interface {
Version(ctx context.Context) (string, error)
BlockByHeight(ctx context.Context, height int64) (*chaintypes.Block, error)
BlockByHash(ctx context.Context, hash types.Hash) (*chaintypes.Block, error)
BlockResultByHeight(ctx context.Context, height int64) (*chaintypes.BlockResult, error)
BlockResultByHash(ctx context.Context, hash types.Hash) (*chaintypes.BlockResult, error)
Tx(ctx context.Context, hash types.Hash) (*chaintypes.Tx, error)
Genesis(ctx context.Context) (*chaintypes.Genesis, error)
ConsensusParams(ctx context.Context) (*types.ConsensusParams, error)
Validators(ctx context.Context) (height int64, validators []*types.Validator, err error)
UnconfirmedTxs(ctx context.Context) (total int, txs []chaintypes.NamedTx, err error)
}
145 changes: 145 additions & 0 deletions core/rpc/client/chain/jsonrpc/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package jsonrpc

import (
"context"
"net/url"

rpcclient "github.com/kwilteam/kwil-db/core/rpc/client"
"github.com/kwilteam/kwil-db/core/rpc/client/chain"
"github.com/kwilteam/kwil-db/core/rpc/client/user"
userClient "github.com/kwilteam/kwil-db/core/rpc/client/user/jsonrpc"
chainjson "github.com/kwilteam/kwil-db/core/rpc/json/chain"
userjson "github.com/kwilteam/kwil-db/core/rpc/json/user"
"github.com/kwilteam/kwil-db/core/types"
chaintypes "github.com/kwilteam/kwil-db/core/types/chain"
)

// Client is a chain RPC client. It provides all methods of the user RPC
// service, plus methods that are specific to the chain service.
type Client struct {
*userClient.Client // expose all user service methods, and methods for chain svc
}

// Version reports the version of the running node.
func (c *Client) Version(ctx context.Context) (string, error) {
req := &userjson.VersionRequest{}
res := &userjson.VersionResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodVersion), req, res)
if err != nil {
return "", err
}
return res.KwilVersion, err
}

func (c *Client) BlockByHeight(ctx context.Context, height int64) (*chaintypes.Block, error) {
req := &chainjson.BlockRequest{
Height: height,
}
res := &chainjson.BlockResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodBlock), req, res)
if err != nil {
return nil, err
}
return (*chaintypes.Block)(res), nil
}

func (c *Client) BlockByHash(ctx context.Context, hash types.Hash) (*chaintypes.Block, error) {
req := &chainjson.BlockRequest{
Hash: hash,
}
res := &chainjson.BlockResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodBlock), req, res)
if err != nil {
return nil, err
}
return (*chaintypes.Block)(res), nil
}

func (c *Client) BlockResultByHeight(ctx context.Context, height int64) (*chaintypes.BlockResult, error) {
req := &chainjson.BlockResultRequest{
Height: height,
}
res := &chainjson.BlockResultResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodBlockResult), req, res)
if err != nil {
return nil, err
}
return (*chaintypes.BlockResult)(res), nil
}

func (c *Client) BlockResultByHash(ctx context.Context, hash types.Hash) (*chaintypes.BlockResult, error) {
req := &chainjson.BlockResultRequest{
Hash: hash,
}
res := &chainjson.BlockResultResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodBlockResult), req, res)
if err != nil {
return nil, err
}
return (*chaintypes.BlockResult)(res), nil
}

func (c *Client) Tx(ctx context.Context, hash types.Hash) (*chaintypes.Tx, error) {
req := &chainjson.TxRequest{
Hash: hash,
}
res := &chainjson.TxResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodTx), req, res)
if err != nil {
return nil, err
}
return (*chaintypes.Tx)(res), err
}

func (c *Client) Genesis(ctx context.Context) (*chaintypes.Genesis, error) {
req := &chainjson.GenesisRequest{}
res := &chainjson.GenesisResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodGenesis), req, res)
if err != nil {
return nil, err
}
return (*chaintypes.Genesis)(res), err
}

func (c *Client) ConsensusParams(ctx context.Context) (*types.ConsensusParams, error) {
req := &chainjson.ConsensusParamsRequest{}
res := &chainjson.ConsensusParamsResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodConsensusParams), req, res)
if err != nil {
return nil, err
}
return (*types.ConsensusParams)(res), nil
}

func (c *Client) Validators(ctx context.Context) (int64, []*types.Validator, error) {
req := &chainjson.ValidatorsRequest{}
res := &chainjson.ValidatorsResponse{}
err := c.CallMethod(ctx, string(chainjson.MethodValidators), req, res)
if err != nil {
return 0, nil, err
}

return res.Height, res.Validators, nil
}

func (c *Client) UnconfirmedTxs(ctx context.Context) (total int, tx []chaintypes.NamedTx, err error) {
req := &chainjson.UnconfirmedTxsRequest{}
res := &chainjson.UnconfirmedTxsResponse{}
err = c.CallMethod(ctx, string(chainjson.MethodUnconfirmedTxs), req, res)
if err != nil {
return 0, nil, err
}

return res.Total, res.Txs, nil
}

// NewClient constructs a new chain Client.
func NewClient(u *url.URL, opts ...rpcclient.RPCClientOpts) *Client {
userClient := userClient.NewClient(u, opts...)
return &Client{
Client: userClient,
}
}

var _ user.TxSvcClient = (*Client)(nil) // via embedded userClient.Client
var _ chain.Client = (*Client)(nil) // with extra methods
32 changes: 32 additions & 0 deletions core/rpc/json/chain/commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package chain

import (
"github.com/kwilteam/kwil-db/core/types"
)

type HealthRequest struct{}

type BlockRequest struct {
Height int64 `json:"height"`
// Hash is the block hash. If both Height and Hash are provided, hash will be used
Hash types.Hash `json:"hash"`
}

type BlockResultRequest struct {
Height int64 `json:"height"`
// Hash is the block hash. If both Height and Hash are provided, hash will be used
Hash types.Hash `json:"hash"`
}

type TxRequest struct {
Hash types.Hash `json:"hash"`
}

type GenesisRequest struct{}
type ConsensusParamsRequest struct{}
type ValidatorsRequest struct {
Height int64 `json:"height"`
}
type UnconfirmedTxsRequest struct {
Limit int `json:"limit"`
}
17 changes: 17 additions & 0 deletions core/rpc/json/chain/methods.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package chain

import (
jsonrpc "github.com/kwilteam/kwil-db/core/rpc/json"
)

const (
MethodVersion jsonrpc.Method = "chain.version"
MethodHealth jsonrpc.Method = "chain.health"
MethodBlock jsonrpc.Method = "chain.block"
MethodBlockResult jsonrpc.Method = "chain.block_result"
MethodTx jsonrpc.Method = "chain.tx"
MethodGenesis jsonrpc.Method = "chain.genesis"
MethodConsensusParams jsonrpc.Method = "chain.consensus_params"
MethodValidators jsonrpc.Method = "chain.validators"
MethodUnconfirmedTxs jsonrpc.Method = "chain.unconfirmed_txs"
)
66 changes: 66 additions & 0 deletions core/rpc/json/chain/responses.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package chain

import (
"encoding/json"

"github.com/kwilteam/kwil-db/core/types"
chaintypes "github.com/kwilteam/kwil-db/core/types/chain"
)

// HealthResponse is the health check response.
type HealthResponse struct {
ChainID string `json:"chain_id"`
Height int64 `json:"height"`
Healthy bool `json:"healthy"`
}

// BlockResponse is the block information
type BlockResponse chaintypes.Block

type BlockResultResponse chaintypes.BlockResult

type TxResponse chaintypes.Tx

// GenesisResponse is the same as kwil-db/config.GenesisConfig, with JSON tags.
type GenesisResponse chaintypes.Genesis

type ConsensusParamsResponse types.ConsensusParams

func (r ConsensusParamsResponse) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
// MaxBlockSize is the maximum size of a block in bytes.
MaxBlockSize int64 `json:"max_block_size"`
// JoinExpiry is the number of blocks after which the validators
// join request expires if not approved.
JoinExpiry int64 `json:"join_expiry"`
// VoteExpiry is the default number of blocks after which the validators
// vote expires if not approved.
VoteExpiry int64 `json:"vote_expiry"`
// DisabledGasCosts dictates whether gas costs are disabled.
DisabledGasCosts bool `json:"disabled_gas_costs"`

// MigrationStatus determines the status of the migration.
MigrationStatus string `json:"migration_status"`

// MaxVotesPerTx is the maximum number of votes that can be included in a
// single transaction.
MaxVotesPerTx int64 `json:"max_votes_per_tx"`
}{
MaxBlockSize: r.MaxBlockSize,
JoinExpiry: r.JoinExpiry,
VoteExpiry: r.VoteExpiry,
DisabledGasCosts: r.DisabledGasCosts,
MigrationStatus: string(r.MigrationStatus),
MaxVotesPerTx: r.MaxVotesPerTx,
})
}

type ValidatorsResponse struct {
Height int64 `json:"height"`
Validators []*types.Validator `json:"validators"`
}

type UnconfirmedTxsResponse struct {
Total int `json:"total"`
Txs []chaintypes.NamedTx `json:"txs"`
}
Loading
Loading