WIP: Nitro integration #65

Closed
roysc wants to merge 38 commits from roy/dev-nitro-bank into main
168 changed files with 9283 additions and 7946 deletions

View File

@ -1,4 +1,4 @@
FROM golang:1.21-bullseye AS builder
FROM golang:1.23.6-bookworm AS builder
# Set working directory for the build
WORKDIR /go/src/git.vdb.to/cerc-io/laconicd
@ -14,21 +14,25 @@ COPY . .
RUN make build
# Final image
FROM ubuntu:22.04
# DEV golang image
FROM golang:1.23.6-bookworm AS base
# FROM ubuntu:24.04
# Install ca-certificates, jq, curl, bash, and other necessary packages
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
jq curl netcat bash \
jq yq curl netcat-openbsd bash \
&& rm -rf /var/lib/apt/lists/*
# Copy over binary from the builder
COPY --from=builder /go/src/git.vdb.to/cerc-io/laconicd/build/laconicd /usr/bin/laconicd
# FROM base
# Copy over init script from builder
COPY --from=builder /go/src/git.vdb.to/cerc-io/laconicd/scripts/init.sh scripts/init.sh
# # Copy over binary from the builder
# COPY --from=builder /go/src/git.vdb.to/cerc-io/laconicd/build/laconicd /usr/bin/laconicd
WORKDIR /
# # Copy over init script from builder
# COPY --from=builder /go/src/git.vdb.to/cerc-io/laconicd/scripts/init.sh scripts/init.sh
# WORKDIR /
# Run laconicd by default
CMD ["laconicd"]
ENTRYPOINT ["laconicd"]

View File

@ -7,12 +7,14 @@ LACONIC_BINARY = laconicd
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
COMMIT := $(shell git log -1 --format='%H')
COSMOS_BUILD_OPTIONS := v2
# don't override user values
ifeq (,$(VERSION))
VERSION := $(shell git describe --exact-match 2>/dev/null)
# if VERSION is empty, then populate it with branch's name and raw commit hash
ifeq (,$(VERSION))
VERSION := $(BRANCH)-$(COMMIT)
VERSION := $(BRANCH)-$(COMMIT)
endif
endif
@ -31,7 +33,7 @@ BUILDDIR ?= $(CURDIR)/build
###########
go.sum: go.mod
echo "Ensure dependencies have not been modified ..." >&2
@echo "Ensure dependencies have not been modified ..." >&2
go mod verify
go mod tidy
@ -42,7 +44,7 @@ build-linux:
GOOS=linux GOARCH=amd64 LEDGER_ENABLED=false $(MAKE) build
$(BUILD_TARGETS): go.sum $(BUILDDIR)/
@echo "--> installing laconicd"
@echo "--> $@ing laconicd"
go $@ $(BUILD_FLAGS) $(BUILD_ARGS) ./...
$(BUILDDIR)/:
@ -56,9 +58,10 @@ all: install
### Protobuf ###
##################
protoVer=0.14.0
protoVer=0.15.3
protoImageName=ghcr.io/cosmos/proto-builder:$(protoVer)
protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName)
protoVolumes=-v $(shell readlink -f ..):/mod
protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoVolumes) $(protoImageName)
proto-all: proto-format proto-lint proto-gen
@ -106,3 +109,7 @@ test-e2e:
test-unit:
go test ./utils/... ./cmd/... -mod=readonly -test.v
test-system: build
test -d ./tests/system/binaries || ln -sf $(BUILDDIR) ./tests/system/binaries
go test ./tests/system -test.v -timeout 10m

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cerc/auction/v1/query.proto
@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Query_Params_FullMethodName = "/cerc.auction.v1.Query/Params"
@ -32,6 +32,8 @@ const (
// QueryClient is the client API for Query service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Query defines the gRPC querier interface for the auction module
type QueryClient interface {
// Params queries auction module params
Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error)
@ -60,8 +62,9 @@ func NewQueryClient(cc grpc.ClientConnInterface) QueryClient {
}
func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryParamsResponse)
err := c.cc.Invoke(ctx, Query_Params_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Params_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -69,8 +72,9 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts .
}
func (c *queryClient) Auctions(ctx context.Context, in *QueryAuctionsRequest, opts ...grpc.CallOption) (*QueryAuctionsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryAuctionsResponse)
err := c.cc.Invoke(ctx, Query_Auctions_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Auctions_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -78,8 +82,9 @@ func (c *queryClient) Auctions(ctx context.Context, in *QueryAuctionsRequest, op
}
func (c *queryClient) GetAuction(ctx context.Context, in *QueryGetAuctionRequest, opts ...grpc.CallOption) (*QueryGetAuctionResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetAuctionResponse)
err := c.cc.Invoke(ctx, Query_GetAuction_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetAuction_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -87,8 +92,9 @@ func (c *queryClient) GetAuction(ctx context.Context, in *QueryGetAuctionRequest
}
func (c *queryClient) GetBid(ctx context.Context, in *QueryGetBidRequest, opts ...grpc.CallOption) (*QueryGetBidResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetBidResponse)
err := c.cc.Invoke(ctx, Query_GetBid_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetBid_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -96,8 +102,9 @@ func (c *queryClient) GetBid(ctx context.Context, in *QueryGetBidRequest, opts .
}
func (c *queryClient) GetBids(ctx context.Context, in *QueryGetBidsRequest, opts ...grpc.CallOption) (*QueryGetBidsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetBidsResponse)
err := c.cc.Invoke(ctx, Query_GetBids_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetBids_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -105,8 +112,9 @@ func (c *queryClient) GetBids(ctx context.Context, in *QueryGetBidsRequest, opts
}
func (c *queryClient) AuctionsByBidder(ctx context.Context, in *QueryAuctionsByBidderRequest, opts ...grpc.CallOption) (*QueryAuctionsByBidderResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryAuctionsByBidderResponse)
err := c.cc.Invoke(ctx, Query_AuctionsByBidder_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_AuctionsByBidder_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -114,8 +122,9 @@ func (c *queryClient) AuctionsByBidder(ctx context.Context, in *QueryAuctionsByB
}
func (c *queryClient) AuctionsByOwner(ctx context.Context, in *QueryAuctionsByOwnerRequest, opts ...grpc.CallOption) (*QueryAuctionsByOwnerResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryAuctionsByOwnerResponse)
err := c.cc.Invoke(ctx, Query_AuctionsByOwner_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_AuctionsByOwner_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -123,8 +132,9 @@ func (c *queryClient) AuctionsByOwner(ctx context.Context, in *QueryAuctionsByOw
}
func (c *queryClient) GetAuctionModuleBalance(ctx context.Context, in *QueryGetAuctionModuleBalanceRequest, opts ...grpc.CallOption) (*QueryGetAuctionModuleBalanceResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetAuctionModuleBalanceResponse)
err := c.cc.Invoke(ctx, Query_GetAuctionModuleBalance_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetAuctionModuleBalance_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -133,7 +143,9 @@ func (c *queryClient) GetAuctionModuleBalance(ctx context.Context, in *QueryGetA
// QueryServer is the server API for Query service.
// All implementations must embed UnimplementedQueryServer
// for forward compatibility
// for forward compatibility.
//
// Query defines the gRPC querier interface for the auction module
type QueryServer interface {
// Params queries auction module params
Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error)
@ -154,9 +166,12 @@ type QueryServer interface {
mustEmbedUnimplementedQueryServer()
}
// UnimplementedQueryServer must be embedded to have forward compatible implementations.
type UnimplementedQueryServer struct {
}
// UnimplementedQueryServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedQueryServer struct{}
func (UnimplementedQueryServer) Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Params not implemented")
@ -183,6 +198,7 @@ func (UnimplementedQueryServer) GetAuctionModuleBalance(context.Context, *QueryG
return nil, status.Errorf(codes.Unimplemented, "method GetAuctionModuleBalance not implemented")
}
func (UnimplementedQueryServer) mustEmbedUnimplementedQueryServer() {}
func (UnimplementedQueryServer) testEmbeddedByValue() {}
// UnsafeQueryServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to QueryServer will
@ -192,6 +208,13 @@ type UnsafeQueryServer interface {
}
func RegisterQueryServer(s grpc.ServiceRegistrar, srv QueryServer) {
// If the following call pancis, it indicates UnimplementedQueryServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Query_ServiceDesc, srv)
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cerc/auction/v1/tx.proto
@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Msg_CreateAuction_FullMethodName = "/cerc.auction.v1.Msg/CreateAuction"
@ -29,6 +29,8 @@ const (
// MsgClient is the client API for Msg service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Tx defines the gRPC tx interface
type MsgClient interface {
// CreateAuction is the command for creating an auction
CreateAuction(ctx context.Context, in *MsgCreateAuction, opts ...grpc.CallOption) (*MsgCreateAuctionResponse, error)
@ -52,8 +54,9 @@ func NewMsgClient(cc grpc.ClientConnInterface) MsgClient {
}
func (c *msgClient) CreateAuction(ctx context.Context, in *MsgCreateAuction, opts ...grpc.CallOption) (*MsgCreateAuctionResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgCreateAuctionResponse)
err := c.cc.Invoke(ctx, Msg_CreateAuction_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_CreateAuction_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -61,8 +64,9 @@ func (c *msgClient) CreateAuction(ctx context.Context, in *MsgCreateAuction, opt
}
func (c *msgClient) CommitBid(ctx context.Context, in *MsgCommitBid, opts ...grpc.CallOption) (*MsgCommitBidResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgCommitBidResponse)
err := c.cc.Invoke(ctx, Msg_CommitBid_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_CommitBid_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -70,8 +74,9 @@ func (c *msgClient) CommitBid(ctx context.Context, in *MsgCommitBid, opts ...grp
}
func (c *msgClient) RevealBid(ctx context.Context, in *MsgRevealBid, opts ...grpc.CallOption) (*MsgRevealBidResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgRevealBidResponse)
err := c.cc.Invoke(ctx, Msg_RevealBid_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_RevealBid_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -79,8 +84,9 @@ func (c *msgClient) RevealBid(ctx context.Context, in *MsgRevealBid, opts ...grp
}
func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgUpdateParamsResponse)
err := c.cc.Invoke(ctx, Msg_UpdateParams_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_UpdateParams_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -88,8 +94,9 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts
}
func (c *msgClient) ReleaseFunds(ctx context.Context, in *MsgReleaseFunds, opts ...grpc.CallOption) (*MsgReleaseFundsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgReleaseFundsResponse)
err := c.cc.Invoke(ctx, Msg_ReleaseFunds_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_ReleaseFunds_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -98,7 +105,9 @@ func (c *msgClient) ReleaseFunds(ctx context.Context, in *MsgReleaseFunds, opts
// MsgServer is the server API for Msg service.
// All implementations must embed UnimplementedMsgServer
// for forward compatibility
// for forward compatibility.
//
// Tx defines the gRPC tx interface
type MsgServer interface {
// CreateAuction is the command for creating an auction
CreateAuction(context.Context, *MsgCreateAuction) (*MsgCreateAuctionResponse, error)
@ -114,9 +123,12 @@ type MsgServer interface {
mustEmbedUnimplementedMsgServer()
}
// UnimplementedMsgServer must be embedded to have forward compatible implementations.
type UnimplementedMsgServer struct {
}
// UnimplementedMsgServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedMsgServer struct{}
func (UnimplementedMsgServer) CreateAuction(context.Context, *MsgCreateAuction) (*MsgCreateAuctionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateAuction not implemented")
@ -134,6 +146,7 @@ func (UnimplementedMsgServer) ReleaseFunds(context.Context, *MsgReleaseFunds) (*
return nil, status.Errorf(codes.Unimplemented, "method ReleaseFunds not implemented")
}
func (UnimplementedMsgServer) mustEmbedUnimplementedMsgServer() {}
func (UnimplementedMsgServer) testEmbeddedByValue() {}
// UnsafeMsgServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MsgServer will
@ -143,6 +156,13 @@ type UnsafeMsgServer interface {
}
func RegisterMsgServer(s grpc.ServiceRegistrar, srv MsgServer) {
// If the following call pancis, it indicates UnimplementedMsgServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Msg_ServiceDesc, srv)
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cerc/bond/v1/query.proto
@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Query_Params_FullMethodName = "/cerc.bond.v1.Query/Params"
@ -29,6 +29,8 @@ const (
// QueryClient is the client API for Query service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Query defines the gRPC querier service for bond module
type QueryClient interface {
// Params queries bonds module params.
Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error)
@ -51,8 +53,9 @@ func NewQueryClient(cc grpc.ClientConnInterface) QueryClient {
}
func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryParamsResponse)
err := c.cc.Invoke(ctx, Query_Params_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Params_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -60,8 +63,9 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts .
}
func (c *queryClient) Bonds(ctx context.Context, in *QueryBondsRequest, opts ...grpc.CallOption) (*QueryBondsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryBondsResponse)
err := c.cc.Invoke(ctx, Query_Bonds_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Bonds_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -69,8 +73,9 @@ func (c *queryClient) Bonds(ctx context.Context, in *QueryBondsRequest, opts ...
}
func (c *queryClient) GetBondById(ctx context.Context, in *QueryGetBondByIdRequest, opts ...grpc.CallOption) (*QueryGetBondByIdResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetBondByIdResponse)
err := c.cc.Invoke(ctx, Query_GetBondById_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetBondById_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -78,8 +83,9 @@ func (c *queryClient) GetBondById(ctx context.Context, in *QueryGetBondByIdReque
}
func (c *queryClient) GetBondsByOwner(ctx context.Context, in *QueryGetBondsByOwnerRequest, opts ...grpc.CallOption) (*QueryGetBondsByOwnerResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetBondsByOwnerResponse)
err := c.cc.Invoke(ctx, Query_GetBondsByOwner_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetBondsByOwner_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -87,8 +93,9 @@ func (c *queryClient) GetBondsByOwner(ctx context.Context, in *QueryGetBondsByOw
}
func (c *queryClient) GetBondModuleBalance(ctx context.Context, in *QueryGetBondModuleBalanceRequest, opts ...grpc.CallOption) (*QueryGetBondModuleBalanceResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetBondModuleBalanceResponse)
err := c.cc.Invoke(ctx, Query_GetBondModuleBalance_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetBondModuleBalance_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -97,7 +104,9 @@ func (c *queryClient) GetBondModuleBalance(ctx context.Context, in *QueryGetBond
// QueryServer is the server API for Query service.
// All implementations must embed UnimplementedQueryServer
// for forward compatibility
// for forward compatibility.
//
// Query defines the gRPC querier service for bond module
type QueryServer interface {
// Params queries bonds module params.
Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error)
@ -112,9 +121,12 @@ type QueryServer interface {
mustEmbedUnimplementedQueryServer()
}
// UnimplementedQueryServer must be embedded to have forward compatible implementations.
type UnimplementedQueryServer struct {
}
// UnimplementedQueryServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedQueryServer struct{}
func (UnimplementedQueryServer) Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Params not implemented")
@ -132,6 +144,7 @@ func (UnimplementedQueryServer) GetBondModuleBalance(context.Context, *QueryGetB
return nil, status.Errorf(codes.Unimplemented, "method GetBondModuleBalance not implemented")
}
func (UnimplementedQueryServer) mustEmbedUnimplementedQueryServer() {}
func (UnimplementedQueryServer) testEmbeddedByValue() {}
// UnsafeQueryServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to QueryServer will
@ -141,6 +154,13 @@ type UnsafeQueryServer interface {
}
func RegisterQueryServer(s grpc.ServiceRegistrar, srv QueryServer) {
// If the following call pancis, it indicates UnimplementedQueryServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Query_ServiceDesc, srv)
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cerc/bond/v1/tx.proto
@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Msg_CreateBond_FullMethodName = "/cerc.bond.v1.Msg/CreateBond"
@ -29,6 +29,8 @@ const (
// MsgClient is the client API for Msg service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Msg defines the bond Msg service.
type MsgClient interface {
// CreateBond defines a method for creating a new bond.
CreateBond(ctx context.Context, in *MsgCreateBond, opts ...grpc.CallOption) (*MsgCreateBondResponse, error)
@ -52,8 +54,9 @@ func NewMsgClient(cc grpc.ClientConnInterface) MsgClient {
}
func (c *msgClient) CreateBond(ctx context.Context, in *MsgCreateBond, opts ...grpc.CallOption) (*MsgCreateBondResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgCreateBondResponse)
err := c.cc.Invoke(ctx, Msg_CreateBond_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_CreateBond_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -61,8 +64,9 @@ func (c *msgClient) CreateBond(ctx context.Context, in *MsgCreateBond, opts ...g
}
func (c *msgClient) RefillBond(ctx context.Context, in *MsgRefillBond, opts ...grpc.CallOption) (*MsgRefillBondResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgRefillBondResponse)
err := c.cc.Invoke(ctx, Msg_RefillBond_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_RefillBond_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -70,8 +74,9 @@ func (c *msgClient) RefillBond(ctx context.Context, in *MsgRefillBond, opts ...g
}
func (c *msgClient) WithdrawBond(ctx context.Context, in *MsgWithdrawBond, opts ...grpc.CallOption) (*MsgWithdrawBondResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgWithdrawBondResponse)
err := c.cc.Invoke(ctx, Msg_WithdrawBond_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_WithdrawBond_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -79,8 +84,9 @@ func (c *msgClient) WithdrawBond(ctx context.Context, in *MsgWithdrawBond, opts
}
func (c *msgClient) CancelBond(ctx context.Context, in *MsgCancelBond, opts ...grpc.CallOption) (*MsgCancelBondResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgCancelBondResponse)
err := c.cc.Invoke(ctx, Msg_CancelBond_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_CancelBond_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -88,8 +94,9 @@ func (c *msgClient) CancelBond(ctx context.Context, in *MsgCancelBond, opts ...g
}
func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgUpdateParamsResponse)
err := c.cc.Invoke(ctx, Msg_UpdateParams_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_UpdateParams_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -98,7 +105,9 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts
// MsgServer is the server API for Msg service.
// All implementations must embed UnimplementedMsgServer
// for forward compatibility
// for forward compatibility.
//
// Msg defines the bond Msg service.
type MsgServer interface {
// CreateBond defines a method for creating a new bond.
CreateBond(context.Context, *MsgCreateBond) (*MsgCreateBondResponse, error)
@ -114,9 +123,12 @@ type MsgServer interface {
mustEmbedUnimplementedMsgServer()
}
// UnimplementedMsgServer must be embedded to have forward compatible implementations.
type UnimplementedMsgServer struct {
}
// UnimplementedMsgServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedMsgServer struct{}
func (UnimplementedMsgServer) CreateBond(context.Context, *MsgCreateBond) (*MsgCreateBondResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateBond not implemented")
@ -134,6 +146,7 @@ func (UnimplementedMsgServer) UpdateParams(context.Context, *MsgUpdateParams) (*
return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented")
}
func (UnimplementedMsgServer) mustEmbedUnimplementedMsgServer() {}
func (UnimplementedMsgServer) testEmbeddedByValue() {}
// UnsafeMsgServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MsgServer will
@ -143,6 +156,13 @@ type UnsafeMsgServer interface {
}
func RegisterMsgServer(s grpc.ServiceRegistrar, srv MsgServer) {
// If the following call pancis, it indicates UnimplementedMsgServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Msg_ServiceDesc, srv)
}

View File

@ -426,7 +426,7 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods {
var (
md_Participant protoreflect.MessageDescriptor
fd_Participant_cosmos_address protoreflect.FieldDescriptor
fd_Participant_nitro_address protoreflect.FieldDescriptor
fd_Participant_public_key protoreflect.FieldDescriptor
fd_Participant_role protoreflect.FieldDescriptor
fd_Participant_kyc_id protoreflect.FieldDescriptor
)
@ -435,7 +435,7 @@ func init() {
file_cerc_onboarding_v1_onboarding_proto_init()
md_Participant = File_cerc_onboarding_v1_onboarding_proto.Messages().ByName("Participant")
fd_Participant_cosmos_address = md_Participant.Fields().ByName("cosmos_address")
fd_Participant_nitro_address = md_Participant.Fields().ByName("nitro_address")
fd_Participant_public_key = md_Participant.Fields().ByName("public_key")
fd_Participant_role = md_Participant.Fields().ByName("role")
fd_Participant_kyc_id = md_Participant.Fields().ByName("kyc_id")
}
@ -511,9 +511,9 @@ func (x *fastReflection_Participant) Range(f func(protoreflect.FieldDescriptor,
return
}
}
if x.NitroAddress != "" {
value := protoreflect.ValueOfString(x.NitroAddress)
if !f(fd_Participant_nitro_address, value) {
if len(x.PublicKey) != 0 {
value := protoreflect.ValueOfBytes(x.PublicKey)
if !f(fd_Participant_public_key, value) {
return
}
}
@ -546,8 +546,8 @@ func (x *fastReflection_Participant) Has(fd protoreflect.FieldDescriptor) bool {
switch fd.FullName() {
case "cerc.onboarding.v1.Participant.cosmos_address":
return x.CosmosAddress != ""
case "cerc.onboarding.v1.Participant.nitro_address":
return x.NitroAddress != ""
case "cerc.onboarding.v1.Participant.public_key":
return len(x.PublicKey) != 0
case "cerc.onboarding.v1.Participant.role":
return x.Role != ""
case "cerc.onboarding.v1.Participant.kyc_id":
@ -570,8 +570,8 @@ func (x *fastReflection_Participant) Clear(fd protoreflect.FieldDescriptor) {
switch fd.FullName() {
case "cerc.onboarding.v1.Participant.cosmos_address":
x.CosmosAddress = ""
case "cerc.onboarding.v1.Participant.nitro_address":
x.NitroAddress = ""
case "cerc.onboarding.v1.Participant.public_key":
x.PublicKey = nil
case "cerc.onboarding.v1.Participant.role":
x.Role = ""
case "cerc.onboarding.v1.Participant.kyc_id":
@ -595,9 +595,9 @@ func (x *fastReflection_Participant) Get(descriptor protoreflect.FieldDescriptor
case "cerc.onboarding.v1.Participant.cosmos_address":
value := x.CosmosAddress
return protoreflect.ValueOfString(value)
case "cerc.onboarding.v1.Participant.nitro_address":
value := x.NitroAddress
return protoreflect.ValueOfString(value)
case "cerc.onboarding.v1.Participant.public_key":
value := x.PublicKey
return protoreflect.ValueOfBytes(value)
case "cerc.onboarding.v1.Participant.role":
value := x.Role
return protoreflect.ValueOfString(value)
@ -626,8 +626,8 @@ func (x *fastReflection_Participant) Set(fd protoreflect.FieldDescriptor, value
switch fd.FullName() {
case "cerc.onboarding.v1.Participant.cosmos_address":
x.CosmosAddress = value.Interface().(string)
case "cerc.onboarding.v1.Participant.nitro_address":
x.NitroAddress = value.Interface().(string)
case "cerc.onboarding.v1.Participant.public_key":
x.PublicKey = value.Bytes()
case "cerc.onboarding.v1.Participant.role":
x.Role = value.Interface().(string)
case "cerc.onboarding.v1.Participant.kyc_id":
@ -654,8 +654,8 @@ func (x *fastReflection_Participant) Mutable(fd protoreflect.FieldDescriptor) pr
switch fd.FullName() {
case "cerc.onboarding.v1.Participant.cosmos_address":
panic(fmt.Errorf("field cosmos_address of message cerc.onboarding.v1.Participant is not mutable"))
case "cerc.onboarding.v1.Participant.nitro_address":
panic(fmt.Errorf("field nitro_address of message cerc.onboarding.v1.Participant is not mutable"))
case "cerc.onboarding.v1.Participant.public_key":
panic(fmt.Errorf("field public_key of message cerc.onboarding.v1.Participant is not mutable"))
case "cerc.onboarding.v1.Participant.role":
panic(fmt.Errorf("field role of message cerc.onboarding.v1.Participant is not mutable"))
case "cerc.onboarding.v1.Participant.kyc_id":
@ -675,8 +675,8 @@ func (x *fastReflection_Participant) NewField(fd protoreflect.FieldDescriptor) p
switch fd.FullName() {
case "cerc.onboarding.v1.Participant.cosmos_address":
return protoreflect.ValueOfString("")
case "cerc.onboarding.v1.Participant.nitro_address":
return protoreflect.ValueOfString("")
case "cerc.onboarding.v1.Participant.public_key":
return protoreflect.ValueOfBytes(nil)
case "cerc.onboarding.v1.Participant.role":
return protoreflect.ValueOfString("")
case "cerc.onboarding.v1.Participant.kyc_id":
@ -754,7 +754,7 @@ func (x *fastReflection_Participant) ProtoMethods() *protoiface.Methods {
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
l = len(x.NitroAddress)
l = len(x.PublicKey)
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
@ -809,10 +809,10 @@ func (x *fastReflection_Participant) ProtoMethods() *protoiface.Methods {
i--
dAtA[i] = 0x1a
}
if len(x.NitroAddress) > 0 {
i -= len(x.NitroAddress)
copy(dAtA[i:], x.NitroAddress)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.NitroAddress)))
if len(x.PublicKey) > 0 {
i -= len(x.PublicKey)
copy(dAtA[i:], x.PublicKey)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.PublicKey)))
i--
dAtA[i] = 0x12
}
@ -906,9 +906,9 @@ func (x *fastReflection_Participant) ProtoMethods() *protoiface.Methods {
iNdEx = postIndex
case 2:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field NitroAddress", wireType)
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType)
}
var stringLen uint64
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
@ -918,23 +918,25 @@ func (x *fastReflection_Participant) ProtoMethods() *protoiface.Methods {
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
if byteLen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
postIndex := iNdEx + byteLen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
x.NitroAddress = string(dAtA[iNdEx:postIndex])
x.PublicKey = append(x.PublicKey[:0], dAtA[iNdEx:postIndex]...)
if x.PublicKey == nil {
x.PublicKey = []byte{}
}
iNdEx = postIndex
case 3:
if wireType != 2 {
@ -1577,8 +1579,8 @@ type Participant struct {
// participant's cosmos (laconic) address
CosmosAddress string `protobuf:"bytes,1,opt,name=cosmos_address,json=cosmosAddress,proto3" json:"cosmos_address,omitempty"`
// participant's Nitro address
NitroAddress string `protobuf:"bytes,2,opt,name=nitro_address,json=nitroAddress,proto3" json:"nitro_address,omitempty"`
// full public key used to derive participant's Nitro address
PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
// participant's role (participant | validator)
Role string `protobuf:"bytes,3,opt,name=role,proto3" json:"role,omitempty"`
// participant's KYC receipt ID
@ -1612,11 +1614,11 @@ func (x *Participant) GetCosmosAddress() string {
return ""
}
func (x *Participant) GetNitroAddress() string {
func (x *Participant) GetPublicKey() []byte {
if x != nil {
return x.NitroAddress
return x.PublicKey
}
return ""
return nil
}
func (x *Participant) GetRole() string {
@ -1692,46 +1694,43 @@ var file_cerc_onboarding_v1_onboarding_proto_rawDesc = []byte{
0x6c, 0x65, 0x64, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6f, 0x6e, 0x62, 0x6f, 0x61,
0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x52, 0x11,
0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65,
0x64, 0x22, 0xa2, 0x02, 0x0a, 0x0b, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e,
0x64, 0x22, 0xed, 0x01, 0x0a, 0x0b, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e,
0x74, 0x12, 0x56, 0x0a, 0x0e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xf2, 0xde, 0x1f, 0x2b, 0x6a,
0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x6f, 0x73, 0x6d, 0x6f,
0x73, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, 0x0d, 0x63, 0x6f, 0x73, 0x6d,
0x6f, 0x73, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x52, 0x0a, 0x0d, 0x6e, 0x69, 0x74,
0x72, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x42, 0x2d, 0xf2, 0xde, 0x1f, 0x29, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6e, 0x69, 0x74, 0x72,
0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a,
0x22, 0x6e, 0x69, 0x74, 0x72, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52,
0x0c, 0x6e, 0x69, 0x74, 0x72, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2f, 0x0a,
0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1b, 0xf2, 0xde, 0x1f,
0x17, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0x20, 0x79, 0x61, 0x6d,
0x6c, 0x3a, 0x22, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x36,
0x0a, 0x06, 0x6b, 0x79, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1f,
0xf2, 0xde, 0x1f, 0x1b, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6b, 0x79, 0x63, 0x5f, 0x69, 0x64,
0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6b, 0x79, 0x63, 0x5f, 0x69, 0x64, 0x22, 0x52,
0x05, 0x6b, 0x79, 0x63, 0x49, 0x64, 0x22, 0x76, 0x0a, 0x0a, 0x45, 0x74, 0x68, 0x50, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xf2, 0xde, 0x1f, 0x1d, 0x6a, 0x73, 0x6f, 0x6e, 0x3a,
0x22, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x12, 0x2b, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x19,
0xf2, 0xde, 0x1f, 0x15, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6d, 0x73, 0x67, 0x22, 0x20, 0x79,
0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x73, 0x67, 0x22, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x42, 0xd4,
0x01, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x6f, 0x6e, 0x62, 0x6f,
0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x42, 0x0f, 0x4f, 0x6e, 0x62, 0x6f, 0x61,
0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3f, 0x67, 0x69,
0x74, 0x2e, 0x76, 0x64, 0x62, 0x2e, 0x74, 0x6f, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2d, 0x69, 0x6f,
0x2f, 0x6c, 0x61, 0x63, 0x6f, 0x6e, 0x69, 0x63, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x65,
0x72, 0x63, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31,
0x3b, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x76, 0x31, 0xa2, 0x02, 0x03,
0x43, 0x4f, 0x58, 0xaa, 0x02, 0x12, 0x43, 0x65, 0x72, 0x63, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61,
0x72, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, 0x43, 0x65, 0x72, 0x63, 0x5c,
0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1e,
0x43, 0x65, 0x72, 0x63, 0x5c, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5c,
0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02,
0x14, 0x43, 0x65, 0x72, 0x63, 0x3a, 0x3a, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e,
0x67, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6f, 0x73, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1b, 0xf2, 0xde, 0x1f, 0x17, 0x6a, 0x73, 0x6f, 0x6e,
0x3a, 0x22, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x72, 0x6f,
0x6c, 0x65, 0x22, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x36, 0x0a, 0x06, 0x6b, 0x79, 0x63,
0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1f, 0xf2, 0xde, 0x1f, 0x1b, 0x6a,
0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6b, 0x79, 0x63, 0x5f, 0x69, 0x64, 0x22, 0x20, 0x79, 0x61, 0x6d,
0x6c, 0x3a, 0x22, 0x6b, 0x79, 0x63, 0x5f, 0x69, 0x64, 0x22, 0x52, 0x05, 0x6b, 0x79, 0x63, 0x49,
0x64, 0x22, 0x76, 0x0a, 0x0a, 0x45, 0x74, 0x68, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12,
0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x42, 0x21, 0xf2, 0xde, 0x1f, 0x1d, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x22, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2b, 0x0a, 0x03,
0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x19, 0xf2, 0xde, 0x1f, 0x15, 0x6a,
0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6d, 0x73, 0x67, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22,
0x6d, 0x73, 0x67, 0x22, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x42, 0xd4, 0x01, 0x0a, 0x16, 0x63, 0x6f,
0x6d, 0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e,
0x67, 0x2e, 0x76, 0x31, 0x42, 0x0f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x2e, 0x76, 0x64, 0x62,
0x2e, 0x74, 0x6f, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2d, 0x69, 0x6f, 0x2f, 0x6c, 0x61, 0x63, 0x6f,
0x6e, 0x69, 0x63, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2f, 0x6f, 0x6e,
0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x3b, 0x6f, 0x6e, 0x62, 0x6f,
0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x4f, 0x58, 0xaa, 0x02,
0x12, 0x43, 0x65, 0x72, 0x63, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x4f, 0x6e, 0x62, 0x6f, 0x61,
0x72, 0x64, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1e, 0x43, 0x65, 0x72, 0x63, 0x5c,
0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50,
0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x43, 0x65, 0x72, 0x63,
0x3a, 0x3a, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x31,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cerc/onboarding/v1/query.proto
@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Query_Participants_FullMethodName = "/cerc.onboarding.v1.Query/Participants"
@ -27,6 +27,8 @@ const (
// QueryClient is the client API for Query service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Query defines the gRPC querier service for onboarding module
type QueryClient interface {
// Participants queries Participants list
Participants(ctx context.Context, in *QueryParticipantsRequest, opts ...grpc.CallOption) (*QueryParticipantsResponse, error)
@ -45,8 +47,9 @@ func NewQueryClient(cc grpc.ClientConnInterface) QueryClient {
}
func (c *queryClient) Participants(ctx context.Context, in *QueryParticipantsRequest, opts ...grpc.CallOption) (*QueryParticipantsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryParticipantsResponse)
err := c.cc.Invoke(ctx, Query_Participants_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Participants_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -54,8 +57,9 @@ func (c *queryClient) Participants(ctx context.Context, in *QueryParticipantsReq
}
func (c *queryClient) GetParticipantByAddress(ctx context.Context, in *QueryGetParticipantByAddressRequest, opts ...grpc.CallOption) (*QueryGetParticipantByAddressResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetParticipantByAddressResponse)
err := c.cc.Invoke(ctx, Query_GetParticipantByAddress_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetParticipantByAddress_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -63,8 +67,9 @@ func (c *queryClient) GetParticipantByAddress(ctx context.Context, in *QueryGetP
}
func (c *queryClient) GetParticipantByNitroAddress(ctx context.Context, in *QueryGetParticipantByNitroAddressRequest, opts ...grpc.CallOption) (*QueryGetParticipantByNitroAddressResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetParticipantByNitroAddressResponse)
err := c.cc.Invoke(ctx, Query_GetParticipantByNitroAddress_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetParticipantByNitroAddress_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -73,7 +78,9 @@ func (c *queryClient) GetParticipantByNitroAddress(ctx context.Context, in *Quer
// QueryServer is the server API for Query service.
// All implementations must embed UnimplementedQueryServer
// for forward compatibility
// for forward compatibility.
//
// Query defines the gRPC querier service for onboarding module
type QueryServer interface {
// Participants queries Participants list
Participants(context.Context, *QueryParticipantsRequest) (*QueryParticipantsResponse, error)
@ -84,9 +91,12 @@ type QueryServer interface {
mustEmbedUnimplementedQueryServer()
}
// UnimplementedQueryServer must be embedded to have forward compatible implementations.
type UnimplementedQueryServer struct {
}
// UnimplementedQueryServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedQueryServer struct{}
func (UnimplementedQueryServer) Participants(context.Context, *QueryParticipantsRequest) (*QueryParticipantsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Participants not implemented")
@ -98,6 +108,7 @@ func (UnimplementedQueryServer) GetParticipantByNitroAddress(context.Context, *Q
return nil, status.Errorf(codes.Unimplemented, "method GetParticipantByNitroAddress not implemented")
}
func (UnimplementedQueryServer) mustEmbedUnimplementedQueryServer() {}
func (UnimplementedQueryServer) testEmbeddedByValue() {}
// UnsafeQueryServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to QueryServer will
@ -107,6 +118,13 @@ type UnsafeQueryServer interface {
}
func RegisterQueryServer(s grpc.ServiceRegistrar, srv QueryServer) {
// If the following call pancis, it indicates UnimplementedQueryServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Query_ServiceDesc, srv)
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cerc/onboarding/v1/tx.proto
@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Msg_OnboardParticipant_FullMethodName = "/cerc.onboarding.v1.Msg/OnboardParticipant"
@ -25,6 +25,8 @@ const (
// MsgClient is the client API for Msg service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Msg defines the onboarding Msg service.
type MsgClient interface {
// OnboardParticipant defines a method for enrolling a new validator.
OnboardParticipant(ctx context.Context, in *MsgOnboardParticipant, opts ...grpc.CallOption) (*MsgOnboardParticipantResponse, error)
@ -39,8 +41,9 @@ func NewMsgClient(cc grpc.ClientConnInterface) MsgClient {
}
func (c *msgClient) OnboardParticipant(ctx context.Context, in *MsgOnboardParticipant, opts ...grpc.CallOption) (*MsgOnboardParticipantResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgOnboardParticipantResponse)
err := c.cc.Invoke(ctx, Msg_OnboardParticipant_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_OnboardParticipant_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -49,21 +52,27 @@ func (c *msgClient) OnboardParticipant(ctx context.Context, in *MsgOnboardPartic
// MsgServer is the server API for Msg service.
// All implementations must embed UnimplementedMsgServer
// for forward compatibility
// for forward compatibility.
//
// Msg defines the onboarding Msg service.
type MsgServer interface {
// OnboardParticipant defines a method for enrolling a new validator.
OnboardParticipant(context.Context, *MsgOnboardParticipant) (*MsgOnboardParticipantResponse, error)
mustEmbedUnimplementedMsgServer()
}
// UnimplementedMsgServer must be embedded to have forward compatible implementations.
type UnimplementedMsgServer struct {
}
// UnimplementedMsgServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedMsgServer struct{}
func (UnimplementedMsgServer) OnboardParticipant(context.Context, *MsgOnboardParticipant) (*MsgOnboardParticipantResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method OnboardParticipant not implemented")
}
func (UnimplementedMsgServer) mustEmbedUnimplementedMsgServer() {}
func (UnimplementedMsgServer) testEmbeddedByValue() {}
// UnsafeMsgServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MsgServer will
@ -73,6 +82,13 @@ type UnsafeMsgServer interface {
}
func RegisterMsgServer(s grpc.ServiceRegistrar, srv MsgServer) {
// If the following call pancis, it indicates UnimplementedMsgServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Msg_ServiceDesc, srv)
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cerc/registry/v1/query.proto
@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Query_Params_FullMethodName = "/cerc.registry.v1.Query/Params"
@ -34,6 +34,8 @@ const (
// QueryClient is the client API for Query service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Query defines the gRPC querier service for registry module
type QueryClient interface {
// Params queries the registry module params.
Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error)
@ -66,8 +68,9 @@ func NewQueryClient(cc grpc.ClientConnInterface) QueryClient {
}
func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryParamsResponse)
err := c.cc.Invoke(ctx, Query_Params_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Params_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -75,8 +78,9 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts .
}
func (c *queryClient) Records(ctx context.Context, in *QueryRecordsRequest, opts ...grpc.CallOption) (*QueryRecordsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryRecordsResponse)
err := c.cc.Invoke(ctx, Query_Records_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Records_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -84,8 +88,9 @@ func (c *queryClient) Records(ctx context.Context, in *QueryRecordsRequest, opts
}
func (c *queryClient) GetRecord(ctx context.Context, in *QueryGetRecordRequest, opts ...grpc.CallOption) (*QueryGetRecordResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetRecordResponse)
err := c.cc.Invoke(ctx, Query_GetRecord_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetRecord_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -93,8 +98,9 @@ func (c *queryClient) GetRecord(ctx context.Context, in *QueryGetRecordRequest,
}
func (c *queryClient) GetRecordsByBondId(ctx context.Context, in *QueryGetRecordsByBondIdRequest, opts ...grpc.CallOption) (*QueryGetRecordsByBondIdResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetRecordsByBondIdResponse)
err := c.cc.Invoke(ctx, Query_GetRecordsByBondId_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetRecordsByBondId_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -102,8 +108,9 @@ func (c *queryClient) GetRecordsByBondId(ctx context.Context, in *QueryGetRecord
}
func (c *queryClient) NameRecords(ctx context.Context, in *QueryNameRecordsRequest, opts ...grpc.CallOption) (*QueryNameRecordsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryNameRecordsResponse)
err := c.cc.Invoke(ctx, Query_NameRecords_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_NameRecords_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -111,8 +118,9 @@ func (c *queryClient) NameRecords(ctx context.Context, in *QueryNameRecordsReque
}
func (c *queryClient) Whois(ctx context.Context, in *QueryWhoisRequest, opts ...grpc.CallOption) (*QueryWhoisResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryWhoisResponse)
err := c.cc.Invoke(ctx, Query_Whois_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Whois_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -120,8 +128,9 @@ func (c *queryClient) Whois(ctx context.Context, in *QueryWhoisRequest, opts ...
}
func (c *queryClient) LookupLrn(ctx context.Context, in *QueryLookupLrnRequest, opts ...grpc.CallOption) (*QueryLookupLrnResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryLookupLrnResponse)
err := c.cc.Invoke(ctx, Query_LookupLrn_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_LookupLrn_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -129,8 +138,9 @@ func (c *queryClient) LookupLrn(ctx context.Context, in *QueryLookupLrnRequest,
}
func (c *queryClient) ResolveLrn(ctx context.Context, in *QueryResolveLrnRequest, opts ...grpc.CallOption) (*QueryResolveLrnResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryResolveLrnResponse)
err := c.cc.Invoke(ctx, Query_ResolveLrn_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_ResolveLrn_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -138,8 +148,9 @@ func (c *queryClient) ResolveLrn(ctx context.Context, in *QueryResolveLrnRequest
}
func (c *queryClient) GetRegistryModuleBalance(ctx context.Context, in *QueryGetRegistryModuleBalanceRequest, opts ...grpc.CallOption) (*QueryGetRegistryModuleBalanceResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryGetRegistryModuleBalanceResponse)
err := c.cc.Invoke(ctx, Query_GetRegistryModuleBalance_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_GetRegistryModuleBalance_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -147,8 +158,9 @@ func (c *queryClient) GetRegistryModuleBalance(ctx context.Context, in *QueryGet
}
func (c *queryClient) Authorities(ctx context.Context, in *QueryAuthoritiesRequest, opts ...grpc.CallOption) (*QueryAuthoritiesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(QueryAuthoritiesResponse)
err := c.cc.Invoke(ctx, Query_Authorities_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Query_Authorities_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -157,7 +169,9 @@ func (c *queryClient) Authorities(ctx context.Context, in *QueryAuthoritiesReque
// QueryServer is the server API for Query service.
// All implementations must embed UnimplementedQueryServer
// for forward compatibility
// for forward compatibility.
//
// Query defines the gRPC querier service for registry module
type QueryServer interface {
// Params queries the registry module params.
Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error)
@ -182,9 +196,12 @@ type QueryServer interface {
mustEmbedUnimplementedQueryServer()
}
// UnimplementedQueryServer must be embedded to have forward compatible implementations.
type UnimplementedQueryServer struct {
}
// UnimplementedQueryServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedQueryServer struct{}
func (UnimplementedQueryServer) Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Params not implemented")
@ -217,6 +234,7 @@ func (UnimplementedQueryServer) Authorities(context.Context, *QueryAuthoritiesRe
return nil, status.Errorf(codes.Unimplemented, "method Authorities not implemented")
}
func (UnimplementedQueryServer) mustEmbedUnimplementedQueryServer() {}
func (UnimplementedQueryServer) testEmbeddedByValue() {}
// UnsafeQueryServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to QueryServer will
@ -226,6 +244,13 @@ type UnsafeQueryServer interface {
}
func RegisterQueryServer(s grpc.ServiceRegistrar, srv QueryServer) {
// If the following call pancis, it indicates UnimplementedQueryServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Query_ServiceDesc, srv)
}

View File

@ -1318,7 +1318,7 @@ var (
fd_Record_owners protoreflect.FieldDescriptor
fd_Record_attributes protoreflect.FieldDescriptor
fd_Record_names protoreflect.FieldDescriptor
fd_Record_type protoreflect.FieldDescriptor
fd_Record_types protoreflect.FieldDescriptor
)
func init() {
@ -1332,7 +1332,7 @@ func init() {
fd_Record_owners = md_Record.Fields().ByName("owners")
fd_Record_attributes = md_Record.Fields().ByName("attributes")
fd_Record_names = md_Record.Fields().ByName("names")
fd_Record_type = md_Record.Fields().ByName("type")
fd_Record_types = md_Record.Fields().ByName("types")
}
var _ protoreflect.Message = (*fastReflection_Record)(nil)
@ -1448,9 +1448,9 @@ func (x *fastReflection_Record) Range(f func(protoreflect.FieldDescriptor, proto
return
}
}
if x.Type_ != "" {
value := protoreflect.ValueOfString(x.Type_)
if !f(fd_Record_type, value) {
if x.Types != "" {
value := protoreflect.ValueOfString(x.Types)
if !f(fd_Record_types, value) {
return
}
}
@ -1485,8 +1485,8 @@ func (x *fastReflection_Record) Has(fd protoreflect.FieldDescriptor) bool {
return len(x.Attributes) != 0
case "cerc.registry.v1.Record.names":
return len(x.Names) != 0
case "cerc.registry.v1.Record.type":
return x.Type_ != ""
case "cerc.registry.v1.Record.types":
return x.Types != ""
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.Record"))
@ -1519,8 +1519,8 @@ func (x *fastReflection_Record) Clear(fd protoreflect.FieldDescriptor) {
x.Attributes = nil
case "cerc.registry.v1.Record.names":
x.Names = nil
case "cerc.registry.v1.Record.type":
x.Type_ = ""
case "cerc.registry.v1.Record.types":
x.Types = ""
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.Record"))
@ -1567,8 +1567,8 @@ func (x *fastReflection_Record) Get(descriptor protoreflect.FieldDescriptor) pro
}
listValue := &_Record_8_list{list: &x.Names}
return protoreflect.ValueOfList(listValue)
case "cerc.registry.v1.Record.type":
value := x.Type_
case "cerc.registry.v1.Record.types":
value := x.Types
return protoreflect.ValueOfString(value)
default:
if descriptor.IsExtension() {
@ -1610,8 +1610,8 @@ func (x *fastReflection_Record) Set(fd protoreflect.FieldDescriptor, value proto
lv := value.List()
clv := lv.(*_Record_8_list)
x.Names = *clv.list
case "cerc.registry.v1.Record.type":
x.Type_ = value.Interface().(string)
case "cerc.registry.v1.Record.types":
x.Types = value.Interface().(string)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.Record"))
@ -1656,8 +1656,8 @@ func (x *fastReflection_Record) Mutable(fd protoreflect.FieldDescriptor) protore
panic(fmt.Errorf("field deleted of message cerc.registry.v1.Record is not mutable"))
case "cerc.registry.v1.Record.attributes":
panic(fmt.Errorf("field attributes of message cerc.registry.v1.Record is not mutable"))
case "cerc.registry.v1.Record.type":
panic(fmt.Errorf("field type of message cerc.registry.v1.Record is not mutable"))
case "cerc.registry.v1.Record.types":
panic(fmt.Errorf("field types of message cerc.registry.v1.Record is not mutable"))
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cerc.registry.v1.Record"))
@ -1689,7 +1689,7 @@ func (x *fastReflection_Record) NewField(fd protoreflect.FieldDescriptor) protor
case "cerc.registry.v1.Record.names":
list := []string{}
return protoreflect.ValueOfList(&_Record_8_list{list: &list})
case "cerc.registry.v1.Record.type":
case "cerc.registry.v1.Record.types":
return protoreflect.ValueOfString("")
default:
if fd.IsExtension() {
@ -1795,7 +1795,7 @@ func (x *fastReflection_Record) ProtoMethods() *protoiface.Methods {
n += 1 + l + runtime.Sov(uint64(l))
}
}
l = len(x.Type_)
l = len(x.Types)
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
@ -1828,10 +1828,10 @@ func (x *fastReflection_Record) ProtoMethods() *protoiface.Methods {
i -= len(x.unknownFields)
copy(dAtA[i:], x.unknownFields)
}
if len(x.Type_) > 0 {
i -= len(x.Type_)
copy(dAtA[i:], x.Type_)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Type_)))
if len(x.Types) > 0 {
i -= len(x.Types)
copy(dAtA[i:], x.Types)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Types)))
i--
dAtA[i] = 0x4a
}
@ -2195,7 +2195,7 @@ func (x *fastReflection_Record) ProtoMethods() *protoiface.Methods {
iNdEx = postIndex
case 9:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Type_", wireType)
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Types", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
@ -2223,7 +2223,7 @@ func (x *fastReflection_Record) ProtoMethods() *protoiface.Methods {
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
x.Type_ = string(dAtA[iNdEx:postIndex])
x.Types = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
@ -6753,7 +6753,7 @@ type Record struct {
Owners []string `protobuf:"bytes,6,rep,name=owners,proto3" json:"owners,omitempty"`
Attributes []byte `protobuf:"bytes,7,opt,name=attributes,proto3" json:"attributes,omitempty"`
Names []string `protobuf:"bytes,8,rep,name=names,proto3" json:"names,omitempty"`
Type_ string `protobuf:"bytes,9,opt,name=type,proto3" json:"type,omitempty"`
Types string `protobuf:"bytes,9,opt,name=types,proto3" json:"types,omitempty"`
}
func (x *Record) Reset() {
@ -6832,9 +6832,9 @@ func (x *Record) GetNames() []string {
return nil
}
func (x *Record) GetType_() string {
func (x *Record) GetTypes() string {
if x != nil {
return x.Type_
return x.Types
}
return ""
}
@ -7352,7 +7352,7 @@ var file_cerc_registry_v1_registry_proto_rawDesc = []byte{
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x61, 0x75, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x5f, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x62, 0x69, 0x64, 0x22, 0x52, 0x1a,
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x41, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x42, 0x69, 0x64, 0x22, 0x89, 0x04, 0x0a, 0x06, 0x52,
0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x42, 0x69, 0x64, 0x22, 0x8b, 0x04, 0x0a, 0x06, 0x52,
0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x27, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x42, 0x17, 0xf2, 0xde, 0x1f, 0x13, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x69, 0x64, 0x22,
0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x69, 0x64, 0x22, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3a,
@ -7382,90 +7382,90 @@ var file_cerc_registry_v1_registry_proto_rawDesc = []byte{
0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x42, 0x1d, 0xf2,
0xde, 0x1f, 0x19, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x20,
0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x52, 0x05, 0x6e, 0x61,
0x6d, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28,
0x09, 0x42, 0x1d, 0xf2, 0xde, 0x1f, 0x19, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x74, 0x79, 0x70,
0x65, 0x73, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22,
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5b, 0x0a, 0x0e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x05,
0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x65,
0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4e,
0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x05, 0x65, 0x6e,
0x74, 0x72, 0x79, 0x22, 0xe6, 0x03, 0x0a, 0x0d, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x5d, 0x0a, 0x10, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x70,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
0x33, 0xf2, 0xde, 0x1f, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6f, 0x77, 0x6e, 0x65, 0x72,
0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x20, 0x79, 0x61, 0x6d,
0x6c, 0x3a, 0x22, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
0x6b, 0x65, 0x79, 0x22, 0x52, 0x0e, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x12, 0x52, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2d, 0xf2, 0xde, 0x1f,
0x29, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6f, 0x77, 0x6e, 0x65,
0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, 0x0c, 0x6f, 0x77, 0x6e, 0x65,
0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67,
0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74,
0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x75, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xf2, 0xde,
0x1f, 0x23, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x61, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x69, 0x64, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x75, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x5f, 0x69, 0x64, 0x22, 0x52, 0x09, 0x61, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64,
0x12, 0x3a, 0x0a, 0x07, 0x62, 0x6f, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x42, 0x21, 0xf2, 0xde, 0x1f, 0x1d, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x62, 0x6f, 0x6e,
0x64, 0x5f, 0x69, 0x64, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x6f, 0x6e, 0x64,
0x5f, 0x69, 0x64, 0x22, 0x52, 0x06, 0x62, 0x6f, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x6e, 0x0a, 0x0b,
0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x31, 0xc8,
0xde, 0x1f, 0x00, 0xf2, 0xde, 0x1f, 0x25, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x65, 0x78, 0x70,
0x69, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22,
0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x90, 0xdf, 0x1f, 0x01,
0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x09,
0x4e, 0x61, 0x6d, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a,
0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63,
0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e,
0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72,
0x79, 0x22, 0x84, 0x01, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
0x12, 0x39, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x21, 0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79,
0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x68,
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63,
0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e,
0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x39, 0x0a, 0x0f, 0x4e, 0x61, 0x6d, 0x65,
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x68,
0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x69,
0x67, 0x68, 0x74, 0x22, 0x74, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65,
0x12, 0x2b, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x19, 0xf2,
0xde, 0x1f, 0x15, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x20, 0x79, 0x61,
0x6d, 0x6c, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x52, 0x03, 0x73, 0x69, 0x67, 0x12, 0x3a, 0x0a,
0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21,
0xf2, 0xde, 0x1f, 0x1d, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65,
0x79, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79,
0x22, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x33, 0x0a, 0x0b, 0x45, 0x78, 0x70,
0x69, 0x72, 0x79, 0x51, 0x75, 0x65, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x23,
0x0a, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x42, 0xc4, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x65, 0x72, 0x63,
0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x52, 0x65,
0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3b, 0x67,
0x69, 0x74, 0x2e, 0x76, 0x64, 0x62, 0x2e, 0x74, 0x6f, 0x2f, 0x63, 0x65, 0x72, 0x63, 0x2d, 0x69,
0x6f, 0x2f, 0x6c, 0x61, 0x63, 0x6f, 0x6e, 0x69, 0x63, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63,
0x65, 0x72, 0x63, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2f, 0x76, 0x31, 0x3b,
0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x52, 0x58,
0xaa, 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79,
0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65, 0x67, 0x69, 0x73,
0x74, 0x72, 0x79, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65,
0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x43, 0x65, 0x72, 0x63, 0x3a, 0x3a, 0x52, 0x65,
0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
0x6d, 0x65, 0x73, 0x12, 0x33, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01,
0x28, 0x09, 0x42, 0x1d, 0xf2, 0xde, 0x1f, 0x19, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x74, 0x79,
0x70, 0x65, 0x73, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x74, 0x79, 0x70, 0x65, 0x73,
0x22, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x5b, 0x0a, 0x0e, 0x41, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35,
0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
0x63, 0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31,
0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x05,
0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xe6, 0x03, 0x0a, 0x0d, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x5d, 0x0a, 0x10, 0x6f, 0x77, 0x6e, 0x65, 0x72,
0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x42, 0x33, 0xf2, 0xde, 0x1f, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6f, 0x77, 0x6e,
0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x20, 0x79,
0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x52, 0x0e, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x52, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2d, 0xf2,
0xde, 0x1f, 0x29, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6f, 0x77,
0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, 0x0c, 0x6f, 0x77,
0x6e, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65,
0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67,
0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x75,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27,
0xf2, 0xde, 0x1f, 0x23, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x61, 0x75, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x5f, 0x69, 0x64, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x75, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x22, 0x52, 0x09, 0x61, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x49, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x62, 0x6f, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20,
0x01, 0x28, 0x09, 0x42, 0x21, 0xf2, 0xde, 0x1f, 0x1d, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x62,
0x6f, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x6f,
0x6e, 0x64, 0x5f, 0x69, 0x64, 0x22, 0x52, 0x06, 0x62, 0x6f, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x6e,
0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42,
0x31, 0xc8, 0xde, 0x1f, 0x00, 0xf2, 0xde, 0x1f, 0x25, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x65,
0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c,
0x3a, 0x22, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x90, 0xdf,
0x1f, 0x01, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x53,
0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
0x32, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76,
0x31, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x05, 0x65, 0x6e,
0x74, 0x72, 0x79, 0x22, 0x84, 0x01, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f,
0x72, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a,
0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21,
0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76,
0x31, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x39, 0x0a, 0x0f, 0x4e, 0x61,
0x6d, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a,
0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68,
0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x74, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
0x72, 0x65, 0x12, 0x2b, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
0x19, 0xf2, 0xde, 0x1f, 0x15, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x20,
0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x52, 0x03, 0x73, 0x69, 0x67, 0x12,
0x3a, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x42, 0x21, 0xf2, 0xde, 0x1f, 0x1d, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x22, 0x70, 0x75, 0x62, 0x5f,
0x6b, 0x65, 0x79, 0x22, 0x20, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x70, 0x75, 0x62, 0x5f, 0x6b,
0x65, 0x79, 0x22, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x33, 0x0a, 0x0b, 0x45,
0x78, 0x70, 0x69, 0x72, 0x79, 0x51, 0x75, 0x65, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x22, 0x23, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12,
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xc4, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x65,
0x72, 0x63, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x42, 0x0d,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
0x3b, 0x67, 0x69, 0x74, 0x2e, 0x76, 0x64, 0x62, 0x2e, 0x74, 0x6f, 0x2f, 0x63, 0x65, 0x72, 0x63,
0x2d, 0x69, 0x6f, 0x2f, 0x6c, 0x61, 0x63, 0x6f, 0x6e, 0x69, 0x63, 0x64, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x63, 0x65, 0x72, 0x63, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2f, 0x76,
0x31, 0x3b, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43,
0x52, 0x58, 0xaa, 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
0x72, 0x79, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x43, 0x65, 0x72, 0x63, 0x5c, 0x52, 0x65, 0x67,
0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x65, 0x72, 0x63, 0x5c,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x43, 0x65, 0x72, 0x63, 0x3a, 0x3a,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: cerc/registry/v1/tx.proto
@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Msg_SetRecord_FullMethodName = "/cerc.registry.v1.Msg/SetRecord"
@ -35,6 +35,8 @@ const (
// MsgClient is the client API for Msg service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Msg is a service which exposes the registry functionality
type MsgClient interface {
// SetRecord records a new record with given payload and bond id
SetRecord(ctx context.Context, in *MsgSetRecord, opts ...grpc.CallOption) (*MsgSetRecordResponse, error)
@ -70,8 +72,9 @@ func NewMsgClient(cc grpc.ClientConnInterface) MsgClient {
}
func (c *msgClient) SetRecord(ctx context.Context, in *MsgSetRecord, opts ...grpc.CallOption) (*MsgSetRecordResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgSetRecordResponse)
err := c.cc.Invoke(ctx, Msg_SetRecord_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_SetRecord_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -79,8 +82,9 @@ func (c *msgClient) SetRecord(ctx context.Context, in *MsgSetRecord, opts ...grp
}
func (c *msgClient) RenewRecord(ctx context.Context, in *MsgRenewRecord, opts ...grpc.CallOption) (*MsgRenewRecordResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgRenewRecordResponse)
err := c.cc.Invoke(ctx, Msg_RenewRecord_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_RenewRecord_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -88,8 +92,9 @@ func (c *msgClient) RenewRecord(ctx context.Context, in *MsgRenewRecord, opts ..
}
func (c *msgClient) AssociateBond(ctx context.Context, in *MsgAssociateBond, opts ...grpc.CallOption) (*MsgAssociateBondResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgAssociateBondResponse)
err := c.cc.Invoke(ctx, Msg_AssociateBond_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_AssociateBond_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -97,8 +102,9 @@ func (c *msgClient) AssociateBond(ctx context.Context, in *MsgAssociateBond, opt
}
func (c *msgClient) DissociateBond(ctx context.Context, in *MsgDissociateBond, opts ...grpc.CallOption) (*MsgDissociateBondResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgDissociateBondResponse)
err := c.cc.Invoke(ctx, Msg_DissociateBond_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_DissociateBond_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -106,8 +112,9 @@ func (c *msgClient) DissociateBond(ctx context.Context, in *MsgDissociateBond, o
}
func (c *msgClient) DissociateRecords(ctx context.Context, in *MsgDissociateRecords, opts ...grpc.CallOption) (*MsgDissociateRecordsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgDissociateRecordsResponse)
err := c.cc.Invoke(ctx, Msg_DissociateRecords_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_DissociateRecords_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -115,8 +122,9 @@ func (c *msgClient) DissociateRecords(ctx context.Context, in *MsgDissociateReco
}
func (c *msgClient) ReassociateRecords(ctx context.Context, in *MsgReassociateRecords, opts ...grpc.CallOption) (*MsgReassociateRecordsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgReassociateRecordsResponse)
err := c.cc.Invoke(ctx, Msg_ReassociateRecords_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_ReassociateRecords_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -124,8 +132,9 @@ func (c *msgClient) ReassociateRecords(ctx context.Context, in *MsgReassociateRe
}
func (c *msgClient) SetName(ctx context.Context, in *MsgSetName, opts ...grpc.CallOption) (*MsgSetNameResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgSetNameResponse)
err := c.cc.Invoke(ctx, Msg_SetName_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_SetName_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -133,8 +142,9 @@ func (c *msgClient) SetName(ctx context.Context, in *MsgSetName, opts ...grpc.Ca
}
func (c *msgClient) DeleteName(ctx context.Context, in *MsgDeleteName, opts ...grpc.CallOption) (*MsgDeleteNameResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgDeleteNameResponse)
err := c.cc.Invoke(ctx, Msg_DeleteName_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_DeleteName_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -142,8 +152,9 @@ func (c *msgClient) DeleteName(ctx context.Context, in *MsgDeleteName, opts ...g
}
func (c *msgClient) ReserveAuthority(ctx context.Context, in *MsgReserveAuthority, opts ...grpc.CallOption) (*MsgReserveAuthorityResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgReserveAuthorityResponse)
err := c.cc.Invoke(ctx, Msg_ReserveAuthority_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_ReserveAuthority_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -151,8 +162,9 @@ func (c *msgClient) ReserveAuthority(ctx context.Context, in *MsgReserveAuthorit
}
func (c *msgClient) SetAuthorityBond(ctx context.Context, in *MsgSetAuthorityBond, opts ...grpc.CallOption) (*MsgSetAuthorityBondResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgSetAuthorityBondResponse)
err := c.cc.Invoke(ctx, Msg_SetAuthorityBond_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_SetAuthorityBond_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -160,8 +172,9 @@ func (c *msgClient) SetAuthorityBond(ctx context.Context, in *MsgSetAuthorityBon
}
func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MsgUpdateParamsResponse)
err := c.cc.Invoke(ctx, Msg_UpdateParams_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Msg_UpdateParams_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -170,7 +183,9 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts
// MsgServer is the server API for Msg service.
// All implementations must embed UnimplementedMsgServer
// for forward compatibility
// for forward compatibility.
//
// Msg is a service which exposes the registry functionality
type MsgServer interface {
// SetRecord records a new record with given payload and bond id
SetRecord(context.Context, *MsgSetRecord) (*MsgSetRecordResponse, error)
@ -198,9 +213,12 @@ type MsgServer interface {
mustEmbedUnimplementedMsgServer()
}
// UnimplementedMsgServer must be embedded to have forward compatible implementations.
type UnimplementedMsgServer struct {
}
// UnimplementedMsgServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedMsgServer struct{}
func (UnimplementedMsgServer) SetRecord(context.Context, *MsgSetRecord) (*MsgSetRecordResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SetRecord not implemented")
@ -236,6 +254,7 @@ func (UnimplementedMsgServer) UpdateParams(context.Context, *MsgUpdateParams) (*
return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented")
}
func (UnimplementedMsgServer) mustEmbedUnimplementedMsgServer() {}
func (UnimplementedMsgServer) testEmbeddedByValue() {}
// UnsafeMsgServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MsgServer will
@ -245,6 +264,13 @@ type UnsafeMsgServer interface {
}
func RegisterMsgServer(s grpc.ServiceRegistrar, srv MsgServer) {
// If the following call pancis, it indicates UnimplementedMsgServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Msg_ServiceDesc, srv)
}

View File

@ -2,91 +2,90 @@ package app
import (
_ "embed"
"io"
"os"
"path/filepath"
"fmt"
dbm "github.com/cosmos/cosmos-db"
"cosmossdk.io/core/appconfig"
coreserver "cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/depinject/appconfig"
"cosmossdk.io/runtime/v2"
serverstore "cosmossdk.io/server/v2/store"
"cosmossdk.io/store/v2"
"cosmossdk.io/store/v2/commitment/iavlv2"
"cosmossdk.io/store/v2/root"
basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject"
bankkeeper "cosmossdk.io/x/bank/keeper"
consensuskeeper "cosmossdk.io/x/consensus/keeper"
distrkeeper "cosmossdk.io/x/distribution/keeper"
govkeeper "cosmossdk.io/x/gov/keeper"
slashingkeeper "cosmossdk.io/x/slashing/keeper"
stakingkeeper "cosmossdk.io/x/staking/keeper"
auctionkeeper "git.vdb.to/cerc-io/laconicd/x/auction/keeper"
bondkeeper "git.vdb.to/cerc-io/laconicd/x/bond/keeper"
onboardingkeeper "git.vdb.to/cerc-io/laconicd/x/onboarding/keeper"
registrykeeper "git.vdb.to/cerc-io/laconicd/x/registry/keeper"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/std"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
consensuskeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper"
crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper"
distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/cosmos/cosmos-sdk/x/gov"
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
_ "cosmossdk.io/api/cosmos/tx/config/v1" // import for side-effects
_ "cosmossdk.io/runtime/v2/services" // import for side-effects
_ "cosmossdk.io/x/accounts" // import for side-effects
_ "cosmossdk.io/x/bank" // import for side-effects
_ "cosmossdk.io/x/consensus" // import for side-effects
_ "cosmossdk.io/x/distribution" // import for side-effects
_ "cosmossdk.io/x/gov" // import for side-effects
_ "cosmossdk.io/x/mint" // import for side-effects
_ "cosmossdk.io/x/protocolpool" // import for side-effects
_ "cosmossdk.io/x/slashing" // import for side-effects
_ "cosmossdk.io/x/staking" // import for side-effects
_ "git.vdb.to/cerc-io/laconicd/x/auction/module" // import for side-effects
_ "git.vdb.to/cerc-io/laconicd/x/bond/module" // import for side-effects
_ "git.vdb.to/cerc-io/laconicd/x/onboarding/module" // import for side-effects
_ "git.vdb.to/cerc-io/laconicd/x/registry/module" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/crypto/codec" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/auth" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/bank" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/consensus" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/crisis" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/distribution" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/mint" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/slashing" // import for side-effects
_ "github.com/cosmos/cosmos-sdk/x/staking" // import for side-effects
"git.vdb.to/cerc-io/laconicd/server/distsig"
"git.vdb.to/cerc-io/laconicd/utils"
auctionkeeper "git.vdb.to/cerc-io/laconicd/x/auction/keeper"
bondkeeper "git.vdb.to/cerc-io/laconicd/x/bond/keeper"
nitrokeeper "git.vdb.to/cerc-io/laconicd/x/nitrobank/keeper"
onboardingkeeper "git.vdb.to/cerc-io/laconicd/x/onboarding/keeper"
registrykeeper "git.vdb.to/cerc-io/laconicd/x/registry/keeper"
)
// DefaultNodeHome default home directories for the application daemon
var DefaultNodeHome string
//go:embed app.yaml
var AppConfigYAML []byte
var (
_ runtime.AppI = (*LaconicApp)(nil)
_ servertypes.Application = (*LaconicApp)(nil)
//go:embed app.yaml
AppConfigYAML []byte
_ = basedepinject.ProvideAccount // TODO: build consensus controlled module accounts
)
type (
Tx = transaction.Tx
AppBuilder = runtime.AppBuilder[Tx]
)
// LaconicApp extends an ABCI application, but with most of its parameters exported.
// They are exported for convenience in creating helper functions, as object
// capabilities aren't needed for testing.
type LaconicApp struct {
*runtime.App
legacyAmino *codec.LegacyAmino
type LaconicApp[T Tx] struct {
*runtime.App[T]
// legacyAmino *codec.LegacyAmino
appCodec codec.Codec
txConfig client.TxConfig
interfaceRegistry codectypes.InterfaceRegistry
store store.RootStore
distsigManager *distsig.Manager
// keepers
// basic keepers
AccountKeeper authkeeper.AccountKeeper
BankKeeper bankkeeper.Keeper
StakingKeeper *stakingkeeper.Keeper
SlashingKeeper slashingkeeper.Keeper
DistrKeeper distrkeeper.Keeper
GovKeeper *govkeeper.Keeper
CrisisKeeper *crisiskeeper.Keeper
ConsensusParamsKeeper consensuskeeper.Keeper
// laconic keepers
@ -94,141 +93,128 @@ type LaconicApp struct {
BondKeeper *bondkeeper.Keeper
RegistryKeeper registrykeeper.Keeper
OnboardingKeeper *onboardingkeeper.Keeper
// simulation manager
sm *module.SimulationManager
}
func init() {
userHomeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
DefaultNodeHome = filepath.Join(userHomeDir, ".laconicd")
NitroKeeper *nitrokeeper.Keeper
}
// AppConfig returns the default app config.
func AppConfig() depinject.Config {
return depinject.Configs(
appconfig.LoadYAML(AppConfigYAML),
runtime.DefaultServiceBindings(),
depinject.Supply(
// supply custom module basics
map[string]module.AppModuleBasic{
genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
govtypes.ModuleName: gov.NewAppModuleBasic(
[]govclient.ProposalHandler{
paramsclient.ProposalHandler,
},
),
},
utils.NewAddressCodec,
utils.NewValAddressCodec,
utils.NewConsAddressCodec,
),
depinject.Provide(
codec.ProvideInterfaceRegistry,
codec.ProvideAddressCodec,
codec.ProvideProtoCodec,
codec.ProvideLegacyAmino, // note: needed by ProvideAppBuilder (runtime/v2)
ProvideRootStoreConfig,
distsig.ProvideManager,
// // inject desired account types:
// basedepinject.ProvideAccount,
// multisigdepinject.ProvideAccount,
// lockupdepinject.ProvideAllLockupAccounts,
// // provide base account options
// basedepinject.ProvideSecp256K1PubKey,
),
depinject.Invoke(
std.RegisterInterfaces,
// std.RegisterLegacyAminoCodec,
),
)
}
// NewLaconicApp returns a reference to an initialized LaconicApp.
func NewLaconicApp(
logger log.Logger,
db dbm.DB,
traceStore io.Writer,
loadLatest bool,
appOpts servertypes.AppOptions,
baseAppOptions ...func(*baseapp.BaseApp),
) (*LaconicApp, error) {
func NewLaconicApp[T Tx](
config depinject.Config,
outputs ...any,
) (*LaconicApp[T], error) {
var (
app = &LaconicApp{}
appBuilder *runtime.AppBuilder
app LaconicApp[T]
appBuilder *runtime.AppBuilder[T]
storeBuilder root.Builder
err error
)
if err := depinject.Inject(
depinject.Configs(
AppConfig(),
depinject.Supply(
logger,
appOpts,
),
),
outputs = append(outputs,
&storeBuilder,
&appBuilder,
&app.appCodec,
&app.legacyAmino,
// &app.legacyAmino,
&app.txConfig,
&app.interfaceRegistry,
&app.distsigManager,
// modules
&app.StakingKeeper,
&app.AccountKeeper,
&app.BankKeeper,
&app.StakingKeeper,
&app.SlashingKeeper,
&app.DistrKeeper,
&app.GovKeeper,
&app.CrisisKeeper,
&app.ConsensusParamsKeeper,
&app.AuctionKeeper,
&app.BondKeeper,
&app.RegistryKeeper,
&app.OnboardingKeeper,
)
if err = depinject.Inject(
depinject.Configs(AppConfig(), config),
outputs...,
); err != nil {
return nil, err
}
app.App = appBuilder.Build(db, traceStore, baseAppOptions...)
// register streaming services
if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil {
app.App, err = appBuilder.Build()
if err != nil {
return nil, err
}
/**** Module Options ****/
app.ModuleManager.RegisterInvariants(app.CrisisKeeper)
// create the simulation manager and define the order of the modules for deterministic simulations
// NOTE: this is not required apps that don't use the simulator for fuzz testing transactions
app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, make(map[string]module.AppModuleSimulation, 0))
app.sm.RegisterStoreDecoders()
if err := app.Load(loadLatest); err != nil {
return nil, err
app.store = storeBuilder.Get()
if app.store == nil {
return nil, fmt.Errorf("store builder did not return a db")
}
return app, nil
// TODO: db config correct?
// TODO: store metrics, tracer?
// TODO: streaming services?
// TODO: upgrade handlers?
if err = app.LoadLatest(); err != nil {
return nil, err
}
return &app, nil
}
// LegacyAmino returns LaconicApp's amino codec.
func (app *LaconicApp) LegacyAmino() *codec.LegacyAmino {
return app.legacyAmino
func (app *LaconicApp[T]) InterfaceRegistry() coreserver.InterfaceRegistry {
return app.interfaceRegistry
}
// GetKey returns the KVStoreKey for the provided store key.
func (app *LaconicApp) GetKey(storeKey string) *storetypes.KVStoreKey {
sk := app.UnsafeFindStoreKey(storeKey)
kvStoreKey, ok := sk.(*storetypes.KVStoreKey)
if !ok {
return nil
}
return kvStoreKey
}
func (app *LaconicApp) kvStoreKeys() map[string]*storetypes.KVStoreKey {
keys := make(map[string]*storetypes.KVStoreKey)
for _, k := range app.GetStoreKeys() {
if kv, ok := k.(*storetypes.KVStoreKey); ok {
keys[kv.Name()] = kv
}
}
return keys
}
// SimulationManager implements the SimulationApp interface
func (app *LaconicApp) SimulationManager() *module.SimulationManager {
return app.sm
}
// RegisterAPIRoutes registers all application module routes with the provided
// API server.
func (app *LaconicApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
app.App.RegisterAPIRoutes(apiSvr, apiConfig)
// register swagger API in app.go so that other applications can override easily
if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil {
panic(err)
func (app *LaconicApp[T]) Store() store.RootStore {
return app.store
}
func (app *LaconicApp[T]) AppCodec() codec.Codec {
return app.appCodec
}
func (app *LaconicApp[T]) DistSigManager() *distsig.Manager {
return app.distsigManager
}
func ProvideRootStoreConfig(config runtime.GlobalConfig) (*root.Config, error) {
cfg, err := serverstore.UnmarshalConfig(config)
if err != nil {
return nil, err
}
cfg.Options.IavlV2Config = iavlv2.DefaultConfig()
cfg.Options.IavlV2Config.MinimumKeepVersions = int64(cfg.Options.SCPruningOption.KeepRecent)
iavlv2.SetGlobalPruneLimit(1)
return cfg, err
}

View File

@ -1,19 +1,43 @@
modules:
- name: runtime
config:
"@type": cosmos.app.runtime.v1alpha1.Module
"@type": cosmos.app.runtime.v2.Module
app_name: LaconicApp
# During begin block slashing happens after distr.BeginBlocker so that
# there is nothing left over in the validator fee pool, so as to keep the CanWithdrawInvariant invariant.
# NOTE: staking module is required if HistoricalEntries param > 0
begin_blockers: [distribution, slashing, staking]
end_blockers: [crisis, gov, staking, auction, registry]
begin_blockers: [distribution, protocolpool, slashing, staking]
end_blockers: [gov, staking, protocolpool, auction, registry]
# NOTE: The genutils module must occur after staking so that pools are properly initialized with tokens from genesis accounts.
# NOTE: The genutils module must also occur after auth so that it can access the params from auth.
init_genesis: [auth, bank, distribution, staking, slashing, gov, crisis, genutil, auction, bond, registry, onboarding]
init_genesis:
- consensus
- accounts
- auth
- bank
- distribution
- staking
- slashing
- gov
- genutil
- protocolpool
- auction
- bond
- registry
- onboarding
gas_config:
validate_tx_gas_limit: 100000,
query_gas_limit: 100000,
simulation_gas_limit: 100000,
override_store_keys:
- module_name: auth
kv_store_key: acc
skip_store_keys:
- tx
- validate
- genutil
- runtime
- vesting
- name: auth
config:
"@type": cosmos.auth.module.v1.Module
@ -27,6 +51,9 @@ modules:
permissions: [burner, staking]
- account: gov
permissions: [burner]
- account: protocolpool
- account: stream_acc
- account: protocolpool_distr
- account: auction
- account: auction_burn
- account: bond
@ -59,9 +86,12 @@ modules:
- name: gov
config:
"@type": cosmos.gov.module.v1.Module
- name: crisis
- name: accounts
config:
"@type": cosmos.crisis.module.v1.Module
"@type": cosmos.accounts.module.v1.Module
- name: protocolpool
config:
"@type": cosmos.protocolpool.module.v1.Module
- name: bond
config:
"@type": cerc.bond.module.v1.Module

107
app/app_abci.go Normal file
View File

@ -0,0 +1,107 @@
package app
import (
"bytes"
"context"
"encoding/gob"
"cosmossdk.io/core/store"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
"git.vdb.to/cerc-io/laconicd/server/distsig"
"git.vdb.to/cerc-io/laconicd/x/onboarding"
)
func (app *LaconicApp[T]) ExtendVote(
ctx context.Context, _ store.ReaderMap, req *abci.ExtendVoteRequest,
) (*abci.ExtendVoteResponse, error) {
dsm := app.DistSigManager()
ourEthAddress := dsm.LongtermEthAddress()
us, err := app.OnboardingKeeper.GetParticipantByNitroAddress(ctx, ourEthAddress.String())
if err != nil {
return nil, err
}
if us == nil { // if we are not a participant, we don't need to do anything
return nil, nil
}
// // If any OnboardParticipant tx (or any tx that changes validator set) has been processed,
// // begin DKG for the new participants. The extension will contain our DKG deals.
// newParticipants := false
// for _, tx := range req.Txs {
// var opMsg onboarding.MsgOnboardParticipant
// if err := opMsg.Unmarshal(tx); err != nil {
// // we've already processed the tx, so we don't need to look at the message; we know the
// // participant set has changed and we need to run DKG.
// newParticipants = true
// }
// }
// // TODO: check if responses are processed, generate commits
// if !newParticipants {
// return nil, nil
// }
// Get public keys of participants
var pubkeys []distsig.Point
if err := app.OnboardingKeeper.Participants.Walk(ctx, nil, func(_ string, p onboarding.Participant) (bool, error) {
var pubkey distsig.Point
if err := pubkey.UnmarshalBinary(p.PublicKey); err != nil {
return false, err
}
pubkeys = append(pubkeys, pubkey)
return false, nil
}); err != nil {
return nil, err
}
if !dsm.NeedDKG(pubkeys) {
app.Logger().Debug("No change in DSS participants")
return nil, nil
}
if err = dsm.StartDKG(req.Height, pubkeys); err != nil {
return nil, err
}
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)
if err := enc.Encode(dsm.FlushDKGMessages()); err != nil {
return nil, err
}
var extension []byte
if len(buf.Bytes()) != 0 {
extension = buf.Bytes()
}
return &abci.ExtendVoteResponse{
VoteExtension: extension,
}, nil
}
func (app *LaconicApp[T]) VerifyVoteExtension(
ctx context.Context, _ store.ReaderMap, req *abci.VerifyVoteExtensionRequest,
) (*abci.VerifyVoteExtensionResponse, error) {
dec := gob.NewDecoder(bytes.NewReader(req.VoteExtension))
var messages distsig.DkgMessages
if err := dec.Decode(&messages); err != nil {
return nil, err
}
// // This method must be deterministic, so just check that there is a deal for each participant
// numParticipants := 0
// app.OnboardingKeeper.Participants.Walk(ctx, nil, func(string, onboarding.Participant) (bool, error) {
// numParticipants++
// return false, nil
// })
// if len(deals) != numParticipants {
// return &abci.VerifyVoteExtensionResponse{
// Status: abci.VERIFY_VOTE_EXTENSION_STATUS_REJECT,
// }, nil
// }
err := app.DistSigManager().ProcessDKGMessages(&messages)
if err != nil {
return nil, err
}
// This method must be deterministic, so just accept whatever for now (TODO: actually verify)
return &abci.VerifyVoteExtensionResponse{
Status: abci.VERIFY_VOTE_EXTENSION_STATUS_ACCEPT,
}, nil
}

176
app/app_test.go Normal file
View File

@ -0,0 +1,176 @@
package app
import (
"context"
"crypto/sha256"
"encoding/json"
"testing"
"time"
"git.vdb.to/cerc-io/laconicd/server/distsig"
"git.vdb.to/cerc-io/laconicd/utils"
"github.com/cometbft/cometbft/types"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"cosmossdk.io/core/comet"
context2 "cosmossdk.io/core/context"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
sdkmath "cosmossdk.io/math"
"cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
serverv2store "cosmossdk.io/server/v2/store"
"cosmossdk.io/store/v2/db"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdktestutil "github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/mock"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"git.vdb.to/cerc-io/laconicd/testutil"
)
func NewTestApp(t *testing.T) (*LaconicApp[Tx], context.Context) {
t.Helper()
logger := log.NewTestLogger(t)
vp := viper.New()
vp.Set(serverv2store.FlagAppDBBackend, string(db.DBTypeGoLevelDB))
vp.Set(serverv2.FlagHome, t.TempDir())
// set up long-term distsig key
kr := testutil.NewKeyring()
accounts := sdktestutil.CreateKeyringAccounts(t, kr, 1)
vp.Set(distsig.FlagLongtermKey, accounts[0].Name)
app, err := NewLaconicApp[Tx](depinject.Configs(
depinject.Supply(logger, runtime.GlobalConfig(vp.AllSettings()), kr),
))
require.NoError(t, err)
genesis := app.ModuleManager().DefaultGenesis()
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)
// create validator set with single validator
validator := types.NewValidator(pubKey, 1)
valSet := types.NewValidatorSet([]*types.Validator{validator})
// generate genesis account
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
accAddr, err := app.txConfig.SigningContext().AddressCodec().BytesToString(acc.GetAddress())
require.NoError(t, err)
balance := banktypes.Balance{
Address: accAddr,
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000))),
}
genesis, err = simtestutil.GenesisStateWithValSet(
app.AppCodec(),
utils.NewAddressCodec(),
utils.NewValAddressCodec(),
genesis,
valSet,
[]authtypes.GenesisAccount{acc},
balance,
)
require.NoError(t, err)
genesisBytes, err := json.Marshal(genesis)
require.NoError(t, err)
st := app.Store()
ci, err := st.LastCommitID()
require.NoError(t, err)
bz := sha256.Sum256([]byte{})
ctx := context.Background()
_, newState, err := app.InitGenesis(
ctx,
&server.BlockRequest[Tx]{
Time: time.Now(),
Hash: bz[:],
ChainId: "theChain",
AppHash: ci.Hash,
IsGenesis: true,
Height: 1,
},
genesisBytes,
nil,
)
require.NoError(t, err)
changes, err := newState.GetStateChanges()
require.NoError(t, err)
_, err = st.Commit(&store.Changeset{Version: 1, Changes: changes})
require.NoError(t, err)
return app, ctx
}
func MoveNextBlock(t *testing.T, app *LaconicApp[Tx], ctx context.Context) {
t.Helper()
bz := sha256.Sum256([]byte{})
st := app.Store()
ci, err := st.LastCommitID()
require.NoError(t, err)
height, err := app.LoadLatestHeight()
height++
require.NoError(t, err)
// TODO: this is a hack to set the comet info in the context for distribution module dependency.
ctx = context.WithValue(ctx, context2.CometInfoKey, comet.Info{
Evidence: nil,
ValidatorsHash: nil,
ProposerAddress: nil,
LastCommit: comet.CommitInfo{},
})
_, newState, err := app.DeliverBlock(
ctx,
&server.BlockRequest[Tx]{
Height: height,
Time: time.Now(),
Hash: bz[:],
AppHash: ci.Hash,
})
require.NoError(t, err)
changes, err := newState.GetStateChanges()
require.NoError(t, err)
_, err = st.Commit(&store.Changeset{Version: height, Changes: changes})
require.NoError(t, err)
}
func TestSimAppExportAndBlockedAddrs_WithOneBlockProduced(t *testing.T) {
app, ctx := NewTestApp(t)
MoveNextBlock(t, app, ctx)
_, err := app.ExportAppStateAndValidators(false, nil)
require.NoError(t, err)
}
func TestSimAppExportAndBlockedAddrs_NoBlocksProduced(t *testing.T) {
app, _ := NewTestApp(t)
_, err := app.ExportAppStateAndValidators(false, nil)
require.NoError(t, err)
}

View File

@ -1,243 +1,54 @@
package app
import (
"encoding/json"
"errors"
"fmt"
"log"
"context"
storetypes "cosmossdk.io/store/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdk "github.com/cosmos/cosmos-sdk/types"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"cosmossdk.io/runtime/v2/services"
"cosmossdk.io/x/staking"
v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2"
)
// ExportAppStateAndValidators exports the state of the application for a genesis file.
func (app *LaconicApp) ExportAppStateAndValidators(
// ExportAppStateAndValidators exports the state of the application for a genesis
// file.
// This is a demonstration of how to export a genesis file. Export may need extended at
// the user discretion for cleaning the genesis state at the end provided with jailAllowedAddrs
// Same applies for forZeroHeight preprocessing.
func (app *LaconicApp[T]) ExportAppStateAndValidators(
forZeroHeight bool,
jailAllowedAddrs []string,
modulesToExport []string,
) (servertypes.ExportedApp, error) {
// as if they could withdraw from the start of the next block
ctx := app.NewContextLegacy(true, tmproto.Header{Height: app.LastBlockHeight()})
) (v2.ExportedApp, error) {
ctx := context.Background()
var exportedApp v2.ExportedApp
// We export at last height + 1, because that's the height at which
// CometBFT will start InitChain.
height := app.LastBlockHeight() + 1
latestHeight, err := app.LoadLatestHeight()
if err != nil {
return exportedApp, err
}
genesis, err := app.ExportGenesis(ctx, latestHeight)
if err != nil {
return exportedApp, err
}
readerMap, err := app.Store().StateAt(latestHeight)
if err != nil {
return exportedApp, err
}
genesisCtx := services.NewGenesisContext(readerMap)
err = genesisCtx.Read(ctx, func(ctx context.Context) error {
exportedApp.Validators, err = staking.WriteValidators(ctx, app.StakingKeeper)
return err
})
if err != nil {
return exportedApp, err
}
exportedApp.AppState = genesis
exportedApp.Height = int64(latestHeight)
if forZeroHeight {
height = 0
app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
exportedApp.Height = 0
}
genState, err := app.ModuleManager.ExportGenesis(ctx, app.appCodec)
if err != nil {
return servertypes.ExportedApp{}, fmt.Errorf("failed to export genesis state: %w", err)
}
appState, err := json.MarshalIndent(genState, "", " ")
if err != nil {
return servertypes.ExportedApp{}, err
}
validators, err := staking.WriteValidators(ctx, app.StakingKeeper)
return servertypes.ExportedApp{
AppState: appState,
Validators: validators,
Height: height,
ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
}, err
}
// prepare for fresh start at zero height
// NOTE zero height genesis is a temporary feature, which will be deprecated in favor of export at a block height
func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) {
applyAllowedAddrs := false
// check if there is a allowed address list
if len(jailAllowedAddrs) > 0 {
applyAllowedAddrs = true
}
allowedAddrsMap := make(map[string]bool)
for _, addr := range jailAllowedAddrs {
_, err := sdk.ValAddressFromBech32(addr)
if err != nil {
log.Fatal(err)
}
allowedAddrsMap[addr] = true
}
/* Handle fee distribution state. */
// withdraw all validator commission
_ = app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator())
if err != nil {
panic(err)
}
_, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, valBz)
return false
})
// withdraw all delegator rewards
dels, err := app.StakingKeeper.GetAllDelegations(ctx)
if err != nil {
panic(err)
}
for _, delegation := range dels {
valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress)
if err != nil {
panic(err)
}
delAddr, err := sdk.AccAddressFromBech32(delegation.DelegatorAddress)
if err != nil {
panic(err)
}
_, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr)
}
// clear validator slash events
app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx)
// clear validator historical rewards
app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx)
// set context height to zero
height := ctx.BlockHeight()
ctx = ctx.WithBlockHeight(0)
// reinitialize all validators
_ = app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator())
if err != nil {
panic(err)
}
// donate any unwithdrawn outstanding reward fraction tokens to the community pool
scraps, err := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, valBz)
if err != nil {
panic(err)
}
feePool, err := app.DistrKeeper.FeePool.Get(ctx)
if err != nil {
panic(err)
}
feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
if err := app.DistrKeeper.FeePool.Set(ctx, feePool); err != nil {
panic(err)
}
if err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, valBz); err != nil {
panic(err)
}
return false
})
// reinitialize all delegations
for _, del := range dels {
valAddr, err := sdk.ValAddressFromBech32(del.ValidatorAddress)
if err != nil {
panic(err)
}
delAddr, err := sdk.AccAddressFromBech32(del.DelegatorAddress)
if err != nil {
panic(err)
}
if err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr); err != nil {
// never called as BeforeDelegationCreated always returns nil
panic(fmt.Errorf("error while incrementing period: %w", err))
}
if err := app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr); err != nil {
// never called as AfterDelegationModified always returns nil
panic(fmt.Errorf("error while creating a new delegation period record: %w", err))
}
}
// reset context height
ctx = ctx.WithBlockHeight(height)
/* Handle staking state. */
// iterate through redelegations, reset creation height
_ = app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) {
for i := range red.Entries {
red.Entries[i].CreationHeight = 0
}
_ = app.StakingKeeper.SetRedelegation(ctx, red)
return false
})
// iterate through unbonding delegations, reset creation height
_ = app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) {
for i := range ubd.Entries {
ubd.Entries[i].CreationHeight = 0
}
_ = app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
return false
})
// Iterate through validators by power descending, reset bond heights, and
// update bond intra-tx counters.
store := ctx.KVStore(app.GetKey(stakingtypes.StoreKey))
iter := storetypes.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey)
counter := int16(0)
for ; iter.Valid(); iter.Next() {
addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key()))
validator, err := app.StakingKeeper.GetValidator(ctx, addr)
if errors.Is(err, stakingtypes.ErrNoValidatorFound) {
panic("expected validator, not found")
} else if err != nil {
panic(err)
}
validator.UnbondingHeight = 0
if applyAllowedAddrs && !allowedAddrsMap[addr.String()] {
validator.Jailed = true
}
_ = app.StakingKeeper.SetValidator(ctx, validator)
counter++
}
if err := iter.Close(); err != nil {
app.Logger().Error("error while closing the key-value store reverse prefix iterator: ", err)
return
}
_, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
if err != nil {
log.Fatal(err)
}
/* Handle slashing state. */
// reset start height on signing infos
err = app.SlashingKeeper.IterateValidatorSigningInfos(
ctx,
func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) {
info.StartHeight = 0
err = app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
if err != nil {
log.Fatal(err)
}
return false
},
)
if err != nil {
log.Fatal(err)
}
return exportedApp, nil
}

View File

@ -1,14 +1,5 @@
package params
import (
"cosmossdk.io/errors"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
const (
CoinUnit = "lnt"
BaseCoinUnit = "alnt"
@ -34,43 +25,18 @@ var (
)
func init() {
SetAddressPrefixes()
RegisterDenoms()
}
func RegisterDenoms() {
err := sdk.RegisterDenom(CoinUnit, math.LegacyOneDec())
if err != nil {
panic(err)
}
// TODO refactor
// err := sdk.RegisterDenom(CoinUnit, math.LegacyOneDec())
// if err != nil {
// panic(err)
// }
err = sdk.RegisterDenom(BaseCoinUnit, math.LegacyNewDecWithPrec(1, LntExponent))
if err != nil {
panic(err)
}
}
func SetAddressPrefixes() {
config := sdk.GetConfig()
config.SetBech32PrefixForAccount(Bech32PrefixAccAddr, Bech32PrefixAccPub)
config.SetBech32PrefixForValidator(Bech32PrefixValAddr, Bech32PrefixValPub)
config.SetBech32PrefixForConsensusNode(Bech32PrefixConsAddr, Bech32PrefixConsPub)
// This is copied from the cosmos sdk v0.43.0-beta1
// source: https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/types/address.go#L141
config.SetAddressVerifier(func(bytes []byte) error {
if len(bytes) == 0 {
return errors.Wrap(sdkerrors.ErrUnknownAddress, "addresses cannot be empty")
}
if len(bytes) > address.MaxAddrLen {
return errors.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", address.MaxAddrLen, len(bytes))
}
if len(bytes) != 20 && len(bytes) != 32 {
return errors.Wrapf(sdkerrors.ErrUnknownAddress, "address length must be 20 or 32 bytes, got %d", len(bytes))
}
return nil
})
// err = sdk.RegisterDenom(BaseCoinUnit, math.LegacyNewDecWithPrec(1, LntExponent))
// if err != nil {
// panic(err)
// }
}

View File

@ -1,71 +1,195 @@
package cmd
import (
"context"
"errors"
"io"
dbm "github.com/cosmos/cosmos-db"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/sync/errgroup"
"cosmossdk.io/client/v2/offchain"
coreserver "cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
runtimev2 "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/api/grpc"
"cosmossdk.io/server/v2/api/rest"
"cosmossdk.io/server/v2/api/telemetry"
"cosmossdk.io/server/v2/cometbft"
serverstore "cosmossdk.io/server/v2/store"
confixcmd "cosmossdk.io/tools/confix/cmd"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/client/debug"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/pruning"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/snapshot"
"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdktelemetry "github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
genutilv2cli "github.com/cosmos/cosmos-sdk/x/genutil/v2/cli"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/gql"
"git.vdb.to/cerc-io/laconicd/server/distsig"
"git.vdb.to/cerc-io/laconicd/server/nitro"
)
func initRootCmd(rootCmd *cobra.Command, txConfig client.TxConfig, basicManager module.BasicManager) {
// CommandDependencies is a struct that contains all the dependencies needed to initialize the root command.
// an alternative design could fetch these even later from the command context
type CommandDependencies[T app.Tx] struct {
GlobalConfig coreserver.ConfigMap
ModuleManager *runtimev2.MM[T]
LaconicApp *app.LaconicApp[T]
ClientContext client.Context
DistSigManager *distsig.Manager
// NitroServer *nitro.Server
}
func InitRootCmd[T app.Tx](
rootCmd *cobra.Command,
logger log.Logger,
deps CommandDependencies[T],
) (serverv2.ConfigWriter, error) {
cfg := sdk.GetConfig()
cfg.Seal()
rootCmd.AddCommand(
genutilcli.InitCmd(basicManager, app.DefaultNodeHome),
genutilcli.InitCmd(deps.ModuleManager),
genesisCommand(deps.ModuleManager, deps.LaconicApp),
NewTestnetCmd(deps.ModuleManager),
debug.Cmd(),
confixcmd.ConfigCommand(),
pruning.Cmd(newApp, app.DefaultNodeHome),
snapshot.Cmd(newApp),
)
server.AddCommands(rootCmd, app.DefaultNodeHome, newApp, appExport, func(startCmd *cobra.Command) {
// Override start command to run the GQL server
newStartCmd := server.StartCmdWithOptions(newApp, app.DefaultNodeHome, server.StartCmdOptions{
PostSetup: func(svrCtx *server.Context, clientCtx client.Context, ctx context.Context, g *errgroup.Group) error {
g.Go(func() error {
return gql.Server(ctx, clientCtx, svrCtx.Logger.With("module", "gql-server"))
})
return nil
},
})
startCmd.RunE = newStartCmd.RunE
})
// add keybase, auxiliary RPC, query, genesis, and tx child commands
rootCmd.AddCommand(
server.StatusCommand(),
genutilcli.Commands(txConfig, basicManager, app.DefaultNodeHome),
// add keybase, auxiliary RPC, query, genesis, and tx child commands
queryCommand(),
txCommand(),
keys.Commands(),
offchain.OffChain(),
)
// TODO
// pruning.Cmd(newApp),
// snapshot.Cmd(newApp),
// build CLI skeleton for initial config parsing or a client application invocation
if deps.LaconicApp == nil {
return serverv2.AddCommands[T](
rootCmd,
logger,
io.NopCloser(nil),
deps.GlobalConfig,
initServerConfig(),
cometbft.NewWithConfigOptions[T](initCometConfig()),
&grpc.Server[T]{},
&serverstore.Server[T]{},
&telemetry.Server[T]{},
&rest.Server[T]{},
// &grpcgateway.Server[T]{},
// &swagger.Server[T]{},
&gql.Server{},
&nitro.Server{},
&distsig.Manager{},
)
}
// build full app!
app := deps.LaconicApp
// store component (not a server)
storeComponent, err := serverstore.New[T](app.Store(), deps.GlobalConfig)
if err != nil {
return nil, err
}
restServer, err := rest.New(logger, app.App.AppManager, deps.GlobalConfig)
if err != nil {
return nil, err
}
// consensus component
consensusServer, err := cometbft.New(
logger,
app.Name(),
app.Store(),
app.App.AppManager,
cometbft.AppCodecs[T]{
AppCodec: app.AppCodec(),
TxCodec: &client.DefaultTxDecoder[T]{TxConfig: deps.ClientContext.TxConfig},
LegacyAmino: deps.ClientContext.LegacyAmino,
ConsensusAddressCodec: deps.ClientContext.ConsensusAddressCodec,
},
app.App.QueryHandlers(),
app.App.SchemaDecoderResolver(),
initCometOptions[T](app),
deps.GlobalConfig,
)
if err != nil {
return nil, err
}
telemetryServer, err := telemetry.New[T](logger, sdktelemetry.EnableTelemetry, deps.GlobalConfig)
if err != nil {
return nil, err
}
grpcServer, err := grpc.New[T](
logger,
app.InterfaceRegistry(),
app.QueryHandlers(),
app.Query,
deps.GlobalConfig,
grpc.WithExtraGRPCHandlers[T](
consensusServer.GRPCServiceRegistrar(
deps.ClientContext,
deps.GlobalConfig,
),
),
)
if err != nil {
return nil, err
}
gqlServer, err := gql.New(logger, deps.GlobalConfig, deps.ClientContext)
if err != nil {
return nil, err
}
nitroServer, err := nitro.NewServer(logger, deps.GlobalConfig, deps.ClientContext.Keyring)
if err != nil {
return nil, err
}
// wire server commands
return serverv2.AddCommands[T](
rootCmd,
logger,
app,
deps.GlobalConfig,
initServerConfig(),
consensusServer,
grpcServer,
storeComponent,
telemetryServer,
restServer,
gqlServer,
deps.DistSigManager,
nitroServer,
)
}
// genesisCommand builds genesis-related `simd genesis` command.
func genesisCommand[T app.Tx](
moduleManager *runtimev2.MM[T],
app *app.LaconicApp[T],
) *cobra.Command {
var genTxValidator func([]transaction.Msg) error
if moduleManager != nil {
genTxValidator = moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule).GenTxValidator()
}
cmd := genutilv2cli.Commands(
genTxValidator,
moduleManager,
app,
)
return cmd
}
func queryCommand() *cobra.Command {
@ -79,12 +203,11 @@ func queryCommand() *cobra.Command {
}
cmd.AddCommand(
rpc.ValidatorCommand(),
server.QueryBlockCmd(),
cometbft.QueryBlockCmd(),
cometbft.QueryBlocksCmd(),
cometbft.QueryBlockResultsCmd(),
authcmd.QueryTxsByEventsCmd(),
server.QueryBlocksCmd(),
authcmd.QueryTxCmd(),
server.QueryBlockResultsCmd(),
)
return cmd
@ -114,64 +237,29 @@ func txCommand() *cobra.Command {
return cmd
}
// newApp is an appCreator
func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application {
baseappOptions := server.DefaultBaseappOptions(appOpts)
app, err := app.NewLaconicApp(logger, db, traceStore, true, appOpts, baseappOptions...)
if err != nil {
panic(err)
}
func RootCommandPersistentPreRun(clientCtx client.Context) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
// set the default command outputs
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())
return app
}
// appExport creates a new app (optionally at a given height) and exports state.
func appExport(
logger log.Logger,
db dbm.DB,
traceStore io.Writer,
height int64,
forZeroHeight bool,
jailAllowedAddrs []string,
appOpts servertypes.AppOptions,
modulesToExport []string,
) (servertypes.ExportedApp, error) {
var (
laconicApp *app.LaconicApp
err error
)
// this check is necessary as we use the flag in x/upgrade.
// we can exit more gracefully by checking the flag here.
homePath, ok := appOpts.Get(flags.FlagHome).(string)
if !ok || homePath == "" {
return servertypes.ExportedApp{}, errors.New("application home not set")
}
viperAppOpts, ok := appOpts.(*viper.Viper)
if !ok {
return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper")
}
// overwrite the FlagInvCheckPeriod
viperAppOpts.Set(server.FlagInvCheckPeriod, 1)
appOpts = viperAppOpts
if height != -1 {
laconicApp, err = app.NewLaconicApp(logger, db, traceStore, false, appOpts)
clientCtx = clientCtx.WithCmdContext(cmd.Context())
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return servertypes.ExportedApp{}, err
return err
}
if err := laconicApp.LoadHeight(height); err != nil {
return servertypes.ExportedApp{}, err
}
} else {
laconicApp, err = app.NewLaconicApp(logger, db, traceStore, true, appOpts)
customClientTemplate, customClientConfig := initClientConfig()
clientCtx, err = config.CreateClientConfig(
clientCtx, customClientTemplate, customClientConfig)
if err != nil {
return servertypes.ExportedApp{}, err
return err
}
}
return laconicApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
if err = client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
return err
}
return nil
}
}

View File

@ -0,0 +1,78 @@
package cmd
import (
"time"
cmtcfg "github.com/cometbft/cometbft/config"
"cosmossdk.io/core/transaction"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/cometbft"
sdk "github.com/cosmos/cosmos-sdk/types"
"git.vdb.to/cerc-io/laconicd/app"
)
// initAppConfig helps to override default client config template and configs.
// return "", nil if no custom configuration is required for the application.
func initClientConfig() (string, interface{}) {
// customClientConfigTemplate, customClientConfig
return "", nil
}
// Allow the chain developer to overwrite the server default app toml config.
func initServerConfig() serverv2.ServerConfig {
serverCfg := serverv2.DefaultServerConfig()
serverCfg.MinGasPrices = "0" + sdk.DefaultBondDenom
// The server's default minimum gas price is set to "0stake" inside
// app.toml. However, the chain developer can set a default app.toml value for their
// validators here. Please update value based on chain denom.
//
// In summary:
// - if you set serverCfg.MinGasPrices value, validators CAN tweak their
// own app.toml to override, or use this default value.
//
// In simapp, we set the min gas prices to 0.
// serverCfg.MinGasPrices = "0stake"
return serverCfg
}
// initCometConfig helps to override default comet config template and configs.
func initCometConfig() cometbft.CfgOption {
cfg := cmtcfg.DefaultConfig()
// display only warn logs by default except for p2p and state
// better default logging
cfg.LogLevel = "*:warn,server:info,p2p:info,state:info"
cfg.LogLevel += ",auction:info,bond:info,registry:info,gql-server:info"
// increase block timeout
cfg.Consensus.TimeoutCommit = 3 * time.Second
// overwrite default pprof listen address
cfg.RPC.PprofListenAddress = "localhost:6060"
// use previous db backend
cfg.DBBackend = "goleveldb"
return cometbft.OverwriteDefaultConfigTomlConfig(cfg)
}
func initCometOptions[T transaction.Tx](laconic *app.LaconicApp[T]) cometbft.ServerOptions[T] {
serverOptions := cometbft.DefaultServerOptions[T]()
// Implement custom handlers (e.g. for Vote Extensions)
// serverOptions.PrepareProposalHandler = CustomPrepareProposal[T]()
// serverOptions.ProcessProposalHandler = CustomProcessProposalHandler[T]()
serverOptions.ExtendVoteHandler = laconic.ExtendVote
serverOptions.VerifyVoteExtensionHandler = laconic.VerifyVoteExtension
// overwrite app mempool, using max-txs option
// serverOptions.Mempool = func(cfg map[string]any) mempool.Mempool[T] {
// if maxTxs := cast.ToInt(cfg[cometbft.FlagMempoolMaxTxs]); maxTxs >= 0 {
// return sdkmempool.NewSenderNonceMempool(
// sdkmempool.SenderNonceMaxTxOpt(maxTxs),
// )
// }
// return mempool.NoOpMempool[T]{}
// }
return serverOptions
}

View File

@ -0,0 +1,70 @@
package cmd
import (
"os"
"cosmossdk.io/core/address"
runtime "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/x/auth/types"
"git.vdb.to/cerc-io/laconicd/server/nitro"
)
func ProvideClientContext(
configMap runtime.GlobalConfig,
appCodec codec.Codec,
interfaceRegistry codectypes.InterfaceRegistry,
txConfig client.TxConfig,
// legacyAmino registry.AminoRegistrar,
addressCodec address.Codec,
validatorAddressCodec address.ValidatorAddressCodec,
consensusAddressCodec address.ConsensusAddressCodec,
) client.Context {
var err error
homeDir, ok := configMap[serverv2.FlagHome].(string)
if !ok {
panic("server.ConfigMap must contain a string value for serverv2.FlagHome")
}
clientCtx := client.Context{}.
WithCodec(appCodec).
WithInterfaceRegistry(interfaceRegistry).
WithTxConfig(txConfig).
// WithLegacyAmino(amino).
WithInput(os.Stdin).
WithAccountRetriever(types.AccountRetriever{}).
WithAddressCodec(addressCodec).
WithValidatorAddressCodec(validatorAddressCodec).
WithConsensusAddressCodec(consensusAddressCodec).
WithHomeDir(homeDir).
WithViper(EnvPrefix) // env variable prefix
// Read the config to overwrite the default values with the values from the config file
customClientTemplate, customClientConfig := initClientConfig()
clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig)
if err != nil {
panic(err)
}
// // Workaround: Unset clientCtx.HomeDir and clientCtx.KeyringDir from depinject clientCtx as they
// // are given precedence over the CLI args (--home flag) in some commands
// // TODO: Implement proper fix
// clientCtx.HomeDir = ""
// clientCtx.KeyringDir = ""
return clientCtx
}
func ProvideKeyring(clientCtx client.Context) keyring.Keyring {
return clientCtx.Keyring
}
func ProvideNitroService(configMap runtime.GlobalConfig) (nitro.Service, error) {
return nil, nil
}

94
cmd/laconicd/cmd/log.go Normal file
View File

@ -0,0 +1,94 @@
package cmd
import (
"fmt"
"io"
"log/slog"
"math"
"time"
"cosmossdk.io/core/server"
"cosmossdk.io/log"
sdk_slog "cosmossdk.io/log/slog"
serverv2 "cosmossdk.io/server/v2"
"github.com/lmittmann/tint"
)
// TODO stderr logger?
func newSlogLogger(cfg server.ConfigMap, out io.Writer) (log.Logger, error) {
handler, err := newSlogHandler(cfg, out)
if err != nil {
return nil, err
}
return sdk_slog.NewCustomLogger(slog.New(handler)), nil
}
// newSlogHandler creates a slog handler based on the server configuration.
func newSlogHandler(cfg server.ConfigMap, out io.Writer) (slog.Handler, error) {
var (
format string
noColor bool
trace bool
level string
)
if v, ok := cfg[serverv2.FlagLogFormat]; ok {
format = v.(string)
}
if v, ok := cfg[serverv2.FlagLogNoColor]; ok {
noColor = v.(bool)
}
if v, ok := cfg[serverv2.FlagTrace]; ok {
trace = v.(bool)
}
if v, ok := cfg[serverv2.FlagLogLevel]; ok {
level = v.(string)
}
_ = trace
logLvl, err := parseSlogLevel(level)
if err != nil {
// If the log level is not a valid zerolog level, then we try to parse it as a key filter.
filterFunc, err := log.ParseLogLevel(level, parseSlogLevel)
if err != nil {
return nil, err
}
out = log.NewFilterWriter(out, filterFunc)
}
var handler slog.Handler
// if json format is requested, ignore no_color
if format == serverv2.OutputFormatJSON {
handler = slog.NewJSONHandler(out, &slog.HandlerOptions{
Level: logLvl,
})
} else {
handler = tint.NewHandler(out, &tint.Options{
Level: logLvl,
TimeFormat: time.Kitchen,
NoColor: noColor,
})
}
return handler, nil
}
func parseSlogLevel(l string) (slog.Level, error) {
// Legal log level values are hardcoded into server/v2 command factory:
// (trace|debug|info|warn|error|fatal|panic|disabled or '*:<level>,<key>:<level>')
// however, slog only has debug, info, warn, error
switch l {
case "debug", "trace":
return slog.LevelDebug, nil
case "info":
return slog.LevelInfo, nil
case "warn":
return slog.LevelWarn, nil
case "error":
return slog.LevelError, nil
case "fatal", "panic":
return slog.LevelError, nil
case "disabled":
return slog.Level(math.MaxInt), nil
}
return 0, fmt.Errorf("invalid log level: %s", l)
}

View File

@ -1,161 +1,132 @@
package cmd
import (
"fmt"
"os"
"time"
"errors"
cmtcfg "github.com/cometbft/cometbft/config"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"cosmossdk.io/client/v2/autocli"
clientv2keyring "cosmossdk.io/client/v2/autocli/keyring"
"cosmossdk.io/core/address"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
runtime "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server"
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
"github.com/cosmos/cosmos-sdk/x/auth/types"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/gql"
"git.vdb.to/cerc-io/laconicd/server/distsig"
)
const EnvPrefix = "LACONIC"
const (
// EnvPrefix is the environment variable prefix for the application
EnvPrefix = "LACONIC"
// NewRootCmd creates a new root command for laconicd. It is called once in the
// main function.
func NewRootCmd() *cobra.Command {
var (
txConfigOpts tx.ConfigOptions
autoCliOpts autocli.AppOptions
moduleBasicManager module.BasicManager
clientCtx client.Context
// DefaultNodeHome is the default data directory name for the application
DefaultNodeHome = ".laconicd"
)
func NewRootCmd[T app.Tx](
args ...string,
) (*cobra.Command, error) {
rootCommand := &cobra.Command{
Use: "laconicd",
SilenceErrors: true,
}
configWriter, err := InitRootCmd(rootCommand, log.NewNopLogger(), CommandDependencies[T]{})
if err != nil {
return nil, err
}
factory, err := serverv2.NewCommandFactory(
serverv2.WithConfigWriter(configWriter),
serverv2.WithStdDefaultHomeDir(DefaultNodeHome),
serverv2.WithLoggerFactory(serverv2.NewLogger),
// serverv2.WithLoggerFactory(newSlogLogger),
)
if err := depinject.Inject(
depinject.Configs(app.AppConfig(),
depinject.Supply(
log.NewNopLogger(),
),
depinject.Provide(
ProvideClientContext,
ProvideKeyring,
),
),
&txConfigOpts,
&autoCliOpts,
&moduleBasicManager,
&clientCtx,
); err != nil {
panic(err)
}
rootCmd := &cobra.Command{
Use: "laconicd",
Short: "Laconic Daemon",
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
// set the default command outputs
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())
clientCtx = clientCtx.WithCmdContext(cmd.Context()).WithViper(EnvPrefix)
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
clientCtx, err = config.ReadFromClientConfig(clientCtx)
if err != nil {
return err
}
// sign mode textual is only available in online mode
if !clientCtx.Offline {
// This needs to go after ReadFromClientConfig, as that function ets the RPC client needed for SIGN_MODE_TEXTUAL.
txConfigOpts.EnabledSignModes = append(txConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL)
txConfigOpts.TextualCoinMetadataQueryFn = txmodule.NewGRPCCoinMetadataQueryFn(clientCtx)
txConfigWithTextual, err := tx.NewTxConfigWithOptions(codec.NewProtoCodec(clientCtx.InterfaceRegistry), txConfigOpts)
if err != nil {
return err
}
clientCtx = clientCtx.WithTxConfig(txConfigWithTextual)
}
if err := client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
return err
}
// overwrite the minimum gas price from the app configuration
srvCfg := serverconfig.DefaultConfig()
srvCfg.MinGasPrices = fmt.Sprintf("0%s", sdk.DefaultBondDenom)
// overwrite the block timeout
cmtCfg := cmtcfg.DefaultConfig()
cmtCfg.Consensus.TimeoutCommit = 3 * time.Second
cmtCfg.LogLevel = "*:error,p2p:info,state:info,auction:info,bond:info,registry:info,gql-server:info" // better default logging
return server.InterceptConfigsPreRunHandler(cmd, serverconfig.DefaultConfigTemplate, srvCfg, cmtCfg)
},
}
initRootCmd(rootCmd, clientCtx.TxConfig, moduleBasicManager)
if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
panic(err)
}
// Add flags for GQL server.
rootCmd = gql.AddGQLFlags(rootCmd)
return rootCmd
}
func ProvideClientContext(
appCodec codec.Codec,
interfaceRegistry codectypes.InterfaceRegistry,
txConfig client.TxConfig,
legacyAmino *codec.LegacyAmino,
) client.Context {
clientCtx := client.Context{}.
WithCodec(appCodec).
WithInterfaceRegistry(interfaceRegistry).
WithTxConfig(txConfig).
WithLegacyAmino(legacyAmino).
WithInput(os.Stdin).
WithAccountRetriever(types.AccountRetriever{}).
WithHomeDir(app.DefaultNodeHome).
WithViper(EnvPrefix) // env variable prefix
// Read the config again to overwrite the default values with the values from the config file
clientCtx, _ = config.ReadFromClientConfig(clientCtx)
// Workaround: Unset clientCtx.HomeDir and clientCtx.KeyringDir from depinject clientCtx as they are given precedence over
// the CLI args (--home flag) in some commands
// TODO: Implement proper fix
clientCtx.HomeDir = ""
clientCtx.KeyringDir = ""
return clientCtx
}
func ProvideKeyring(clientCtx client.Context, addressCodec address.Codec) (clientv2keyring.Keyring, error) {
kb, err := client.NewKeyringFromBackend(clientCtx, clientCtx.Keyring.Backend())
if err != nil {
return nil, err
}
return keyring.NewAutoCLIKeyring(kb)
var autoCliOpts autocli.AppOptions
if err := depinject.Inject(
depinject.Configs(
app.AppConfig(),
depinject.Supply(runtime.GlobalConfig{}, log.NewNopLogger())),
&autoCliOpts,
); err != nil {
return nil, err
}
if err = autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
}
subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
if err != nil {
if errors.Is(err, pflag.ErrHelp) {
return rootCommand, nil
}
return nil, err
}
var (
moduleManager *runtime.MM[T]
clientCtx client.Context
laconic *app.LaconicApp[T]
dsManager *distsig.Manager
// nitroServer *nitro.Server
depinjectConfig = depinject.Configs(
depinject.Supply(logger, runtime.GlobalConfig(configMap)),
depinject.Provide(
ProvideClientContext,
ProvideKeyring,
),
)
)
if serverv2.IsAppRequired(subCommand) {
// server construction
laconic, err = app.NewLaconicApp[T](
depinjectConfig,
&autoCliOpts, &moduleManager, &clientCtx, &dsManager,
)
if err != nil {
return nil, err
}
} else {
// client construction
if err = depinject.Inject(
depinject.Configs(
app.AppConfig(),
depinjectConfig,
),
&autoCliOpts, &moduleManager, &clientCtx, &dsManager,
); err != nil {
return nil, err
}
}
commandDeps := CommandDependencies[T]{
GlobalConfig: configMap,
ModuleManager: moduleManager,
LaconicApp: laconic,
ClientContext: clientCtx,
DistSigManager: dsManager,
// NitroServer: nitroServer,
}
rootCommand = &cobra.Command{
Use: "laconicd",
Short: "Laconic Daemon",
SilenceErrors: true,
PersistentPreRunE: RootCommandPersistentPreRun(clientCtx),
}
factory.EnhanceRootCommand(rootCommand)
_, err = InitRootCmd(rootCommand, logger, commandDeps)
if err != nil {
return nil, err
}
if err := autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
}
return rootCommand, nil
}

View File

@ -0,0 +1,67 @@
package cmd_test
import (
"bytes"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
)
func TestInitCmd(t *testing.T) {
args := []string{
"init", // Test the init cmd
"laconicd-test", // Moniker
fmt.Sprintf("--%s=%s", cli.FlagOverwrite, "true"), // Overwrite genesis.json, in case it already exists
}
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
}
func TestHomeFlagRegistration(t *testing.T) {
homeDir := "/tmp/foo"
args := []string{
"query",
fmt.Sprintf("--%s", flags.FlagHome),
homeDir,
}
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
result, err := rootCmd.Flags().GetString(flags.FlagHome)
require.NoError(t, err)
require.Equal(t, result, homeDir)
}
func TestHelpRequested(t *testing.T) {
argz := [][]string{
{"query", "--help"},
{"query", "tx", "-h"},
{"--help"},
{"start", "-h"},
}
for _, args := range argz {
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
require.NoError(t, err)
var out bytes.Buffer
rootCmd.SetArgs(args)
rootCmd.SetOut(&out)
require.NoError(t, rootCmd.Execute())
require.Contains(t, out.String(), args[0])
require.Contains(t, out.String(), "--help")
require.Contains(t, out.String(), "Usage:")
}
}

490
cmd/laconicd/cmd/testnet.go Normal file
View File

@ -0,0 +1,490 @@
package cmd
import (
"bufio"
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
"time"
cmtconfig "github.com/cometbft/cometbft/config"
cmttime "github.com/cometbft/cometbft/types/time"
"github.com/spf13/cobra"
"cosmossdk.io/core/transaction"
"cosmossdk.io/math"
"cosmossdk.io/math/unsafe"
runtimev2 "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/api/grpc"
"cosmossdk.io/server/v2/cometbft"
"cosmossdk.io/server/v2/store"
banktypes "cosmossdk.io/x/bank/types"
stakingtypes "cosmossdk.io/x/staking/types"
"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/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
)
var (
flagNodeDirPrefix = "node-dir-prefix"
flagNumValidators = "validator-count"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagStartingIPAddress = "starting-ip-address"
flagListenIPAddress = "listen-ip-address"
flagStakingDenom = "staking-denom"
flagCommitTimeout = "commit-timeout"
flagSingleHost = "single-host"
)
type initArgs struct {
algo string
chainID string
keyringBackend string
minGasPrices string
nodeDaemonHome string
nodeDirPrefix string
numValidators int
outputDir string
startingIPAddress string
listenIPAddress string
singleMachine bool
bondTokenDenom string
}
func addTestnetFlagsToCmd(cmd *cobra.Command) {
cmd.Flags().IntP(flagNumValidators, "n", 4, "Number of validators to initialize the testnet with")
cmd.Flags().StringP(flagOutputDir, "o", "./.testnets", "Directory to store initialization data for the testnet")
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
cmd.Flags().String(serverv2.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
cmd.Flags().String(flags.FlagKeyType, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for")
cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix for the name of per-validator subdirectories (to be number-suffixed like node0, node1, ...)")
cmd.Flags().String(flagNodeDaemonHome, "laconicd", "Home directory of the node's daemon configuration")
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
cmd.Flags().String(flagListenIPAddress, "127.0.0.1", "TCP or UNIX socket IP address for the RPC server to listen on")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
cmd.Flags().Duration(flagCommitTimeout, 5*time.Second, "Time to wait after a block commit before starting on the new height")
cmd.Flags().Bool(flagSingleHost, false, "Cluster runs on a single host machine with different ports")
cmd.Flags().String(flagStakingDenom, sdk.DefaultBondDenom, "Default staking token denominator")
}
// NewTestnetCmd creates a root testnet command with subcommands to run an in-process testnet or initialize
// validator configuration files for running a multi-validator testnet in a separate process
func NewTestnetCmd[T transaction.Tx](mm *runtimev2.MM[T]) *cobra.Command {
testnetCmd := &cobra.Command{
Use: "testnet",
Short: "subcommands for starting or configuring local testnets",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
testnetCmd.AddCommand(testnetInitFilesCmd(mm))
return testnetCmd
}
// testnetInitFilesCmd returns a cmd to initialize all files for CometBFT testnet and application
func testnetInitFilesCmd[T transaction.Tx](mm *runtimev2.MM[T]) *cobra.Command {
cmd := &cobra.Command{
Use: "init-files",
Short: "Initialize config directories & files for a multi-validator testnet running locally via separate processes (e.g. Docker Compose or similar)",
Long: fmt.Sprintf(`init-files will setup one directory per validator and populate each with
necessary files (private validator, genesis, config, etc.) for running validator nodes.
Booting up a network with these validator folders is intended to be used with Docker Compose,
or a similar setup where each node has a manually configurable IP address.
Note, strict routability for addresses is turned off in the config file.
Example:
%s testnet init-files --validator-count 4 --output-dir ./.testnets --starting-ip-address 192.168.10.2
`, version.AppName),
RunE: func(cmd *cobra.Command, _ []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
config := client.GetConfigFromCmd(cmd)
args := initArgs{}
args.outputDir, _ = cmd.Flags().GetString(flagOutputDir)
args.keyringBackend, _ = cmd.Flags().GetString(flags.FlagKeyringBackend)
args.chainID, _ = cmd.Flags().GetString(flags.FlagChainID)
args.minGasPrices, _ = cmd.Flags().GetString(serverv2.FlagMinGasPrices)
args.nodeDirPrefix, _ = cmd.Flags().GetString(flagNodeDirPrefix)
args.nodeDaemonHome, _ = cmd.Flags().GetString(flagNodeDaemonHome)
args.startingIPAddress, _ = cmd.Flags().GetString(flagStartingIPAddress)
args.listenIPAddress, _ = cmd.Flags().GetString(flagListenIPAddress)
args.numValidators, _ = cmd.Flags().GetInt(flagNumValidators)
args.algo, _ = cmd.Flags().GetString(flags.FlagKeyType)
args.bondTokenDenom, _ = cmd.Flags().GetString(flagStakingDenom)
args.singleMachine, _ = cmd.Flags().GetBool(flagSingleHost)
config.Consensus.TimeoutCommit, err = cmd.Flags().GetDuration(flagCommitTimeout)
if err != nil {
return err
}
return initTestnetFiles(clientCtx, cmd, config, mm, args)
},
}
addTestnetFlagsToCmd(cmd)
return cmd
}
const nodeDirPerm = 0o755
// initTestnetFiles initializes testnet files for a testnet to be run in a separate process
func initTestnetFiles[T transaction.Tx](
clientCtx client.Context,
cmd *cobra.Command,
nodeConfig *cmtconfig.Config,
mm *runtimev2.MM[T],
args initArgs,
) error {
if args.chainID == "" {
args.chainID = "chain-" + unsafe.Str(6)
}
nodeIDs := make([]string, args.numValidators)
valPubKeys := make([]cryptotypes.PubKey, args.numValidators)
var (
genAccounts []authtypes.GenesisAccount
genBalances []banktypes.Balance
genFiles []string
)
const (
rpcPort = 26657
apiPort = 1317
grpcPort = 9090
)
p2pPortStart := 26656
inBuf := bufio.NewReader(cmd.InOrStdin())
// generate private keys, node IDs, and initial transactions
for i := 0; i < args.numValidators; i++ {
var portOffset int
grpcConfig := grpc.DefaultConfig()
if args.singleMachine {
portOffset = i
p2pPortStart = 16656 // use different start point to not conflict with rpc port
nodeConfig.P2P.AddrBookStrict = false
nodeConfig.P2P.PexReactor = false
nodeConfig.P2P.AllowDuplicateIP = true
grpcConfig = &grpc.Config{
Enable: true,
Address: fmt.Sprintf("127.0.0.1:%d", grpcPort+portOffset),
MaxRecvMsgSize: grpc.DefaultConfig().MaxRecvMsgSize,
MaxSendMsgSize: grpc.DefaultConfig().MaxSendMsgSize,
}
}
nodeDirName := fmt.Sprintf("%s%d", args.nodeDirPrefix, i)
nodeDir := filepath.Join(args.outputDir, nodeDirName, args.nodeDaemonHome)
cmd.Println("Node dir", nodeDir)
gentxsDir := filepath.Join(args.outputDir, "gentxs")
nodeConfig.SetRoot(nodeDir)
nodeConfig.Moniker = nodeDirName
nodeConfig.RPC.ListenAddress = fmt.Sprintf("tcp://%s:%d", args.listenIPAddress, rpcPort+portOffset)
if err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm); err != nil {
_ = os.RemoveAll(args.outputDir)
return err
}
var (
err error
ip string
)
if args.singleMachine {
ip = "127.0.0.1"
} else {
ip, err = getIP(i, args.startingIPAddress)
if err != nil {
_ = os.RemoveAll(args.outputDir)
return err
}
}
nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(nodeConfig, args.algo)
if err != nil {
_ = os.RemoveAll(args.outputDir)
return err
}
memo := fmt.Sprintf("%s@%s:%d", nodeIDs[i], ip, p2pPortStart+portOffset)
genFiles = append(genFiles, nodeConfig.GenesisFile())
kb, err := keyring.New(sdk.KeyringServiceName(), args.keyringBackend, nodeDir, inBuf, clientCtx.Codec)
if err != nil {
return err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(args.algo, keyringAlgos)
if err != nil {
return err
}
addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, "", true, algo, sdk.GetFullBIP44Path())
if err != nil {
_ = os.RemoveAll(args.outputDir)
return err
}
info := map[string]string{"secret": secret}
cliPrint, err := json.Marshal(info)
if err != nil {
return err
}
// save private key seed words
if err := writeFile(fmt.Sprintf("%v.json", "key_seed"), nodeDir, cliPrint); err != nil {
return err
}
accTokens := sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction)
accStakingTokens := sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction)
coins := sdk.Coins{
sdk.NewCoin("testtoken", accTokens),
sdk.NewCoin(args.bondTokenDenom, accStakingTokens),
}
addrStr, err := clientCtx.AddressCodec.BytesToString(addr)
if err != nil {
return err
}
// TODO: use x/accounts?
genBalances = append(genBalances, banktypes.Balance{Address: addrStr, Coins: coins.Sort()})
genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0))
valStr, err := clientCtx.ValidatorAddressCodec.BytesToString(addr)
if err != nil {
return err
}
valTokens := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction)
createValMsg, err := stakingtypes.NewMsgCreateValidator(
valStr,
valPubKeys[i],
sdk.NewCoin(args.bondTokenDenom, valTokens),
stakingtypes.NewDescription(nodeDirName, "", "", "", "", &stakingtypes.Metadata{}),
stakingtypes.NewCommissionRates(math.LegacyOneDec(), math.LegacyOneDec(), math.LegacyOneDec()),
math.OneInt(),
)
if err != nil {
return err
}
txBuilder := clientCtx.TxConfig.NewTxBuilder()
if err := txBuilder.SetMsgs(createValMsg); err != nil {
return err
}
txBuilder.SetMemo(memo)
txBuilder.SetGasLimit(flags.DefaultGasLimit)
txBuilder.SetFeePayer(addr)
txFactory := tx.Factory{}
txFactory = txFactory.
WithChainID(args.chainID).
WithMemo(memo).
WithKeybase(kb).
WithTxConfig(clientCtx.TxConfig)
if err := tx.Sign(clientCtx, txFactory, nodeDirName, txBuilder, true); err != nil {
return err
}
txBz, err := clientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
if err != nil {
return err
}
if err := writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz); err != nil {
return err
}
serverCfg := serverv2.DefaultServerConfig()
serverCfg.MinGasPrices = args.minGasPrices
cometServer := cometbft.NewWithConfigOptions[T](cometbft.OverwriteDefaultConfigTomlConfig(nodeConfig))
storeServer := &store.Server[T]{}
grpcServer := grpc.NewWithConfigOptions[T](grpc.OverwriteDefaultConfig(grpcConfig))
server := serverv2.NewServer[T](serverCfg, cometServer, storeServer, grpcServer)
err = server.WriteConfig(filepath.Join(nodeDir, "config"))
if err != nil {
return err
}
}
if err := initGenFiles(clientCtx, mm, args.chainID, genAccounts, genBalances, genFiles, args.numValidators); err != nil {
return err
}
err := collectGenFiles(
clientCtx, nodeConfig, args.chainID, nodeIDs, valPubKeys, args.numValidators,
args.outputDir, args.nodeDirPrefix, args.nodeDaemonHome,
rpcPort, p2pPortStart, args.singleMachine,
)
if err != nil {
return err
}
// Update viper root
serverv2.GetViperFromCmd(cmd).Set(flags.FlagHome, nodeConfig.RootDir)
cmd.PrintErrf("Successfully initialized %d node directories\n", args.numValidators)
return nil
}
func initGenFiles[T transaction.Tx](
clientCtx client.Context, mm *runtimev2.MM[T], chainID string,
genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance,
genFiles []string, numValidators int,
) error {
appGenState := mm.DefaultGenesis()
// set the accounts in the genesis state
var authGenState authtypes.GenesisState
clientCtx.Codec.MustUnmarshalJSON(appGenState[authtypes.ModuleName], &authGenState)
accounts, err := authtypes.PackAccounts(genAccounts)
if err != nil {
return err
}
authGenState.Accounts = accounts
appGenState[authtypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&authGenState)
// set the balances in the genesis state
var bankGenState banktypes.GenesisState
clientCtx.Codec.MustUnmarshalJSON(appGenState[banktypes.ModuleName], &bankGenState)
bankGenState.Balances, err = banktypes.SanitizeGenesisBalances(genBalances, clientCtx.AddressCodec)
if err != nil {
return err
}
for _, bal := range bankGenState.Balances {
bankGenState.Supply = bankGenState.Supply.Add(bal.Coins...)
}
appGenState[banktypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&bankGenState)
appGenStateJSON, err := json.MarshalIndent(appGenState, "", " ")
if err != nil {
return err
}
appGenesis := genutiltypes.NewAppGenesisWithVersion(chainID, appGenStateJSON)
// generate empty genesis files for each validator and save
for i := 0; i < numValidators; i++ {
if err := appGenesis.SaveAs(genFiles[i]); err != nil {
return err
}
}
return nil
}
func collectGenFiles(
clientCtx client.Context, nodeConfig *cmtconfig.Config, chainID string,
nodeIDs []string, valPubKeys []cryptotypes.PubKey, numValidators int,
outputDir, nodeDirPrefix, nodeDaemonHome string,
rpcPortStart, p2pPortStart int,
singleMachine bool,
) error {
var appState json.RawMessage
genTime := cmttime.Now()
for i := 0; i < numValidators; i++ {
if singleMachine {
portOffset := i
nodeConfig.RPC.ListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", rpcPortStart+portOffset)
nodeConfig.P2P.ListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", p2pPortStart+portOffset)
}
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome)
gentxsDir := filepath.Join(outputDir, "gentxs")
nodeConfig.Moniker = nodeDirName
nodeConfig.SetRoot(nodeDir)
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
initCfg := genutiltypes.NewInitConfig(chainID, gentxsDir, nodeID, valPubKey)
appGenesis, err := genutiltypes.AppGenesisFromFile(nodeConfig.GenesisFile())
if err != nil {
return err
}
nodeAppState, err := genutil.GenAppStateFromConfig(clientCtx.Codec, clientCtx.TxConfig, nodeConfig, initCfg, appGenesis, genutiltypes.DefaultMessageValidator,
clientCtx.ValidatorAddressCodec, clientCtx.AddressCodec)
if err != nil {
return err
}
if appState == nil {
// set the canonical application state (they should not differ)
appState = nodeAppState
}
genFile := nodeConfig.GenesisFile()
// overwrite each validator's genesis file to have a canonical genesis time
if err := genutil.ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime); err != nil {
return err
}
}
return nil
}
func getIP(i int, startingIPAddr string) (ip string, err error) {
if len(startingIPAddr) == 0 {
ip, err = serverv2.ExternalIP()
if err != nil {
return "", err
}
return ip, nil
}
return calculateIP(startingIPAddr, i)
}
func calculateIP(ip string, i int) (string, error) {
ipv4 := net.ParseIP(ip).To4()
if ipv4 == nil {
return "", fmt.Errorf("%v: non ipv4 address", ip)
}
for j := 0; j < i; j++ {
ipv4[3]++
}
return ipv4.String(), nil
}
func writeFile(name, dir string, contents []byte) error {
file := filepath.Join(dir, name)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("could not create directory %q: %w", dir, err)
}
return os.WriteFile(file, contents, 0o600)
}

View File

@ -0,0 +1,26 @@
package cmd_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
)
func TestInitTestFilesCmd(t *testing.T) {
args := []string{
"testnet", // Test the testnet init-files command
"init-files",
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), // Set keyring-backend to test
}
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
}

View File

@ -1,28 +0,0 @@
package main_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client/flags"
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
"github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
)
func TestInitCmd(t *testing.T) {
rootCmd := cmd.NewRootCmd()
rootCmd.SetArgs([]string{
"init", // Test the init cmd
"localtestnet", // Moniker
fmt.Sprintf("--%s=%s", cli.FlagOverwrite, "true"), // Overwrite genesis.json, in case it already exists
fmt.Sprintf("--%s=%s", flags.FlagChainID, "laconic_9000-1"),
})
err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome)
require.NoError(t, err)
}

View File

@ -1,22 +1,31 @@
package main
import (
"errors"
"fmt"
"os"
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/app/params"
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
_ "git.vdb.to/cerc-io/laconicd/app/params" // import for side-effects
)
func main() {
params.SetAddressPrefixes()
rootCmd := cmd.NewRootCmd()
if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil {
fmt.Fprintln(rootCmd.OutOrStderr(), err)
// reproduce default cobra behavior so that eager parsing of flags is possible.
// see: https://github.com/spf13/cobra/blob/e94f6d0dd9a5e5738dca6bce03c4b1207ffbc0ec/command.go#L1082
args := os.Args[1:]
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
if err != nil {
if _, pErr := fmt.Fprintln(os.Stderr, err); pErr != nil {
panic(errors.Join(err, pErr))
}
os.Exit(1)
}
if err = rootCmd.Execute(); err != nil {
if _, pErr := fmt.Fprintln(rootCmd.OutOrStderr(), err); pErr != nil {
panic(errors.Join(err, pErr))
}
os.Exit(1)
}
}

372
go.mod
View File

@ -1,10 +1,11 @@
module git.vdb.to/cerc-io/laconicd
go 1.21
go 1.23.5
toolchain go1.21.0
toolchain go1.23.6
replace (
github.com/ethereum/go-ethereum => ../mod/go-ethereum
// Fix upstream GHSA-h395-qcrw-5vmq vulnerability.
// TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0
@ -13,190 +14,339 @@ replace (
)
require (
cosmossdk.io/api v0.7.2
cosmossdk.io/client/v2 v2.0.0-beta.1
cosmossdk.io/collections v0.4.0
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4
cosmossdk.io/api v0.8.2
cosmossdk.io/client/v2 v2.0.0-beta.6
cosmossdk.io/collections v1.1.0
cosmossdk.io/core v1.0.0
cosmossdk.io/depinject v1.1.0
cosmossdk.io/errors v1.0.1
cosmossdk.io/log v1.3.0
cosmossdk.io/math v1.2.0
cosmossdk.io/store v1.0.2
cosmossdk.io/log v1.5.0
cosmossdk.io/math v1.5.0
cosmossdk.io/runtime/v2 v2.0.0-00010101000000-000000000000
cosmossdk.io/server/v2 v2.0.0-beta.1
cosmossdk.io/server/v2/cometbft v0.0.0-20241017154543-c1707b830856
cosmossdk.io/store v1.10.0-rc.1
cosmossdk.io/store/v2 v2.0.0-beta.1
cosmossdk.io/tools/confix v0.1.0
git.vdb.to/cerc-io/chainsig v0.1.0
github.com/99designs/gqlgen v0.17.22
github.com/cometbft/cometbft v0.38.2
github.com/cosmos/cosmos-db v1.0.0
github.com/cosmos/cosmos-proto v1.0.0-beta.3
github.com/cosmos/cosmos-sdk v0.50.3
github.com/cometbft/cometbft v1.0.1
github.com/cosmos/cosmos-proto v1.0.0-beta.5
github.com/cosmos/cosmos-sdk v1.0.0
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/gogoproto v1.4.11
github.com/cosmos/gogoproto v1.7.0
github.com/deckarep/golang-set v1.8.0
github.com/ethereum/go-ethereum v1.14.5
github.com/ethereum/go-ethereum v1.14.13
github.com/gibson042/canonicaljson-go v1.0.3
github.com/go-chi/chi/v5 v5.0.8
github.com/golang/protobuf v1.5.4
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/ipfs/go-cid v0.4.1
github.com/ipld/go-ipld-prime v0.21.0
github.com/rs/cors v1.8.3
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.17.0
github.com/statechannels/go-nitro v0.1.2
github.com/stretchr/testify v1.8.4
github.com/lmittmann/tint v1.0.7
github.com/rs/cors v1.11.1
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.6
github.com/statechannels/go-nitro v0.2.0
github.com/stretchr/testify v1.10.0
github.com/tidwall/gjson v1.14.4
github.com/tidwall/sjson v1.2.5
github.com/vektah/gqlparser/v2 v2.5.11
golang.org/x/sync v0.7.0
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f
google.golang.org/grpc v1.60.1
google.golang.org/protobuf v1.33.0
go.dedis.ch/kyber/v3 v3.1.0
go.uber.org/mock v0.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a
google.golang.org/grpc v1.70.0
google.golang.org/protobuf v1.36.4
gopkg.in/yaml.v3 v3.0.1
)
require (
cosmossdk.io/x/tx v0.13.0 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
cosmossdk.io/systemtests v0.0.0-00010101000000-000000000000
cosmossdk.io/x/accounts v1.0.0-alpha.4
cosmossdk.io/x/accounts/defaults/base v0.0.0-00010101000000-000000000000
cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91
cosmossdk.io/x/consensus v0.0.0-20241007000829-38662ecb209f
cosmossdk.io/x/distribution v0.0.0-20241007000829-38662ecb209f
cosmossdk.io/x/gov v1.0.0-alpha.4
cosmossdk.io/x/mint v0.0.0-20241004153623-489aaae40234
cosmossdk.io/x/protocolpool v1.0.0-alpha.4
cosmossdk.io/x/slashing v0.0.0-20241007000829-38662ecb209f
cosmossdk.io/x/staking v1.0.0-alpha.4
github.com/cometbft/cometbft/api v1.0.0
github.com/spf13/viper v1.19.0
)
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.4-20241120201313-68e42a58b301.1 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.4-20240130113600-88ef6483f90f.1 // indirect
cosmossdk.io/core/testing v0.0.2 // indirect
cosmossdk.io/errors/v2 v2.0.0 // indirect
cosmossdk.io/schema v1.0.0 // indirect
cosmossdk.io/server/v2/appmanager v1.0.0-beta.2 // indirect
cosmossdk.io/server/v2/stf v1.0.0-beta.2 // indirect
cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect
cosmossdk.io/x/tx v1.1.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.1 // indirect
github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/DataDog/datadog-go v4.8.3+incompatible // indirect
github.com/DataDog/zstd v1.5.6 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/btcsuite/btcd/btcutil v1.1.5 // indirect
github.com/bgentry/speakeasy v0.2.0 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/bvinc/go-sqlite-lite v0.6.1 // indirect
github.com/bytedance/sonic v1.12.8 // indirect
github.com/bytedance/sonic/loader v0.2.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v1.1.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/cockroachdb/errors v1.11.3 // indirect
github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect
github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect
github.com/cockroachdb/pebble v1.1.4 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/cometbft/cometbft-db v0.9.1 // indirect
github.com/cometbft/cometbft-db v1.0.2 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/iavl v1.0.0 // indirect
github.com/cosmos/ics23/go v0.10.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect
github.com/creachadair/atomicfile v0.3.1 // indirect
github.com/creachadair/tomledit v0.0.24 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/cosmos/cosmos-db v1.1.1 // indirect
github.com/cosmos/iavl v1.3.5 // indirect
github.com/cosmos/iavl/v2 v2.0.0-alpha.4 // indirect
github.com/cosmos/ics23/go v0.11.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect
github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect
github.com/creachadair/atomicfile v0.3.7 // indirect
github.com/creachadair/tomledit v0.0.27 // indirect
github.com/danieljoos/wincred v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dgraph-io/badger/v4 v4.5.1 // indirect
github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/emicklei/dot v1.6.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/getsentry/sentry-go v0.25.0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/getsentry/sentry-go v0.31.1 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/flatbuffers v25.1.24+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-bexpr v0.1.10 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-metrics v0.5.1 // indirect
github.com/hashicorp/go-plugin v1.5.2 // indirect
github.com/hashicorp/go-metrics v0.5.4 // indirect
github.com/hashicorp/go-plugin v1.6.3 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
github.com/holiman/uint256 v1.2.4 // indirect
github.com/huandu/skiplist v1.2.0 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/holiman/uint256 v1.3.1 // indirect
github.com/huandu/skiplist v1.2.1 // indirect
github.com/huin/goupnp v1.3.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/kocubinski/costor-api v1.1.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/linxGnu/grocksdb v1.8.6 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/libp2p/go-libp2p v0.37.0 // indirect
github.com/linxGnu/grocksdb v1.9.8 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mdp/qrterminal/v3 v3.2.0 // indirect
github.com/minio/highwayhash v1.0.3 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/pointerstructure v1.2.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr v0.13.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.34.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/polydawn/refmt v0.89.0 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rs/zerolog v1.31.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/supranational/blst v0.3.13 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tidwall/btree v1.7.0 // indirect
github.com/tidwall/buntdb v1.2.10 // indirect
github.com/tidwall/grect v0.1.4 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/urfave/cli/v2 v2.25.7 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v0.14.3 // indirect
go.etcd.io/bbolt v1.3.8 // indirect
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
go.dedis.ch/fixbuf v1.0.3 // indirect
go.dedis.ch/protobuf v1.0.11 // indirect
go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
golang.org/x/arch v0.13.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250122153221-138b5a5a4fd4 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
pgregory.net/rapid v1.1.0 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
rsc.io/qr v0.2.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
replace github.com/statechannels/go-nitro v0.1.2 => github.com/cerc-io/go-nitro v0.1.3-ts-port-0.1.10
replace (
git.vdb.to/cerc-io/chainsig => ../mod/chainsig
// github.com/statechannels/go-nitro v0.1.2 => github.com/cerc-io/go-nitro v0.1.3-ts-port-0.1.10
github.com/statechannels/go-nitro => ../mod/go-nitro
)
// replace (
// cosmossdk.io/core v0.7.6 => github.com/roysc/cosmos-sdk/core v0.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/api v0.7.6 => github.com/roysc/cosmos-sdk/api v0.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/client/v2 => github.com/roysc/cosmos-sdk/client/v2 v2.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/store => github.com/roysc/cosmos-sdk/store v0.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/x/bank => github.com/roysc/cosmos-sdk/x/bank v0.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/x/mint => github.com/roysc/cosmos-sdk/x/mint v0.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/x/gov => github.com/roysc/cosmos-sdk/x/gov v0.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/x/staking => github.com/roysc/cosmos-sdk/x/staking v0.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/x/tx => github.com/roysc/cosmos-sdk/x/tx v0.0.0-20241001191620-a3729c1ad6ba
// cosmossdk.io/x/epochs => github.com/roysc/cosmos-sdk/x/epochs v0.0.0-20241001191620-a3729c1ad6ba
// github.com/cosmos/cosmos-sdk => github.com/roysc/cosmos-sdk v1.0.0-dev
// )
// dev
replace (
// cosmossdk.io/core => ../mod/cosmos-sdk/core
cosmossdk.io/api => ../mod/cosmos-sdk/api
cosmossdk.io/client/v2 => ../mod/cosmos-sdk/client/v2
cosmossdk.io/core/testing => ../mod/cosmos-sdk/core/testing
cosmossdk.io/depinject => ../mod/cosmos-sdk/depinject
cosmossdk.io/log => ../mod/cosmos-sdk/log
cosmossdk.io/runtime/v2 => ../mod/cosmos-sdk/runtime/v2
cosmossdk.io/server/v2 => ../mod/cosmos-sdk/server/v2
cosmossdk.io/server/v2/appmanager => ../mod/cosmos-sdk/server/v2/appmanager
cosmossdk.io/server/v2/cometbft => ../mod/cosmos-sdk/server/v2/cometbft
cosmossdk.io/server/v2/stf => ../mod/cosmos-sdk/server/v2/stf
cosmossdk.io/store => ../mod/cosmos-sdk/store
cosmossdk.io/store/v2 => ../mod/cosmos-sdk/store/v2
cosmossdk.io/systemtests => ../mod/cosmos-sdk/systemtests
cosmossdk.io/tools/confix => ../mod/cosmos-sdk/tools/confix
)
replace (
cosmossdk.io/x/accounts => ../mod/cosmos-sdk/x/accounts
cosmossdk.io/x/accounts/defaults/base => ../mod/cosmos-sdk/x/accounts/defaults/base
cosmossdk.io/x/accounts/defaults/lockup => ../mod/cosmos-sdk/x/accounts/defaults/lockup
cosmossdk.io/x/accounts/defaults/multisig => ../mod/cosmos-sdk/x/accounts/defaults/multisig
cosmossdk.io/x/bank => ../mod/cosmos-sdk/x/bank
cosmossdk.io/x/consensus => ../mod/cosmos-sdk/x/consensus
cosmossdk.io/x/distribution => ../mod/cosmos-sdk/x/distribution
cosmossdk.io/x/epochs => ../mod/cosmos-sdk/x/epochs
cosmossdk.io/x/gov => ../mod/cosmos-sdk/x/gov
cosmossdk.io/x/mint => ../mod/cosmos-sdk/x/mint
cosmossdk.io/x/params => ../mod/cosmos-sdk/x/params
cosmossdk.io/x/protocolpool => ../mod/cosmos-sdk/x/protocolpool
cosmossdk.io/x/slashing => ../mod/cosmos-sdk/x/slashing
cosmossdk.io/x/staking => ../mod/cosmos-sdk/x/staking
cosmossdk.io/x/tx => ../mod/cosmos-sdk/x/tx
)
replace (
github.com/cometbft/cometbft => ../mod/cometbft
// github.com/cometbft/cometbft/api => ../mod/cometbft/api
github.com/cosmos/cosmos-sdk => ../mod/cosmos-sdk
go.dedis.ch/kyber/v3 => ../mod/kyber
)
// replace google.golang.org/protobuf => /Users/roy/clone/protobuf-go

1266
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ On having some change in the GQL schema (for example: adding a new query) update
## Start server
```shell
laconicd start --gql-playground --gql-server
laconicd start --gql.playground --gql.server
```
Basic node status:

19
gql/config.go Normal file
View File

@ -0,0 +1,19 @@
package gql
func DefaultConfig() *Config {
return &Config{
Enable: false,
Playground: false,
PlaygroundAPIBase: "",
Port: 9473,
// LogFile: "",
}
}
type Config struct {
Enable bool `mapstructure:"enable" toml:"enable" comment:"Enable the GraphQL server."`
Playground bool `mapstructure:"playground" toml:"playground" comment:"Enable the GraphQL playground."`
PlaygroundAPIBase string `mapstructure:"playground-api-base" toml:"playground-api-base" comment:"GraphQL API base path to use in the playground."`
Port uint `mapstructure:"port" toml:"port" comment:"Port to use for the GraphQL server."`
// LogFile string `mapstructure:"log-file" toml:"log-file" comment:"File to tail for the 'getLogs' API."`
}

View File

@ -1,15 +1,24 @@
package gql
import "github.com/spf13/cobra"
import "github.com/spf13/pflag"
// AddGQLFlags adds gql flags for
func AddGQLFlags(cmd *cobra.Command) *cobra.Command {
// Add flags for GQL server.
cmd.PersistentFlags().Bool("gql-server", false, "Start GQL server.")
cmd.PersistentFlags().Bool("gql-playground", false, "Enable GQL playground.")
cmd.PersistentFlags().String("gql-playground-api-base", "", "GQL API base path to use in GQL playground.")
cmd.PersistentFlags().String("gql-port", "9473", "Port to use for the GQL server.")
cmd.PersistentFlags().String("log-file", "", "File to tail for GQL 'getLogs' API.")
var (
FlagEnable = prefix("enable")
FlagPlayground = prefix("playground")
FlagPlaygroundAPIBase = prefix("playground-api-base")
FlagPort = prefix("port")
//FlagLogFile = prefix("log-file")
)
return cmd
// AddGQLFlags adds flags for the GraphQL server.
func AddGQLFlags(flags *pflag.FlagSet) {
flags.Bool(FlagEnable, false, "Enable the GraphQL server")
flags.Bool(FlagPlayground, false, "Enable the GraphQL playground")
flags.String(FlagPlaygroundAPIBase, "", "GraphQL API base path to use in the playground")
flags.String(FlagPort, "9473", "Port to use for the GraphQL server.")
// cmd.PersistentFlags().String(FlagLogFile, "", "File to tail for GraphQL 'getLogs' API")
}
func prefix(f string) string {
return ServerName + "." + f
}

View File

@ -4,9 +4,9 @@
schema:
- cerc-io/laconicd/*.graphql
exec:
filename: generated.go
filename: schema/generated.go
model:
filename: models_gen.go
filename: schema/models_gen.go
resolver:
filename: resolver.go
type: Resolver
@ -14,4 +14,4 @@ resolver:
models:
Link:
model:
- git.vdb.to/cerc-io/laconicd/gql.Link
- git.vdb.to/cerc-io/laconicd/gql/schema.Link

View File

@ -6,12 +6,14 @@ import (
"strconv"
"strings"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/client"
types "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"git.vdb.to/cerc-io/laconicd/gql/schema"
"git.vdb.to/cerc-io/laconicd/utils"
auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
onboardingTypes "git.vdb.to/cerc-io/laconicd/x/onboarding"
@ -33,13 +35,13 @@ type Resolver struct {
}
// Query is the entry point to query execution.
func (r *Resolver) Query() QueryResolver {
func (r *Resolver) Query() schema.QueryResolver {
return &queryResolver{r}
}
type queryResolver struct{ *Resolver }
func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*Authority, error) {
func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*schema.Authority, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx)
auctionQueryClient := auctiontypes.NewQueryClient(q.ctx)
@ -53,14 +55,14 @@ func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*Au
return nil, err
}
authorities := make([]*Authority, len(authoritiesResp.GetAuthorities()))
authorities := make([]*schema.Authority, len(authoritiesResp.GetAuthorities()))
for i, a := range authoritiesResp.Authorities {
entry, err := getAuthorityRecord(*a.Entry, auctionQueryClient)
if err != nil {
return nil, err
}
authorities[i] = &Authority{
authorities[i] = &schema.Authority{
Name: a.Name,
Entry: entry,
}
@ -69,10 +71,10 @@ func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*Au
return authorities, nil
}
func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([]*AuthorityRecord, error) {
func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([]*schema.AuthorityRecord, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx)
auctionQueryClient := auctiontypes.NewQueryClient(q.ctx)
gqlResponse := []*AuthorityRecord{}
gqlResponse := []*schema.AuthorityRecord{}
for _, name := range names {
res, err := nsQueryClient.Whois(context.Background(), &registrytypes.QueryWhoisRequest{Name: name})
@ -97,9 +99,9 @@ func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([
return gqlResponse, nil
}
func (q queryResolver) ResolveNames(ctx context.Context, names []string) ([]*Record, error) {
func (q queryResolver) ResolveNames(ctx context.Context, names []string) ([]*schema.Record, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx)
var gqlResponse []*Record
var gqlResponse []*schema.Record
for _, name := range names {
res, err := nsQueryClient.ResolveLrn(context.Background(), &registrytypes.QueryResolveLrnRequest{Lrn: name})
if err != nil {
@ -118,9 +120,9 @@ func (q queryResolver) ResolveNames(ctx context.Context, names []string) ([]*Rec
return gqlResponse, nil
}
func (q queryResolver) LookupNames(ctx context.Context, names []string) ([]*NameRecord, error) {
func (q queryResolver) LookupNames(ctx context.Context, names []string) ([]*schema.NameRecord, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx)
var gqlResponse []*NameRecord
var gqlResponse []*schema.NameRecord
for _, name := range names {
res, err := nsQueryClient.LookupLrn(context.Background(), &registrytypes.QueryLookupLrnRequest{Lrn: name})
@ -140,7 +142,7 @@ func (q queryResolver) LookupNames(ctx context.Context, names []string) ([]*Name
return gqlResponse, nil
}
func (q queryResolver) QueryRecords(ctx context.Context, attributes []*KeyValueInput, all *bool, limit *int, offset *int) ([]*Record, error) {
func (q queryResolver) QueryRecords(ctx context.Context, attributes []*schema.KeyValueInput, all *bool, limit *int, offset *int) ([]*schema.Record, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx)
var pagination *query.PageRequest
@ -175,7 +177,7 @@ func (q queryResolver) QueryRecords(ctx context.Context, attributes []*KeyValueI
}
records := res.GetRecords()
gqlResponse := make([]*Record, len(records))
gqlResponse := make([]*schema.Record, len(records))
for i, record := range records {
gqlRecord, err := getGQLRecord(context.Background(), q, record)
@ -188,9 +190,9 @@ func (q queryResolver) QueryRecords(ctx context.Context, attributes []*KeyValueI
return gqlResponse, nil
}
func (q queryResolver) GetRecordsByIds(ctx context.Context, ids []string) ([]*Record, error) {
func (q queryResolver) GetRecordsByIds(ctx context.Context, ids []string) ([]*schema.Record, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx)
gqlResponse := make([]*Record, len(ids))
gqlResponse := make([]*schema.Record, len(ids))
for i, id := range ids {
res, err := nsQueryClient.GetRecord(context.Background(), &registrytypes.QueryGetRecordRequest{Id: id})
@ -209,7 +211,7 @@ func (q queryResolver) GetRecordsByIds(ctx context.Context, ids []string) ([]*Re
return gqlResponse, nil
}
func (q queryResolver) GetStatus(ctx context.Context) (*Status, error) {
func (q queryResolver) GetStatus(ctx context.Context) (*schema.Status, error) {
nodeInfo, syncInfo, validatorInfo, err := getStatusInfo(q.ctx)
if err != nil {
return nil, err
@ -230,7 +232,7 @@ func (q queryResolver) GetStatus(ctx context.Context) (*Status, error) {
return nil, err
}
return &Status{
return &schema.Status{
Version: RegistryVersion,
Node: nodeInfo,
Sync: syncInfo,
@ -242,8 +244,8 @@ func (q queryResolver) GetStatus(ctx context.Context) (*Status, error) {
}, nil
}
func (q queryResolver) GetAccounts(ctx context.Context, addresses []string) ([]*Account, error) {
accounts := make([]*Account, len(addresses))
func (q queryResolver) GetAccounts(ctx context.Context, addresses []string) ([]*schema.Account, error) {
accounts := make([]*schema.Account, len(addresses))
for index, address := range addresses {
account, err := q.GetAccount(ctx, address)
if err != nil {
@ -254,7 +256,7 @@ func (q queryResolver) GetAccounts(ctx context.Context, addresses []string) ([]*
return accounts, nil
}
func (q queryResolver) GetAccount(ctx context.Context, address string) (*Account, error) {
func (q queryResolver) GetAccount(ctx context.Context, address string) (*schema.Account, error) {
authQueryClient := authtypes.NewQueryClient(q.ctx)
accountResponse, err := authQueryClient.Account(ctx, &authtypes.QueryAccountRequest{Address: address})
if err != nil {
@ -280,7 +282,7 @@ func (q queryResolver) GetAccount(ctx context.Context, address string) (*Account
accNum := strconv.FormatUint(account.GetAccountNumber(), 10)
seq := strconv.FormatUint(account.GetSequence(), 10)
return &Account{
return &schema.Account{
Address: address,
Number: accNum,
Sequence: seq,
@ -289,8 +291,8 @@ func (q queryResolver) GetAccount(ctx context.Context, address string) (*Account
}, nil
}
func (q queryResolver) GetBondsByIds(ctx context.Context, ids []string) ([]*Bond, error) {
bonds := make([]*Bond, len(ids))
func (q queryResolver) GetBondsByIds(ctx context.Context, ids []string) ([]*schema.Bond, error) {
bonds := make([]*schema.Bond, len(ids))
for index, id := range ids {
bondObj, err := q.GetBond(ctx, id)
if err != nil {
@ -302,7 +304,7 @@ func (q queryResolver) GetBondsByIds(ctx context.Context, ids []string) ([]*Bond
return bonds, nil
}
func (q *queryResolver) GetBond(ctx context.Context, id string) (*Bond, error) {
func (q *queryResolver) GetBond(ctx context.Context, id string) (*schema.Bond, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bondResp, err := bondQueryClient.GetBondById(context.Background(), &bondtypes.QueryGetBondByIdRequest{Id: id})
if err != nil {
@ -320,14 +322,14 @@ func (q *queryResolver) GetBond(ctx context.Context, id string) (*Bond, error) {
return getGQLBond(bondResp.GetBond())
}
func (q queryResolver) QueryBonds(ctx context.Context) ([]*Bond, error) {
func (q queryResolver) QueryBonds(ctx context.Context) ([]*schema.Bond, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bonds, err := bondQueryClient.Bonds(context.Background(), &bondtypes.QueryBondsRequest{})
if err != nil {
return nil, err
}
gqlResponse := make([]*Bond, len(bonds.GetBonds()))
gqlResponse := make([]*schema.Bond, len(bonds.GetBonds()))
for i, bondObj := range bonds.GetBonds() {
gqlBond, err := getGQLBond(bondObj)
if err != nil {
@ -340,8 +342,8 @@ func (q queryResolver) QueryBonds(ctx context.Context) ([]*Bond, error) {
}
// QueryBondsByOwner will return bonds by owner
func (q queryResolver) QueryBondsByOwner(ctx context.Context, ownerAddresses []string) ([]*OwnerBonds, error) {
ownerBonds := make([]*OwnerBonds, len(ownerAddresses))
func (q queryResolver) QueryBondsByOwner(ctx context.Context, ownerAddresses []string) ([]*schema.OwnerBonds, error) {
ownerBonds := make([]*schema.OwnerBonds, len(ownerAddresses))
for index, ownerAddress := range ownerAddresses {
bondsObj, err := q.GetBondsByOwner(ctx, ownerAddress)
if err != nil {
@ -353,14 +355,14 @@ func (q queryResolver) QueryBondsByOwner(ctx context.Context, ownerAddresses []s
return ownerBonds, nil
}
func (q queryResolver) GetBondsByOwner(ctx context.Context, address string) (*OwnerBonds, error) {
func (q queryResolver) GetBondsByOwner(ctx context.Context, address string) (*schema.OwnerBonds, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bondResp, err := bondQueryClient.GetBondsByOwner(context.Background(), &bondtypes.QueryGetBondsByOwnerRequest{Owner: address})
if err != nil {
return nil, err
}
ownerBonds := make([]*Bond, len(bondResp.GetBonds()))
ownerBonds := make([]*schema.Bond, len(bondResp.GetBonds()))
for i, bond := range bondResp.GetBonds() {
// #nosec G601
bondObj, err := getGQLBond(&bond) //nolint: all
@ -370,12 +372,12 @@ func (q queryResolver) GetBondsByOwner(ctx context.Context, address string) (*Ow
ownerBonds[i] = bondObj
}
return &OwnerBonds{Bonds: ownerBonds, Owner: address}, nil
return &schema.OwnerBonds{Bonds: ownerBonds, Owner: address}, nil
}
func (q queryResolver) GetAuctionsByIds(ctx context.Context, ids []string) ([]*Auction, error) {
func (q queryResolver) GetAuctionsByIds(ctx context.Context, ids []string) ([]*schema.Auction, error) {
auctionQueryClient := auctiontypes.NewQueryClient(q.ctx)
gqlAuctionResponse := make([]*Auction, len(ids))
gqlAuctionResponse := make([]*schema.Auction, len(ids))
for i, id := range ids {
auctionObj, err := auctionQueryClient.GetAuction(context.Background(), &auctiontypes.QueryGetAuctionRequest{Id: id})
if err != nil {
@ -397,18 +399,22 @@ func (q queryResolver) GetAuctionsByIds(ctx context.Context, ids []string) ([]*A
return gqlAuctionResponse, nil
}
func (q queryResolver) GetParticipants(ctx context.Context) ([]*Participant, error) {
func (q queryResolver) GetParticipants(ctx context.Context) ([]*schema.Participant, error) {
onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx)
participantResp, err := onboardingQueryClient.Participants(context.Background(), &onboardingTypes.QueryParticipantsRequest{})
if err != nil {
return nil, err
}
participants := make([]*Participant, len(participantResp.GetParticipants()))
participants := make([]*schema.Participant, len(participantResp.GetParticipants()))
for i, p := range participantResp.Participants {
participants[i] = &Participant{
nitroAddress, err := utils.EthAddressFromPubKey(p.PublicKey)
if err != nil {
return nil, err
}
participants[i] = &schema.Participant{
CosmosAddress: p.CosmosAddress,
NitroAddress: p.NitroAddress,
NitroAddress: nitroAddress.String(),
Role: p.Role,
KycID: p.KycId,
}
@ -417,7 +423,7 @@ func (q queryResolver) GetParticipants(ctx context.Context) ([]*Participant, err
return participants, nil
}
func (q queryResolver) GetParticipantByAddress(ctx context.Context, address string) (*Participant, error) {
func (q queryResolver) GetParticipantByAddress(ctx context.Context, address string) (*schema.Participant, error) {
onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx)
participantResp, err := onboardingQueryClient.GetParticipantByAddress(ctx, &onboardingTypes.QueryGetParticipantByAddressRequest{Address: address})
if err != nil {
@ -425,9 +431,13 @@ func (q queryResolver) GetParticipantByAddress(ctx context.Context, address stri
}
p := participantResp.Participant
participant := &Participant{
nitroAddress, err := utils.EthAddressFromPubKey(p.PublicKey)
if err != nil {
return nil, err
}
participant := &schema.Participant{
CosmosAddress: p.CosmosAddress,
NitroAddress: p.NitroAddress,
NitroAddress: nitroAddress.String(),
Role: p.Role,
KycID: p.KycId,
}
@ -435,7 +445,7 @@ func (q queryResolver) GetParticipantByAddress(ctx context.Context, address stri
return participant, nil
}
func (q queryResolver) GetParticipantByNitroAddress(ctx context.Context, nitroAddress string) (*Participant, error) {
func (q queryResolver) GetParticipantByNitroAddress(ctx context.Context, nitroAddress string) (*schema.Participant, error) {
onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx)
participantResp, err := onboardingQueryClient.GetParticipantByNitroAddress(
ctx,
@ -448,9 +458,9 @@ func (q queryResolver) GetParticipantByNitroAddress(ctx context.Context, nitroAd
}
p := participantResp.Participant
participant := &Participant{
participant := &schema.Participant{
CosmosAddress: p.CosmosAddress,
NitroAddress: p.NitroAddress,
NitroAddress: nitroAddress,
Role: p.Role,
KycID: p.KycId,
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
package gql
package schema
import (
"context"

View File

@ -1,6 +1,6 @@
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
package gql
package schema
type Value interface {
IsValue()

View File

@ -2,74 +2,124 @@ package gql
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
serverv2 "cosmossdk.io/server/v2"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/go-chi/chi/v5"
"github.com/rs/cors"
"github.com/spf13/viper"
"github.com/spf13/pflag"
"git.vdb.to/cerc-io/laconicd/gql/schema"
"github.com/cosmos/cosmos-sdk/client"
)
// Server configures and starts the GQL server.
func Server(ctx context.Context, clientCtx client.Context, logger log.Logger) error {
if !viper.GetBool("gql-server") {
return nil
const (
ServerName = "gql"
)
var (
_ serverv2.ServerComponent[transaction.Tx] = (*Server)(nil)
_ serverv2.HasStartFlags = (*Server)(nil)
_ serverv2.HasConfig = (*Server)(nil)
)
type Server struct {
logger log.Logger
router chi.Router
config *Config
httpServer *http.Server
}
func New(logger log.Logger, cfg server.ConfigMap, clientCtx client.Context) (*Server, error) {
s := &Server{
logger: logger.With(log.ModuleKey, ServerName),
router: chi.NewRouter(),
}
router := chi.NewRouter()
s.config = s.Config().(*Config)
if len(cfg) > 0 {
if err := serverv2.UnmarshalSubConfig(cfg, s.Name(), &s.config); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
}
// Add CORS middleware around every request
// See https://github.com/rs/cors for full option listing
router.Use(cors.New(cors.Options{
s.router.Use(cors.New(cors.Options{
AllowedOrigins: []string{"*"},
Debug: false,
}).Handler)
logFile := viper.GetString("log-file")
port := viper.GetString("gql-port")
srv := handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: &Resolver{
ctx: clientCtx,
logFile: logFile,
srv := handler.NewDefaultServer(schema.NewExecutableSchema(schema.Config{Resolvers: &Resolver{
ctx: clientCtx,
// logFile: logFile,
}}))
router.Handle("/", PlaygroundHandler("/api"))
s.router.Handle("/", PlaygroundHandler("/api"))
if viper.GetBool("gql-playground") {
apiBase := viper.GetString("gql-playground-api-base")
router.Handle("/webui", PlaygroundHandler(apiBase+"/api"))
router.Handle("/console", PlaygroundHandler(apiBase+"/graphql"))
if s.config.Playground {
apiBase := s.config.PlaygroundAPIBase
s.router.Handle("/webui", PlaygroundHandler(apiBase+"/api"))
s.router.Handle("/console", PlaygroundHandler(apiBase+"/graphql"))
}
router.Handle("/api", srv)
router.Handle("/graphql", srv)
s.router.Handle("/api", srv)
s.router.Handle("/graphql", srv)
return s, nil
}
errCh := make(chan error)
func (s *Server) Name() string {
return ServerName
}
go func() {
logger.Info(fmt.Sprintf("Connect to GraphQL playground url: http://localhost:%s", port))
server := &http.Server{
Addr: ":" + port,
Handler: router,
ReadHeaderTimeout: 3 * time.Second,
}
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
// Gracefully stop the GQL server.
logger.Info("Stopping GQL server...")
// Server configures and starts the GQL server.
func (s *Server) Start(ctx context.Context) error {
if !s.config.Enable {
s.logger.Info(fmt.Sprintf("%s server is disabled via config", s.Name()))
return nil
case err := <-errCh:
logger.Error(fmt.Sprintf("Failed to start GQL server: %s", err))
}
if s.config.Playground {
s.logger.Info(fmt.Sprintf("Connect to GraphQL playground URL at http://localhost:%d", s.config.Port))
}
s.httpServer = &http.Server{
Addr: fmt.Sprintf(":%d", s.config.Port),
Handler: s.router,
ReadHeaderTimeout: 3 * time.Second,
}
if err := s.httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
s.logger.Error("Failed to start GraphQL server", "error", err)
return err
}
return nil
}
func (s *Server) Stop(ctx context.Context) error {
if !s.config.Enable {
return nil
}
s.logger.Info("stopping GraphQL server")
return s.httpServer.Shutdown(ctx)
}
func (s *Server) Config() any {
if s.config == nil {
return DefaultConfig()
}
return s.config
}
func (s *Server) StartCmdFlags() *pflag.FlagSet {
flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError)
AddGQLFlags(flags)
return flags
}

View File

@ -7,13 +7,14 @@ import (
"strconv"
"strings"
"git.vdb.to/cerc-io/laconicd/gql/schema"
"github.com/cosmos/cosmos-sdk/client"
)
// NodeDataPath is the path to the laconicd data folder.
var NodeDataPath = os.ExpandEnv("$HOME/.laconicd/data")
func getStatusInfo(client client.Context) (*NodeInfo, *SyncInfo, *ValidatorInfo, error) {
func getStatusInfo(client client.Context) (*schema.NodeInfo, *schema.SyncInfo, *schema.ValidatorInfo, error) {
nodeClient, err := client.GetNode()
if err != nil {
return nil, nil, nil, err
@ -23,16 +24,16 @@ func getStatusInfo(client client.Context) (*NodeInfo, *SyncInfo, *ValidatorInfo,
return nil, nil, nil, err
}
return &NodeInfo{
return &schema.NodeInfo{
ID: string(nodeStatus.NodeInfo.ID()),
Network: nodeStatus.NodeInfo.Network,
Moniker: nodeStatus.NodeInfo.Moniker,
}, &SyncInfo{
}, &schema.SyncInfo{
LatestBlockHash: nodeStatus.SyncInfo.LatestBlockHash.String(),
LatestBlockHeight: strconv.FormatInt(nodeStatus.SyncInfo.LatestBlockHeight, 10),
LatestBlockTime: nodeStatus.SyncInfo.LatestBlockTime.String(),
CatchingUp: nodeStatus.SyncInfo.CatchingUp,
}, &ValidatorInfo{
}, &schema.ValidatorInfo{
Address: nodeStatus.ValidatorInfo.Address.String(),
VotingPower: strconv.FormatInt(nodeStatus.ValidatorInfo.VotingPower, 10),
ProposerPriority: nil,
@ -40,7 +41,7 @@ func getStatusInfo(client client.Context) (*NodeInfo, *SyncInfo, *ValidatorInfo,
}
// nolint: all
func getNetInfo(_ client.Context) (string, []*PeerInfo, error) {
func getNetInfo(_ client.Context) (string, []*schema.PeerInfo, error) {
// TODO: Implement
// nodeClient, err := client.GetNode()
@ -68,10 +69,10 @@ func getNetInfo(_ client.Context) (string, []*PeerInfo, error) {
// return strconv.FormatInt(int64(netInfo.NPeers), 10), peersInfo, nil
return strconv.FormatInt(int64(0), 10), []*PeerInfo{}, nil
return strconv.FormatInt(int64(0), 10), []*schema.PeerInfo{}, nil
}
func getValidatorSet(client client.Context) ([]*ValidatorInfo, error) {
func getValidatorSet(client client.Context) ([]*schema.ValidatorInfo, error) {
nodeClient, err := client.GetNode()
if err != nil {
return nil, err
@ -81,10 +82,10 @@ func getValidatorSet(client client.Context) ([]*ValidatorInfo, error) {
return nil, err
}
validatorSet := make([]*ValidatorInfo, len(res.Validators))
validatorSet := make([]*schema.ValidatorInfo, len(res.Validators))
for index, validator := range res.Validators {
proposerPriority := strconv.FormatInt(validator.ProposerPriority, 10)
validatorSet[index] = &ValidatorInfo{
validatorSet[index] = &schema.ValidatorInfo{
Address: validator.Address.String(),
VotingPower: strconv.FormatInt(validator.VotingPower, 10),
ProposerPriority: &proposerPriority,

View File

@ -9,6 +9,7 @@ import (
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagjson"
"git.vdb.to/cerc-io/laconicd/gql/schema"
auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
registrytypes "git.vdb.to/cerc-io/laconicd/x/registry"
@ -23,8 +24,8 @@ const BondIDAttributeName = "bondId"
// ExpiryTimeAttributeName denotes the record expiry time.
const ExpiryTimeAttributeName = "expiryTime"
func getGQLCoin(coin sdk.Coin) *Coin {
gqlCoin := Coin{
func getGQLCoin(coin sdk.Coin) *schema.Coin {
gqlCoin := schema.Coin{
Type: coin.Denom,
Quantity: coin.Amount.BigInt().String(),
}
@ -32,8 +33,8 @@ func getGQLCoin(coin sdk.Coin) *Coin {
return &gqlCoin
}
func getGQLCoins(coins sdk.Coins) []*Coin {
gqlCoins := make([]*Coin, len(coins))
func getGQLCoins(coins sdk.Coins) []*schema.Coin {
gqlCoins := make([]*schema.Coin, len(coins))
for index, coin := range coins {
gqlCoins[index] = getGQLCoin(coin)
}
@ -41,12 +42,12 @@ func getGQLCoins(coins sdk.Coins) []*Coin {
return gqlCoins
}
func GetGQLNameAuthorityRecord(record *registrytypes.NameAuthority) (*AuthorityRecord, error) {
func GetGQLNameAuthorityRecord(record *registrytypes.NameAuthority) (*schema.AuthorityRecord, error) {
if record == nil {
return nil, nil
}
return &AuthorityRecord{
return &schema.AuthorityRecord{
OwnerAddress: record.OwnerAddress,
OwnerPublicKey: record.OwnerPublicKey,
Height: strconv.FormatUint(record.Height, 10),
@ -56,7 +57,7 @@ func GetGQLNameAuthorityRecord(record *registrytypes.NameAuthority) (*AuthorityR
}, nil
}
func getGQLRecord(ctx context.Context, resolver QueryResolver, record registrytypes.Record) (*Record, error) {
func getGQLRecord(ctx context.Context, resolver schema.QueryResolver, record registrytypes.Record) (*schema.Record, error) {
// Nil record.
if record.Deleted {
return nil, nil
@ -81,22 +82,22 @@ func getGQLRecord(ctx context.Context, resolver QueryResolver, record registryty
return nil, err
}
return &Record{
return &schema.Record{
ID: record.Id,
BondID: record.GetBondId(),
CreateTime: record.GetCreateTime(),
ExpiryTime: record.GetExpiryTime(),
Owners: record.GetOwners(),
Names: record.GetNames(),
Attributes: attributes.(MapValue).Value,
Attributes: attributes.(schema.MapValue).Value,
References: references,
}, nil
}
func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
func resolveIPLDNode(node ipld.Node, links *[]string) (schema.Value, error) {
switch node.Kind() {
case ipld.Kind_Map:
var entries []*Attribute
var entries []*schema.Attribute
for itr := node.MapIterator(); !itr.Done(); {
k, v, err := itr.Next()
if err != nil {
@ -113,14 +114,14 @@ func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
if err != nil {
return nil, err
}
entries = append(entries, &Attribute{
entries = append(entries, &schema.Attribute{
Key: s,
Value: val,
})
}
return MapValue{entries}, nil
return schema.MapValue{entries}, nil
case ipld.Kind_List:
var values []Value
var values []schema.Value
for itr := node.ListIterator(); !itr.Done(); {
_, v, err := itr.Next()
if err != nil {
@ -132,7 +133,7 @@ func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
}
values = append(values, val)
}
return ArrayValue{values}, nil
return schema.ArrayValue{values}, nil
case ipld.Kind_Null:
return nil, nil
case ipld.Kind_Bool:
@ -140,82 +141,82 @@ func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
if err != nil {
return nil, err
}
return BooleanValue{val}, nil
return schema.BooleanValue{val}, nil
case ipld.Kind_Int:
val, err := node.AsInt()
if err != nil {
return nil, err
}
// TODO: handle bigger ints
return IntValue{int(val)}, nil
return schema.IntValue{int(val)}, nil
case ipld.Kind_Float:
val, err := node.AsFloat()
if err != nil {
return nil, err
}
return FloatValue{val}, nil
return schema.FloatValue{val}, nil
case ipld.Kind_String:
val, err := node.AsString()
if err != nil {
return nil, err
}
return StringValue{val}, nil
return schema.StringValue{val}, nil
case ipld.Kind_Bytes:
val, err := node.AsBytes()
if err != nil {
return nil, err
}
return BytesValue{string(val)}, nil
return schema.BytesValue{string(val)}, nil
case ipld.Kind_Link:
val, err := node.AsLink()
if err != nil {
return nil, err
}
*links = append(*links, val.String())
return LinkValue{Link(val.String())}, nil
return schema.LinkValue{schema.Link(val.String())}, nil
default:
return nil, fmt.Errorf("invalid node kind")
}
}
func getGQLNameRecord(record *registrytypes.NameRecord) (*NameRecord, error) {
func getGQLNameRecord(record *registrytypes.NameRecord) (*schema.NameRecord, error) {
if record == nil {
return nil, fmt.Errorf("got nil record")
}
records := make([]*NameRecordEntry, len(record.History))
records := make([]*schema.NameRecordEntry, len(record.History))
for index, entry := range record.History {
records[index] = getNameRecordEntry(entry)
}
return &NameRecord{
return &schema.NameRecord{
Latest: getNameRecordEntry(record.Latest),
History: records,
}, nil
}
func getNameRecordEntry(record *registrytypes.NameRecordEntry) *NameRecordEntry {
return &NameRecordEntry{
func getNameRecordEntry(record *registrytypes.NameRecordEntry) *schema.NameRecordEntry {
return &schema.NameRecordEntry{
ID: record.Id,
Height: strconv.FormatUint(record.Height, 10),
}
}
func getGQLBond(bondObj *bondtypes.Bond) (*Bond, error) {
func getGQLBond(bondObj *bondtypes.Bond) (*schema.Bond, error) {
// Nil record.
if bondObj == nil {
return nil, nil
}
return &Bond{
return &schema.Bond{
ID: bondObj.Id,
Owner: bondObj.Owner,
Balance: getGQLCoins(bondObj.Balance),
}, nil
}
func getAuctionBid(bid *auctiontypes.Bid) *AuctionBid {
return &AuctionBid{
func getAuctionBid(bid *auctiontypes.Bid) *schema.AuctionBid {
return &schema.AuctionBid{
BidderAddress: bid.BidderAddress,
Status: bid.Status,
CommitHash: bid.CommitHash,
@ -227,14 +228,14 @@ func getAuctionBid(bid *auctiontypes.Bid) *AuctionBid {
}
}
func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*Auction, error) {
func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*schema.Auction, error) {
if auction == nil {
return nil, nil
}
numProviders := int(auction.NumProviders)
gqlAuction := Auction{
gqlAuction := schema.Auction{
ID: auction.Id,
Status: auction.Status,
OwnerAddress: auction.OwnerAddress,
@ -253,7 +254,7 @@ func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*Au
FundsReleased: auction.FundsReleased,
}
auctionBids := make([]*AuctionBid, len(bids))
auctionBids := make([]*schema.AuctionBid, len(bids))
for index, entry := range bids {
auctionBids[index] = getAuctionBid(entry)
}
@ -263,7 +264,7 @@ func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*Au
return &gqlAuction, nil
}
func toRPCValue(value *ValueInput) *registrytypes.QueryRecordsRequest_ValueInput {
func toRPCValue(value *schema.ValueInput) *registrytypes.QueryRecordsRequest_ValueInput {
var rpcval registrytypes.QueryRecordsRequest_ValueInput
switch {
@ -295,7 +296,7 @@ func toRPCValue(value *ValueInput) *registrytypes.QueryRecordsRequest_ValueInput
return &rpcval
}
func toRPCAttributes(attrs []*KeyValueInput) []*registrytypes.QueryRecordsRequest_KeyValueInput {
func toRPCAttributes(attrs []*schema.KeyValueInput) []*registrytypes.QueryRecordsRequest_KeyValueInput {
kvPairs := []*registrytypes.QueryRecordsRequest_KeyValueInput{}
for _, value := range attrs {
@ -310,7 +311,7 @@ func toRPCAttributes(attrs []*KeyValueInput) []*registrytypes.QueryRecordsReques
return kvPairs
}
func getAuthorityRecord(nameAuthority registrytypes.NameAuthority, auctionQueryClient auctiontypes.QueryClient) (*AuthorityRecord, error) {
func getAuthorityRecord(nameAuthority registrytypes.NameAuthority, auctionQueryClient auctiontypes.QueryClient) (*schema.AuthorityRecord, error) {
gqlNameAuthorityRecord, err := GetGQLNameAuthorityRecord(&nameAuthority)
if err != nil {
return nil, err

View File

@ -4,6 +4,7 @@ deps:
- buf.build/cosmos/cosmos-proto
- buf.build/cosmos/gogo-proto
- buf.build/googleapis/googleapis
- buf.build/protocolbuffers/wellknowntypes
lint:
use:
- DEFAULT

View File

@ -0,0 +1,10 @@
syntax = "proto3";
package cerc.nitro.v1;
option go_package = "git.vdb.to/cerc-io/laconicd/server/nitro";
// P2PMessage wraps a json-encoded Nitro protocols.Message
// TODO: proper proto message?
message P2PMessage {
string content = 1;
}

View File

@ -0,0 +1,65 @@
syntax = "proto3";
package cerc.nitrobank.v1;
import "cosmos/msg/v1/msg.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
// import "cosmos_proto/cosmos.proto";
import "cerc/nitrobank/v1/nitrobank.proto";
option go_package = "git.vdb.to/cerc-io/laconicd/x/nitrobank";
// 1. user account initiates opening of ledger channel with consensus-controlled module account as
// counterparty
//
// 2. open-channel request is gossiped to validator set
//
// 3. validators submit partial signatures for pending open-channel request
//
// 4. block proposer checks pending open-channel requests and creates ledger channels for those with
// complete signatures
// MsgInitAccount initializes a nitro-based account
message MsgInitAccount {
string nitro_address = 1;
}
message MsgInitAccountResponse {}
// MsgOpenChannel opens a ledger channel with the sending account as a participant
message MsgOpenChannel {
option (cosmos.msg.v1.signer) = "from_address";
// TODO: this is the nitro address of the sending account
// // Nitro address of sending party
string from_address = 1;
// Nitro address of counterparty
string to_address = 2;
// Simplified outcome just includes the funding amount from payer
string amount = 3;
// TODO
// uint32 challenge_duration = 3;
}
message MsgOpenChannelResponse {}
service Msg {
option (cosmos.msg.v1.service) = true;
rpc ProposeChannel(MsgProposeChannel) returns (MsgProposeChannelResponse) {
option (google.api.http).post = "/cerc/nitrobank/v1/propose_channel";
}
}
message MsgProposeChannel {
option (cosmos.msg.v1.signer) = "from_address";
// Nitro address of sending party (payer)
string from_address = 1;
// Nitro address of counterparty
string to_address = 2;
// Simplified outcome just includes the funding amount from payer
string amount = 3;
// TODO
// uint32 challenge_duration = 3;
}
message MsgProposeChannelResponse {}

View File

@ -21,10 +21,8 @@ message Participant {
[ (gogoproto.moretags) =
"json:\"cosmos_address\" yaml:\"cosmos_address\"" ];
// participant's Nitro address
string nitro_address = 2
[ (gogoproto.moretags) =
"json:\"nitro_address\" yaml:\"nitro_address\"" ];
// full public key used to derive participant's Nitro address
bytes public_key = 2;
// participant's role (participant | validator)
string role = 3 [ (gogoproto.moretags) = "json:\"role\" yaml:\"role\"" ];

View File

@ -96,7 +96,7 @@ message Record {
[ (gogoproto.moretags) = "json:\"attributes\" yaml:\"attributes\"" ];
repeated string names = 8
[ (gogoproto.moretags) = "json:\"names\" yaml:\"names\"" ];
string type = 9 [ (gogoproto.moretags) = "json:\"types\" yaml:\"types\"" ];
string types = 9 [ (gogoproto.moretags) = "json:\"types\" yaml:\"types\"" ];
}
// AuthorityEntry defines a registry authority

View File

@ -1,6 +1,13 @@
#!/bin/bash
KEY="alice"
if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then
set -x
fi
LACONIC_BIN=${LACONIC_BIN:-laconicd}
LACONIC_HOME="${LACONIC_HOME:-$HOME/.laconicd}"
KEY="node_key"
CHAINID=${CHAINID:-"laconic_9000-1"}
MONIKER=${MONIKER:-"localtestnet"}
KEYRING=${KEYRING:-"test"}
@ -10,7 +17,22 @@ LOGLEVEL=${LOGLEVEL:-"info"}
input_genesis_file=${GENESIS_FILE}
if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
laconicd="$LACONIC_BIN --home=$LACONIC_HOME --log_level=debug"
set -e
hang() {
tail -f /dev/null
}
trap hang EXIT
if [[ "$OSTYPE" == "darwin"* ]]; then
sed_i="sed -i ''"
else
sed_i="sed -i"
fi
if [[ "$1" == "clean" ]] || [[ ! -d "$LACONIC_HOME/data/blockstore.db" ]]; then
# validate dependencies are installed
command -v jq > /dev/null 2>&1 || {
echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"
@ -18,29 +40,29 @@ if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
}
# remove existing daemon and client
rm -rf $HOME/.laconicd/*
rm -rf $LACONIC_HOME/*
if [ -n "`which make`" ]; then
make install
fi
laconicd config set client chain-id $CHAINID
laconicd config set client keyring-backend $KEYRING
$laconicd config set client chain-id $CHAINID
$laconicd config set client keyring-backend $KEYRING
# if $KEY exists it should be deleted
laconicd keys add $KEY --keyring-backend $KEYRING
printf "y\n" | $laconicd keys add $KEY --keyring-backend $KEYRING --no-backup
# Set the Nitro node PK
# TODO generate?
echo "$NITRO_PK" | $laconicd keys import-hex "${KEY}_nitro"
# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
laconicd init $MONIKER --chain-id $CHAINID --default-denom $DENOM
$laconicd init $MONIKER --chain-id $CHAINID --default-denom $DENOM
if [[ -f ${input_genesis_file} ]]; then
# Use provided genesis config
cp $input_genesis_file $HOME/.laconicd/config/genesis.json
cp $input_genesis_file $LACONIC_HOME/config/genesis.json
fi
update_genesis() {
jq "$1" $HOME/.laconicd/config/genesis.json > $HOME/.laconicd/config/tmp_genesis.json &&
mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
jq "$1" $LACONIC_HOME/config/genesis.json > $LACONIC_HOME/config/tmp_genesis.json &&
mv $LACONIC_HOME/config/tmp_genesis.json $LACONIC_HOME/config/genesis.json
}
if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then
@ -93,49 +115,55 @@ if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
# Set gas limit in genesis
update_genesis '.consensus["params"]["block"]["max_gas"]="10000000"'
# disable produce empty block
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
else
sed -i 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
fi
update_config() {
mv -f "$2" "${2}.bak" && tomlq --toml-output "$1" "${2}.bak" > "$2"
}
# Run this to allow requests from any origin
sed -i 's/cors_allowed_origins.*$/cors_allowed_origins = ["*"]/' $HOME/.laconicd/config/config.toml
# disable empty blocks
update_config '.consensus.create_empty_blocks = false' $LACONIC_HOME/config/config.toml
# Allow requests from any origin
update_config '.rpc.cors_allowed_origins = ["*"]' $LACONIC_HOME/config/config.toml
# Enable telemetry (prometheus metrics: http://localhost:1317/metrics?format=prometheus)
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' 's/enabled = false/enabled = true/g' $HOME/.laconicd/config/app.toml
sed -i '' 's/prometheus-retention-time = 0/prometheus-retention-time = 60/g' $HOME/.laconicd/config/app.toml
sed -i '' 's/prometheus = false/prometheus = true/g' $HOME/.laconicd/config/config.toml
else
sed -i 's/enabled = false/enabled = true/g' $HOME/.laconicd/config/app.toml
sed -i 's/prometheus-retention-time = 0/prometheus-retention-time = 60/g' $HOME/.laconicd/config/app.toml
sed -i 's/prometheus = false/prometheus = true/g' $HOME/.laconicd/config/config.toml
fi
update_config '.telemetry.enabled = true' $LACONIC_HOME/config/app.toml
update_config '.telemetry."prometheus-retention-time" = 60' $LACONIC_HOME/config/app.toml
update_config '.instrumentation.prometheus = true' $LACONIC_HOME/config/config.toml
# Nitro config
update_config "
.nitro.\"eth-pk\" = \"${KEY}\" |
.nitro.\"eth-url\" = \"${NITRO_ETH_URL}\" |
.nitro.\"eth-ca-address\" = \"${NITRO_ETH_CA_ADDRESS}\" |
.nitro.\"eth-na-address\" = \"${NITRO_ETH_NA_ADDRESS}\" |
.nitro.\"eth-vpa-address\" = \"${NITRO_ETH_VPA_ADDRESS}\" |
.nitro.\"eth-start-block\" = \"${NITRO_ETH_START_BLOCK}\" |
.nitro.pk = \"${KEY}_nitro\" |
.nitro.\"boot-peers\" = \"${NITRO_BOOT_PEERS}\"
" $LACONIC_HOME/config/app.toml
# Allocate genesis accounts (cosmos formatted addresses)
# 10^30 alnt | 10^12 lnt
laconicd genesis add-genesis-account $KEY 1000000000000000000000000000000$DENOM --keyring-backend $KEYRING
$laconicd genesis add-genesis-account $KEY 1000000000000000000000000000000$DENOM --keyring-backend $KEYRING
# Sign genesis transaction
# 10^15 alnt
laconicd genesis gentx $KEY $STAKING_AMOUNT$DENOM --keyring-backend $KEYRING --chain-id $CHAINID
$laconicd genesis gentx $KEY $STAKING_AMOUNT$DENOM --keyring-backend $KEYRING --chain-id $CHAINID
# Collect genesis tx
laconicd genesis collect-gentxs
$laconicd genesis collect-gentxs
# Run this to ensure everything worked and that the genesis file is setup correctly
laconicd genesis validate
$laconicd genesis validate
else
echo "Using existing database at $HOME/.laconicd. To replace, run '`basename $0` clean'"
echo "Using existing database at $LACONIC_HOME. To replace, run '`basename $0` clean'"
fi
# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
laconicd start \
--pruning=nothing \
--log_level $LOGLEVEL \
--minimum-gas-prices=1$DENOM \
--api.enable \
# TODO new pruning config
$laconicd start \
--log_level "$LOGLEVEL" \
--server.minimum-gas-prices="1$DENOM" \
--rpc.laddr="tcp://0.0.0.0:26657" \
--gql-server --gql-playground
--grpc.address="127.0.0.1:9091" \
--gql.enable --gql.playground

13
server/distsig/config.go Normal file
View File

@ -0,0 +1,13 @@
package distsig
type Config struct {
LongtermKey string `mapstructure:"longterm-key" toml:"longterm-key" comment:"The long-term key used in distributed signatures"`
// TODO: set this in genesis
ThresholdRatio float64 `mapstructure:"threshold-ratio" toml:"threshold-ratio" comment:"The ratio of signers required to sign a message"`
}
func DefaultConfig() *Config {
return &Config{
ThresholdRatio: 4. / 7,
}
}

View File

@ -0,0 +1,175 @@
package distsig
import (
"errors"
"math/big"
"testing"
"cosmossdk.io/log"
"git.vdb.to/cerc-io/chainsig/ethschnorr"
sdktestutil "github.com/cosmos/cosmos-sdk/testutil"
"github.com/stretchr/testify/require"
"git.vdb.to/cerc-io/laconicd/testutil"
)
func NewTestManager(t *testing.T) (*Manager, Point) {
logger := log.NewTestLogger(t)
kr := testutil.NewKeyring()
accounts := sdktestutil.CreateKeyringAccounts(t, kr, 1)
cfg := DefaultConfig()
cfg.LongtermKey = accounts[0].Name
dsm, err := New(logger, cfg, kr)
require.NoError(t, err)
longterm, err := kr.Key(cfg.LongtermKey)
require.NoError(t, err)
longtermPoint, err := KeyRecordToPoint(longterm)
require.NoError(t, err)
return dsm, longtermPoint
}
type round struct {
name string
verify func(*Manager) error
tweak func([]PeerMessages)
}
var (
dkgRounds = []round{
{
name: "deal",
},
{
name: "response",
verify: func(m *Manager) error {
if !m.currentDkg().Certified() {
return errors.New("not certified")
}
return nil
},
},
{
name: "commit",
verify: func(m *Manager) error {
if !m.currentDkg().Finished() {
return errors.New("run not finished")
}
if m.currentDkg().share == nil {
return errors.New("dist key share is absent")
}
return nil
},
},
}
dssRounds = []round{
{
name: "sign",
verify: func(m *Manager) error {
dss := m.sigs[m.completeSigs[0]]
if dss.sig == nil {
return errors.New("signature is nil")
}
dkg, err := m.getDkg(dss.dkgID)
if err != nil {
return err
}
return ethschnorr.Verify(dkg.share.Public(), dss.Message(), dss.sig)
},
},
}
)
func runRound(t *testing.T, r round, members []*Manager) {
buf := make([]PeerMessages, len(members))
for i := range members {
buf[i] = members[i].FlushMessages()
}
if r.tweak != nil {
r.tweak(buf)
}
for i := range members {
for j := range members {
if i == j {
continue
}
require.NoError(t, members[i].ProcessMessages(&buf[j]),
"round=%s, i=%d, j=%d", r.name, i, j)
}
}
if r.verify != nil {
for i, m := range members {
require.NoError(t, r.verify(m), "round=%s, i=%d", r.name, i)
}
}
}
func TestDkgBasic(t *testing.T) {
numMembers := 2
blockHeight := int64(1)
members := make([]*Manager, numMembers)
pubkeys := make([]Point, numMembers)
for i := range members {
members[i], pubkeys[i] = NewTestManager(t)
}
t.Logf("DKG with %d members", numMembers)
for i, m := range members {
require.NoError(t, m.StartDKG(blockHeight, pubkeys), "i=%d", i)
}
for _, r := range dkgRounds {
runRound(t, r, members)
}
require.False(t, members[0].NeedDKG(pubkeys))
require.Error(t, members[0].StartDKG(blockHeight, pubkeys))
// add participants and refresh DKG
for len(members) < 7 {
blockHeight++
m, pub := NewTestManager(t)
members = append(members, m)
pubkeys = append(pubkeys, pub)
t.Logf("DKG with %d members", len(members))
for i, m := range members {
require.True(t, m.NeedDKG(pubkeys), "i=%d", i)
require.NoError(t, m.StartDKG(blockHeight, pubkeys), "i=%d", i)
}
for _, r := range dkgRounds {
runRound(t, r, members)
}
}
}
func TestSignatureBasic(t *testing.T) {
numMembers := 7
members := make([]*Manager, numMembers)
pubkeys := make([]Point, numMembers)
for i := range members {
members[i], pubkeys[i] = NewTestManager(t)
}
for _, m := range members {
require.NoError(t, m.StartDKG(1, pubkeys))
}
for _, r := range dkgRounds {
runRound(t, r, members)
}
msg := big.NewInt(42)
for _, m := range members {
require.NoError(t, m.StartSignature(m.currentDkgID, msg))
}
runRound(t, dssRounds[0], members)
require.Error(t, members[0].StartSignature(0, msg))
require.NoError(t, members[0].StartDKG(2, pubkeys[:3]))
require.Error(t, members[0].StartSignature(2, msg))
}

19
server/distsig/flags.go Normal file
View File

@ -0,0 +1,19 @@
package distsig
import (
"fmt"
"github.com/spf13/pflag"
)
func prefix(f string) string {
return fmt.Sprintf("%s.%s", componentName, f)
}
var (
FlagLongtermKey = prefix("longterm-key")
)
func AddNitroFlags(flags *pflag.FlagSet) {
flags.String(FlagLongtermKey, "", "The long-term key used in distributed signatures")
}

224
server/distsig/keygen.go Normal file
View File

@ -0,0 +1,224 @@
package distsig
import (
"fmt"
dkg "go.dedis.ch/kyber/v3/share/dkg/rabin"
)
// DkgMessages collects local DKG messages that are pending broadcast.
type DkgMessages struct {
runID DkgRunID
messages []dkgMessage
}
// DKG steps (actions) that are executed by the DKG protocol
type dkgStep int
const (
dkg_deal dkgStep = iota
dkg_certify
dkg_commit
dkg_finish
dkg_done
)
type dkgRun struct {
*dkg.DistKeyGenerator
// runID RunID
msgBuffer []dkgMessage
step dkgStep
share *dkg.DistKeyShare
}
type dkgMessage interface {
send(*dkgRun) (dkgMessage, error)
from() uint32
target() uint32
}
// prepareMessages produces DKG state transitions that don't rely on peer inputs, i.e. the deal or
// commit steps. This is called during ExtendVote by all validators.
func (d *dkgRun) prepareMessages() error {
out, err := d.handleMessage(nil)
if err != nil {
return err
}
if out != nil {
d.msgBuffer = append(d.msgBuffer, out...)
}
return nil
}
func (d *dkgRun) flushMessages() []dkgMessage {
buf := d.msgBuffer
d.msgBuffer = nil
return buf
}
// processMessages processes incoming DKG messages and produces outgoing messages. This is called
// during VerifyVoteExtension by all validators (TODO: verify).
func (d *dkgRun) processMessages(in []dkgMessage) error {
for _, msg := range in {
out, err := d.handleMessage(msg)
if err != nil {
return err
}
if out != nil {
d.msgBuffer = append(d.msgBuffer, out...)
}
}
return nil
}
func (d *dkgRun) handleMessage(in dkgMessage) ([]dkgMessage, error) {
// fmt.Printf("[%d, %7s] handle: %T", d.index, d.step, in)
// if in != nil {
// fmt.Printf(" (from %d to %+v)", in.from(), in.target())
// }
// fmt.Println()
// nil input means we try to execute a step requiring no peer input
if in == nil {
var out []dkgMessage
switch d.step {
case dkg_deal:
deals, err := d.Deals()
if err != nil {
return nil, err
}
for index, deal := range deals {
out = append(out, msgDeal{index: uint32(index), msg: deal})
}
case dkg_commit:
sc, err := d.SecretCommits()
if err != nil {
return nil, err
}
out = []dkgMessage{msgSecretCommits{msg: sc}}
case dkg_done:
dks, err := d.DistKeyShare()
if err != nil {
return nil, err
}
d.share = dks
default:
return nil, fmt.Errorf("unexpected stage: %v", d.step)
}
d.step = nextStep(d.step)
return out, nil
}
var out []dkgMessage
if msg, err := in.send(d); err != nil {
return nil, err
} else if msg != nil {
out = []dkgMessage{msg}
}
if (d.step == dkg_certify && d.Certified()) ||
(d.step == dkg_finish && d.Finished()) {
d.step = nextStep(d.step)
msgs, err := d.handleMessage(nil)
if err != nil {
return nil, err
}
out = append(out, msgs...)
}
return out, nil
}
func nextStep(step dkgStep) dkgStep {
if step == dkg_done {
return dkg_done
}
return step + 1
}
type (
msgDeal struct {
msg *dkg.Deal
index uint32 // recipient index
}
msgResponse struct{ msg *dkg.Response }
msgJustification struct{ msg *dkg.Justification }
msgSecretCommits struct{ msg *dkg.SecretCommits }
msgComplaintCommits struct{ msg *dkg.ComplaintCommits }
msgReconstructCommits struct{ msg *dkg.ReconstructCommits }
)
func (m msgDeal) send(d *dkgRun) (dkgMessage, error) {
if m.index != uint32(d.Index()) {
return nil, nil
}
out, err := d.ProcessDeal(m.msg)
if err != nil {
return nil, err
}
return msgResponse{out}, nil
}
func (m msgResponse) send(d *dkgRun) (dkgMessage, error) {
if out, err := d.ProcessResponse(m.msg); err != nil {
return nil, err
} else if out != nil {
return msgJustification{out}, nil
}
return nil, nil
}
func (m msgJustification) send(d *dkgRun) (dkgMessage, error) {
return nil, d.ProcessJustification(m.msg)
}
func (m msgSecretCommits) send(d *dkgRun) (dkgMessage, error) {
if out, err := d.ProcessSecretCommits(m.msg); err != nil {
return nil, err
} else if out != nil {
return msgComplaintCommits{out}, nil
}
return nil, nil
}
func (m msgComplaintCommits) send(d *dkgRun) (dkgMessage, error) {
out, err := d.ProcessComplaintCommits(m.msg)
if err != nil {
return nil, err
}
return msgReconstructCommits{out}, nil
}
func (m msgReconstructCommits) send(d *dkgRun) (dkgMessage, error) {
return nil, d.ProcessReconstructCommits(m.msg)
}
func (d dkgStep) String() string {
switch d {
case dkg_deal:
return "deal"
case dkg_certify:
return "certify"
case dkg_commit:
return "commit"
case dkg_finish:
return "finish"
case dkg_done:
return "done"
default:
return "unknown"
}
}
// for debugging
func (m msgDeal) from() uint32 { return m.msg.Index }
func (m msgResponse) from() uint32 { return m.msg.Response.Index }
func (m msgJustification) from() uint32 { return m.msg.Justification.Index }
func (m msgSecretCommits) from() uint32 { return m.msg.Index }
func (m msgComplaintCommits) from() uint32 { return m.msg.Index }
func (m msgReconstructCommits) from() uint32 { return m.msg.Index }
func (m msgDeal) target() uint32 { return m.index }
func (m msgResponse) target() uint32 { return m.msg.Index }
func (m msgJustification) target() uint32 { return m.msg.Index }
func (m msgSecretCommits) target() uint32 { return 0 }
func (m msgComplaintCommits) target() uint32 { return m.msg.DealerIndex }
func (m msgReconstructCommits) target() uint32 { return m.msg.DealerIndex }

280
server/distsig/manager.go Normal file
View File

@ -0,0 +1,280 @@
package distsig
import (
"context"
"fmt"
"math"
"math/big"
"github.com/ethereum/go-ethereum/common"
dkg "go.dedis.ch/kyber/v3/share/dkg/rabin"
"cosmossdk.io/log"
"cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
clientdss "git.vdb.to/cerc-io/chainsig/ethdss"
"git.vdb.to/cerc-io/chainsig/ethschnorr"
"git.vdb.to/cerc-io/laconicd/utils"
)
type (
DealMap = map[int]*dkg.Deal
DkgRunID int64
SigRunID string
)
const (
componentName = "distsig"
)
type Manager struct {
config *Config
logger log.Logger
longterm Scalar
longtermPubKey cryptotypes.PubKey
dkgs map[DkgRunID]*dkgRun
currentDkgID DkgRunID // zero indicates no current run
sigs map[SigRunID]*sigRun
completeSigs []SigRunID
}
type PeerMessages struct {
dkg *DkgMessages
dss []SigMessages
}
func New(logger log.Logger, cfg *Config, kr keyring.Keyring) (*Manager, error) {
longtermPrivKey, err := utils.ExtractPrivateKey(kr, cfg.LongtermKey)
if err != nil {
return nil, fmt.Errorf("failed to extract longterm key: %w", err)
}
m := &Manager{
longterm: suite.Scalar().SetBytes(longtermPrivKey.Bytes()),
longtermPubKey: longtermPrivKey.PubKey(),
config: cfg,
dkgs: make(map[DkgRunID]*dkgRun),
sigs: make(map[SigRunID]*sigRun),
}
m.logger = logger.With(log.ModuleKey, m.Name())
return m, nil
}
func (m *Manager) getDkg(runid DkgRunID) (*dkgRun, error) {
if runid == 0 {
// runid = m.currentDkg
return nil, fmt.Errorf("invalid run ID")
}
if run, ok := m.dkgs[runid]; ok {
return run, nil
}
return nil, fmt.Errorf("DKG not initialized for run: %v", runid)
}
func (m *Manager) currentDkg() *dkgRun {
run, err := m.getDkg(m.currentDkgID)
if err != nil {
panic(err)
}
return run
}
func (m *Manager) LongtermPublicKey() cryptotypes.PubKey {
return m.longtermPubKey
}
func (m *Manager) LongtermEthAddress() common.Address {
pubkey, err := SuitePublicKeyFromBytes(m.LongtermPublicKey().Bytes())
if err != nil {
panic(fmt.Errorf("failed to parse longterm pubkey: %w", err))
}
return pubkey.Address()
}
func thresholdForRatio(m int, tr float64) int {
return int(math.Ceil(float64(m) * tr))
}
func (m *Manager) initDKG(members []Point) (*dkgRun, error) {
t := thresholdForRatio(len(members), m.config.ThresholdRatio)
keygen, err := dkg.NewDistKeyGenerator(suite.(dkg.Suite), m.longterm, members, t)
if err != nil {
return nil, err
}
return &dkgRun{DistKeyGenerator: keygen}, nil
}
// NeedDKG returns true if DKG needs to be run for the given participants.
func (m *Manager) NeedDKG(pubkeys []Point) bool {
return m.currentDkgID == 0 || !equalPoints(m.currentDkg().Participants(), pubkeys)
}
// StartDKG begins a new DKG run including the given participants.
func (m *Manager) StartDKG(block int64, pubkeys []Point) error {
// TODO: generate runid from block height and hash of pubkeys?
runid := DkgRunID(block)
if _, ok := m.dkgs[runid]; ok {
return fmt.Errorf("DKG run %v already exists", runid)
}
if len(pubkeys) < 2 {
m.currentDkgID = 0
m.logger.Debug("Too few participants for distributed signature")
return nil
}
run, err := m.initDKG(pubkeys)
if err != nil {
return err
}
m.dkgs[runid] = run
m.currentDkgID = runid
return run.prepareMessages()
}
func (m *Manager) initDSS(dkgid DkgRunID, msg *big.Int) (*sigRun, error) {
run, err := m.getDkg(dkgid)
if err != nil {
return nil, err
}
if !run.Finished() {
return nil, fmt.Errorf("DKG run has not finished: %v", dkgid)
}
random, err := run.DistKeyShare()
if err != nil {
return nil, err
}
dss, err := clientdss.NewDSS(clientdss.DSSArgs{
Secret: m.longterm,
Participants: run.Participants(),
Long: run.share,
Random: random,
Msg: msg,
T: run.Threshold(),
// Qualified: run.QUAL(),
})
if err != nil {
return nil, err
}
return &sigRun{DSS: dss, dkgID: dkgid}, nil
}
// StartSignature begins a DSS run for the given message and DKG state.
func (m *Manager) StartSignature(msg *big.Int) error {
if m.currentDkgID == 0 {
return fmt.Errorf("no distributed key prepared")
}
run, err := m.initDSS(m.currentDkgID, msg)
if err != nil {
return err
}
sigid := run.SigRunID()
m.sigs[sigid] = run
return run.prepareMessages()
}
func (m *Manager) CompletedSignatures() map[SigRunID]ethschnorr.Signature {
var ret map[SigRunID]ethschnorr.Signature
for _, id := range m.completeSigs {
run, ok := m.sigs[id]
if !ok {
panic(fmt.Errorf("DSS run not found: %v", id))
}
if run.sig == nil {
panic(fmt.Errorf("DSS signature not completed: %v", id))
}
// Deterministically pick a participant responsible for submitting the signature
session := new(big.Int).SetBytes(run.SessionID()[:8])
submitterIdx := session.Uint64() % uint64(len(run.Participants()))
if run.Index() == int(submitterIdx) {
ret[id] = run.sig
}
}
return ret
}
// FlushMessages flushes the message buffers for any active DKG and DSS runs.
func (m *Manager) FlushMessages() PeerMessages {
var ret PeerMessages
if buf := m.currentDkg().flushMessages(); len(buf) != 0 {
ret.dkg = &DkgMessages{runID: m.currentDkgID, messages: buf}
}
for id, run := range m.sigs {
if buf := run.flushMessages(); buf != nil {
ret.dss = append(ret.dss, SigMessages{id, buf})
}
}
return ret
}
// ProcessMessages processes DKG and DSS peer messages.
func (m *Manager) ProcessMessages(dm *PeerMessages) error {
if dkg := dm.dkg; dkg != nil {
run, err := m.getDkg(dkg.runID)
if err != nil {
return err
}
if err := run.processMessages(dkg.messages); err != nil {
return err
}
}
for _, dss := range dm.dss {
run, ok := m.sigs[dss.runID]
if !ok {
return fmt.Errorf("DSS not initialized for run: %v", dss.runID)
}
if err := run.processMessage(dss.messages); err != nil {
return err
}
if run.sig != nil {
m.completeSigs = append(m.completeSigs, dss.runID)
}
}
return nil
}
func equalPoints(a, b []Point) bool {
if len(a) != len(b) {
return false
}
for i, p := range a {
if !p.Equal(b[i]) {
return false
}
}
return true
}
func (*Manager) Name() string { return componentName }
func (*Manager) Start(context.Context) error { return nil }
func (*Manager) Stop(context.Context) error { return nil }
func (m *Manager) Config() any {
if m.config == nil {
return DefaultConfig()
}
return m.config
}
func (pm PeerMessages) Empty() bool {
return pm.dkg == nil && len(pm.dss) == 0
}
func UnmarshalConfig(cfg map[string]any) (*Config, error) {
config := DefaultConfig()
if err := serverv2.UnmarshalSubConfig(cfg, componentName, config); err != nil {
return nil, fmt.Errorf("failed to unmarshal %T: %w", config, err)
}
return config, nil
}
func ProvideManager(logger log.Logger, globalConfig runtime.GlobalConfig, kr keyring.Keyring) (*Manager, error) {
config, err := UnmarshalConfig(globalConfig)
if err != nil {
return nil, err
}
return New(logger, config, kr)
}

View File

@ -0,0 +1,61 @@
package distsig
import (
"fmt"
clientdss "git.vdb.to/cerc-io/chainsig/ethdss"
"git.vdb.to/cerc-io/chainsig/ethschnorr"
)
type SigMessages struct {
runID SigRunID
messages sigMessage
}
type sigStep int
const (
sig_partial sigStep = iota
sig_complete
)
type sigRun struct {
*clientdss.DSS
msgBuffer sigMessage
dkgID DkgRunID
step sigStep
sig ethschnorr.Signature
}
type sigMessage = *clientdss.PartialSig
func (d *sigRun) SigRunID() SigRunID {
return SigRunID(fmt.Sprintf("%020d-%x", d.dkgID, d.SessionID()[:10]))
}
func (d *sigRun) prepareMessages() error {
var err error
d.msgBuffer, err = d.PartialSig()
return err
}
func (d *sigRun) flushMessages() sigMessage {
buf := d.msgBuffer
d.msgBuffer = nil
return buf
}
func (d *sigRun) processMessage(in sigMessage) error {
err := d.ProcessPartialSig(in)
if err != nil {
return err
}
// return d.EnoughPartialSig(), nil
if d.EnoughPartialSig() {
d.sig, err = d.Signature()
return err
}
return nil
}

37
server/distsig/suite.go Normal file
View File

@ -0,0 +1,37 @@
package distsig
import (
"fmt"
"git.vdb.to/cerc-io/chainsig/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/suites"
)
type (
Scalar = kyber.Scalar
Point = kyber.Point
PublicKey = secp256k1.PublicKey
)
var (
suite suites.Suite = secp256k1.NewBlakeKeccackSecp256k1()
// Note: the compressed encoding of pubkeys used by the SDK and our library are the same.
// See gitlab.com/yawning/secp256k1-voi/secec
SuitePublicKeyFromBytes = secp256k1.NewPublicKeyFromBytes
)
func KeyRecordToPoint(longterm *keyring.Record) (kyber.Point, error) {
pubkey, err := longterm.GetPubKey()
if err != nil {
return nil, fmt.Errorf("failed to access public key: %w", err)
}
suitePubkey, err := SuitePublicKeyFromBytes(pubkey.Bytes())
if err != nil {
return nil, fmt.Errorf("failed to decode public key: %w", err)
}
return suitePubkey.Point()
}

26
server/distsig/utils.go Normal file
View File

@ -0,0 +1,26 @@
package distsig
import "encoding/hex"
type BlockHash [32]byte
func (bh BlockHash) String() string {
return hex.EncodeToString(bh[:])
}
func (bh BlockHash) Bytes() []byte {
return bh[:]
}
func (bh BlockHash) Equal(other BlockHash) bool {
return bh == other
}
func BlockHashFromBytes(b []byte) BlockHash {
if len(b) != 32 {
panic("invalid block hash length")
}
var bh BlockHash
copy(bh[:], b)
return bh
}

70
server/nitro/commands.go Normal file
View File

@ -0,0 +1,70 @@
package nitro
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/spf13/cobra"
"github.com/statechannels/go-nitro/channel/state/outcome"
gonitrotypes "github.com/statechannels/go-nitro/types"
)
const (
FlagAssetAddress = "asset"
)
func (s *Server) OpenChannelCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "open-channel <amount>", // TODO: doc args?
Short: "Open a payment channel with the Laconic custodian",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
// clientCtx, err := client.GetClientTxContext(cmd)
// if err != nil {
// return err
// }
// TODO
// use Coin types for eth and tokens?
// how do we map denoms to token addresses?
amount, ok := new(big.Int).SetString(args[1], 10)
if !ok {
return fmt.Errorf("invalid amount: %s", args[1])
}
assetStr, err := cmd.Flags().GetString(FlagAssetAddress)
if err != nil {
return err
}
var asset common.Address // 0 address mean ETH
if assetStr != "" {
asset = common.HexToAddress(assetStr)
}
destination := LaconicCustodianAddress
exit := outcome.Exit{
outcome.SingleAssetExit{
Asset: asset,
Allocations: []outcome.Allocation{
{ // TODO: what should initial allocation be?
Destination: gonitrotypes.AddressToDestination(s.ethAddress),
Amount: amount,
},
},
},
}
r, err := s.CreateLedgerChannel(destination, 0, exit)
if err != nil {
return err
}
cmd.Println("objective response:", r)
return nil
},
}
cmd.Flags().String(FlagAssetAddress, "", "The address of the asset to fund the channel with")
addClientFlags(cmd.Flags())
return cmd
}

35
server/nitro/config.go Normal file
View File

@ -0,0 +1,35 @@
package nitro
type Config struct {
// TODO: use keyring
Pk string `mapstructure:"pk" toml:"pk" comment:"The private key used by the Nitro node."`
EthPk string `mapstructure:"eth-pk" toml:"eth-pk" comment:"The private key used when interacting with the Ethereum chain."`
EthUrl string `mapstructure:"eth-url" toml:"eth-url" comment:"The URL of the Ethereum node to connect to."`
EthAuthToken string `mapstructure:"eth-auth-token" toml:"eth-auth-token" comment:"The bearer token used for auth in requests to the Ethereum chain's RPC endpoint."`
EthStartBlock uint64 `mapstructure:"eth-start-block" toml:"eth-start-block" comment:"Ethereum block number to start listening for Nitro Adjudicator events."`
EthNaAddress string `mapstructure:"eth-na-address" toml:"na-address" comment:"Ethereum address of the Nitro Adjudicator contract."`
EthVpaAddress string `mapstructure:"eth-vpa-address" toml:"vpa-address" comment:"Ethereum address of the Virtual Payment App contract."`
EthCaAddress string `mapstructure:"eth-ca-address" toml:"ca-address" comment:"Ethereum address of the Consensus App contract."`
BootPeers string `mapstructure:"boot-peers" toml:"boot-peers" comment:"Comma-delimited list of peer multiaddrs the messaging service will connect to when initialized."`
PublicIp string `mapstructure:"public-ip" toml:"public-ip" comment:"The public IP address used for the Nitro message service."`
ExtMultiAddr string `mapstructure:"ext-multiaddr" toml:"ext-multiaddr" comment:"An additional external multiaddr to advertise."`
MsgPort int `mapstructure:"msg-port" toml:"msg-port" comment:"The TCP port for the Nitro message service."`
WsMsgPort int `mapstructure:"ws-msg-port" toml:"ws-msg-port" comment:"The WebSocket port for the Nitro message service."`
RpcPort int `mapstructure:"rpc-port" toml:"rpc-port" comment:"The TCP port for the Nitro RPC server."`
TlsCertFilepath string `mapstructure:"tls-cert-filepath" toml:"tls-cert-filepath" comment:"Filepath to the TLS certificate. If not specified, TLS will not be used with the RPC transport."`
TlsKeyFilepath string `mapstructure:"tls-key-filepath" toml:"tls-key-filepath" comment:"Filepath to the TLS private key. If not specified, TLS will not be used with the RPC transport."`
}
func DefaultConfig() *Config {
return &Config{
EthUrl: "http://localhost:8545",
PublicIp: "127.0.0.1",
MsgPort: 3005,
WsMsgPort: 6005,
RpcPort: 4005,
// TlsCertFilepath: "./tls/statechannels.org.pem",
// TlsKeyFilepath: "./tls/statechannels.org_key.pem",
}
}

View File

@ -0,0 +1,23 @@
package nitro
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
)
var (
// (DEV) EOA placeholder for consensus-controlled smart contract account
LaconicCustodianAddress common.Address
LaconicCustodianPrivKey = secp256k1.PrivKey{Key: crypto.Keccak256([]byte("laconic-custodian"))}
// LaconicCustodianPrivKey *ecdsa.PrivateKey
)
func init() {
ecdsaPrivKey, err := crypto.ToECDSA(LaconicCustodianPrivKey.Key)
if err != nil {
panic(err)
}
LaconicCustodianAddress = crypto.PubkeyToAddress(ecdsaPrivKey.PublicKey)
}

103
server/nitro/flags.go Normal file
View File

@ -0,0 +1,103 @@
package nitro
import (
"fmt"
"github.com/spf13/pflag"
)
// start flags are prefixed with the server name
func prefix(f string) string {
return fmt.Sprintf("%s.%s", serverName, f)
}
var (
flag_pk = prefix("pk") // "pk"
flag_eth_pk = prefix("eth-pk") // "chainpk"
flag_eth_url = prefix("eth-url") // "chainurl"
flag_eth_start_block = prefix("eth-start-block") // "chainstartblock"
flag_eth_auth_token = prefix("eth-auth-token") // "chainauthtoken"
flag_eth_na_address = prefix("eth-na-address") // "naaddress"
flag_eth_vpa_address = prefix("eth-vpa-address") // "vpaaddress"
flag_eth_ca_address = prefix("eth-ca-address") // "caaddress"
// flag_bridge_address = prefix("bridge-address") // "bridgeaddress"
flag_public_ip = prefix("public-ip") // "publicip"
flag_msg_port = prefix("msg-port") // "msgport"
flag_ws_msg_port = prefix("ws-msg-port") // "wsmsgport"
flag_rpc_port = prefix("rpc-port") // "rpcport"
flag_boot_peers = prefix("boot-peers") // "bootpeers"
flag_ext_multiaddr = prefix("ext-multiaddr") // "extmultiaddr"
flag_tls_cert_filepath = prefix("tls-cert-filepath") // "tlscertfilepath"
flag_tls_key_filepath = prefix("tls-key-filepath") // "tlskeyfilepath"
// flag_gui_port = prefix("gui-port") // "guiport"
)
func addServerFlags(flags *pflag.FlagSet) {
flags.String(flag_pk, "",
"name of private key used by the Nitro node",
// EnvVars: []string{"SC_PK"},
)
flags.String(flag_eth_url, "ws://127.0.0.1:8545",
"URL of the Ethereum node to connect to",
// EnvVars: []string{"CHAIN_URL"},
)
flags.String(flag_eth_auth_token, "",
"bearer token used for auth in requests to the Ethereum chain's RPC endpoint",
// EnvVars: []string{"CHAIN_AUTH_TOKEN"},
)
flags.Uint64(flag_eth_start_block, 0,
"Ethereum block number to start listening for Nitro Adjudicator events",
// EnvVars: []string{"CHAIN_START_BLOCK"},
)
flags.String(flag_eth_na_address, "",
"Ethereum address of the Nitro Adjudicator contract",
)
flags.String(flag_eth_vpa_address, "",
"Ethereum address of the Virtual Payment App contract",
)
flags.String(flag_eth_ca_address, "",
"Ethereum address of the Consensus App contract",
)
// flags.String(flag_bridge_address, "",
// "Specifies the address of the bridge contract.",
// )
flags.String(flag_public_ip, "127.0.0.1",
"public IP address used for the Nitro message service",
// EnvVars: []string{"NITRO_PUBLIC_IP"},
)
flags.String(flag_ext_multiaddr, "",
"additional external multiaddr to advertise",
)
flags.Int(flag_msg_port, 3005,
"TCP port for the Nitro message service",
)
flags.Int(flag_ws_msg_port, 6005,
"WebSocket port for the Nitro message service",
)
flags.Int(flag_rpc_port, 4005,
"TCP port for the Nitro RPC server",
)
// flags.Int(flag_gui_port, 5005,
// "Specifies the tcp port for the Nitro Connect GUI.",
// )
flags.String(flag_boot_peers, "",
"comma-delimited list of peer multiaddrs the messaging service will connect to when initialized",
)
flags.String(flag_tls_cert_filepath, "", // "./tls/statechannels.org.pem",
"filepath to the TLS certificate; if not specified, TLS will not be used with the RPC transport",
)
flags.String(flag_tls_key_filepath, "", // "./tls/statechannels.org_key.pem",
"filepath to the TLS private key; if not specified, TLS will not be used with the RPC transport",
)
}
func addClientFlags(flags *pflag.FlagSet) {
// TODO: this is only used by "client" (user) nodes
flags.String(flag_eth_pk, "",
"name of private key to use when interacting with the Ethereum chain",
// EnvVars: []string{"CHAIN_PK"},
)
addServerFlags(flags)
}

169
server/nitro/p2p.go Normal file
View File

@ -0,0 +1,169 @@
package nitro
import (
"fmt"
"github.com/cometbft/cometbft/p2p"
"github.com/cosmos/gogoproto/proto"
nitrop2p "github.com/statechannels/go-nitro/node/engine/messageservice"
"github.com/statechannels/go-nitro/protocols"
)
const (
P2PMessageChannel = byte(0x80)
// SigRequestChannel = byte(0x81)
)
type msgService struct {
id string
incoming chan nitrop2p.Message
outgoing chan nitrop2p.Message
// dummy channel, we don't need these requests
// TODO: make this optional in nitro
signreqs chan nitrop2p.SignatureRequest
reactor *reactor // one reactor per msg service
}
// reactor handles incoming Nitro P2P messages via CometBFT
type reactor struct {
p2p.BaseReactor
ms *msgService
}
type streamDesc struct {
id byte
msgType proto.Message
}
func (sd streamDesc) StreamID() byte { return sd.id }
// TODO: convert Message to protobuf
func (sd streamDesc) MessageType() proto.Message { return sd.msgType }
// MessageService
func newMessageService(id string) *msgService {
return &msgService{
incoming: make(chan nitrop2p.Message),
outgoing: make(chan nitrop2p.Message),
signreqs: make(chan nitrop2p.SignatureRequest),
}
}
func (ms *msgService) P2PMessages() <-chan nitrop2p.Message {
return ms.incoming
}
func (ms *msgService) SignRequests() <-chan nitrop2p.SignatureRequest {
return ms.signreqs
}
func (ms *msgService) Send(m nitrop2p.Message) error {
ms.outgoing <- m
return nil
}
func (ms *msgService) Close() error {
close(ms.incoming)
close(ms.outgoing)
close(ms.signreqs)
return nil
}
func (ms *msgService) Id() string {
return ms.id
}
// Reactor
func getReactor(ms *msgService) *reactor {
if ms.reactor != nil {
return ms.reactor
}
ret := &reactor{ms: ms}
ret.BaseReactor = *p2p.NewBaseReactor("nitro-reactor", ret)
ms.reactor = ret
return ret
}
// StreamDescriptors returns the stream descriptor for Nitro messages.
func (r *reactor) StreamDescriptors() []p2p.ChannelDescriptor {
return []p2p.ChannelDescriptor{
{
ID: P2PMessageChannel,
MessageType: &P2PMessage{},
},
}
}
// AddPeer begins sending messages to a peer.
func (r *reactor) AddPeer(peer p2p.Peer) {
if !r.IsRunning() {
return
}
go r.streamTo(peer)
}
func (r *reactor) streamTo(peer p2p.Peer) {
logger := r.Logger.With("peer", peer)
// if !peer.HasChannel(P2PMessageChannel) {
// logger.Info("Peer does not implement NitroMsgChannel")
// return
// }
for {
if !peer.IsRunning() || !r.IsRunning() {
return
}
inner_loop:
for {
select {
case msg := <-r.ms.outgoing:
encoded, err := msg.Serialize()
if err != nil {
logger.Error("Failed to serialize message", "msg", msg, "err", err)
continue inner_loop
}
sent := peer.Send(p2p.Envelope{
Message: &P2PMessage{Content: encoded},
ChannelID: P2PMessageChannel,
})
if !sent {
logger.Error("Failed to send message", "msg", msg) //, "err", err)
return
}
default:
break inner_loop
}
}
// time.Sleep()
}
}
// Receive handles an envelope received from any connected peer on any registered channel.
func (r *reactor) Receive(e p2p.Envelope) {
if !r.IsRunning() {
r.Logger.Debug("Receive", "src", e.Src, "chId", e.ChannelID)
return
}
switch e.ChannelID {
case P2PMessageChannel:
switch msg := e.Message.(type) {
case *P2PMessage:
nitroMsg, err := protocols.DeserializeMessage(msg.Content)
if err != nil {
r.Logger.Error("Failed to deserialize message", "err", err)
r.Switch.StopPeerForError(e.Src, err)
return
}
r.ms.incoming <- nitroMsg
default:
r.Logger.Error(fmt.Sprintf("Unknown message type: %T", e.Message))
}
default:
r.Logger.Error(fmt.Sprintf("Unknown channel ID: %X", e.ChannelID))
}
}

315
server/nitro/p2p.pb.go Normal file
View File

@ -0,0 +1,315 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: cerc/nitro/v1/p2p.proto
package nitro
import (
fmt "fmt"
proto "github.com/cosmos/gogoproto/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type P2PMessage struct {
Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
}
func (m *P2PMessage) Reset() { *m = P2PMessage{} }
func (m *P2PMessage) String() string { return proto.CompactTextString(m) }
func (*P2PMessage) ProtoMessage() {}
func (*P2PMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_97350824263b9206, []int{0}
}
func (m *P2PMessage) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *P2PMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_P2PMessage.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *P2PMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_P2PMessage.Merge(m, src)
}
func (m *P2PMessage) XXX_Size() int {
return m.Size()
}
func (m *P2PMessage) XXX_DiscardUnknown() {
xxx_messageInfo_P2PMessage.DiscardUnknown(m)
}
var xxx_messageInfo_P2PMessage proto.InternalMessageInfo
func (m *P2PMessage) GetContent() string {
if m != nil {
return m.Content
}
return ""
}
func init() {
proto.RegisterType((*P2PMessage)(nil), "cerc.nitro.v1.P2PMessage")
}
func init() { proto.RegisterFile("cerc/nitro/v1/p2p.proto", fileDescriptor_97350824263b9206) }
var fileDescriptor_97350824263b9206 = []byte{
// 162 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4f, 0x4e, 0x2d, 0x4a,
0xd6, 0xcf, 0xcb, 0x2c, 0x29, 0xca, 0xd7, 0x2f, 0x33, 0xd4, 0x2f, 0x30, 0x2a, 0xd0, 0x2b, 0x28,
0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x05, 0x49, 0xe8, 0x81, 0x25, 0xf4, 0xca, 0x0c, 0x95, 0xd4, 0xb8,
0xb8, 0x02, 0x8c, 0x02, 0x7c, 0x53, 0x8b, 0x8b, 0x13, 0xd3, 0x53, 0x85, 0x24, 0xb8, 0xd8, 0x93,
0xf3, 0xf3, 0x4a, 0x52, 0xf3, 0x4a, 0x24, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0x60, 0x5c, 0x27,
0xa7, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63,
0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, 0x48, 0xcf, 0x2c, 0xd1,
0x2b, 0x4b, 0x49, 0xd2, 0x2b, 0xc9, 0xd7, 0x07, 0x99, 0xad, 0x9b, 0x99, 0xaf, 0x9f, 0x93, 0x98,
0x9c, 0x9f, 0x97, 0x99, 0x9c, 0xa2, 0x5f, 0x9c, 0x5a, 0x54, 0x96, 0x5a, 0x04, 0x71, 0x47, 0x12,
0x1b, 0xd8, 0x05, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x79, 0x5d, 0x6d, 0x7c, 0x9c, 0x00,
0x00, 0x00,
}
func (m *P2PMessage) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *P2PMessage) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *P2PMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Content) > 0 {
i -= len(m.Content)
copy(dAtA[i:], m.Content)
i = encodeVarintP2P(dAtA, i, uint64(len(m.Content)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintP2P(dAtA []byte, offset int, v uint64) int {
offset -= sovP2P(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *P2PMessage) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Content)
if l > 0 {
n += 1 + l + sovP2P(uint64(l))
}
return n
}
func sovP2P(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozP2P(x uint64) (n int) {
return sovP2P(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *P2PMessage) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowP2P
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: P2PMessage: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: P2PMessage: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowP2P
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthP2P
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthP2P
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Content = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipP2P(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthP2P
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipP2P(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowP2P
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowP2P
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowP2P
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthP2P
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupP2P
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthP2P
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthP2P = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowP2P = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupP2P = fmt.Errorf("proto: unexpected end of group")
)

207
server/nitro/server.go Normal file
View File

@ -0,0 +1,207 @@
package nitro
import (
"context"
"encoding/hex"
"fmt"
"log/slog"
"path/filepath"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/statechannels/go-nitro/node"
"github.com/statechannels/go-nitro/node/engine"
"github.com/statechannels/go-nitro/node/engine/chainservice"
"github.com/statechannels/go-nitro/node/engine/store"
nitrotypes "github.com/statechannels/go-nitro/types"
"cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
serverv2 "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"git.vdb.to/cerc-io/laconicd/utils"
)
const (
serverName = "nitro"
)
var (
_ serverv2.ServerComponent[transaction.Tx] = (*Server)(nil)
_ serverv2.HasCLICommands = (*Server)(nil)
_ serverv2.HasStartFlags = (*Server)(nil)
_ serverv2.HasConfig = (*Server)(nil)
// _ serverv2.ConfigWriter = (*Server)(nil)
)
// TODO:
// - move multisig stuff into here. DKG is init'd from eth key.
// - server.SetParticipants() updates DKG members
// - onboarding module calls this
// - onboarding sets deals?
type Server struct {
*node.Node
ms *msgService
logger log.Logger
config *Config
storeDir string // path to Nitro store directory
ethAddress common.Address
stateChannelAddress nitrotypes.ParticipantAddress
}
func NewServer(logger log.Logger, globalConfig server.ConfigMap, kr keyring.Keyring) (*Server, error) {
home, _ := globalConfig[serverv2.FlagHome].(string)
cfg, err := UnmarshalConfig(globalConfig)
if err != nil {
return nil, err
}
s := &Server{
config: cfg,
storeDir: filepath.Join(home, "nitro"),
}
s.logger = logger.With(log.ModuleKey, s.Name())
return s, s.init(kr)
}
func (s *Server) init(kr keyring.Keyring) error {
c := s.config
var ethkey cryptotypes.PrivKey
if c.EthPk != "" {
var err error
ethkey, err = utils.ExtractPrivateKey(kr, c.EthPk)
if err != nil {
return err
}
} else {
// TODO for server, inject signer callback into nitro node instead of naked privkey
// multisig will be negotiated over ABCI, then funds are sent via custodian contract
s.logger.Warn("(DEV) using fake Laconic custodian Ethereum private key")
ethkey = &LaconicCustodianPrivKey
}
sckey, err := utils.ExtractPrivateKey(kr, c.Pk)
if err != nil {
return err
}
storeOpts := store.StoreOpts{
PkBytes: sckey.Bytes(),
UseDurableStore: true,
DurableStoreFolder: s.storeDir,
}
chainOpts := chainservice.ChainOpts{
ChainUrl: c.EthUrl,
ChainStartBlockNum: c.EthStartBlock,
ChainAuthToken: c.EthAuthToken,
// TODO see above
ChainPk: hex.EncodeToString(ethkey.Bytes()),
NaAddress: common.HexToAddress(c.EthNaAddress),
VpaAddress: common.HexToAddress(c.EthVpaAddress),
CaAddress: common.HexToAddress(c.EthCaAddress),
}
// inject SDK logger into slog, which Nitro uses
loggerImpl, ok := s.logger.Impl().(*slog.Logger)
if !ok {
s.logger.Warn("logger does not have slog implementation")
}
slog.SetDefault(loggerImpl)
s.logger.Info("Initializing chain service")
store, err := store.NewStore(storeOpts)
if err != nil {
return err
}
// Compare chainOpts.ChainStartBlock to lastBlockNum seen in store. The larger of the two
// gets passed as an argument when creating NewEthChainService
storeBlockNum, err := store.GetLastBlockNumSeen()
if err != nil {
return err
}
if storeBlockNum > chainOpts.ChainStartBlockNum {
chainOpts.ChainStartBlockNum = storeBlockNum
}
chain, err := chainservice.NewL1ChainService(chainOpts)
if err != nil {
return err
}
// note: utils.EthAddressFromPubKey expects uncompressed keys
ethPubkey, err := crypto.DecompressPubkey(ethkey.PubKey().Bytes())
if err != nil {
return err
}
s.ms = newMessageService(store.GetAddress().String())
s.Node = node.New(s.ms, chain, store, &engine.PermissivePolicy{})
s.ethAddress = crypto.PubkeyToAddress(*ethPubkey)
s.stateChannelAddress = *store.GetAddress()
return nil
}
func (s *Server) Name() string {
return serverName
}
func (s *Server) Start(ctx context.Context) error {
s.logger.Info("starting Nitro server",
"rpc-port", fmt.Sprintf("http://%s:%d", s.config.PublicIp, s.config.RpcPort))
s.Node.Start()
return nil
}
func (s *Server) Stop(context.Context) error {
return s.Close()
}
func (s *Server) Config() any {
if s.config == nil {
return DefaultConfig()
}
return s.config
}
func (s *Server) StartCmdFlags() *pflag.FlagSet {
flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError)
addServerFlags(flags)
return flags
}
// func (s *Server) WriteConfig(path string) error
func (s *Server) CLICommands() serverv2.CLIConfig {
return serverv2.CLIConfig{
Commands: []*cobra.Command{
s.OpenChannelCmd(),
},
// Queries: []*cobra.Command{},
}
}
func (s *Server) CometReactor() *reactor {
return getReactor(s.ms)
}
func UnmarshalConfig(cfg map[string]any) (*Config, error) {
config := DefaultConfig()
if err := serverv2.UnmarshalSubConfig(cfg, serverName, config); err != nil {
return nil, fmt.Errorf("failed to unmarshal %T: %w", config, err)
}
return config, nil
}
// func ProvideServer(logger log.Logger, globalConfig runtime.GlobalConfig, kr keyring.Keyring) (*Server, error) {
// home, _ := globalConfig[serverv2.FlagHome].(string)
// config, err := UnmarshalConfig(globalConfig)
// if err != nil {
// return nil, err
// }
// return NewServer(logger, config, kr, filepath.Join(home, "nitro"))
// }

19
server/nitro/service.go Normal file
View File

@ -0,0 +1,19 @@
package nitro
import (
"github.com/cometbft/cometbft/types"
"github.com/statechannels/go-nitro/channel/state/outcome"
"github.com/statechannels/go-nitro/protocols/directfund"
"github.com/statechannels/go-nitro/protocols/virtualfund"
)
// Service represents a service which triggers Nitro state channel actions
type Service interface {
// CreatePaymentChannel creates a new virtual payment channel with the specified intermediaries,
// counterparty, ChallengeDuration, and outcome
CreatePaymentChannel(intermediaries []types.Address, counterparty types.Address, ChallengeDuration uint32, outcome outcome.Exit) (virtualfund.ObjectiveResponse, error)
// CreateLedgerChannel creates a new ledger channel with the specified counterparty,
// ChallengeDuration, and outcome
CreateLedgerChannel(counterparty types.Address, ChallengeDuration uint32, outcome outcome.Exit) (directfund.ObjectiveResponse, error)
}

View File

@ -1,17 +0,0 @@
package auction
import (
"testing"
"github.com/stretchr/testify/suite"
"git.vdb.to/cerc-io/laconicd/tests/e2e"
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
func TestAuctionE2ETestSuite(t *testing.T) {
cfg := network.DefaultConfig(e2e.NewTestNetworkFixture)
cfg.NumValidators = 1
suite.Run(t, NewE2ETestSuite(cfg))
}

View File

@ -1,263 +0,0 @@
package auction
import (
"fmt"
"github.com/cosmos/cosmos-sdk/testutil"
auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction"
)
const (
randomAuctionId = "randomAuctionId"
randomBidderAddress = "randomBidderAddress"
randomOwnerAddress = "randomOwnerAddress"
)
func (ets *E2ETestSuite) TestQueryParamsGrpc() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/params", val.APIAddress)
ets.Run("valid request to get auction params", func() {
resp, err := testutil.GetRequest(reqURL)
ets.Require().NoError(err)
var params auctiontypes.QueryParamsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &params)
sr.NoError(err)
sr.Equal(*params.GetParams(), auctiontypes.DefaultParams())
})
}
func (ets *E2ETestSuite) TestGetAllAuctionsGrpc() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/auctions", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
}{
{
"invalid request to get all auctions",
reqURL + randomAuctionId,
"",
true,
},
{
"valid request to get all auctions",
reqURL,
"",
false,
},
}
for _, tc := range testCases {
ets.Run(tc.msg, func() {
resp, err := testutil.GetRequest(tc.url)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var auctions auctiontypes.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auctions)
sr.NoError(err)
sr.NotZero(len(auctions.Auctions.Auctions))
}
})
}
}
func (ets *E2ETestSuite) TestGetAuctionGrpc() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/auctions/", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
preRun func() string
}{
{
"invalid request to get an auction",
reqURL + randomAuctionId,
"",
true,
func() string { return "" },
},
{
"valid request to get an auction",
reqURL,
"",
false,
func() string { return ets.defaultAuctionId },
},
}
for _, tc := range testCases {
ets.Run(tc.msg, func() {
auctionId := tc.preRun()
resp, err := testutil.GetRequest(tc.url + auctionId)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var auction auctiontypes.QueryGetAuctionResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auction)
sr.NoError(err)
sr.Equal(auctionId, auction.Auction.Id)
}
})
}
}
func (ets *E2ETestSuite) TestGetBidsGrpc() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/bids/", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
preRun func() string
}{
{
"invalid request to get all bids",
reqURL,
"",
true,
func() string { return "" },
},
{
"valid request to get all bids",
reqURL,
"",
false,
func() string { return ets.createAuctionAndBid(false, true) },
},
}
for _, tc := range testCases {
ets.Run(tc.msg, func() {
auctionId := tc.preRun()
tc.url += auctionId
resp, err := testutil.GetRequest(tc.url)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var bids auctiontypes.QueryGetBidsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bids)
sr.NoError(err)
sr.Equal(auctionId, bids.Bids[0].AuctionId)
}
})
}
}
func (ets *E2ETestSuite) TestGetBidGrpc() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/bids/", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
preRun func() string
}{
{
"invalid request to get bid",
reqURL,
"",
true,
func() string { return randomAuctionId },
},
{
"valid request to get bid",
reqURL,
"",
false,
func() string { return ets.createAuctionAndBid(false, true) },
},
}
for _, tc := range testCases {
ets.Run(tc.msg, func() {
auctionId := tc.preRun()
tc.url += auctionId + "/" + bidderAddress
resp, err := testutil.GetRequest(tc.url)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var bid auctiontypes.QueryGetBidResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bid)
sr.NoError(err)
}
})
}
}
func (ets *E2ETestSuite) TestGetAuctionsByOwnerGrpc() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/by-owner/", val.APIAddress)
testCases := []struct {
msg string
url string
errorMsg string
isErrorExpected bool
}{
{
"invalid request to get auctions by owner",
reqURL,
"",
true,
},
{
"valid request to get auctions by owner",
fmt.Sprintf("%s/%s", reqURL, ownerAddress),
"",
false,
},
}
for _, tc := range testCases {
ets.Run(tc.msg, func() {
resp, err := testutil.GetRequest(tc.url)
if tc.isErrorExpected {
sr.Contains(string(resp), tc.errorMsg)
} else {
sr.NoError(err)
var auctions auctiontypes.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auctions)
sr.NoError(err)
}
})
}
}
func (ets *E2ETestSuite) TestQueryBalanceGrpc() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/balance", val.APIAddress)
msg := "valid request to get the auction module balance"
ets.createAuctionAndBid(false, true)
ets.Run(msg, func() {
resp, err := testutil.GetRequest(reqURL)
sr.NoError(err)
var response auctiontypes.QueryGetAuctionModuleBalanceResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetBalance()))
})
}

View File

@ -1,45 +0,0 @@
package auction
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
types "git.vdb.to/cerc-io/laconicd/x/auction"
"git.vdb.to/cerc-io/laconicd/x/auction/client/cli"
)
var queryJSONFlag = []string{fmt.Sprintf("--%s=json", flags.FlagOutput)}
func (ets *E2ETestSuite) TestGetCmdList() {
val := ets.network.Validators[0]
sr := ets.Require()
testCases := []struct {
msg string
createAuction bool
}{
{
"list auctions when no auctions exist",
false,
},
{
"list auctions after creating an auction",
true,
},
}
for _, test := range testCases {
ets.Run(fmt.Sprintf("Case %s", test.msg), func() {
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), queryJSONFlag)
sr.NoError(err)
var auctions types.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &auctions)
sr.NoError(err)
if test.createAuction {
sr.NotZero(len(auctions.Auctions.Auctions))
}
})
}
}

View File

@ -1,151 +0,0 @@
package auction
import (
"fmt"
"os"
"path/filepath"
"cosmossdk.io/math"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
laconictestcli "git.vdb.to/cerc-io/laconicd/testutil/cli"
"git.vdb.to/cerc-io/laconicd/testutil/network"
types "git.vdb.to/cerc-io/laconicd/x/auction"
"git.vdb.to/cerc-io/laconicd/x/auction/client/cli"
)
var (
ownerAccount = "owner"
bidderAccount = "bidder"
ownerAddress string
bidderAddress string
)
type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
defaultAuctionId string
}
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
return &E2ETestSuite{cfg: cfg}
}
func (ets *E2ETestSuite) SetupSuite() { //nolint: all
sr := ets.Require()
ets.T().Log("setting up e2e test suite")
var err error
ets.network, err = network.New(ets.T(), ets.T().TempDir(), ets.cfg)
sr.NoError(err)
_, err = ets.network.WaitForHeight(1)
sr.NoError(err)
// setting up random owner and bidder accounts
ets.createAccountWithBalance(ownerAccount, &ownerAddress)
ets.createAccountWithBalance(bidderAccount, &bidderAddress)
ets.defaultAuctionId = ets.createAuctionAndBid(true, false)
}
func (ets *E2ETestSuite) TearDownSuite() {
ets.T().Log("tearing down integration test suite")
ets.network.Cleanup()
ets.cleanupBidFiles()
}
func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) {
val := ets.network.Validators[0]
sr := ets.Require()
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr, _ := info.GetAddress()
out, err := clitestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(200000))),
addresscodec.NewBech32Codec("laconic"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()),
)
sr.NoError(err)
var response sdk.TxResponse
sr.NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, response.TxHash, 0))
*accountAddress = newAddr.String()
}
func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) string {
val := ets.network.Validators[0]
sr := ets.Require()
auctionId := ""
if createAuction {
auctionArgs := []string{
types.AuctionKindVickrey,
sampleCommitTime, sampleRevealTime,
fmt.Sprintf("10%s", ets.cfg.BondDenom),
fmt.Sprintf("10%s", ets.cfg.BondDenom),
fmt.Sprintf("100%s", ets.cfg.BondDenom),
fmt.Sprintf("0%s", ets.cfg.BondDenom),
"0",
}
resp, err := ets.executeTx(cli.GetCmdCreateAuction(), auctionArgs, ownerAccount)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, resp.TxHash, 0))
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), queryJSONFlag)
sr.NoError(err)
var queryResponse types.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
auctionId = queryResponse.Auctions.Auctions[0].Id
} else {
auctionId = ets.defaultAuctionId
}
if createBid {
bidArgs := []string{auctionId, fmt.Sprintf("200%s", ets.cfg.BondDenom)}
resp, err := ets.executeTx(cli.GetCmdCommitBid(), bidArgs, bidderAccount)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, resp.TxHash, 0))
}
return auctionId
}
func (ets *E2ETestSuite) cleanupBidFiles() {
matches, err := filepath.Glob(fmt.Sprintf("%s-*.json", bidderAccount))
if err != nil {
ets.T().Errorf("Error matching bidder files: %v\n", err)
}
for _, match := range matches {
err := os.Remove(match)
if err != nil {
ets.T().Errorf("Error removing bidder file: %v\n", err)
}
}
}

View File

@ -1,105 +0,0 @@
package auction
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"
laconictestcli "git.vdb.to/cerc-io/laconicd/testutil/cli"
auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction"
"git.vdb.to/cerc-io/laconicd/x/auction/client/cli"
)
const (
sampleCommitTime = "90s"
sampleRevealTime = "5s"
placeholderAuctionId = "placeholder_auction_id"
)
func (ets *E2ETestSuite) TestTxCommitBid() {
val := ets.network.Validators[0]
sr := ets.Require()
testCases := []struct {
msg string
args []string
createAuction bool
}{
{
"commit bid with missing args",
[]string{fmt.Sprintf("200%s", ets.cfg.BondDenom)},
false,
},
{
"commit bid with valid args",
[]string{
placeholderAuctionId,
fmt.Sprintf("200%s", ets.cfg.BondDenom),
},
true,
},
}
for _, test := range testCases {
ets.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuction {
auctionArgs := []string{
auctiontypes.AuctionKindVickrey,
sampleCommitTime, sampleRevealTime,
fmt.Sprintf("10%s", ets.cfg.BondDenom),
fmt.Sprintf("10%s", ets.cfg.BondDenom),
fmt.Sprintf("100%s", ets.cfg.BondDenom),
fmt.Sprintf("0%s", ets.cfg.BondDenom),
"0",
}
resp, err := ets.executeTx(cli.GetCmdCreateAuction(), auctionArgs, ownerAccount)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, resp.TxHash, 0))
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(),
[]string{fmt.Sprintf("--%s=json", flags.FlagOutput)})
sr.NoError(err)
var queryResponse auctiontypes.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
sr.NotNil(queryResponse.GetAuctions())
test.args[0] = queryResponse.GetAuctions().Auctions[0].Id
}
resp, err := ets.executeTx(cli.GetCmdCommitBid(), test.args, bidderAccount)
if test.createAuction {
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, resp.TxHash, 0))
} else {
sr.Error(err)
}
})
}
}
func (ets *E2ETestSuite) executeTx(cmd *cobra.Command, args []string, caller string) (sdk.TxResponse, error) {
val := ets.network.Validators[0]
additionalArgs := []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, caller),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
args = append(args, additionalArgs...)
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
if err != nil {
return sdk.TxResponse{}, err
}
var resp sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp)
if err != nil {
return sdk.TxResponse{}, err
}
return resp, nil
}

View File

@ -1,17 +0,0 @@
package bond
import (
"testing"
"github.com/stretchr/testify/suite"
"git.vdb.to/cerc-io/laconicd/tests/e2e"
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
func TestBondE2ETestSuite(t *testing.T) {
cfg := network.DefaultConfig(e2e.NewTestNetworkFixture)
cfg.NumValidators = 1
suite.Run(t, NewE2ETestSuite(cfg))
}

View File

@ -1,183 +0,0 @@
package bond
import (
"fmt"
"github.com/cosmos/cosmos-sdk/testutil"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
)
func (ets *E2ETestSuite) TestGRPCGetParams() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/bond/v1/params", val.APIAddress)
resp, err := testutil.GetRequest(reqURL)
ets.Require().NoError(err)
var params bondtypes.QueryParamsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &params)
sr.NoError(err)
sr.Equal(params.GetParams().MaxBondAmount, bondtypes.DefaultParams().MaxBondAmount)
}
func (ets *E2ETestSuite) TestGRPCGetBonds() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/bond/v1/bonds", val.APIAddress)
testCases := []struct {
name string
url string
expErr bool
errorMsg string
preRun func() string
}{
{
"invalid request with headers",
reqURL + "asdasdas",
true,
"",
func() string { return "" },
},
{
"valid request",
reqURL,
false,
"",
func() string { return ets.createBond() },
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
tc.preRun()
resp, _ := testutil.GetRequest(tc.url)
if tc.expErr {
sr.Contains(string(resp), tc.errorMsg)
} else {
var response bondtypes.QueryBondsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetBonds()))
}
})
}
}
func (ets *E2ETestSuite) TestGRPCGetBondsByOwner() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/bond/v1/by-owner/%s"
testCases := []struct {
name string
url string
expErr bool
preRun func() string
}{
{
"empty list",
fmt.Sprintf(reqURL, "asdasd"),
true,
func() string { return "" },
},
{
"valid request",
fmt.Sprintf(reqURL, ets.accountAddress),
false,
func() string { return ets.createBond() },
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
tc.preRun()
resp, err := testutil.GetRequest(tc.url)
ets.Require().NoError(err)
var bonds bondtypes.QueryGetBondsByOwnerResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bonds)
sr.NoError(err)
if tc.expErr {
sr.Empty(bonds.GetBonds())
} else {
bondsList := bonds.GetBonds()
sr.NotZero(len(bondsList))
sr.Equal(ets.accountAddress, bondsList[0].GetOwner())
}
})
}
}
func (ets *E2ETestSuite) TestGRPCGetBondById() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/bond/v1/bonds/%s"
testCases := []struct {
name string
url string
expErr bool
preRun func() string
}{
{
"invalid request",
fmt.Sprintf(reqURL, "asdadad"),
true,
func() string { return "" },
},
{
"valid request",
reqURL,
false,
func() string { return ets.createBond() },
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
var bondId string
if !tc.expErr {
bondId = tc.preRun()
tc.url = fmt.Sprintf(reqURL, bondId)
}
resp, err := testutil.GetRequest(tc.url)
ets.Require().NoError(err)
var bonds bondtypes.QueryGetBondByIdResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bonds)
if tc.expErr {
sr.Empty(bonds.GetBond().GetId())
} else {
sr.NoError(err)
sr.NotZero(bonds.GetBond().GetId())
sr.Equal(bonds.GetBond().GetId(), bondId)
}
})
}
}
func (ets *E2ETestSuite) TestGRPCGetBondModuleBalance() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/bond/v1/balance", val.APIAddress)
// creating the bond
ets.createBond()
ets.Run("valid request", func() {
resp, err := testutil.GetRequest(reqURL)
sr.NoError(err)
var response bondtypes.QueryGetBondModuleBalanceResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.False(response.GetBalance().IsZero())
})
}

View File

@ -1,49 +0,0 @@
package bond
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
"git.vdb.to/cerc-io/laconicd/x/bond/client/cli"
)
func (ets *E2ETestSuite) TestGetQueryBondList() {
val := ets.network.Validators[0]
sr := ets.Require()
testCases := []struct {
name string
args []string
createBond bool
preRun func()
}{
{
"create and get bond lists",
[]string{fmt.Sprintf("--%s=json", flags.FlagOutput)},
true,
func() {
ets.createBond()
},
},
}
for _, tc := range testCases {
ets.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
if tc.createBond {
tc.preRun()
}
cmd := cli.GetQueryBondList()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
sr.NoError(err)
var queryResponse bondtypes.QueryBondsResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
sr.NotZero(len(queryResponse.GetBonds()))
})
}
}

View File

@ -1,125 +0,0 @@
package bond
import (
"fmt"
"cosmossdk.io/math"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
laconictestcli "git.vdb.to/cerc-io/laconicd/testutil/cli"
"git.vdb.to/cerc-io/laconicd/testutil/network"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
"git.vdb.to/cerc-io/laconicd/x/bond/client/cli"
)
type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
accountName string
accountAddress string
}
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
return &E2ETestSuite{cfg: cfg}
}
func (ets *E2ETestSuite) SetupSuite() { //nolint: all
sr := ets.Require()
ets.T().Log("setting up e2e test suite")
var err error
ets.network, err = network.New(ets.T(), ets.T().TempDir(), ets.cfg)
sr.NoError(err)
_, err = ets.network.WaitForHeight(1)
sr.NoError(err)
// setting up random account
ets.accountName = "accountName"
ets.createAccountWithBalance(ets.accountName, &ets.accountAddress)
}
func (ets *E2ETestSuite) TearDownSuite() {
ets.T().Log("tearing down e2e test suite")
ets.network.Cleanup()
}
func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) {
val := ets.network.Validators[0]
sr := ets.Require()
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr, _ := info.GetAddress()
out, err := clitestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(200000))),
addresscodec.NewBech32Codec("laconic"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()),
)
sr.NoError(err)
var response sdk.TxResponse
sr.NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, response.TxHash, 0))
*accountAddress = newAddr.String()
}
func (ets *E2ETestSuite) createBond() string {
val := ets.network.Validators[0]
sr := ets.Require()
createBondCmd := cli.NewCreateBondCmd()
args := []string{
fmt.Sprintf("10%s", ets.cfg.BondDenom),
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, createBondCmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.Zero(d.Code)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
// getting the bonds list and returning the bond-id
clientCtx := val.ClientCtx
cmd := cli.GetQueryBondList()
args = []string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
}
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var queryResponse bondtypes.QueryBondsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
// extract bond id from bonds list
bonds := queryResponse.GetBonds()
sr.NotEmpty(bonds)
return queryResponse.GetBonds()[0].GetId()
}

View File

@ -1,63 +0,0 @@
package bond
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"git.vdb.to/cerc-io/laconicd/x/bond/client/cli"
)
func (ets *E2ETestSuite) TestTxCreateBond() {
val := ets.network.Validators[0]
sr := ets.Require()
testCases := []struct {
name string
args []string
err bool
}{
{
"without deposit",
[]string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
},
true,
},
{
"create bond",
[]string{
fmt.Sprintf("10%s", ets.cfg.BondDenom),
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
},
false,
},
}
for _, tc := range testCases {
ets.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
cmd := cli.NewCreateBondCmd()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.err {
sr.Error(err)
} else {
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.Nil(err)
sr.NoError(err)
sr.Zero(d.Code)
}
})
}
}

View File

@ -1,69 +0,0 @@
package e2e
import (
"fmt"
"os"
"cosmossdk.io/log"
pruningtypes "cosmossdk.io/store/pruning/types"
dbm "github.com/cosmos/cosmos-db"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client/flags"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
"github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/staking"
laconicApp "git.vdb.to/cerc-io/laconicd/app"
auctionmodule "git.vdb.to/cerc-io/laconicd/x/auction/module"
bondmodule "git.vdb.to/cerc-io/laconicd/x/bond/module"
registrymodule "git.vdb.to/cerc-io/laconicd/x/registry/module"
_ "git.vdb.to/cerc-io/laconicd/app/params" // import for side-effects (see init)
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
// NewTestNetworkFixture returns a new LaconicApp AppConstructor for network simulation tests
func NewTestNetworkFixture() network.TestFixture {
dir, err := os.MkdirTemp("", "laconic")
if err != nil {
panic(fmt.Sprintf("failed creating temporary directory: %v", err))
}
defer os.RemoveAll(dir)
app, err := laconicApp.NewLaconicApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(dir))
if err != nil {
panic(fmt.Sprintf("failed to create laconic app: %v", err))
}
appCtr := func(val network.ValidatorI) servertypes.Application {
app, err := laconicApp.NewLaconicApp(
val.GetCtx().Logger, dbm.NewMemDB(), nil, true,
simtestutil.NewAppOptionsWithFlagHome(val.GetCtx().Config.RootDir),
bam.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
bam.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
bam.SetChainID(val.GetCtx().Viper.GetString(flags.FlagChainID)),
)
if err != nil {
panic(fmt.Sprintf("failed creating temporary directory: %v", err))
}
return app
}
return network.TestFixture{
AppConstructor: appCtr,
GenesisState: app.DefaultGenesis(),
EncodingConfig: testutil.MakeTestEncodingConfig(
auth.AppModuleBasic{},
bank.AppModuleBasic{},
staking.AppModuleBasic{},
auctionmodule.AppModule{},
bondmodule.AppModule{},
registrymodule.AppModule{},
),
}
}

View File

@ -1,17 +0,0 @@
package registry
import (
"testing"
"github.com/stretchr/testify/suite"
"git.vdb.to/cerc-io/laconicd/tests/e2e"
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
func TestRegistryE2ETestSuite(t *testing.T) {
cfg := network.DefaultConfig(e2e.NewTestNetworkFixture)
cfg.NumValidators = 1
suite.Run(t, NewE2ETestSuite(cfg))
}

View File

@ -1,429 +0,0 @@
package registry
import (
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
registrytypes "git.vdb.to/cerc-io/laconicd/x/registry"
"git.vdb.to/cerc-io/laconicd/x/registry/client/cli"
)
const badPath = "/asdasd"
func (ets *E2ETestSuite) TestGRPCQueryParams() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/params"
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
}{
{
"invalid request",
reqURL + badPath,
true,
"",
},
{
"valid request",
reqURL,
false,
"",
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
resp, err := testutil.GetRequest(tc.url)
ets.NoError(err)
require := ets.Require()
if tc.expectErr {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryParamsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
params := registrytypes.DefaultParams()
ets.updateParams(&params)
sr.Equal(params.String(), response.GetParams().String())
}
})
}
}
func (ets *E2ETestSuite) TestGRPCQueryWhoIs() {
val := ets.network.Validators[0]
sr := ets.Require()
reqUrl := val.APIAddress + "/cerc/registry/v1/whois/%s"
authorityName := "QueryWhoIS"
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func(authorityName string)
}{
{
"invalid url",
reqUrl + badPath,
true,
"",
func(authorityName string) {
},
},
{
"valid request",
reqUrl,
false,
"",
func(authorityName string) { ets.reserveName(authorityName) },
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
tc.preRun(authorityName)
tc.url = fmt.Sprintf(tc.url, authorityName)
resp, err := testutil.GetRequest(tc.url)
ets.NoError(err)
require := ets.Require()
if tc.expectErr {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryWhoisResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.Equal(registrytypes.AuthorityActive, response.GetNameAuthority().Status)
}
})
}
}
func (ets *E2ETestSuite) TestGRPCQueryLookup() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/lookup"
authorityName := "QueryLookUp"
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func(authorityName string)
}{
{
"invalid url",
reqURL + badPath,
true,
"",
func(authorityName string) {
},
},
{
"valid request",
fmt.Sprintf(reqURL+"?lrn=lrn://%s/", authorityName),
false,
"",
func(authorityName string) {
// create name record
ets.createNameRecord(authorityName)
},
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
tc.preRun(authorityName)
resp, err := testutil.GetRequest(tc.url)
ets.NoError(err)
if tc.expectErr {
sr.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryLookupLrnResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.Name.Latest.Id))
}
})
}
}
func (ets *E2ETestSuite) TestGRPCQueryListRecords() {
val := ets.network.Validators[0]
sr := ets.Require()
reqUrl := val.APIAddress + "/cerc/registry/v1/records"
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func(bondId string)
}{
{
"invalid url",
reqUrl + badPath,
true,
"",
func(bondId string) {
},
},
{
"valid request",
reqUrl,
false,
"",
func(bondId string) { ets.createRecord(bondId) },
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
tc.preRun(ets.bondId)
resp, err := testutil.GetRequest(tc.url)
ets.NoError(err)
require := ets.Require()
if tc.expectErr {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryRecordsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetRecords()))
sr.Equal(ets.bondId, response.GetRecords()[0].GetBondId())
}
})
}
}
func (ets *E2ETestSuite) TestGRPCQueryGetRecordById() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/records/%s"
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func(bondId string) string
}{
{
"invalid url",
reqURL + badPath,
true,
"",
func(bondId string) string {
return ""
},
},
{
"valid request",
reqURL,
false,
"",
func(bondId string) string {
// creating the record
ets.createRecord(bondId)
// list the records
clientCtx := val.ClientCtx
cmd := cli.GetCmdList()
args := []string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
}
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var records []registrytypes.ReadableRecord
err = json.Unmarshal(out.Bytes(), &records)
sr.NoError(err)
return records[0].Id
},
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
recordId := tc.preRun(ets.bondId)
tc.url = fmt.Sprintf(reqURL, recordId)
resp, err := testutil.GetRequest(tc.url)
ets.NoError(err)
require := ets.Require()
if tc.expectErr {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryGetRecordResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
record := response.GetRecord()
sr.NotZero(len(record.GetId()))
sr.Equal(record.GetId(), recordId)
}
})
}
}
func (ets *E2ETestSuite) TestGRPCQueryGetRecordByBondId() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/records-by-bond-id/%s"
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func(bondId string)
}{
{
"invalid url",
reqURL + badPath,
true,
"",
func(bondId string) {
},
},
{
"valid request",
reqURL,
false,
"",
func(bondId string) {
// creating the record
ets.createRecord(bondId)
},
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
tc.preRun(ets.bondId)
tc.url = fmt.Sprintf(reqURL, ets.bondId)
resp, err := testutil.GetRequest(tc.url)
ets.NoError(err)
require := ets.Require()
if tc.expectErr {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryGetRecordsByBondIdResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
records := response.GetRecords()
sr.NotZero(len(records))
sr.Equal(records[0].GetBondId(), ets.bondId)
}
})
}
}
func (ets *E2ETestSuite) TestGRPCQueryGetRegistryModuleBalance() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/balance"
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func(bondId string)
}{
{
"invalid url",
reqURL + badPath,
true,
"",
func(bondId string) {
},
},
{
"Success",
reqURL,
false,
"",
func(bondId string) {
// creating the record
ets.createRecord(bondId)
},
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
tc.preRun(ets.bondId)
resp, err := testutil.GetRequest(tc.url)
ets.NoError(err)
require := ets.Require()
if tc.expectErr {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryGetRegistryModuleBalanceResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetBalances()))
}
})
}
}
func (ets *E2ETestSuite) TestGRPCQueryNamesList() {
val := ets.network.Validators[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/names"
testCases := []struct {
name string
url string
expectErr bool
errorMsg string
preRun func(authorityName string)
}{
{
"invalid url",
reqURL + badPath,
true,
"",
func(authorityName string) {
},
},
{
"valid request",
reqURL,
false,
"",
func(authorityName string) {
// create name record
ets.createNameRecord(authorityName)
},
},
}
for _, tc := range testCases {
ets.Run(tc.name, func() {
tc.preRun("ListNameRecords")
resp, err := testutil.GetRequest(tc.url)
ets.NoError(err)
require := ets.Require()
if tc.expectErr {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryNameRecordsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetNames()))
}
})
}
}

View File

@ -1,265 +0,0 @@
package registry
import (
"fmt"
"path/filepath"
"time"
"cosmossdk.io/math"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
laconictestcli "git.vdb.to/cerc-io/laconicd/testutil/cli"
"git.vdb.to/cerc-io/laconicd/testutil/network"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
bondcli "git.vdb.to/cerc-io/laconicd/x/bond/client/cli"
registrytypes "git.vdb.to/cerc-io/laconicd/x/registry"
"git.vdb.to/cerc-io/laconicd/x/registry/client/cli"
)
type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
accountName string
accountAddress string
bondId string
}
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
return &E2ETestSuite{cfg: cfg}
}
func (ets *E2ETestSuite) SetupSuite() {
sr := ets.Require()
ets.T().Log("setting up e2e test suite")
var err error
genesisState := ets.cfg.GenesisState
var registryGenesis registrytypes.GenesisState
ets.Require().NoError(ets.cfg.Codec.UnmarshalJSON(genesisState[registrytypes.ModuleName], &registryGenesis))
ets.updateParams(&registryGenesis.Params)
registryGenesisBz, err := ets.cfg.Codec.MarshalJSON(&registryGenesis)
ets.Require().NoError(err)
genesisState[registrytypes.ModuleName] = registryGenesisBz
ets.cfg.GenesisState = genesisState
ets.network, err = network.New(ets.T(), ets.T().TempDir(), ets.cfg)
sr.NoError(err)
_, err = ets.network.WaitForHeight(2)
sr.NoError(err)
// setting up random account
ets.accountName = "accountName"
ets.createAccountWithBalance(ets.accountName, &ets.accountAddress)
ets.bondId = ets.createBond()
}
func (ets *E2ETestSuite) TearDownSuite() {
ets.T().Log("tearing down e2e test suite")
ets.network.Cleanup()
}
func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) {
val := ets.network.Validators[0]
sr := ets.Require()
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr, _ := info.GetAddress()
out, err := clitestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100000000))),
addresscodec.NewBech32Codec("laconic"),
fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()),
)
sr.NoError(err)
var response sdk.TxResponse
sr.NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, response.TxHash, 0))
*accountAddress = newAddr.String()
}
func (ets *E2ETestSuite) createBond() string {
val := ets.network.Validators[0]
sr := ets.Require()
createBondCmd := bondcli.NewCreateBondCmd()
args := []string{
fmt.Sprintf("1000000%s", ets.cfg.BondDenom),
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, createBondCmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
// getting the bonds list and returning the bond-id
clientCtx := val.ClientCtx
cmd := bondcli.GetQueryBondList()
args = []string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
}
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var queryResponse bondtypes.QueryBondsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
// extract bond id from bonds list
bond := queryResponse.GetBonds()[0]
return bond.GetId()
}
func (ets *E2ETestSuite) reserveName(authorityName string) {
val := ets.network.Validators[0]
sr := ets.Require()
clientCtx := val.ClientCtx
cmd := cli.GetCmdReserveAuthority()
args := []string{
authorityName,
ets.accountAddress,
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
}
func (ets *E2ETestSuite) createNameRecord(authorityName string) {
val := ets.network.Validators[0]
sr := ets.Require()
// reserving the name
clientCtx := val.ClientCtx
cmd := cli.GetCmdReserveAuthority()
args := []string{
authorityName,
ets.accountAddress,
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
// Get the bond-id
bondId := ets.bondId
// adding bond-id to name authority
args = []string{
authorityName, bondId,
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
cmd = cli.GetCmdSetAuthorityBond()
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
args = []string{
fmt.Sprintf("lrn://%s/", authorityName),
"test_hello_cid",
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
cmd = cli.GetCmdSetName()
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
}
func (ets *E2ETestSuite) createRecord(bondId string) {
val := ets.network.Validators[0]
sr := ets.Require()
payloadPath := "../../data/examples/service_provider_example.yml"
payloadFilePath, err := filepath.Abs(payloadPath)
sr.NoError(err)
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
args = append([]string{payloadFilePath, bondId}, args...)
clientCtx := val.ClientCtx
cmd := cli.GetCmdSetRecord()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
}
func (ets *E2ETestSuite) updateParams(params *registrytypes.Params) {
params.RecordRent = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000))
params.RecordRentDuration = 10 * time.Second
params.AuthorityRent = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000))
params.AuthorityGracePeriod = 10 * time.Second
params.AuthorityAuctionCommitFee = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100))
params.AuthorityAuctionRevealFee = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100))
params.AuthorityAuctionMinimumBid = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(500))
}

View File

@ -1,70 +0,0 @@
package registry
import (
"fmt"
"path/filepath"
"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"git.vdb.to/cerc-io/laconicd/x/registry/client/cli"
)
func (ets *E2ETestSuite) TestGetCmdSetRecord() {
val := ets.network.Validators[0]
sr := ets.Require()
bondId := ets.bondId
payloadPath := "../../data/examples/service_provider_example.yml"
payloadFilePath, err := filepath.Abs(payloadPath)
sr.NoError(err)
testCases := []struct {
name string
args []string
err bool
}{
{
"invalid request without bond id/without payload",
[]string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
},
true,
},
{
"success",
[]string{
payloadFilePath, bondId,
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
},
false,
},
}
for _, tc := range testCases {
ets.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
cmd := cli.GetCmdSetRecord()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.err {
sr.Error(err)
} else {
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.Zero(d.Code)
}
})
}
}

View File

@ -1,30 +0,0 @@
package keeper_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
types "git.vdb.to/cerc-io/laconicd/x/auction"
)
type KeeperTestSuite struct {
suite.Suite
integrationTest.TestFixture
queryClient types.QueryClient
}
func (kts *KeeperTestSuite) SetupTest() {
err := kts.TestFixture.Setup()
assert.Nil(kts.T(), err)
qr := kts.App.QueryHelper()
kts.queryClient = types.NewQueryClient(qr)
}
func TestAuctionKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

View File

@ -1,359 +0,0 @@
package keeper_test
import (
"context"
"fmt"
"time"
"cosmossdk.io/math"
sdkmath "cosmossdk.io/math"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
types "git.vdb.to/cerc-io/laconicd/x/auction"
)
const testCommitHash = "71D8CF34026E32A3A34C2C2D4ADF25ABC8D7943A4619761BE27F196603D91B9D"
func (kts *KeeperTestSuite) TestGrpcQueryParams() {
testCases := []struct {
msg string
req *types.QueryParamsRequest
}{
{
"fetch params",
&types.QueryParamsRequest{},
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
resp, err := kts.queryClient.Params(context.Background(), test.req)
kts.Require().Nil(err)
kts.Require().Equal(*(resp.Params), types.DefaultParams())
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetAuction() {
testCases := []struct {
msg string
req *types.QueryGetAuctionRequest
createAuction bool
}{
{
"fetch auction with empty auction ID",
&types.QueryGetAuctionRequest{},
false,
},
{
"fetch auction with valid auction ID",
&types.QueryGetAuctionRequest{},
true,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
var expectedAuction types.Auction
if test.createAuction {
auction, _, err := kts.createAuctionAndCommitBid(false)
kts.Require().Nil(err)
test.req.Id = auction.Id
expectedAuction = *auction
}
resp, err := kts.queryClient.GetAuction(context.Background(), test.req)
if test.createAuction {
kts.Require().Nil(err)
kts.Require().NotNil(resp.GetAuction())
kts.Require().EqualExportedValues(expectedAuction, *(resp.GetAuction()))
} else {
kts.Require().NotNil(err)
kts.Require().Error(err)
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetAllAuctions() {
testCases := []struct {
msg string
req *types.QueryAuctionsRequest
createAuctions bool
auctionCount int
}{
{
"fetch auctions when no auctions exist",
&types.QueryAuctionsRequest{},
false,
0,
},
{
"fetch auctions with one auction created",
&types.QueryAuctionsRequest{},
true,
1,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctions {
_, _, err := kts.createAuctionAndCommitBid(false)
kts.Require().Nil(err)
}
resp, _ := kts.queryClient.Auctions(context.Background(), test.req)
kts.Require().Equal(test.auctionCount, len(resp.GetAuctions().Auctions))
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetBids() {
testCases := []struct {
msg string
req *types.QueryGetBidsRequest
createAuction bool
commitBid bool
bidCount int
}{
{
"fetch all bids when no auction exists",
&types.QueryGetBidsRequest{},
false,
false,
0,
},
{
"fetch all bids for valid auction but no added bids",
&types.QueryGetBidsRequest{},
true,
false,
0,
},
{
"fetch all bids for valid auction and valid bid",
&types.QueryGetBidsRequest{},
true,
true,
1,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuction {
auction, _, err := kts.createAuctionAndCommitBid(test.commitBid)
kts.Require().NoError(err)
test.req.AuctionId = auction.Id
}
resp, err := kts.queryClient.GetBids(context.Background(), test.req)
if test.createAuction {
kts.Require().Nil(err)
kts.Require().Equal(test.bidCount, len(resp.GetBids()))
} else {
kts.Require().NotNil(err)
kts.Require().Error(err)
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetBid() {
testCases := []struct {
msg string
req *types.QueryGetBidRequest
createAuctionAndBid bool
}{
{
"fetch bid when bid does not exist",
&types.QueryGetBidRequest{},
false,
},
{
"fetch bid when valid bid exists",
&types.QueryGetBidRequest{},
true,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctionAndBid {
auction, bid, err := kts.createAuctionAndCommitBid(test.createAuctionAndBid)
kts.Require().NoError(err)
test.req.AuctionId = auction.Id
test.req.Bidder = bid.BidderAddress
}
resp, err := kts.queryClient.GetBid(context.Background(), test.req)
if test.createAuctionAndBid {
kts.Require().NoError(err)
kts.Require().NotNil(resp.Bid)
kts.Require().Equal(test.req.Bidder, resp.Bid.BidderAddress)
} else {
kts.Require().NotNil(err)
kts.Require().Error(err)
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetAuctionsByBidder() {
testCases := []struct {
msg string
req *types.QueryAuctionsByBidderRequest
createAuctionAndCommitBid bool
auctionCount int
}{
{
"get auctions by bidder with invalid bidder address",
&types.QueryAuctionsByBidderRequest{},
false,
0,
},
{
"get auctions by bidder with valid auction and bid",
&types.QueryAuctionsByBidderRequest{},
true,
1,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctionAndCommitBid {
_, bid, err := kts.createAuctionAndCommitBid(test.createAuctionAndCommitBid)
kts.Require().NoError(err)
test.req.BidderAddress = bid.BidderAddress
}
resp, err := kts.queryClient.AuctionsByBidder(context.Background(), test.req)
if test.createAuctionAndCommitBid {
kts.Require().NoError(err)
kts.Require().NotNil(resp.Auctions)
kts.Require().Equal(test.auctionCount, len(resp.Auctions.Auctions))
} else {
kts.Require().NotNil(err)
kts.Require().Error(err)
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetAuctionsByOwner() {
testCases := []struct {
msg string
req *types.QueryAuctionsByOwnerRequest
createAuction bool
auctionCount int
}{
{
"get auctions by owner with invalid owner address",
&types.QueryAuctionsByOwnerRequest{},
false,
0,
},
{
"get auctions by owner with valid auction",
&types.QueryAuctionsByOwnerRequest{},
true,
1,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuction {
auction, _, err := kts.createAuctionAndCommitBid(false)
kts.Require().NoError(err)
test.req.OwnerAddress = auction.OwnerAddress
}
resp, err := kts.queryClient.AuctionsByOwner(context.Background(), test.req)
if test.createAuction {
kts.Require().NoError(err)
kts.Require().NotNil(resp.Auctions)
kts.Require().Equal(test.auctionCount, len(resp.Auctions.Auctions))
} else {
kts.Require().NotNil(err)
kts.Require().Error(err)
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcQueryBalance() {
testCases := []struct {
msg string
req *types.QueryGetAuctionModuleBalanceRequest
createAuction bool
auctionCount int
}{
{
"get balance with no auctions created",
&types.QueryGetAuctionModuleBalanceRequest{},
false,
0,
},
{
"get balance with single auction created",
&types.QueryGetAuctionModuleBalanceRequest{},
true,
1,
},
}
for _, test := range testCases {
if test.createAuction {
_, _, err := kts.createAuctionAndCommitBid(true)
kts.Require().NoError(err)
}
resp, err := kts.queryClient.GetAuctionModuleBalance(context.Background(), test.req)
kts.Require().NoError(err)
kts.Require().Equal(test.auctionCount, len(resp.GetBalance()))
}
}
func (kts *KeeperTestSuite) createAuctionAndCommitBid(commitBid bool) (*types.Auction, *types.Bid, error) {
ctx, k := kts.SdkCtx, kts.AuctionKeeper
accCount := 1
if commitBid {
accCount++
}
// Create funded account(s)
accounts := simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, accCount, math.NewInt(1000000))
auction, err := k.CreateAuction(
ctx,
types.MsgCreateAuction{
Kind: types.AuctionKindVickrey,
Signer: accounts[0].String(),
CommitsDuration: 5 * time.Minute,
RevealsDuration: 5 * time.Minute,
CommitFee: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(1000)),
RevealFee: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(1000)),
MinimumBid: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(1000000)),
},
)
if err != nil {
return nil, nil, err
}
if commitBid {
bid, err := k.CommitBid(ctx, types.NewMsgCommitBid(auction.Id, testCommitHash, accounts[1]))
if err != nil {
return nil, nil, err
}
return auction, bid, nil
}
return auction, nil, nil
}

View File

@ -1,30 +0,0 @@
package keeper_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
types "git.vdb.to/cerc-io/laconicd/x/bond"
)
type KeeperTestSuite struct {
suite.Suite
integrationTest.TestFixture
queryClient types.QueryClient
}
func (kts *KeeperTestSuite) SetupTest() {
err := kts.TestFixture.Setup()
assert.Nil(kts.T(), err)
qr := kts.App.QueryHelper()
kts.queryClient = types.NewQueryClient(qr)
}
func TestBondKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

View File

@ -1,210 +0,0 @@
package keeper_test
import (
"context"
"fmt"
"cosmossdk.io/math"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
types "git.vdb.to/cerc-io/laconicd/x/bond"
)
func (kts *KeeperTestSuite) TestGrpcQueryParams() {
testCases := []struct {
msg string
req *types.QueryParamsRequest
}{
{
"fetch params",
&types.QueryParamsRequest{},
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
resp, err := kts.queryClient.Params(context.Background(), test.req)
kts.Require().Nil(err)
kts.Require().Equal(*(resp.Params), types.DefaultParams())
})
}
}
func (kts *KeeperTestSuite) TestGrpcQueryBondsList() {
testCases := []struct {
msg string
req *types.QueryBondsRequest
resp *types.QueryBondsResponse
noOfBonds int
createBonds bool
}{
{
"empty request",
&types.QueryBondsRequest{},
&types.QueryBondsResponse{},
0,
false,
},
{
"Get Bonds",
&types.QueryBondsRequest{},
&types.QueryBondsResponse{},
1,
true,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createBonds {
_, err := kts.createBond()
kts.Require().NoError(err)
}
resp, _ := kts.queryClient.Bonds(context.Background(), test.req)
kts.Require().Equal(test.noOfBonds, len(resp.GetBonds()))
})
}
}
func (kts *KeeperTestSuite) TestGrpcQueryBondByBondId() {
testCases := []struct {
msg string
req *types.QueryGetBondByIdRequest
createBonds bool
errResponse bool
bondId string
}{
{
"empty request",
&types.QueryGetBondByIdRequest{},
false,
true,
"",
},
{
"Get Bond By ID",
&types.QueryGetBondByIdRequest{},
true,
false,
"",
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createBonds {
bond, err := kts.createBond()
kts.Require().NoError(err)
test.req.Id = bond.Id
}
resp, err := kts.queryClient.GetBondById(context.Background(), test.req)
if !test.errResponse {
kts.Require().Nil(err)
kts.Require().NotNil(resp.GetBond())
kts.Require().Equal(test.req.Id, resp.GetBond().GetId())
} else {
kts.Require().NotNil(err)
kts.Require().Error(err)
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetBondsByOwner() {
testCases := []struct {
msg string
req *types.QueryGetBondsByOwnerRequest
noOfBonds int
createBonds bool
errResponse bool
bondId string
}{
{
"empty request",
&types.QueryGetBondsByOwnerRequest{},
0,
false,
true,
"",
},
{
"Get Bond By Owner",
&types.QueryGetBondsByOwnerRequest{},
1,
true,
false,
"",
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createBonds {
bond, err := kts.createBond()
kts.Require().NoError(err)
test.req.Owner = bond.Owner
}
resp, err := kts.queryClient.GetBondsByOwner(context.Background(), test.req)
if !test.errResponse {
kts.Require().Nil(err)
kts.Require().NotNil(resp.GetBonds())
kts.Require().Equal(test.noOfBonds, len(resp.GetBonds()))
} else {
kts.Require().NotNil(err)
kts.Require().Error(err)
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetModuleBalance() {
testCases := []struct {
msg string
req *types.QueryGetBondModuleBalanceRequest
noOfBonds int
createBonds bool
errResponse bool
}{
{
"empty request",
&types.QueryGetBondModuleBalanceRequest{},
0,
true,
false,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createBonds {
_, err := kts.createBond()
kts.Require().NoError(err)
}
resp, err := kts.queryClient.GetBondModuleBalance(context.Background(), test.req)
if !test.errResponse {
kts.Require().Nil(err)
kts.Require().NotNil(resp.GetBalance())
kts.Require().Equal(resp.GetBalance(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))))
} else {
kts.Require().NotNil(err)
kts.Require().Error(err)
}
})
}
}
func (kts *KeeperTestSuite) createBond() (*types.Bond, error) {
ctx, k := kts.SdkCtx, kts.BondKeeper
accCount := 1
// Create funded account(s)
accounts := simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, accCount, math.NewInt(1000))
bond, err := k.CreateBond(ctx, accounts[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))))
if err != nil {
return nil, err
}
return bond, nil
}

View File

@ -1,165 +0,0 @@
package integration_test
import (
"context"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
cmtprototypes "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/testutil/integration"
sdk "github.com/cosmos/cosmos-sdk/types"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/auth"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/bank"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
auctionTypes "git.vdb.to/cerc-io/laconicd/x/auction"
auctionkeeper "git.vdb.to/cerc-io/laconicd/x/auction/keeper"
auctionmodule "git.vdb.to/cerc-io/laconicd/x/auction/module"
bondTypes "git.vdb.to/cerc-io/laconicd/x/bond"
bondkeeper "git.vdb.to/cerc-io/laconicd/x/bond/keeper"
bondmodule "git.vdb.to/cerc-io/laconicd/x/bond/module"
registryTypes "git.vdb.to/cerc-io/laconicd/x/registry"
registrykeeper "git.vdb.to/cerc-io/laconicd/x/registry/keeper"
registrymodule "git.vdb.to/cerc-io/laconicd/x/registry/module"
)
type TestFixture struct {
App *integration.App
SdkCtx sdk.Context
cdc codec.Codec
keys map[string]*storetypes.KVStoreKey
AccountKeeper authkeeper.AccountKeeper
BankKeeper bankkeeper.Keeper
AuctionKeeper *auctionkeeper.Keeper
BondKeeper *bondkeeper.Keeper
RegistryKeeper registrykeeper.Keeper
}
func (tf *TestFixture) Setup() error {
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, auctionTypes.StoreKey, bondTypes.StoreKey, registryTypes.StoreKey,
)
cdc := moduletestutil.MakeTestEncodingConfig(
auth.AppModuleBasic{},
auctionmodule.AppModule{},
bondmodule.AppModule{},
registrymodule.AppModule{},
).Codec
logger := log.NewNopLogger() // Use log.NewTestLogger(kts.T()) for help with debugging
cms := integration.CreateMultiStore(keys, logger)
newCtx := sdk.NewContext(cms, cmtprototypes.Header{}, true, logger)
authority := authtypes.NewModuleAddress("gov")
maccPerms := map[string][]string{
minttypes.ModuleName: {authtypes.Minter},
auctionTypes.ModuleName: {},
auctionTypes.AuctionBurnModuleAccountName: {},
bondTypes.ModuleName: {},
registryTypes.ModuleName: {},
registryTypes.RecordRentModuleAccountName: {},
registryTypes.AuthorityRentModuleAccountName: {},
}
accountKeeper := authkeeper.NewAccountKeeper(
cdc,
runtime.NewKVStoreService(keys[authtypes.StoreKey]),
authtypes.ProtoBaseAccount,
maccPerms,
addresscodec.NewBech32Codec(sdk.Bech32MainPrefix),
sdk.Bech32MainPrefix,
authority.String(),
)
blockedAddresses := map[string]bool{
accountKeeper.GetAuthority(): false,
}
bankKeeper := bankkeeper.NewBaseKeeper(
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
accountKeeper,
blockedAddresses,
authority.String(),
log.NewNopLogger(),
)
auctionKeeper := auctionkeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[auctionTypes.StoreKey]), accountKeeper, bankKeeper, authority.String())
bondKeeper := bondkeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[bondTypes.StoreKey]), accountKeeper, bankKeeper, authority.String())
registryKeeper := registrykeeper.NewKeeper(
cdc,
runtime.NewKVStoreService(keys[registryTypes.StoreKey]),
accountKeeper,
bankKeeper,
bondKeeper,
auctionKeeper,
authority.String(),
)
authModule := auth.NewAppModule(cdc, accountKeeper, authsims.RandomGenesisAccounts, nil)
bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper, nil)
auctionModule := auctionmodule.NewAppModule(cdc, auctionKeeper)
bondModule := bondmodule.NewAppModule(cdc, bondKeeper)
registryModule := registrymodule.NewAppModule(cdc, registryKeeper)
integrationApp := integration.NewIntegrationApp(newCtx, logger, keys, cdc, map[string]appmodule.AppModule{
authtypes.ModuleName: authModule,
banktypes.ModuleName: bankModule,
auctionTypes.ModuleName: auctionModule,
bondTypes.ModuleName: bondModule,
registryTypes.ModuleName: registryModule,
})
sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context())
// Register MsgServer and QueryServer
auctionTypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), auctionkeeper.NewMsgServerImpl(auctionKeeper))
auctionTypes.RegisterQueryServer(integrationApp.QueryHelper(), auctionkeeper.NewQueryServerImpl(auctionKeeper))
bondTypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), bondkeeper.NewMsgServerImpl(bondKeeper))
bondTypes.RegisterQueryServer(integrationApp.QueryHelper(), bondkeeper.NewQueryServerImpl(bondKeeper))
registryTypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), registrykeeper.NewMsgServerImpl(registryKeeper))
registryTypes.RegisterQueryServer(integrationApp.QueryHelper(), registrykeeper.NewQueryServerImpl(registryKeeper))
// set default params
if err := auctionKeeper.Params.Set(sdkCtx, auctionTypes.DefaultParams()); err != nil {
return err
}
if err := bondKeeper.Params.Set(sdkCtx, bondTypes.DefaultParams()); err != nil {
return err
}
if err := registryKeeper.Params.Set(sdkCtx, registryTypes.DefaultParams()); err != nil {
return err
}
tf.App = integrationApp
tf.SdkCtx, tf.cdc, tf.keys = sdkCtx, cdc, keys
tf.AccountKeeper, tf.BankKeeper = accountKeeper, bankKeeper
tf.AuctionKeeper, tf.BondKeeper, tf.RegistryKeeper = auctionKeeper, bondKeeper, registryKeeper
return nil
}
type BondDenomProvider struct{}
func (bdp BondDenomProvider) BondDenom(ctx context.Context) (string, error) {
return sdk.DefaultBondDenom, nil
}

View File

@ -1,60 +0,0 @@
package keeper_test
import (
"testing"
"cosmossdk.io/math"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
bondTypes "git.vdb.to/cerc-io/laconicd/x/bond"
types "git.vdb.to/cerc-io/laconicd/x/registry"
)
type KeeperTestSuite struct {
suite.Suite
integrationTest.TestFixture
queryClient types.QueryClient
accounts []sdk.AccAddress
bond bondTypes.Bond
}
func (kts *KeeperTestSuite) SetupTest() {
err := kts.TestFixture.Setup()
assert.Nil(kts.T(), err)
// set default params
err = kts.RegistryKeeper.Params.Set(kts.SdkCtx, types.DefaultParams())
assert.Nil(kts.T(), err)
qr := kts.App.QueryHelper()
kts.queryClient = types.NewQueryClient(qr)
// Create a bond
bond, err := kts.createBond()
assert.Nil(kts.T(), err)
kts.bond = *bond
}
func TestRegistryKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
func (kts *KeeperTestSuite) createBond() (*bondTypes.Bond, error) {
ctx := kts.SdkCtx
// Create a funded account
kts.accounts = simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, 1, math.NewInt(1000000000000))
bond, err := kts.BondKeeper.CreateBond(ctx, kts.accounts[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000000))))
if err != nil {
return nil, err
}
return bond, nil
}

View File

@ -1,421 +0,0 @@
package keeper_test
import (
"context"
"fmt"
"path/filepath"
"reflect"
types "git.vdb.to/cerc-io/laconicd/x/registry"
"git.vdb.to/cerc-io/laconicd/x/registry/client/cli"
"git.vdb.to/cerc-io/laconicd/x/registry/helpers"
registryKeeper "git.vdb.to/cerc-io/laconicd/x/registry/keeper"
)
func (kts *KeeperTestSuite) TestGrpcQueryParams() {
testCases := []struct {
msg string
req *types.QueryParamsRequest
}{
{
"Get Params",
&types.QueryParamsRequest{},
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
resp, _ := kts.queryClient.Params(context.Background(), test.req)
defaultParams := types.DefaultParams()
kts.Require().Equal(defaultParams.String(), resp.GetParams().String())
})
}
}
func (kts *KeeperTestSuite) TestGrpcGetRecordLists() {
ctx, queryClient := kts.SdkCtx, kts.queryClient
sr := kts.Require()
var recordId string
examples := []string{
"../../../data/examples/service_provider_example.yml",
"../../../data/examples/website_registration_example.yml",
"../../../data/examples/general_record_example.yml",
}
testCases := []struct {
msg string
req *types.QueryRecordsRequest
createRecords bool
expErr bool
noOfRecords int
}{
{
"Empty Records",
&types.QueryRecordsRequest{},
false,
false,
0,
},
{
"List Records",
&types.QueryRecordsRequest{},
true,
false,
3,
},
{
"Filter with type",
&types.QueryRecordsRequest{
Attributes: []*types.QueryRecordsRequest_KeyValueInput{
{
Key: "type",
Value: &types.QueryRecordsRequest_ValueInput{
Value: &types.QueryRecordsRequest_ValueInput_String_{String_: "WebsiteRegistrationRecord"},
},
},
},
All: true,
},
true,
false,
1,
},
// Skip the following test as querying with recursive values not supported (PR https://git.vdb.to/cerc-io/laconicd/pulls/112)
// See function RecordsFromAttributes (QueryValueToJSON call) in the registry keeper implementation (x/registry/keeper/keeper.go)
// {
// "Filter with tag (extant) (https://git.vdb.to/cerc-io/laconicd/issues/129)",
// &types.QueryRecordsRequest{
// Attributes: []*types.QueryRecordsRequest_KeyValueInput{
// {
// Key: "tags",
// // Value: &types.QueryRecordsRequest_ValueInput{
// // Value: &types.QueryRecordsRequest_ValueInput_String_{"tagA"},
// // },
// Value: &types.QueryRecordsRequest_ValueInput{
// Value: &types.QueryRecordsRequest_ValueInput_Array{Array: &types.QueryRecordsRequest_ArrayInput{
// Values: []*types.QueryRecordsRequest_ValueInput{
// {
// Value: &types.QueryRecordsRequest_ValueInput_String_{"tagA"},
// },
// },
// }},
// },
// // Throws: "Recursive query values are not supported"
// },
// },
// All: true,
// },
// true,
// false,
// 1,
// },
{
"Filter with tag (non-existent) (https://git.vdb.to/cerc-io/laconicd/issues/129)",
&types.QueryRecordsRequest{
Attributes: []*types.QueryRecordsRequest_KeyValueInput{
{
Key: "tags",
Value: &types.QueryRecordsRequest_ValueInput{
Value: &types.QueryRecordsRequest_ValueInput_String_{String_: "NOEXIST"},
},
},
},
All: true,
},
true,
false,
0,
},
{
"Filter test for key collision (https://git.vdb.to/cerc-io/laconicd/issues/122)",
&types.QueryRecordsRequest{
Attributes: []*types.QueryRecordsRequest_KeyValueInput{
{
Key: "typ",
Value: &types.QueryRecordsRequest_ValueInput{
Value: &types.QueryRecordsRequest_ValueInput_String_{String_: "eWebsiteRegistrationRecord"},
},
},
},
All: true,
},
true,
false,
0,
},
{
"Filter with attributes ServiceProviderRegistration",
&types.QueryRecordsRequest{
Attributes: []*types.QueryRecordsRequest_KeyValueInput{
{
Key: "x500state_name",
Value: &types.QueryRecordsRequest_ValueInput{
Value: &types.QueryRecordsRequest_ValueInput_String_{String_: "california"},
},
},
},
All: true,
},
true,
false,
1,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createRecords {
for _, example := range examples {
filePath, err := filepath.Abs(example)
sr.NoError(err)
payloadType, err := cli.GetPayloadFromFile(filePath)
sr.NoError(err)
payload := payloadType.ToPayload()
record, err := kts.RegistryKeeper.SetRecord(ctx, types.MsgSetRecord{
BondId: kts.bond.GetId(),
Signer: kts.accounts[0].String(),
Payload: payload,
})
sr.NoError(err)
sr.NotNil(record.Id)
}
}
resp, err := queryClient.Records(context.Background(), test.req)
if test.expErr {
kts.Error(err)
} else {
sr.NoError(err)
sr.Equal(test.noOfRecords, len(resp.GetRecords()))
if test.createRecords && test.noOfRecords > 0 {
recordId = resp.GetRecords()[0].GetId()
sr.NotZero(resp.GetRecords())
sr.Equal(resp.GetRecords()[0].GetBondId(), kts.bond.GetId())
for _, record := range resp.GetRecords() {
recAttr := helpers.MustUnmarshalJSON[types.AttributeMap](record.Attributes)
for _, attr := range test.req.GetAttributes() {
enc, err := registryKeeper.QueryValueToJSON(attr.Value)
sr.NoError(err)
av := helpers.MustUnmarshalJSON[any](enc)
if nil != av && nil != recAttr[attr.Key] &&
reflect.Slice == reflect.TypeOf(recAttr[attr.Key]).Kind() &&
reflect.Slice != reflect.TypeOf(av).Kind() {
found := false
allValues := recAttr[attr.Key].([]interface{})
for i := range allValues {
if av == allValues[i] {
fmt.Printf("Found %s in %s", allValues[i], recAttr[attr.Key])
found = true
}
}
sr.Equal(true, found, fmt.Sprintf("Unable to find %s in %s", av, recAttr[attr.Key]))
} else {
if attr.Key[:4] == "x500" {
sr.Equal(av, recAttr["x500"].(map[string]interface{})[attr.Key[4:]])
} else {
sr.Equal(av, recAttr[attr.Key])
}
}
}
}
}
}
})
}
// Get the records by record id
testCases1 := []struct {
msg string
req *types.QueryGetRecordRequest
createRecord bool
expErr bool
noOfRecords int
}{
{
"Invalid Request without record id",
&types.QueryGetRecordRequest{},
false,
true,
0,
},
{
"With Record ID",
&types.QueryGetRecordRequest{
Id: recordId,
},
true,
false,
1,
},
}
for _, test := range testCases1 {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
resp, err := queryClient.GetRecord(context.Background(), test.req)
if test.expErr {
kts.Error(err)
} else {
sr.NoError(err)
sr.NotNil(resp.GetRecord())
if test.createRecord {
sr.Equal(resp.GetRecord().BondId, kts.bond.GetId())
sr.Equal(resp.GetRecord().Id, recordId)
}
}
})
}
// Get the records by record id
testCasesByBondId := []struct {
msg string
req *types.QueryGetRecordsByBondIdRequest
createRecord bool
expErr bool
noOfRecords int
}{
{
"Invalid Request without bond id",
&types.QueryGetRecordsByBondIdRequest{},
false,
true,
0,
},
{
"With Bond ID",
&types.QueryGetRecordsByBondIdRequest{
Id: kts.bond.GetId(),
},
true,
false,
1,
},
}
for _, test := range testCasesByBondId {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
resp, err := queryClient.GetRecordsByBondId(context.Background(), test.req)
if test.expErr {
sr.Zero(resp.GetRecords())
} else {
sr.NoError(err)
sr.NotNil(resp.GetRecords())
if test.createRecord {
sr.NotZero(resp.GetRecords())
sr.Equal(resp.GetRecords()[0].GetBondId(), kts.bond.GetId())
}
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcQueryRegistryModuleBalance() {
queryClient, ctx := kts.queryClient, kts.SdkCtx
sr := kts.Require()
examples := []string{
"../../../data/examples/service_provider_example.yml",
"../../../data/examples/website_registration_example.yml",
}
testCases := []struct {
msg string
req *types.QueryGetRegistryModuleBalanceRequest
createRecords bool
expErr bool
noOfRecords int
}{
{
"Get Module Balance",
&types.QueryGetRegistryModuleBalanceRequest{},
true,
false,
1,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createRecords {
for _, example := range examples {
filePath, err := filepath.Abs(example)
sr.NoError(err)
payloadType, err := cli.GetPayloadFromFile(filePath)
sr.NoError(err)
payload := payloadType.ToPayload()
record, err := kts.RegistryKeeper.SetRecord(ctx, types.MsgSetRecord{
BondId: kts.bond.GetId(),
Signer: kts.accounts[0].String(),
Payload: payload,
})
sr.NoError(err)
sr.NotNil(record.Id)
}
}
resp, err := queryClient.GetRegistryModuleBalance(context.Background(), test.req)
if test.expErr {
kts.Error(err)
} else {
sr.NoError(err)
sr.Equal(test.noOfRecords, len(resp.GetBalances()))
if test.createRecords {
balance := resp.GetBalances()[0]
sr.Equal(balance.AccountName, types.RecordRentModuleAccountName)
}
}
})
}
}
func (kts *KeeperTestSuite) TestGrpcQueryWhoIs() {
queryClient, ctx := kts.queryClient, kts.SdkCtx
sr := kts.Require()
authorityName := "TestGrpcQueryWhoIs"
testCases := []struct {
msg string
req *types.QueryWhoisRequest
createName bool
expErr bool
noOfRecords int
}{
{
"Invalid Request without name",
&types.QueryWhoisRequest{},
false,
true,
1,
},
{
"Success",
&types.QueryWhoisRequest{},
true,
false,
1,
},
}
for _, test := range testCases {
kts.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createName {
err := kts.RegistryKeeper.ReserveAuthority(ctx, types.MsgReserveAuthority{
Name: authorityName,
Signer: kts.accounts[0].String(),
Owner: kts.accounts[0].String(),
})
sr.NoError(err)
test.req = &types.QueryWhoisRequest{Name: authorityName}
}
resp, err := queryClient.Whois(context.Background(), test.req)
if test.expErr {
kts.Error(err)
sr.Nil(resp)
} else {
sr.NoError(err)
if test.createName {
nameAuth := resp.NameAuthority
sr.NotNil(nameAuth)
sr.Equal(nameAuth.OwnerAddress, kts.accounts[0].String())
sr.Equal(types.AuthorityActive, nameAuth.Status)
}
}
})
}
}

28
tests/system/cli.go Normal file
View File

@ -0,0 +1,28 @@
package system
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"cosmossdk.io/systemtests"
)
func NewCLIWrapper(t *testing.T, sut *SystemUnderTest, verbose bool, fees string) *systemtests.CLIWrapper {
t.Helper()
return systemtests.NewCLIWrapperX(
t,
sut.execBinary,
sut.rpcAddr,
sut.chainID,
sut.AwaitNextBlock,
sut.nodesCount,
filepath.Join(WorkDir, sut.outputDir),
fees,
verbose,
assert.NoError,
false,
true,
)
}

151
tests/system/events.go Normal file
View File

@ -0,0 +1,151 @@
package system
import (
"context"
"testing"
"time"
"github.com/cometbft/cometbft/libs/sync"
client "github.com/cometbft/cometbft/rpc/client/http"
ctypes "github.com/cometbft/cometbft/rpc/core/types"
"github.com/stretchr/testify/require"
)
// EventListener watches for events on the chain
type EventListener struct {
t *testing.T
client *client.HTTP
}
var DefaultWaitTime = 30 * time.Second
type (
CleanupFn func()
EventConsumer func(e ctypes.ResultEvent) (more bool)
)
// NewEventListener event listener
func NewEventListener(t *testing.T, rpcAddr string) *EventListener {
t.Helper()
httpClient, err := client.New(rpcAddr)
require.NoError(t, err)
require.NoError(t, httpClient.Start())
return &EventListener{client: httpClient, t: t}
}
// Subscribe to receive events for a topic. Does not block.
// For query syntax See https://docs.cosmos.network/master/core/events.html#subscribing-to-events
func (l *EventListener) Subscribe(query string, cb EventConsumer) func() {
ctx, done := context.WithCancel(context.Background())
l.t.Cleanup(done)
eventsChan, err := l.client.WSEvents.Subscribe(ctx, "testing", query)
require.NoError(l.t, err)
cleanup := func() {
ctx, _ := context.WithTimeout(ctx, DefaultWaitTime) //nolint:govet // used in cleanup only
go l.client.WSEvents.Unsubscribe(ctx, "testing", query) //nolint:errcheck // used by tests only
done()
}
go func() {
for e := range eventsChan {
if !cb(e) {
return
}
}
}()
return cleanup
}
// AwaitQuery blocks and waits for a single result or timeout. This can be used with `broadcast-mode=async`.
// For query syntax See https://docs.cosmos.network/master/core/events.html#subscribing-to-events
func (l *EventListener) AwaitQuery(query string, optMaxWaitTime ...time.Duration) *ctypes.ResultEvent {
c, result := CaptureSingleEventConsumer()
maxWaitTime := DefaultWaitTime
if len(optMaxWaitTime) != 0 {
maxWaitTime = optMaxWaitTime[0]
}
cleanupFn := l.Subscribe(query, TimeoutConsumer(l.t, maxWaitTime, c))
l.t.Cleanup(cleanupFn)
return result
}
// TimeoutConsumer is an event consumer decorator with a max wait time. Panics when wait time exceeded without
// a result returned
func TimeoutConsumer(t *testing.T, maxWaitTime time.Duration, next EventConsumer) EventConsumer {
t.Helper()
ctx, done := context.WithCancel(context.Background())
t.Cleanup(done)
timeout := time.NewTimer(maxWaitTime)
timedOut := make(chan struct{}, 1)
go func() {
select {
case <-ctx.Done():
case <-timeout.C:
timedOut <- struct{}{}
close(timedOut)
}
}()
return func(e ctypes.ResultEvent) (more bool) {
select {
case <-timedOut:
t.Fatalf("Timeout waiting for new events %s", maxWaitTime)
return false
default:
timeout.Reset(maxWaitTime)
result := next(e)
if !result {
done()
}
return result
}
}
}
// CaptureSingleEventConsumer consumes one event. No timeout
func CaptureSingleEventConsumer() (EventConsumer, *ctypes.ResultEvent) {
var result ctypes.ResultEvent
return func(e ctypes.ResultEvent) (more bool) {
return false
}, &result
}
// CaptureAllEventsConsumer is an `EventConsumer` that captures all events until `done()` is called to stop or timeout happens.
// The consumer works async in the background and returns all the captured events when `done()` is called.
// This can be used to verify that certain events have happened.
// Example usage:
//
// c, done := CaptureAllEventsConsumer(t)
// query := `tm.event='Tx'`
// cleanupFn := l.Subscribe(query, c)
// t.Cleanup(cleanupFn)
//
// // do something in your test that create events
//
// assert.Len(t, done(), 1) // then verify your assumption
func CaptureAllEventsConsumer(t *testing.T, optMaxWaitTime ...time.Duration) (c EventConsumer, done func() []ctypes.ResultEvent) {
t.Helper()
maxWaitTime := DefaultWaitTime
if len(optMaxWaitTime) != 0 {
maxWaitTime = optMaxWaitTime[0]
}
var (
mu sync.Mutex
capturedEvents []ctypes.ResultEvent
exit bool
)
collectEventsConsumer := func(e ctypes.ResultEvent) (more bool) {
mu.Lock()
defer mu.Unlock()
if exit {
return false
}
capturedEvents = append(capturedEvents, e)
return true
}
return TimeoutConsumer(t, maxWaitTime, collectEventsConsumer), func() []ctypes.ResultEvent {
mu.Lock()
defer mu.Unlock()
exit = true
return capturedEvents
}
}

View File

@ -0,0 +1,7 @@
package system
import "testing"
func TestMain(m *testing.M) {
RunTests(m)
}

View File

@ -0,0 +1,253 @@
package system
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"cosmossdk.io/math"
"cosmossdk.io/systemtests"
accountstypes "cosmossdk.io/x/accounts/v1"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
"git.vdb.to/cerc-io/laconicd/x/nitrobank"
registrytypes "git.vdb.to/cerc-io/laconicd/x/registry"
)
var recordFilePath = "../data/examples/service_provider_example.yml"
func init() {
var err error
if recordFilePath, err = filepath.Abs(recordFilePath); err != nil {
panic(err)
}
if _, err = os.Stat(recordFilePath); err != nil {
panic(err)
}
}
type systemTestSuite struct {
t *testing.T
fees string
}
type registryTestSuite struct {
*systemTestSuite
accountName string
accountAddress string
bondDenom string
bondId string
}
func newSystemTestSuite(t *testing.T, fees string) *systemTestSuite {
return &systemTestSuite{
t: t,
fees: fees,
}
}
func (s *systemTestSuite) cli() *systemtests.CLIWrapper {
return NewCLIWrapper(s.t, sut, verbose, s.fees)
}
func (s *systemTestSuite) SubTest(name string, f func(t *systemTestSuite)) {
s.t.Run(name, func(t *testing.T) {
subsuite := newSystemTestSuite(t, s.fees)
f(subsuite)
})
}
// run manually:
// go test ./tests/system -test.v -timeout 10m --verbose --nodes-count 1 -run TestRegistrySetRecord
func TestRegistrySetRecord(t *testing.T) {
s := setupSuite(t)
testCases := []struct {
name string
args []string
err bool
}{
{
"request with invalid payload file arg",
[]string{"bad-file", s.bondId},
true,
},
{
"success",
append([]string{recordFilePath, s.bondId}, s.commonTxFlags()...),
false,
},
}
for _, tc := range testCases {
s.SubTest(fmt.Sprintf("Case %s", tc.name), func(s *systemTestSuite) {
cli := s.cli()
cmd := append([]string{"tx", "registry", "set"}, tc.args...)
if tc.err {
cli := cli.WithRunErrorMatcher(assert.Error)
_ = cli.RunCommandWithArgs(cmd...)
} else {
txhash := cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
}
})
}
}
func setupSuite(t *testing.T) *registryTestSuite {
sut.ResetChain(t)
accountName := "node0"
bondDenom := sdk.DefaultBondDenom
var accountAddress string
s := newSystemTestSuite(t, "3"+bondDenom)
cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
sut.ModifyGenesisJSON(t, func(genesis []byte) []byte {
accountAddress = s.cli().GetKeyAddr(accountName)
// update registry genesis params
var regState registrytypes.GenesisState
raw := gjson.Get(string(genesis), "app_state.registry").String()
require.NoError(t, cdc.UnmarshalJSON([]byte(raw), &regState))
updateParams(&regState.Params, bondDenom)
regStateBz, err := cdc.MarshalJSON(&regState)
require.NoError(t, err)
genesis, err = sjson.SetRawBytes(genesis, "app_state.registry", regStateBz)
require.NoError(t, err)
// add consensus-controlled module account(s)
bondinitmsg, err := codectypes.NewAnyWithValue(&nitrobank.MsgInitAccount{})
require.NoError(t, err)
var accountsState accountstypes.GenesisState
raw = gjson.Get(string(genesis), "app_state.accounts").String()
require.NoError(t, cdc.UnmarshalJSON([]byte(raw), &accountsState))
accountsState.InitAccountMsgs = []*accountstypes.MsgInit{
{
Sender: accountAddress,
AccountType: "nitrobank",
Message: bondinitmsg,
},
}
accountsStateBz, err := cdc.MarshalJSON(&accountsState)
require.NoError(t, err)
genesis, err = sjson.SetRawBytes(genesis, "app_state.accounts", accountsStateBz)
require.NoError(t, err)
return genesis
})
sut.StartChain(t)
rts := registryTestSuite{
systemTestSuite: s,
accountName: accountName,
accountAddress: accountAddress,
bondDenom: bondDenom,
}
rts.bondId = createBond(&rts)
return &rts
}
func createBond(s *registryTestSuite) string {
cli := s.cli()
cmd := []string{
"tx", "bond", "create",
fmt.Sprintf("1000000%s", s.bondDenom),
"--from", s.accountName,
}
txhash := cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
raw := cli.CustomQuery("q", "bond", "list")
var queryResponse bondtypes.QueryBondsResponse
require.NoError(s.t, json.Unmarshal([]byte(raw), &queryResponse))
bonds := queryResponse.GetBonds()
require.NotEmpty(s.t, bonds)
return bonds[0].GetId()
}
func reserveName(s *registryTestSuite, authorityName string) {
cli := s.cli()
cmd := []string{
"tx", "registry", "reserve-authority",
authorityName,
s.accountAddress,
}
txhash := cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
}
func createNameRecord(s *registryTestSuite, authorityName string) {
cli := s.cli()
// reserve name authority
cmd := []string{
"tx", "registry", "reserve-authority",
authorityName,
s.accountAddress,
}
txhash := cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
// add bond-id to name authority
cmd = []string{
"tx", "registry", "authority-bond",
authorityName, s.bondId,
}
txhash = cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
cmd = []string{
"tx", "registry", "set-name",
fmt.Sprintf("lrn://%s/", authorityName),
"test_hello_cid",
}
txhash = cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
}
func createRecord(s *registryTestSuite, bondId string) {
cmd := []string{
"tx", "registry", "set",
recordFilePath, bondId,
}
txhash := s.cli().Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
}
func updateParams(params *registrytypes.Params, bondDenom string) {
params.RecordRent = sdk.NewCoin(bondDenom, math.NewInt(1000))
params.RecordRentDuration = 10 * time.Second
params.AuthorityRent = sdk.NewCoin(bondDenom, math.NewInt(1000))
params.AuthorityGracePeriod = 10 * time.Second
params.AuthorityAuctionCommitFee = sdk.NewCoin(bondDenom, math.NewInt(100))
params.AuthorityAuctionRevealFee = sdk.NewCoin(bondDenom, math.NewInt(100))
params.AuthorityAuctionMinimumBid = sdk.NewCoin(bondDenom, math.NewInt(500))
}
func (s registryTestSuite) commonTxFlags() []string {
return []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.accountName),
// fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
// fmt.Sprintf("--%s=json", flags.FlagOutput),
// fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
// fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", s.bondDenom)),
}
}

133
tests/system/test_runner.go Normal file
View File

@ -0,0 +1,133 @@
package system
import (
"flag"
"fmt"
"os"
"os/exec"
"strconv"
"strings"
"testing"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var (
sut *SystemUnderTest
verbose bool
execBinaryName = "laconicd"
// block time (commit timeout) should match what the testnet command generates
blockTime = time.Second
)
func RunTests(m *testing.M) {
waitTime := flag.Duration("wait-time", DefaultWaitTime, "time to wait for chain events")
nodesCount := flag.Int("nodes-count", 4, "number of nodes in the cluster")
// blockTime := flag.Duration("block-time", 1000*time.Millisecond, "block creation time")
// execBinary := flag.String("binary", "simd", "executable binary for server/ client side")
// bech32Prefix := flag.String("bech32", "cosmos", "bech32 prefix to be used with addresses")
flag.BoolVar(&verbose, "verbose", false, "verbose output")
flag.Parse()
// fail fast on most common setup issue
requireEnoughFileHandlers(*nodesCount + 1) // +1 as tests may start another node
dir, err := os.Getwd()
if err != nil {
panic(err)
}
WorkDir = dir
if verbose {
println("Work dir: ", WorkDir)
}
initSDKConfig("laconic")
DefaultWaitTime = *waitTime
// if *execBinary == "" {
// panic("executable binary name must not be empty")
// }
// sdk systemtests expects this to be set for v2 server/runtime
os.Setenv("COSMOS_BUILD_OPTIONS", "v2")
sut = NewSystemUnderTest(execBinaryName, verbose, *nodesCount, blockTime)
sut.SetupChain() // setup chain and keyring
// run tests
exitCode := m.Run()
// postprocess
sut.StopChain()
if verbose || exitCode != 0 {
sut.PrintBuffer()
printResultFlag(exitCode == 0)
}
os.Exit(exitCode)
}
func GetSystemUnderTest() *SystemUnderTest {
return sut
}
func IsVerbose() bool {
return verbose
}
func GetExecutableName() string {
return execBinaryName
}
// requireEnoughFileHandlers uses `ulimit`
func requireEnoughFileHandlers(nodesCount int) {
ulimit, err := exec.LookPath("ulimit")
if err != nil || ulimit == "" { // skip when not available
return
}
cmd := exec.Command(ulimit, "-n")
cmd.Dir = WorkDir
out, err := cmd.CombinedOutput()
if err != nil {
panic(fmt.Sprintf("unexpected error :%#+v, output: %s", err, string(out)))
}
fileDescrCount, err := strconv.Atoi(strings.Trim(string(out), " \t\n"))
if err != nil {
panic(fmt.Sprintf("unexpected error :%#+v, output: %s", err, string(out)))
}
expFH := nodesCount * 260 // random number that worked on my box
if fileDescrCount < expFH {
panic(fmt.Sprintf("Fail fast. Insufficient setup. Run 'ulimit -n %d'", expFH))
}
}
func initSDKConfig(bech32Prefix string) {
config := sdk.GetConfig()
config.SetBech32PrefixForAccount(bech32Prefix, bech32Prefix+sdk.PrefixPublic)
config.SetBech32PrefixForValidator(bech32Prefix+sdk.PrefixValidator+sdk.PrefixOperator, bech32Prefix+sdk.PrefixValidator+sdk.PrefixOperator+sdk.PrefixPublic)
config.SetBech32PrefixForConsensusNode(bech32Prefix+sdk.PrefixValidator+sdk.PrefixConsensus, bech32Prefix+sdk.PrefixValidator+sdk.PrefixConsensus+sdk.PrefixPublic)
}
const (
successFlag = `
___ _ _ ___ ___ ___ ___ ___
/ __| | | |/ __/ __/ _ \/ __/ __|
\__ \ |_| | (_| (_| __/\__ \__ \
|___/\__,_|\___\___\___||___/___/`
failureFlag = `
__ _ _ _
/ _| (_) | | |
| |_ __ _ _| | ___ __| |
| _/ _| | | |/ _ \/ _| |
| || (_| | | | __/ (_| |
|_| \__,_|_|_|\___|\__,_|`
)
func printResultFlag(ok bool) {
if ok {
fmt.Println(successFlag)
} else {
fmt.Println(failureFlag)
}
}

View File

@ -1,43 +0,0 @@
package cli
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
// Reference: https://github.com/cosmos/cosmos-sdk/blob/v0.50.3/testutil/cli/tx.go#L15
// CheckTxCode verifies that the transaction result returns a specific code
// Takes a network, wait for two blocks and fetch the transaction from its hash
func CheckTxCode(network *network.Network, clientCtx client.Context, txHash string, expectedCode uint32) error {
// wait for 2 blocks
for i := 0; i < 2; i++ {
if err := network.WaitForNextBlock(); err != nil {
return fmt.Errorf("failed to wait for next block: %w", err)
}
}
cmd := authcli.QueryTxCmd()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, []string{txHash, fmt.Sprintf("--%s=json", flags.FlagOutput)})
if err != nil {
return err
}
var response sdk.TxResponse
if err := clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response); err != nil {
return err
}
if response.Code != expectedCode {
return fmt.Errorf("expected code %d, got %d", expectedCode, response.Code)
}
return nil
}

15
testutil/keyring.go Normal file
View File

@ -0,0 +1,15 @@
package testutil
import (
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
modtestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
"git.vdb.to/cerc-io/laconicd/utils"
)
func NewKeyring() keyring.Keyring {
codecOpts := codectestutil.NewCodecOptionsWithCodecs(utils.NewAddressCodec(), utils.NewValAddressCodec())
encCfg := modtestutil.MakeTestEncodingConfig(codecOpts)
return keyring.NewInMemory(encCfg.Codec)
}

View File

@ -1,74 +0,0 @@
/*
Package network implements and exposes a fully operational in-process CometBFT
test network that consists of at least one or potentially many validators. This
test network can be used primarily for integration tests or unit test suites.
The test network utilizes SimApp as the ABCI application and uses all the modules
defined in the Cosmos SDK. An in-process test network can be configured with any
number of validators as well as account funds and even custom genesis state.
When creating a test network, a series of Validator objects are returned. Each
Validator object has useful information such as their address and public key. A
Validator will also provide its RPC, P2P, and API addresses that can be useful
for integration testing. In addition, a CometBFT local RPC client is also provided
which can be handy for making direct RPC calls to CometBFT.
Note, due to limitations in concurrency and the design of the RPC layer in
CometBFT, only the first Validator object will have an RPC and API client
exposed. Due to this exact same limitation, only a single test network can exist
at a time. A caller must be certain it calls Cleanup after it no longer needs
the network.
A typical testing flow might look like the following:
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := network.DefaultConfig()
cfg.NumValidators = 1
s.cfg = cfg
var err error
s.network, err = network.New(s.T(), s.T().TempDir(), cfg)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
// This is important and must be called to ensure other tests can create
// a network!
s.network.Cleanup()
}
func (s *IntegrationTestSuite) TestQueryBalancesRequestHandlerFn() {
val := s.network.Validators[0]
baseURL := val.APIAddress
// Use baseURL to make API HTTP requests or use val.RPCClient to make direct
// CometBFT RPC calls.
// ...
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
*/
package network
/*
NOTE:
Copied over from https://github.com/cosmos/cosmos-sdk/tree/v0.50.3/testutil/network
Patch:
- Skipped network.LatestHeight() call at the end of New()
- Removed block timeouts
*/

View File

@ -1,852 +0,0 @@
package network
import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
"testing"
"time"
"github.com/cometbft/cometbft/node"
cmtclient "github.com/cometbft/cometbft/rpc/client"
dbm "github.com/cosmos/cosmos-db"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
sdkmath "cosmossdk.io/math"
"cosmossdk.io/math/unsafe"
pruningtypes "cosmossdk.io/store/pruning/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
"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"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/configurator"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
_ "github.com/cosmos/cosmos-sdk/x/auth" // import auth as a blank
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import auth tx config as a blank
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
_ "github.com/cosmos/cosmos-sdk/x/bank" // import bank as a blank
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
_ "github.com/cosmos/cosmos-sdk/x/consensus" // import consensus as a blank
"github.com/cosmos/cosmos-sdk/x/genutil"
_ "github.com/cosmos/cosmos-sdk/x/params" // import params as a blank
_ "github.com/cosmos/cosmos-sdk/x/staking" // import staking as a blank
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// package-wide network lock to only allow one test network at a time
var (
lock = new(sync.Mutex)
portPool = make(chan string, 200)
)
func init() {
closeFns := []func() error{}
for i := 0; i < 200; i++ {
_, port, closeFn, err := FreeTCPAddr()
if err != nil {
panic(err)
}
portPool <- port
closeFns = append(closeFns, closeFn)
}
for _, closeFn := range closeFns {
err := closeFn()
if err != nil {
panic(err)
}
}
}
// AppConstructor defines a function which accepts a network configuration and
// creates an ABCI Application to provide to CometBFT.
type (
AppConstructor = func(val ValidatorI) servertypes.Application
TestFixtureFactory = func() TestFixture
)
type TestFixture struct {
AppConstructor AppConstructor
GenesisState map[string]json.RawMessage
EncodingConfig moduletestutil.TestEncodingConfig
}
// Config defines the necessary configuration used to bootstrap and start an
// in-process local testing network.
type Config struct {
Codec codec.Codec
LegacyAmino *codec.LegacyAmino // TODO: Remove!
InterfaceRegistry codectypes.InterfaceRegistry
TxConfig client.TxConfig
AccountRetriever client.AccountRetriever
AppConstructor AppConstructor // the ABCI application constructor
GenesisState map[string]json.RawMessage // custom genesis state to provide
TimeoutCommit time.Duration // the consensus commitment timeout
ChainID string // the network chain-id
NumValidators int // the total number of validators to create and bond
Mnemonics []string // custom user-provided validator operator mnemonics
BondDenom string // the staking bond denomination
MinGasPrices string // the minimum gas prices each validator will accept
AccountTokens sdkmath.Int // the amount of unique validator tokens (e.g. 1000node0)
StakingTokens sdkmath.Int // the amount of tokens each validator has available to stake
BondedTokens sdkmath.Int // the amount of tokens each validator stakes
PruningStrategy string // the pruning strategy each validator will have
EnableLogging bool // enable logging to STDOUT
CleanupDir bool // remove base temporary directory during cleanup
SigningAlgo string // signing algorithm for keys
KeyringOptions []keyring.Option // keyring configuration options
RPCAddress string // RPC listen address (including port)
APIAddress string // REST API listen address (including port)
GRPCAddress string // GRPC server listen address (including port)
PrintMnemonic bool // print the mnemonic of first validator as log output for testing
}
// DefaultConfig returns a sane default configuration suitable for nearly all
// testing requirements.
func DefaultConfig(factory TestFixtureFactory) Config {
fixture := factory()
return Config{
Codec: fixture.EncodingConfig.Codec,
TxConfig: fixture.EncodingConfig.TxConfig,
LegacyAmino: fixture.EncodingConfig.Amino,
InterfaceRegistry: fixture.EncodingConfig.InterfaceRegistry,
AccountRetriever: authtypes.AccountRetriever{},
AppConstructor: fixture.AppConstructor,
GenesisState: fixture.GenesisState,
TimeoutCommit: 2 * time.Second,
ChainID: "chain-" + unsafe.Str(6),
NumValidators: 4,
BondDenom: sdk.DefaultBondDenom,
MinGasPrices: fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom),
AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction),
StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction),
BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction),
PruningStrategy: pruningtypes.PruningOptionNothing,
CleanupDir: true,
SigningAlgo: string(hd.Secp256k1Type),
KeyringOptions: []keyring.Option{},
PrintMnemonic: false,
}
}
// MinimumAppConfig defines the minimum of modules required for a call to New to succeed
func MinimumAppConfig() depinject.Config {
return configurator.NewAppConfig(
configurator.AuthModule(),
configurator.ParamsModule(),
configurator.BankModule(),
configurator.GenutilModule(),
configurator.StakingModule(),
configurator.ConsensusModule(),
configurator.TxModule(),
)
}
func DefaultConfigWithAppConfig(appConfig depinject.Config) (Config, error) {
var (
appBuilder *runtime.AppBuilder
txConfig client.TxConfig
legacyAmino *codec.LegacyAmino
cdc codec.Codec
interfaceRegistry codectypes.InterfaceRegistry
)
if err := depinject.Inject(
depinject.Configs(
appConfig,
depinject.Supply(log.NewNopLogger()),
),
&appBuilder,
&txConfig,
&cdc,
&legacyAmino,
&interfaceRegistry,
); err != nil {
return Config{}, err
}
cfg := DefaultConfig(func() TestFixture {
return TestFixture{}
})
cfg.Codec = cdc
cfg.TxConfig = txConfig
cfg.LegacyAmino = legacyAmino
cfg.InterfaceRegistry = interfaceRegistry
cfg.GenesisState = appBuilder.DefaultGenesis()
cfg.AppConstructor = func(val ValidatorI) servertypes.Application {
// we build a unique app instance for every validator here
var appBuilder *runtime.AppBuilder
if err := depinject.Inject(
depinject.Configs(
appConfig,
depinject.Supply(val.GetCtx().Logger),
),
&appBuilder); err != nil {
panic(err)
}
app := appBuilder.Build(
dbm.NewMemDB(),
nil,
baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
baseapp.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
baseapp.SetChainID(cfg.ChainID),
)
testdata.RegisterQueryServer(app.GRPCQueryRouter(), testdata.QueryImpl{})
if err := app.Load(true); err != nil {
panic(err)
}
return app
}
return cfg, nil
}
type (
// Network defines a local in-process testing network using SimApp. It can be
// configured to start any number of validators, each with its own RPC and API
// clients. Typically, this test network would be used in client and integration
// testing where user input is expected.
//
// Note, due to CometBFT constraints in regards to RPC functionality, there
// may only be one test network running at a time. Thus, any caller must be
// sure to Cleanup after testing is finished in order to allow other tests
// to create networks. In addition, only the first validator will have a valid
// RPC and API server/client.
Network struct {
Logger Logger
BaseDir string
Validators []*Validator
Config Config
}
// Validator defines an in-process CometBFT validator node. Through this object,
// a client can make RPC and API calls and interact with any client command
// or handler.
Validator struct {
AppConfig *srvconfig.Config
ClientCtx client.Context
Ctx *server.Context
Dir string
NodeID string
PubKey cryptotypes.PubKey
Moniker string
APIAddress string
RPCAddress string
P2PAddress string
Address sdk.AccAddress
ValAddress sdk.ValAddress
RPCClient cmtclient.Client
app servertypes.Application
tmNode *node.Node
api *api.Server
grpc *grpc.Server
grpcWeb *http.Server
errGroup *errgroup.Group
cancelFn context.CancelFunc
}
// ValidatorI expose a validator's context and configuration
ValidatorI interface {
GetCtx() *server.Context
GetAppConfig() *srvconfig.Config
}
// Logger is a network logger interface that exposes testnet-level Log() methods for an in-process testing network
// This is not to be confused with logging that may happen at an individual node or validator level
Logger interface {
Log(args ...interface{})
Logf(format string, args ...interface{})
}
)
var (
_ Logger = (*testing.T)(nil)
_ Logger = (*CLILogger)(nil)
_ ValidatorI = Validator{}
)
func (v Validator) GetCtx() *server.Context {
return v.Ctx
}
func (v Validator) GetAppConfig() *srvconfig.Config {
return v.AppConfig
}
// CLILogger wraps a cobra.Command and provides command logging methods.
type CLILogger struct {
cmd *cobra.Command
}
// Log logs given args.
func (s CLILogger) Log(args ...interface{}) {
s.cmd.Println(args...)
}
// Logf logs given args according to a format specifier.
func (s CLILogger) Logf(format string, args ...interface{}) {
s.cmd.Printf(format, args...)
}
// NewCLILogger creates a new CLILogger.
func NewCLILogger(cmd *cobra.Command) CLILogger {
return CLILogger{cmd}
}
// New creates a new Network for integration tests or in-process testnets run via the CLI
func New(l Logger, baseDir string, cfg Config) (*Network, error) {
// only one caller/test can create and use a network at a time
l.Log("acquiring test network lock")
lock.Lock()
network := &Network{
Logger: l,
BaseDir: baseDir,
Validators: make([]*Validator, cfg.NumValidators),
Config: cfg,
}
l.Logf("preparing test network with chain-id \"%s\"\n", cfg.ChainID)
monikers := make([]string, cfg.NumValidators)
nodeIDs := make([]string, cfg.NumValidators)
valPubKeys := make([]cryptotypes.PubKey, cfg.NumValidators)
var (
genAccounts []authtypes.GenesisAccount
genBalances []banktypes.Balance
genFiles []string
)
buf := bufio.NewReader(os.Stdin)
// generate private keys, node IDs, and initial transactions
for i := 0; i < cfg.NumValidators; i++ {
appCfg := srvconfig.DefaultConfig()
appCfg.Pruning = cfg.PruningStrategy
appCfg.MinGasPrices = cfg.MinGasPrices
appCfg.API.Enable = true
appCfg.API.Swagger = false
appCfg.Telemetry.Enabled = false
ctx := server.NewDefaultContext()
cmtCfg := ctx.Config
cmtCfg.Consensus.TimeoutCommit = cfg.TimeoutCommit
// Only allow the first validator to expose an RPC, API and gRPC
// server/client due to CometBFT in-process constraints.
apiAddr := ""
cmtCfg.RPC.ListenAddress = ""
appCfg.GRPC.Enable = false
appCfg.GRPCWeb.Enable = false
apiListenAddr := ""
if i == 0 {
if cfg.APIAddress != "" {
apiListenAddr = cfg.APIAddress
} else {
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for API server")
}
port := <-portPool
apiListenAddr = fmt.Sprintf("tcp://0.0.0.0:%s", port)
}
appCfg.API.Address = apiListenAddr
apiURL, err := url.Parse(apiListenAddr)
if err != nil {
return nil, err
}
apiAddr = fmt.Sprintf("http://%s:%s", apiURL.Hostname(), apiURL.Port())
if cfg.RPCAddress != "" {
cmtCfg.RPC.ListenAddress = cfg.RPCAddress
} else {
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for RPC server")
}
port := <-portPool
cmtCfg.RPC.ListenAddress = fmt.Sprintf("tcp://0.0.0.0:%s", port)
}
if cfg.GRPCAddress != "" {
appCfg.GRPC.Address = cfg.GRPCAddress
} else {
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for GRPC server")
}
port := <-portPool
appCfg.GRPC.Address = fmt.Sprintf("0.0.0.0:%s", port)
}
appCfg.GRPC.Enable = true
appCfg.GRPCWeb.Enable = true
}
logger := log.NewNopLogger()
if cfg.EnableLogging {
logger = log.NewLogger(os.Stdout) // TODO(mr): enable selection of log destination.
}
ctx.Logger = logger
nodeDirName := fmt.Sprintf("node%d", i)
nodeDir := filepath.Join(network.BaseDir, nodeDirName, "simd")
clientDir := filepath.Join(network.BaseDir, nodeDirName, "simcli")
gentxsDir := filepath.Join(network.BaseDir, "gentxs")
err := os.MkdirAll(filepath.Join(nodeDir, "config"), 0o755)
if err != nil {
return nil, err
}
err = os.MkdirAll(clientDir, 0o755)
if err != nil {
return nil, err
}
cmtCfg.SetRoot(nodeDir)
cmtCfg.Moniker = nodeDirName
monikers[i] = nodeDirName
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for Proxy server")
}
port := <-portPool
proxyAddr := fmt.Sprintf("tcp://0.0.0.0:%s", port)
cmtCfg.ProxyApp = proxyAddr
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for Proxy server")
}
port = <-portPool
p2pAddr := fmt.Sprintf("tcp://0.0.0.0:%s", port)
cmtCfg.P2P.ListenAddress = p2pAddr
cmtCfg.P2P.AddrBookStrict = false
cmtCfg.P2P.AllowDuplicateIP = true
nodeID, pubKey, err := genutil.InitializeNodeValidatorFiles(cmtCfg)
if err != nil {
return nil, err
}
nodeIDs[i] = nodeID
valPubKeys[i] = pubKey
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.Codec, cfg.KeyringOptions...)
if err != nil {
return nil, err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos)
if err != nil {
return nil, err
}
var mnemonic string
if i < len(cfg.Mnemonics) {
mnemonic = cfg.Mnemonics[i]
}
addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, mnemonic, true, algo)
if err != nil {
return nil, err
}
// if PrintMnemonic is set to true, we print the first validator node's secret to the network's logger
// for debugging and manual testing
if cfg.PrintMnemonic && i == 0 {
printMnemonic(l, secret)
}
info := map[string]string{"secret": secret}
infoBz, err := json.Marshal(info)
if err != nil {
return nil, err
}
// save private key seed words
err = writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, infoBz)
if err != nil {
return nil, err
}
balances := sdk.NewCoins(
sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), cfg.AccountTokens),
sdk.NewCoin(cfg.BondDenom, cfg.StakingTokens),
)
genFiles = append(genFiles, cmtCfg.GenesisFile())
genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: balances.Sort()})
genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0))
commission, err := sdkmath.LegacyNewDecFromStr("0.5")
if err != nil {
return nil, err
}
createValMsg, err := stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(addr).String(),
valPubKeys[i],
sdk.NewCoin(cfg.BondDenom, cfg.BondedTokens),
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
stakingtypes.NewCommissionRates(commission, sdkmath.LegacyOneDec(), sdkmath.LegacyOneDec()),
sdkmath.OneInt(),
)
if err != nil {
return nil, err
}
p2pURL, err := url.Parse(p2pAddr)
if err != nil {
return nil, err
}
memo := fmt.Sprintf("%s@%s:%s", nodeIDs[i], p2pURL.Hostname(), p2pURL.Port())
fee := sdk.NewCoins(sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), sdkmath.NewInt(0)))
txBuilder := cfg.TxConfig.NewTxBuilder()
err = txBuilder.SetMsgs(createValMsg)
if err != nil {
return nil, err
}
txBuilder.SetFeeAmount(fee) // Arbitrary fee
txBuilder.SetGasLimit(1000000) // Need at least 100386
txBuilder.SetMemo(memo)
txFactory := tx.Factory{}
txFactory = txFactory.
WithChainID(cfg.ChainID).
WithMemo(memo).
WithKeybase(kb).
WithTxConfig(cfg.TxConfig)
err = tx.Sign(context.Background(), txFactory, nodeDirName, txBuilder, true)
if err != nil {
return nil, err
}
txBz, err := cfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
if err != nil {
return nil, err
}
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz)
if err != nil {
return nil, err
}
srvconfig.WriteConfigFile(filepath.Join(nodeDir, "config", "app.toml"), appCfg)
clientCtx := client.Context{}.
WithKeyringDir(clientDir).
WithKeyring(kb).
WithHomeDir(cmtCfg.RootDir).
WithChainID(cfg.ChainID).
WithInterfaceRegistry(cfg.InterfaceRegistry).
WithCodec(cfg.Codec).
WithLegacyAmino(cfg.LegacyAmino).
WithTxConfig(cfg.TxConfig).
WithAccountRetriever(cfg.AccountRetriever).
WithNodeURI(cmtCfg.RPC.ListenAddress)
// Provide ChainID here since we can't modify it in the Comet config.
ctx.Viper.Set(flags.FlagChainID, cfg.ChainID)
network.Validators[i] = &Validator{
AppConfig: appCfg,
ClientCtx: clientCtx,
Ctx: ctx,
Dir: filepath.Join(network.BaseDir, nodeDirName),
NodeID: nodeID,
PubKey: pubKey,
Moniker: nodeDirName,
RPCAddress: cmtCfg.RPC.ListenAddress,
P2PAddress: cmtCfg.P2P.ListenAddress,
APIAddress: apiAddr,
Address: addr,
ValAddress: sdk.ValAddress(addr),
}
}
err := initGenFiles(cfg, genAccounts, genBalances, genFiles)
if err != nil {
return nil, err
}
err = collectGenFiles(cfg, network.Validators, network.BaseDir)
if err != nil {
return nil, err
}
l.Log("starting test network...")
for idx, v := range network.Validators {
if err := startInProcess(cfg, v); err != nil {
return nil, err
}
l.Log("started validator", idx)
}
// height, err := network.LatestHeight()
// if err != nil {
// return nil, err
// }
// l.Log("started test network at height:", height)
// Ensure we cleanup incase any test was abruptly halted (e.g. SIGINT) as any
// defer in a test would not be called.
trapSignal(network.Cleanup)
return network, nil
}
// trapSignal traps SIGINT and SIGTERM and calls os.Exit once a signal is received.
func trapSignal(cleanupFunc func()) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
if cleanupFunc != nil {
cleanupFunc()
}
exitCode := 128
switch sig {
case syscall.SIGINT:
exitCode += int(syscall.SIGINT)
case syscall.SIGTERM:
exitCode += int(syscall.SIGTERM)
}
os.Exit(exitCode)
}()
}
// LatestHeight returns the latest height of the network or an error if the
// query fails or no validators exist.
func (n *Network) LatestHeight() (int64, error) {
if len(n.Validators) == 0 {
return 0, errors.New("no validators available")
}
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
timeout := time.NewTimer(time.Second * 5)
defer timeout.Stop()
var latestHeight int64
val := n.Validators[0]
queryClient := cmtservice.NewServiceClient(val.ClientCtx)
for {
select {
case <-ticker.C:
done := make(chan struct{})
go func() {
res, err := queryClient.GetLatestBlock(context.Background(), &cmtservice.GetLatestBlockRequest{})
if err == nil && res != nil {
latestHeight = res.SdkBlock.Header.Height
}
done <- struct{}{}
}()
select {
case <-timeout.C:
return latestHeight, errors.New("timeout exceeded waiting for block")
case <-done:
if latestHeight != 0 {
return latestHeight, nil
}
}
default: //nolint: all
}
}
}
// WaitForHeight performs a blocking check where it waits for a block to be
// committed after a given block.
func (n *Network) WaitForHeight(h int64) (int64, error) {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
if len(n.Validators) == 0 {
return 0, errors.New("no validators available")
}
var latestHeight int64
val := n.Validators[0]
queryClient := cmtservice.NewServiceClient(val.ClientCtx)
for {
select {
case <-ticker.C:
res, err := queryClient.GetLatestBlock(context.Background(), &cmtservice.GetLatestBlockRequest{})
if err == nil && res != nil {
latestHeight = res.GetSdkBlock().Header.Height
if latestHeight >= h {
return latestHeight, nil
}
}
default: //nolint: all
}
}
}
// RetryForBlocks will wait for the next block and execute the function provided.
// It will do this until the function returns a nil error or until the number of
// blocks has been reached.
func (n *Network) RetryForBlocks(retryFunc func() error, blocks int) error {
for i := 0; i < blocks; i++ {
_ = n.WaitForNextBlock()
err := retryFunc()
if err == nil {
return nil
}
// we've reached the last block to wait, return the error
if i == blocks-1 {
return err
}
}
return nil
}
// WaitForNextBlock waits for the next block to be committed, returning an error
// upon failure.
func (n *Network) WaitForNextBlock() error {
lastBlock, err := n.LatestHeight()
if err != nil {
return err
}
_, err = n.WaitForHeight(lastBlock + 1)
if err != nil {
return err
}
return err
}
// Cleanup removes the root testing (temporary) directory and stops both the
// CometBFT and API services. It allows other callers to create and start
// test networks. This method must be called when a test is finished, typically
// in a defer.
func (n *Network) Cleanup() {
defer func() {
lock.Unlock()
n.Logger.Log("released test network lock")
}()
n.Logger.Log("cleaning up test network...")
for _, v := range n.Validators {
// cancel the validator's context which will signal to the gRPC and API
// goroutines that they should gracefully exit.
v.cancelFn()
if err := v.errGroup.Wait(); err != nil {
n.Logger.Log("unexpected error waiting for validator gRPC and API processes to exit", "err", err)
}
if v.tmNode != nil && v.tmNode.IsRunning() {
if err := v.tmNode.Stop(); err != nil {
n.Logger.Log("failed to stop validator CometBFT node", "err", err)
}
}
if v.grpcWeb != nil {
_ = v.grpcWeb.Close()
}
if v.app != nil {
if err := v.app.Close(); err != nil {
n.Logger.Log("failed to stop validator ABCI application", "err", err)
}
}
}
time.Sleep(100 * time.Millisecond)
if n.Config.CleanupDir {
_ = os.RemoveAll(n.BaseDir)
}
n.Logger.Log("finished cleaning up test network")
}
// printMnemonic prints a provided mnemonic seed phrase on a network logger
// for debugging and manual testing
func printMnemonic(l Logger, secret string) {
lines := []string{
"THIS MNEMONIC IS FOR TESTING PURPOSES ONLY",
"DO NOT USE IN PRODUCTION",
"",
strings.Join(strings.Fields(secret)[0:8], " "),
strings.Join(strings.Fields(secret)[8:16], " "),
strings.Join(strings.Fields(secret)[16:24], " "),
}
lineLengths := make([]int, len(lines))
for i, line := range lines {
lineLengths[i] = len(line)
}
maxLineLength := 0
for _, lineLen := range lineLengths {
if lineLen > maxLineLength {
maxLineLength = lineLen
}
}
l.Log("\n")
l.Log(strings.Repeat("+", maxLineLength+8))
for _, line := range lines {
l.Logf("++ %s ++\n", centerText(line, maxLineLength))
}
l.Log(strings.Repeat("+", maxLineLength+8))
l.Log("\n")
}
// centerText centers text across a fixed width, filling either side with whitespace buffers
func centerText(text string, width int) string {
textLen := len(text)
leftBuffer := strings.Repeat(" ", (width-textLen)/2)
rightBuffer := strings.Repeat(" ", (width-textLen)/2+(width-textLen)%2)
return fmt.Sprintf("%s%s%s", leftBuffer, text, rightBuffer)
}

View File

@ -1,240 +0,0 @@
package network
import (
"context"
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
cmtcfg "github.com/cometbft/cometbft/config"
"github.com/cometbft/cometbft/node"
"github.com/cometbft/cometbft/p2p"
pvm "github.com/cometbft/cometbft/privval"
"github.com/cometbft/cometbft/proxy"
"github.com/cometbft/cometbft/rpc/client/local"
cmttypes "github.com/cometbft/cometbft/types"
cmttime "github.com/cometbft/cometbft/types/time"
"golang.org/x/sync/errgroup"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
servercmtlog "github.com/cosmos/cosmos-sdk/server/log"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
)
func startInProcess(cfg Config, val *Validator) error {
logger := val.Ctx.Logger
cmtCfg := val.Ctx.Config
cmtCfg.Instrumentation.Prometheus = false
if err := val.AppConfig.ValidateBasic(); err != nil {
return err
}
nodeKey, err := p2p.LoadOrGenNodeKey(cmtCfg.NodeKeyFile())
if err != nil {
return err
}
app := cfg.AppConstructor(*val)
val.app = app
appGenesisProvider := func() (*cmttypes.GenesisDoc, error) {
appGenesis, err := genutiltypes.AppGenesisFromFile(cmtCfg.GenesisFile())
if err != nil {
return nil, err
}
return appGenesis.ToGenesisDoc()
}
cmtApp := server.NewCometABCIWrapper(app)
tmNode, err := node.NewNode( //resleak:notresource
cmtCfg,
pvm.LoadOrGenFilePV(cmtCfg.PrivValidatorKeyFile(), cmtCfg.PrivValidatorStateFile()),
nodeKey,
proxy.NewLocalClientCreator(cmtApp),
appGenesisProvider,
cmtcfg.DefaultDBProvider,
node.DefaultMetricsProvider(cmtCfg.Instrumentation),
servercmtlog.CometLoggerWrapper{Logger: logger.With("module", val.Moniker)},
)
if err != nil {
return err
}
if err := tmNode.Start(); err != nil {
return err
}
val.tmNode = tmNode
if val.RPCAddress != "" {
val.RPCClient = local.New(tmNode)
}
// We'll need a RPC client if the validator exposes a gRPC or REST endpoint.
if val.APIAddress != "" || val.AppConfig.GRPC.Enable {
val.ClientCtx = val.ClientCtx.
WithClient(val.RPCClient)
app.RegisterTxService(val.ClientCtx)
app.RegisterTendermintService(val.ClientCtx)
app.RegisterNodeService(val.ClientCtx, *val.AppConfig)
}
ctx := context.Background()
ctx, val.cancelFn = context.WithCancel(ctx)
val.errGroup, ctx = errgroup.WithContext(ctx)
grpcCfg := val.AppConfig.GRPC
if grpcCfg.Enable {
grpcSrv, err := servergrpc.NewGRPCServer(val.ClientCtx, app, grpcCfg)
if err != nil {
return err
}
// Start the gRPC server in a goroutine. Note, the provided ctx will ensure
// that the server is gracefully shut down.
val.errGroup.Go(func() error {
return servergrpc.StartGRPCServer(ctx, logger.With(log.ModuleKey, "grpc-server"), grpcCfg, grpcSrv)
})
val.grpc = grpcSrv
}
if val.APIAddress != "" {
apiSrv := api.New(val.ClientCtx, logger.With(log.ModuleKey, "api-server"), val.grpc)
app.RegisterAPIRoutes(apiSrv, val.AppConfig.API)
val.errGroup.Go(func() error {
return apiSrv.Start(ctx, *val.AppConfig)
})
val.api = apiSrv
}
return nil
}
func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error {
genTime := cmttime.Now()
for i := 0; i < cfg.NumValidators; i++ {
cmtCfg := vals[i].Ctx.Config
nodeDir := filepath.Join(outputDir, vals[i].Moniker, "simd")
gentxsDir := filepath.Join(outputDir, "gentxs")
cmtCfg.Moniker = vals[i].Moniker
cmtCfg.SetRoot(nodeDir)
initCfg := genutiltypes.NewInitConfig(cfg.ChainID, gentxsDir, vals[i].NodeID, vals[i].PubKey)
genFile := cmtCfg.GenesisFile()
appGenesis, err := genutiltypes.AppGenesisFromFile(genFile)
if err != nil {
return err
}
appState, err := genutil.GenAppStateFromConfig(cfg.Codec, cfg.TxConfig,
cmtCfg, initCfg, appGenesis,
banktypes.GenesisBalancesIterator{},
genutiltypes.DefaultMessageValidator,
cfg.TxConfig.SigningContext().ValidatorAddressCodec(),
)
if err != nil {
return err
}
// overwrite each validator's genesis file to have a canonical genesis time
if err := genutil.ExportGenesisFileWithTime(genFile, cfg.ChainID, nil, appState, genTime); err != nil {
return err
}
}
return nil
}
func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance, genFiles []string) error {
// set the accounts in the genesis state
var authGenState authtypes.GenesisState
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[authtypes.ModuleName], &authGenState)
accounts, err := authtypes.PackAccounts(genAccounts)
if err != nil {
return err
}
authGenState.Accounts = append(authGenState.Accounts, accounts...)
cfg.GenesisState[authtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&authGenState)
// set the balances in the genesis state
var bankGenState banktypes.GenesisState
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[banktypes.ModuleName], &bankGenState)
bankGenState.Balances = append(bankGenState.Balances, genBalances...)
cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState)
appGenStateJSON, err := json.MarshalIndent(cfg.GenesisState, "", " ")
if err != nil {
return err
}
appGenesis := genutiltypes.AppGenesis{
ChainID: cfg.ChainID,
AppState: appGenStateJSON,
Consensus: &genutiltypes.ConsensusGenesis{
Validators: nil,
},
}
// generate empty genesis files for each validator and save
for i := 0; i < cfg.NumValidators; i++ {
if err := appGenesis.SaveAs(genFiles[i]); err != nil {
return err
}
}
return nil
}
func writeFile(name, dir string, contents []byte) error {
file := filepath.Join(dir, name)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("could not create directory %q: %w", dir, err)
}
if err := os.WriteFile(file, contents, 0o600); err != nil {
return err
}
return nil
}
// Get a free address for a test CometBFT server
// protocol is either tcp, http, etc
func FreeTCPAddr() (addr, port string, closeFn func() error, err error) {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return "", "", nil, err
}
closeFn = func() error {
return l.Close()
}
portI := l.Addr().(*net.TCPAddr).Port
port = fmt.Sprintf("%d", portI)
addr = fmt.Sprintf("tcp://0.0.0.0:%s", port)
return
}

53
utils/address.go Normal file
View File

@ -0,0 +1,53 @@
package utils
import (
"cosmossdk.io/core/address"
errorsmod "cosmossdk.io/errors"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"git.vdb.to/cerc-io/laconicd/app/params"
)
type addressCodec struct {
address.Codec
}
func (ac addressCodec) StringToBytes(text string) ([]byte, error) {
bz, err := ac.Codec.StringToBytes(text)
if err != nil {
return nil, err
}
if len(bz) != 20 && len(bz) != 32 {
return nil, errorsmod.Wrapf(sdkerrors.ErrUnknownAddress,
"address length must be 20 or 32 bz, got %d", len(bz))
}
return bz, nil
}
func NewAddressCodec() address.Codec {
return addressCodec{
Codec: addresscodec.NewBech32Codec(params.Bech32PrefixAccAddr),
}
}
func NewValAddressCodec() address.ValidatorAddressCodec {
return addressCodec{
Codec: addresscodec.NewBech32Codec(params.Bech32PrefixValAddr),
}
}
func NewConsAddressCodec() address.ConsensusAddressCodec {
return addressCodec{
Codec: addresscodec.NewBech32Codec(params.Bech32PrefixConsAddr),
}
}
func MustBytesToString(ac address.Codec, bz []byte) string {
str, err := ac.BytesToString(bz)
if err != nil {
panic(err)
}
return str
}

View File

@ -3,12 +3,15 @@ package utils
import (
"fmt"
"cosmossdk.io/core/gas"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const RefundModuleGasDescriptor = "laconic module gas refund"
func CtxWithCustomKVGasConfig(ctx *sdk.Context) *sdk.Context {
updatedCtx := ctx.WithKVGasConfig(storetypes.GasConfig{
HasCost: 0,
@ -23,7 +26,16 @@ func CtxWithCustomKVGasConfig(ctx *sdk.Context) *sdk.Context {
return &updatedCtx
}
func LogTxGasConsumed(ctx sdk.Context, logger log.Logger, tx string) {
gasConsumed := ctx.GasMeter().GasConsumed()
logger.Info("tx executed", "method", tx, "gas_consumed", fmt.Sprintf("%d", gasConsumed))
func LogTxGasConsumed(gm gas.Meter, logger log.Logger, method string) {
gasConsumed := gm.Consumed()
logger.Info("tx executed", "method", method, "gas_consumed", fmt.Sprintf("%d", gasConsumed))
}
func TrackGasConsumption(meter gas.Meter) func(log.Logger, string) {
startGas := meter.Consumed()
return func(logger log.Logger, method string) {
endGas := meter.Consumed()
meter.Refund(endGas-startGas, RefundModuleGasDescriptor)
LogTxGasConsumed(meter, logger, method)
}
}

28
utils/keys.go Normal file
View File

@ -0,0 +1,28 @@
package utils
import (
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
// cosmos-sdk crypto/keyring/record.go:138
func extractPrivKeyFromLocal(rl *keyring.Record_Local) (cryptotypes.PrivKey, error) {
if rl.PrivKey == nil {
return nil, keyring.ErrPrivKeyNotAvailable
}
priv, ok := rl.PrivKey.GetCachedValue().(cryptotypes.PrivKey)
if !ok {
return nil, errorsmod.Wrap(keyring.ErrCastAny, "PrivKey")
}
return priv, nil
}
func ExtractPrivateKey(kr keyring.Keyring, uid string) (cryptotypes.PrivKey, error) {
ethkr, err := kr.Key(uid)
if err != nil {
return nil, err
}
return extractPrivKeyFromLocal(ethkr.GetLocal())
}

38
utils/modules.go Normal file
View File

@ -0,0 +1,38 @@
package utils
import (
"cosmossdk.io/core/address"
errorsmod "cosmossdk.io/errors"
govtypes "cosmossdk.io/x/gov/types"
"github.com/cosmos/cosmos-sdk/types"
sdk "github.com/cosmos/cosmos-sdk/types"
addresstypes "github.com/cosmos/cosmos-sdk/types/address"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AddressOrModuleAddress returns with this precedence:
// - the preferred address if it is valid, or
// - a module address with the preferred name, or
// - a module address with the alt name
func AddressOrModuleAddress(preferred, alt string) types.AccAddress {
if preferred != "" {
addrCodec := NewAddressCodec()
if addr, err := addrCodec.StringToBytes(preferred); err == nil {
return addr
}
return addresstypes.Module(preferred)
}
return addresstypes.Module(alt)
}
func CheckAuthorityAddress(ac address.Codec, expected sdk.AccAddress, msgaddr string) error {
authority, err := ac.StringToBytes(msgaddr)
if err != nil {
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msgaddr)
}
if !expected.Equals(types.AccAddress(authority)) {
return errorsmod.Wrapf(govtypes.ErrInvalidSigner,
"invalid authority; expected %s, got %s", MustBytesToString(ac, expected), msgaddr)
}
return nil
}

View File

@ -2,17 +2,33 @@ package utils
import (
"github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/statechannels/go-nitro/crypto"
)
func DecodeEthereumAddress(message []byte, sig string) (string, error) {
func DecodeEthereumAddress(message []byte, sig string) (common.Address, error) {
if len(sig) > 2 && sig[:2] == "0x" {
sig = sig[2:]
}
signature := crypto.SplitSignature(common.Hex2Bytes(sig))
ethereumAddress, err := crypto.RecoverEthereumMessageSigner(message, signature)
return ethereumAddress.String(), err
return crypto.RecoverEthMessageSignerAddress(message, signature)
}
func DecodeEthereumPubKey(message []byte, sig string) ([]byte, error) {
if len(sig) > 2 && sig[:2] == "0x" {
sig = sig[2:]
}
signature := crypto.SplitSignature(common.Hex2Bytes(sig))
return crypto.RecoverEthMessageSignerPubKey(message, signature)
}
func EthAddressFromPubKey(pubkey []byte) (common.Address, error) {
ecdsaPubKey, err := ethcrypto.UnmarshalPubkey(pubkey)
if err != nil {
return common.Address{}, err
}
return ethcrypto.PubkeyToAddress(*ecdsaPubKey), nil
}

Some files were not shown because too many files have changed in this diff Show More