WIP: Nitro integration #76
21
Dockerfile
21
Dockerfile
@ -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,24 @@ COPY . .
|
||||
RUN make build
|
||||
|
||||
# Final image
|
||||
FROM ubuntu:22.04
|
||||
# DEV golang image
|
||||
FROM golang:1.23.6-bookworm AS base
|
||||
|
||||
# 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 bc \
|
||||
jq curl netcat-openbsd bash bc yq \
|
||||
&& 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"]
|
||||
|
||||
21
Makefile
21
Makefile
@ -12,7 +12,7 @@ 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 +31,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 +42,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) ./cmd/laconicd
|
||||
|
||||
$(BUILDDIR)/:
|
||||
@ -56,22 +56,23 @@ all: install
|
||||
### Protobuf ###
|
||||
##################
|
||||
|
||||
protoVer=0.14.0
|
||||
protoVer=0.17.1
|
||||
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
|
||||
|
||||
proto-gen:
|
||||
@echo "Generating protobuf files..."
|
||||
@$(protoImage) sh ./scripts/protocgen.sh
|
||||
@$(protoRun) sh ./scripts/protocgen.sh
|
||||
@go mod tidy
|
||||
|
||||
proto-format:
|
||||
@$(protoImage) find ./ -name "*.proto" -exec clang-format -i {} \;
|
||||
@$(protoRun) find ./ -name "*.proto" -exec clang-format -i {} \;
|
||||
|
||||
proto-lint:
|
||||
@$(protoImage) buf lint proto/ --error-format=json
|
||||
@$(protoRun) buf lint proto/ --error-format=json
|
||||
|
||||
.PHONY: proto-all proto-gen proto-format proto-lint
|
||||
|
||||
@ -106,3 +107,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 -v
|
||||
|
||||
@ -37,8 +37,8 @@ Run tests:
|
||||
# integration tests
|
||||
make test-integration
|
||||
|
||||
# e2e tests
|
||||
make test-e2e
|
||||
# system tests
|
||||
make test-system
|
||||
```
|
||||
|
||||
## Community
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -3037,7 +3037,7 @@ var file_cerc_onboarding_v1_query_proto_rawDesc = []byte{
|
||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x6f, 0x6e, 0x62,
|
||||
0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69,
|
||||
0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70,
|
||||
0x61, 0x6e, 0x74, 0x32, 0xba, 0x04, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x95, 0x01,
|
||||
0x61, 0x6e, 0x74, 0x32, 0xc3, 0x04, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x95, 0x01,
|
||||
0x0a, 0x0c, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2c,
|
||||
0x2e, 0x63, 0x65, 0x72, 0x63, 0x2e, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69,
|
||||
@ -3059,7 +3059,7 @@ var file_cerc_onboarding_v1_query_proto_rawDesc = []byte{
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f, 0x63,
|
||||
0x65, 0x72, 0x63, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x76,
|
||||
0x31, 0x2f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x2f, 0x7b,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0xd5, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0xde, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74,
|
||||
0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x42, 0x79, 0x4e, 0x69, 0x74,
|
||||
0x72, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3c, 0x2e, 0x63, 0x65, 0x72, 0x63,
|
||||
0x2e, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x51,
|
||||
@ -3069,24 +3069,25 @@ var file_cerc_onboarding_v1_query_proto_rawDesc = []byte{
|
||||
0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65,
|
||||
0x72, 0x79, 0x47, 0x65, 0x74, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74,
|
||||
0x42, 0x79, 0x4e, 0x69, 0x74, 0x72, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x12, 0x30,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3b, 0x12, 0x39,
|
||||
0x2f, 0x63, 0x65, 0x72, 0x63, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
|
||||
0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73,
|
||||
0x2f, 0x7b, 0x6e, 0x69, 0x74, 0x72, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d,
|
||||
0x42, 0xcf, 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, 0x0a, 0x51, 0x75, 0x65,
|
||||
0x72, 0x79, 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,
|
||||
0x2d, 0x62, 0x79, 0x2d, 0x6e, 0x69, 0x74, 0x72, 0x6f, 0x2f, 0x7b, 0x6e, 0x69, 0x74, 0x72, 0x6f,
|
||||
0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x42, 0xcf, 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, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 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 (
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
180
app/abci.go
Normal file
180
app/abci.go
Normal file
@ -0,0 +1,180 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
abci "github.com/cometbft/cometbft/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server/distsig"
|
||||
)
|
||||
|
||||
type (
|
||||
// VoteExtensionHandler defines the vote extension handler for LaconicApp.
|
||||
VoteExtensionHandler struct {
|
||||
app *LaconicApp
|
||||
}
|
||||
|
||||
// VoteExtension defines the structure used to create a vote extension.
|
||||
VoteExtension struct {
|
||||
Hash []byte
|
||||
Height int64
|
||||
Data []byte
|
||||
}
|
||||
)
|
||||
|
||||
func NewVoteExtensionHandler() *VoteExtensionHandler {
|
||||
return &VoteExtensionHandler{}
|
||||
}
|
||||
|
||||
func (app *LaconicApp) NewVoteExtensionHandler() *VoteExtensionHandler {
|
||||
return &VoteExtensionHandler{app: app}
|
||||
}
|
||||
|
||||
func (h *VoteExtensionHandler) SetHandlers(bApp *baseapp.BaseApp) {
|
||||
if h.app != nil {
|
||||
// Use the real laconic handlers when app is available
|
||||
bApp.SetExtendVoteHandler(h.ExtendVoteWithLaconic())
|
||||
bApp.SetVerifyVoteExtensionHandler(h.VerifyVoteExtensionWithLaconic())
|
||||
bApp.SetPrepareProposal(h.PrepareProposal())
|
||||
bApp.SetProcessProposal(h.ProcessProposal())
|
||||
} else {
|
||||
// Use dummy handlers for testing
|
||||
bApp.SetExtendVoteHandler(h.ExtendVote())
|
||||
bApp.SetVerifyVoteExtensionHandler(h.VerifyVoteExtension())
|
||||
}
|
||||
}
|
||||
|
||||
func (h *VoteExtensionHandler) ExtendVote() sdk.ExtendVoteHandler {
|
||||
return func(_ sdk.Context, req *abci.RequestExtendVote) (*abci.ResponseExtendVote, error) {
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
_, err := rand.Read(buf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate random vote extension data: %w", err)
|
||||
}
|
||||
|
||||
ve := VoteExtension{
|
||||
Hash: req.Hash,
|
||||
Height: req.Height,
|
||||
Data: buf,
|
||||
}
|
||||
|
||||
bz, err := json.Marshal(ve)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encode vote extension: %w", err)
|
||||
}
|
||||
|
||||
return &abci.ResponseExtendVote{VoteExtension: bz}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (h *VoteExtensionHandler) VerifyVoteExtension() sdk.VerifyVoteExtensionHandler {
|
||||
return func(ctx sdk.Context, req *abci.RequestVerifyVoteExtension) (*abci.ResponseVerifyVoteExtension, error) {
|
||||
var ve VoteExtension
|
||||
|
||||
if err := json.Unmarshal(req.VoteExtension, &ve); err != nil {
|
||||
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_REJECT}, nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case req.Height != ve.Height:
|
||||
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_REJECT}, nil
|
||||
|
||||
case !bytes.Equal(req.Hash, ve.Hash):
|
||||
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_REJECT}, nil
|
||||
|
||||
case len(ve.Data) != 1024:
|
||||
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_REJECT}, nil
|
||||
}
|
||||
|
||||
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_ACCEPT}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareProposal is responsible for:
|
||||
// - collecting Nitro state updates and applying them as inserted transactions in the block proposal
|
||||
func (h *VoteExtensionHandler) PrepareProposal() sdk.PrepareProposalHandler {
|
||||
return func(ctx sdk.Context, req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) {
|
||||
|
||||
// paramsResp, err := h.app.ConsensusParamsKeeper.Params(ctx, &consensustypes.QueryParamsRequest{})
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// var maxBlockGas uint64
|
||||
// if b := paramsResp.GetParams().Block; b != nil {
|
||||
// maxBlockGas = uint64(b.MaxGas)
|
||||
// }
|
||||
|
||||
// Decode transactions from bytes
|
||||
txs := make([]sdk.Tx, 0, len(req.Txs))
|
||||
for _, txBz := range req.Txs {
|
||||
tx, err := h.app.txConfig.TxDecoder()(txBz)
|
||||
if err != nil {
|
||||
continue // Skip invalid transactions
|
||||
}
|
||||
txs = append(txs, tx)
|
||||
}
|
||||
|
||||
// For now, just return the transactions as-is
|
||||
// TODO: Add custom transaction selection logic here
|
||||
return &abci.ResponsePrepareProposal{Txs: req.Txs}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (h *VoteExtensionHandler) ProcessProposal() sdk.ProcessProposalHandler {
|
||||
return func(ctx sdk.Context, req *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) {
|
||||
// For now, accept all proposals
|
||||
// TODO: Add custom proposal validation logic here
|
||||
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExtendVoteWithLaconic implements the real Laconic-specific vote extension logic
|
||||
// - renews distsig key (DKG) if validator set has changed
|
||||
// - broadcasts prepared DKG and distsig messages
|
||||
func (h *VoteExtensionHandler) ExtendVoteWithLaconic() sdk.ExtendVoteHandler {
|
||||
return func(ctx sdk.Context, req *abci.RequestExtendVote) (*abci.ResponseExtendVote, error) {
|
||||
// Check if we have a distributed signature manager
|
||||
// Since we can't access DistSigManager() directly in v1, we'll implement a simpler version
|
||||
// TODO: Integrate with actual distributed signature manager when available
|
||||
|
||||
// Check if we are a participant
|
||||
if h.app.OnboardingKeeper != nil {
|
||||
// For now, return empty vote extension
|
||||
// TODO: Implement the full distsig logic here
|
||||
return &abci.ResponseExtendVote{VoteExtension: []byte{}}, nil
|
||||
}
|
||||
|
||||
return &abci.ResponseExtendVote{VoteExtension: []byte{}}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// VerifyVoteExtensionWithLaconic implements the real Laconic-specific vote extension verification
|
||||
func (h *VoteExtensionHandler) VerifyVoteExtensionWithLaconic() sdk.VerifyVoteExtensionHandler {
|
||||
return func(ctx sdk.Context, req *abci.RequestVerifyVoteExtension) (*abci.ResponseVerifyVoteExtension, error) {
|
||||
if len(req.VoteExtension) == 0 {
|
||||
// Empty vote extension is acceptable
|
||||
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_ACCEPT}, nil
|
||||
}
|
||||
|
||||
// Decode and verify the vote extension
|
||||
dec := gob.NewDecoder(bytes.NewReader(req.VoteExtension))
|
||||
var messages distsig.PeerMessages
|
||||
if err := dec.Decode(&messages); err != nil {
|
||||
// If we can't decode, reject
|
||||
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_REJECT}, nil
|
||||
}
|
||||
|
||||
// TODO: Actually verify the messages with the distributed signature manager
|
||||
// For now, just accept
|
||||
return &abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_ACCEPT}, nil
|
||||
}
|
||||
}
|
||||
158
app/app.go
158
app/app.go
@ -3,22 +3,15 @@ package app
|
||||
import (
|
||||
_ "embed"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
|
||||
"cosmossdk.io/core/appconfig"
|
||||
clienthelpers "cosmossdk.io/client/v2/helpers"
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
evidencekeeper "cosmossdk.io/x/evidence/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"
|
||||
types "git.vdb.to/cerc-io/laconicd/x/types/v1"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
@ -35,41 +28,40 @@ import (
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
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"
|
||||
protocolpoolkeeper "github.com/cosmos/cosmos-sdk/x/protocolpool/keeper"
|
||||
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/x/evidence" // import for side-effects
|
||||
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/nitro/keeper"
|
||||
onboardingkeeper "git.vdb.to/cerc-io/laconicd/x/onboarding/keeper"
|
||||
registrykeeper "git.vdb.to/cerc-io/laconicd/x/registry/keeper"
|
||||
types "git.vdb.to/cerc-io/laconicd/x/types/v1"
|
||||
|
||||
_ "cosmossdk.io/api/cosmos/tx/config/v1" // import for side-effects
|
||||
_ "cosmossdk.io/x/evidence" // 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/distribution" // import for side-effects
|
||||
_ "github.com/cosmos/cosmos-sdk/x/mint" // import for side-effects
|
||||
_ "github.com/cosmos/cosmos-sdk/x/protocolpool" // 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/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/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
|
||||
)
|
||||
|
||||
// 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)
|
||||
@ -85,52 +77,36 @@ type LaconicApp struct {
|
||||
txConfig client.TxConfig
|
||||
interfaceRegistry codectypes.InterfaceRegistry
|
||||
|
||||
// keepers
|
||||
// essential keepers
|
||||
AccountKeeper authkeeper.AccountKeeper
|
||||
BankKeeper bankkeeper.Keeper
|
||||
BankKeeper bankkeeper.BaseKeeper
|
||||
StakingKeeper *stakingkeeper.Keeper
|
||||
SlashingKeeper slashingkeeper.Keeper
|
||||
DistrKeeper distrkeeper.Keeper
|
||||
GovKeeper *govkeeper.Keeper
|
||||
CrisisKeeper *crisiskeeper.Keeper
|
||||
ConsensusParamsKeeper consensuskeeper.Keeper
|
||||
EvidenceKeeper evidencekeeper.Keeper
|
||||
|
||||
// supplementary keepers
|
||||
ProtocolPoolKeeper protocolpoolkeeper.Keeper
|
||||
|
||||
// laconic keepers
|
||||
AuctionKeeper *auctionkeeper.Keeper // (Use * as per ProvideModule implementation)
|
||||
AuctionKeeper *auctionkeeper.Keeper
|
||||
BondKeeper *bondkeeper.Keeper
|
||||
RegistryKeeper registrykeeper.Keeper
|
||||
OnboardingKeeper *onboardingkeeper.Keeper
|
||||
NitroKeeper nitrokeeper.Keeper
|
||||
|
||||
// simulation manager
|
||||
sm *module.SimulationManager
|
||||
}
|
||||
|
||||
func init() {
|
||||
userHomeDir, err := os.UserHomeDir()
|
||||
var err error
|
||||
DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory(".laconicd")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
DefaultNodeHome = filepath.Join(userHomeDir, ".laconicd")
|
||||
}
|
||||
|
||||
// AppConfig returns the default app config.
|
||||
func AppConfig() depinject.Config {
|
||||
return depinject.Configs(
|
||||
appconfig.LoadYAML(AppConfigYAML),
|
||||
depinject.Supply(
|
||||
// supply custom module basics
|
||||
map[string]module.AppModuleBasic{
|
||||
genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
|
||||
govtypes.ModuleName: gov.NewAppModuleBasic(
|
||||
[]govclient.ProposalHandler{
|
||||
paramsclient.ProposalHandler,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// NewLaconicApp returns a reference to an initialized LaconicApp.
|
||||
@ -145,16 +121,20 @@ func NewLaconicApp(
|
||||
var (
|
||||
app = &LaconicApp{}
|
||||
appBuilder *runtime.AppBuilder
|
||||
)
|
||||
|
||||
if err := depinject.Inject(
|
||||
depinject.Configs(
|
||||
AppConfig(),
|
||||
appConfig = depinject.Configs(
|
||||
AppModuleConfig,
|
||||
depinject.Supply(
|
||||
logger,
|
||||
appOpts,
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
// if err := depinject.Inject(appConfig,
|
||||
if err := depinject.InjectDebug(
|
||||
depinject.FileLogger("/Users/roy/vulcanize/dump/laconic-debug/depinject_app.log"),
|
||||
appConfig,
|
||||
&appBuilder,
|
||||
&app.appCodec,
|
||||
&app.legacyAmino,
|
||||
@ -166,13 +146,14 @@ func NewLaconicApp(
|
||||
&app.SlashingKeeper,
|
||||
&app.DistrKeeper,
|
||||
&app.GovKeeper,
|
||||
&app.CrisisKeeper,
|
||||
&app.ConsensusParamsKeeper,
|
||||
&app.EvidenceKeeper,
|
||||
&app.ProtocolPoolKeeper,
|
||||
&app.AuctionKeeper,
|
||||
&app.BondKeeper,
|
||||
&app.RegistryKeeper,
|
||||
&app.OnboardingKeeper,
|
||||
&app.NitroKeeper,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -181,6 +162,13 @@ func NewLaconicApp(
|
||||
RegisterCustomInterfaces(app.interfaceRegistry)
|
||||
RegisterCustomLegacyAminoCodec(app.legacyAmino)
|
||||
|
||||
// create and set vote extension handler
|
||||
voteExtOp := func(bApp *baseapp.BaseApp) {
|
||||
voteExtHandler := app.NewVoteExtensionHandler()
|
||||
voteExtHandler.SetHandlers(bApp)
|
||||
}
|
||||
baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution())
|
||||
|
||||
app.App = appBuilder.Build(db, traceStore, baseAppOptions...)
|
||||
|
||||
// register streaming services
|
||||
@ -190,15 +178,13 @@ func NewLaconicApp(
|
||||
|
||||
/**** 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()
|
||||
|
||||
// set custom ante handlers
|
||||
app.setCustomAnteHandler()
|
||||
// set custom ante handler
|
||||
app.setAnteHandler()
|
||||
|
||||
if err := app.Load(loadLatest); err != nil {
|
||||
return nil, err
|
||||
@ -207,12 +193,56 @@ func NewLaconicApp(
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// setCustomAnteHandler overwrites default ante handlers with custom ante handlers
|
||||
// Reference: https://github.com/cosmos/cosmos-sdk/blob/v0.50.10/x/auth/tx/config/config.go#L149
|
||||
func (app *LaconicApp) setAnteHandler() error {
|
||||
anteHandler, err := ante.NewAnteHandler(
|
||||
ante.HandlerOptions{
|
||||
AccountKeeper: app.AccountKeeper,
|
||||
BankKeeper: app.BankKeeper,
|
||||
SignModeHandler: app.txConfig.SignModeHandler(),
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
TxFeeChecker: checkTxFeeWithValidatorMinGasPrices,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the AnteHandler for the app
|
||||
app.SetAnteHandler(anteHandler)
|
||||
return nil
|
||||
}
|
||||
|
||||
// LegacyAmino returns LaconicApp's amino codec.
|
||||
//
|
||||
// NOTE: This is solely to be used for testing purposes as it may be desirable
|
||||
// for modules to register their own custom testing types.
|
||||
func (app *LaconicApp) LegacyAmino() *codec.LegacyAmino {
|
||||
return app.legacyAmino
|
||||
}
|
||||
|
||||
// AppCodec returns LaconicApp's app codec.
|
||||
//
|
||||
// NOTE: This is solely to be used for testing purposes as it may be desirable
|
||||
// for modules to register their own custom testing types.
|
||||
func (app *LaconicApp) AppCodec() codec.Codec {
|
||||
return app.appCodec
|
||||
}
|
||||
|
||||
// InterfaceRegistry returns LaconicApp's InterfaceRegistry.
|
||||
func (app *LaconicApp) InterfaceRegistry() codectypes.InterfaceRegistry {
|
||||
return app.interfaceRegistry
|
||||
}
|
||||
|
||||
// TxConfig returns LaconicApp's TxConfig
|
||||
func (app *LaconicApp) TxConfig() client.TxConfig {
|
||||
return app.txConfig
|
||||
}
|
||||
|
||||
// GetKey returns the KVStoreKey for the provided store key.
|
||||
//
|
||||
// NOTE: This is solely to be used for testing purposes.
|
||||
func (app *LaconicApp) GetKey(storeKey string) *storetypes.KVStoreKey {
|
||||
sk := app.UnsafeFindStoreKey(storeKey)
|
||||
kvStoreKey, ok := sk.(*storetypes.KVStoreKey)
|
||||
|
||||
41
app/app.yaml
41
app/app.yaml
@ -6,14 +6,35 @@ modules:
|
||||
# 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, evidence, staking]
|
||||
end_blockers: [crisis, gov, staking, auction, registry]
|
||||
begin_blockers: [distribution, protocolpool, slashing, evidence, 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, evidence, auction, bond, registry, onboarding]
|
||||
init_genesis:
|
||||
- consensus
|
||||
- auth
|
||||
- bank
|
||||
- distribution
|
||||
- staking
|
||||
- slashing
|
||||
- gov
|
||||
- genutil
|
||||
- evidence
|
||||
- protocolpool
|
||||
- auction
|
||||
- bond
|
||||
- registry
|
||||
- onboarding
|
||||
- nitro
|
||||
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 +48,8 @@ modules:
|
||||
permissions: [burner, staking]
|
||||
- account: gov
|
||||
permissions: [burner]
|
||||
- account: protocolpool
|
||||
- account: protocolpool_escrow
|
||||
- account: auction
|
||||
- account: auction_burn
|
||||
- account: bond
|
||||
@ -34,11 +57,12 @@ modules:
|
||||
- account: record_rent
|
||||
- account: authority_rent
|
||||
- account: lps_lockup
|
||||
enable_unordered_transactions: true
|
||||
- name: bank
|
||||
config:
|
||||
"@type": cosmos.bank.module.v1.Module
|
||||
blocked_module_accounts_override:
|
||||
[auth, distribution, bonded_tokens_pool, not_bonded_tokens_pool]
|
||||
[fee_collector, distribution, bonded_tokens_pool, not_bonded_tokens_pool]
|
||||
- name: staking
|
||||
config:
|
||||
"@type": cosmos.staking.module.v1.Module
|
||||
@ -60,12 +84,12 @@ modules:
|
||||
- name: gov
|
||||
config:
|
||||
"@type": cosmos.gov.module.v1.Module
|
||||
- name: crisis
|
||||
config:
|
||||
"@type": cosmos.crisis.module.v1.Module
|
||||
- name: evidence
|
||||
config:
|
||||
"@type": cosmos.evidence.module.v1.Module
|
||||
- name: protocolpool
|
||||
config:
|
||||
"@type": cosmos.protocolpool.module.v1.Module
|
||||
- name: bond
|
||||
config:
|
||||
"@type": cerc.bond.module.v1.Module
|
||||
@ -78,3 +102,6 @@ modules:
|
||||
- name: onboarding
|
||||
config:
|
||||
"@type": cerc.onboarding.module.v1.Module
|
||||
- name: nitro
|
||||
config:
|
||||
"@type": cerc.nitro.module.v1.Module
|
||||
|
||||
50
app/app_test.go
Normal file
50
app/app_test.go
Normal file
@ -0,0 +1,50 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
abci "github.com/cometbft/cometbft/abci/types"
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
)
|
||||
|
||||
func TestLaconicAppExportAndBlockedAccounts(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
logger := log.NewTestLogger(t)
|
||||
app := NewLaconicAppWithCustomOptions(t, false, SetupOptions{
|
||||
Logger: logger.With("instance", "first"),
|
||||
DB: db,
|
||||
AppOpts: simtestutil.NewAppOptionsWithFlagHome(t.TempDir()),
|
||||
})
|
||||
|
||||
// BlockedAddresses returns a map of addresses in app v1 and a map of modules name in app di.
|
||||
for _, acc := range BlockedAccounts() {
|
||||
addr := app.AccountKeeper.GetModuleAddress(acc)
|
||||
|
||||
require.True(
|
||||
t,
|
||||
app.BankKeeper.BlockedAddr(addr),
|
||||
fmt.Sprintf("ensure that blocked addresses are properly set in bank keeper: %s should be blocked", acc),
|
||||
)
|
||||
}
|
||||
|
||||
// finalize block so we have CheckTx state set
|
||||
_, err := app.FinalizeBlock(&abci.RequestFinalizeBlock{
|
||||
Height: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = app.Commit()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Making a new app object with the db, so that initchain hasn't been called
|
||||
app2, err := NewLaconicApp(logger.With("instance", "second"), db, nil, true, simtestutil.NewAppOptionsWithFlagHome(t.TempDir()))
|
||||
require.NoError(t, err)
|
||||
_, err = app2.ExportAppStateAndValidators(false, []string{}, []string{})
|
||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||
}
|
||||
42
app/config.go
Normal file
42
app/config.go
Normal file
@ -0,0 +1,42 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/depinject/appconfig"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"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"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed app.yaml
|
||||
AppModuleConfigYAML []byte
|
||||
|
||||
// AppModuleConfig returns the default app config.
|
||||
AppModuleConfig = depinject.Configs(
|
||||
appconfig.LoadYAML(AppModuleConfigYAML),
|
||||
depinject.Provide(
|
||||
server.NewGasService,
|
||||
),
|
||||
depinject.Supply(
|
||||
utils.NewAddressCodec,
|
||||
utils.NewValidatorAddressCodec,
|
||||
utils.NewConsensusAddressCodec,
|
||||
// supply custom module basics
|
||||
map[string]module.AppModuleBasic{
|
||||
genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
|
||||
govtypes.ModuleName: gov.NewAppModuleBasic(
|
||||
[]govclient.ProposalHandler{},
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
)
|
||||
62
app/config/config.go
Normal file
62
app/config/config.go
Normal file
@ -0,0 +1,62 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app/params"
|
||||
"git.vdb.to/cerc-io/laconicd/server/nitro"
|
||||
"git.vdb.to/cerc-io/laconicd/server/relay"
|
||||
)
|
||||
|
||||
type LaconicAppConfig struct {
|
||||
serverconfig.Config `mapstructure:",squash"`
|
||||
customConfigs `mapstructure:",squash"`
|
||||
}
|
||||
|
||||
// the custom parts of the full config, so we can encode them separately
|
||||
type customConfigs struct {
|
||||
Nitro nitro.Config `mapstructure:"nitro" toml:"nitro"`
|
||||
Relay relay.Config `mapstructure:"relay" toml:"relay"`
|
||||
}
|
||||
|
||||
var DefaultConfigTemplate string
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
DefaultConfigTemplate, err = createConfigTemplate()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultConfig() LaconicAppConfig {
|
||||
srvCfg := serverconfig.DefaultConfig()
|
||||
// In laconicd, we set the min gas prices to 0.
|
||||
srvCfg.MinGasPrices = "0" + params.CoinUnit
|
||||
|
||||
// Now we set the custom config default values.
|
||||
customAppConfig := LaconicAppConfig{
|
||||
*srvCfg,
|
||||
customConfigs{
|
||||
Nitro: *nitro.DefaultConfig(),
|
||||
Relay: *relay.DefaultConfig(),
|
||||
},
|
||||
}
|
||||
return customAppConfig
|
||||
}
|
||||
|
||||
func createConfigTemplate() (string, error) {
|
||||
defaultCustomConfigs := customConfigs{
|
||||
Nitro: *nitro.DefaultConfig(),
|
||||
Relay: *relay.DefaultConfig(),
|
||||
}
|
||||
b, err := toml.Marshal(defaultCustomConfigs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s\n%s", serverconfig.DefaultConfigTemplate, b), nil
|
||||
}
|
||||
@ -2,12 +2,13 @@ package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
|
||||
|
||||
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"
|
||||
@ -15,14 +16,11 @@ import (
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
)
|
||||
|
||||
// ExportAppStateAndValidators exports the state of the application for a genesis file.
|
||||
func (app *LaconicApp) ExportAppStateAndValidators(
|
||||
forZeroHeight bool,
|
||||
jailAllowedAddrs []string,
|
||||
modulesToExport []string,
|
||||
) (servertypes.ExportedApp, error) {
|
||||
// ExportAppStateAndValidators exports the state of the application for a genesis
|
||||
// file.
|
||||
func (app *LaconicApp) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs, 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()})
|
||||
ctx := app.NewContextLegacy(true, cmtproto.Header{Height: app.LastBlockHeight()})
|
||||
|
||||
// We export at last height + 1, because that's the height at which
|
||||
// CometBFT will start InitChain.
|
||||
@ -32,9 +30,9 @@ func (app *LaconicApp) ExportAppStateAndValidators(
|
||||
app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
|
||||
}
|
||||
|
||||
genState, err := app.ModuleManager.ExportGenesis(ctx, app.appCodec)
|
||||
genState, err := app.ModuleManager.ExportGenesisForModules(ctx, app.appCodec, modulesToExport)
|
||||
if err != nil {
|
||||
return servertypes.ExportedApp{}, fmt.Errorf("failed to export genesis state: %w", err)
|
||||
return servertypes.ExportedApp{}, err
|
||||
}
|
||||
|
||||
appState, err := json.MarshalIndent(genState, "", " ")
|
||||
@ -47,19 +45,18 @@ func (app *LaconicApp) ExportAppStateAndValidators(
|
||||
AppState: appState,
|
||||
Validators: validators,
|
||||
Height: height,
|
||||
ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
|
||||
ConsensusParams: app.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
|
||||
// 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
|
||||
applyAllowedAddrs := len(jailAllowedAddrs) > 0
|
||||
|
||||
// check if there is a allowed address list
|
||||
if len(jailAllowedAddrs) > 0 {
|
||||
applyAllowedAddrs = true
|
||||
}
|
||||
|
||||
allowedAddrsMap := make(map[string]bool)
|
||||
|
||||
@ -74,15 +71,17 @@ func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddr
|
||||
/* Handle fee distribution state. */
|
||||
|
||||
// withdraw all validator commission
|
||||
_ = app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
|
||||
err := 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
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// withdraw all delegator rewards
|
||||
dels, err := app.StakingKeeper.GetAllDelegations(ctx)
|
||||
@ -96,10 +95,7 @@ func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddr
|
||||
panic(err)
|
||||
}
|
||||
|
||||
delAddr, err := sdk.AccAddressFromBech32(delegation.DelegatorAddress)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
delAddr := sdk.MustAccAddressFromBech32(delegation.DelegatorAddress)
|
||||
|
||||
_, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr)
|
||||
}
|
||||
@ -115,23 +111,20 @@ func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddr
|
||||
ctx = ctx.WithBlockHeight(0)
|
||||
|
||||
// reinitialize all validators
|
||||
_ = app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
|
||||
err = 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)
|
||||
@ -149,11 +142,7 @@ func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddr
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
delAddr, err := sdk.AccAddressFromBech32(del.DelegatorAddress)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
delAddr := sdk.MustAccAddressFromBech32(del.DelegatorAddress)
|
||||
|
||||
if err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr); err != nil {
|
||||
// never called as BeforeDelegationCreated always returns nil
|
||||
@ -172,36 +161,45 @@ func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddr
|
||||
/* Handle staking state. */
|
||||
|
||||
// iterate through redelegations, reset creation height
|
||||
_ = app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) {
|
||||
err = 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)
|
||||
err = app.StakingKeeper.SetRedelegation(ctx, red)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return false
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error while iterating redelegations: %w", err))
|
||||
}
|
||||
|
||||
// iterate through unbonding delegations, reset creation height
|
||||
_ = app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) {
|
||||
err = 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)
|
||||
err = app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return false
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error while iterating unbonding delegations: %w", err))
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if err != nil {
|
||||
panic("expected validator, not found")
|
||||
} else if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
validator.UnbondingHeight = 0
|
||||
@ -209,8 +207,10 @@ func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddr
|
||||
validator.Jailed = true
|
||||
}
|
||||
|
||||
_ = app.StakingKeeper.SetValidator(ctx, validator)
|
||||
counter++
|
||||
err = app.StakingKeeper.SetValidator(ctx, validator)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unable to set validator: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
@ -232,12 +232,12 @@ func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddr
|
||||
info.StartHeight = 0
|
||||
err = app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
panic("unable to set validator signing info")
|
||||
}
|
||||
return false
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
panic(fmt.Errorf("error while iterating validator signing info: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ var (
|
||||
func init() {
|
||||
SetAddressPrefixes()
|
||||
RegisterDenoms()
|
||||
sdk.DefaultBondDenom = CoinUnit
|
||||
}
|
||||
|
||||
func RegisterDenoms() {
|
||||
|
||||
@ -1,21 +1,18 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/cometbft/cometbft/node"
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
confixcmd "cosmossdk.io/tools/confix/cmd"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"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"
|
||||
@ -25,37 +22,41 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app"
|
||||
"git.vdb.to/cerc-io/laconicd/gql"
|
||||
laconicserver "git.vdb.to/cerc-io/laconicd/server"
|
||||
"git.vdb.to/cerc-io/laconicd/server/nitro"
|
||||
"git.vdb.to/cerc-io/laconicd/server/relay"
|
||||
)
|
||||
|
||||
func initRootCmd(rootCmd *cobra.Command, txConfig client.TxConfig, basicManager module.BasicManager) {
|
||||
func initRootCmd(
|
||||
rootCmd *cobra.Command,
|
||||
txConfig client.TxConfig,
|
||||
basicManager module.BasicManager,
|
||||
) *laconicserver.ServerAux {
|
||||
cfg := sdk.GetConfig()
|
||||
cfg.Seal()
|
||||
|
||||
rootCmd.AddCommand(
|
||||
genutilcli.InitCmd(basicManager, app.DefaultNodeHome),
|
||||
NewTestnetCmd(basicManager, banktypes.GenesisBalancesIterator{}),
|
||||
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
|
||||
addStartComponents := func(startCmd *cobra.Command) {
|
||||
laconicserver.SetRequiredComponents(startCmd, &gql.Server{}, &nitro.Server{}, &relay.Server{})
|
||||
}
|
||||
var srv laconicserver.ServerAux
|
||||
server.AddCommandsWithStartCmdOptions(rootCmd, app.DefaultNodeHome, newApp, appExport, server.StartCmdOptions{
|
||||
AddFlags: addStartComponents,
|
||||
// reactors will be configured at start, after the command is fully initialized
|
||||
CometNodeOptions: []node.Option{srv.AddReactors},
|
||||
})
|
||||
|
||||
// Capture the genesis command from genutilcli and add new commands
|
||||
@ -65,11 +66,60 @@ func initRootCmd(rootCmd *cobra.Command, txConfig client.TxConfig, basicManager
|
||||
// add keybase, auxiliary RPC, query, genesis, and tx child commands
|
||||
rootCmd.AddCommand(
|
||||
server.StatusCommand(),
|
||||
genesisCmd,
|
||||
genesisCommand(txConfig, basicManager),
|
||||
queryCommand(),
|
||||
txCommand(),
|
||||
keys.Commands(),
|
||||
)
|
||||
return &srv
|
||||
}
|
||||
|
||||
// initializes all server components needed by a command
|
||||
func initComponents(
|
||||
configMap laconicserver.ConfigMap,
|
||||
clientCtx client.Context,
|
||||
logger log.Logger,
|
||||
needComponent func(string) bool,
|
||||
) ([]laconicserver.ServerComponent, error) {
|
||||
var (
|
||||
components []laconicserver.ServerComponent
|
||||
gqlServer = &gql.Server{}
|
||||
nitroServer = &nitro.Server{}
|
||||
relayServer = &relay.Server{}
|
||||
err error
|
||||
)
|
||||
if needComponent(gqlServer.Name()) {
|
||||
gqlServer, err = gql.New(clientCtx, configMap, logger.With("module", "gql-server"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
components = append(components, gqlServer)
|
||||
}
|
||||
if needComponent(nitroServer.Name()) {
|
||||
nitroServer, err = nitro.New(configMap, logger, clientCtx.Keyring)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
components = append(components, nitroServer)
|
||||
}
|
||||
if needComponent(relayServer.Name()) {
|
||||
relayServer, err = relay.New(configMap, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
components = append(components, relayServer)
|
||||
}
|
||||
return components, nil
|
||||
}
|
||||
|
||||
// genesisCommand builds genesis-related `laconicd genesis` command. Users may provide application specific commands as a parameter
|
||||
func genesisCommand(txConfig client.TxConfig, basicManager module.BasicManager, cmds ...*cobra.Command) *cobra.Command {
|
||||
cmd := genutilcli.Commands(txConfig, basicManager, app.DefaultNodeHome)
|
||||
|
||||
for _, subCmd := range cmds {
|
||||
cmd.AddCommand(subCmd)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func queryCommand() *cobra.Command {
|
||||
@ -83,7 +133,7 @@ func queryCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
rpc.ValidatorCommand(),
|
||||
rpc.WaitTxCmd(),
|
||||
server.QueryBlockCmd(),
|
||||
authcmd.QueryTxsByEventsCmd(),
|
||||
server.QueryBlocksCmd(),
|
||||
@ -118,18 +168,26 @@ 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 {
|
||||
// newApp creates the application
|
||||
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...)
|
||||
ret, err := app.NewLaconicApp(
|
||||
logger, db, traceStore, true,
|
||||
appOpts,
|
||||
baseappOptions...,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return app
|
||||
return ret
|
||||
}
|
||||
|
||||
// appExport creates a new app (optionally at a given height) and exports state.
|
||||
// appExport creates a new laconicd (optionally at a given height) and exports state.
|
||||
func appExport(
|
||||
logger log.Logger,
|
||||
db dbm.DB,
|
||||
@ -140,18 +198,6 @@ func appExport(
|
||||
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")
|
||||
@ -161,18 +207,17 @@ func appExport(
|
||||
viperAppOpts.Set(server.FlagInvCheckPeriod, 1)
|
||||
appOpts = viperAppOpts
|
||||
|
||||
var laconicApp *app.LaconicApp
|
||||
var err error
|
||||
if height != -1 {
|
||||
laconicApp, err = app.NewLaconicApp(logger, db, traceStore, false, appOpts)
|
||||
if err != nil {
|
||||
if laconicApp, err = app.NewLaconicApp(logger, db, traceStore, false, appOpts); err != nil {
|
||||
return servertypes.ExportedApp{}, err
|
||||
}
|
||||
|
||||
if err := laconicApp.LoadHeight(height); err != nil {
|
||||
if err = laconicApp.LoadHeight(height); err != nil {
|
||||
return servertypes.ExportedApp{}, err
|
||||
}
|
||||
} else {
|
||||
laconicApp, err = app.NewLaconicApp(logger, db, traceStore, true, appOpts)
|
||||
if err != nil {
|
||||
if laconicApp, err = app.NewLaconicApp(logger, db, traceStore, true, appOpts); err != nil {
|
||||
return servertypes.ExportedApp{}, err
|
||||
}
|
||||
}
|
||||
|
||||
36
cmd/laconicd/cmd/config.go
Normal file
36
cmd/laconicd/cmd/config.go
Normal file
@ -0,0 +1,36 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
cmtcfg "github.com/cometbft/cometbft/config"
|
||||
)
|
||||
|
||||
// initCometBFTConfig helps to override default CometBFT config values.
|
||||
func initCometBFTConfig() *cmtcfg.Config {
|
||||
cfg := cmtcfg.DefaultConfig()
|
||||
|
||||
// display only warn logs by default for builtin modules except server, p2p, state
|
||||
cfg.LogLevel = "*:warn,server:info,p2p:info,state:info"
|
||||
cfg.LogLevel += ",auction:info,bond:info,registry:info,gql-server:info"
|
||||
|
||||
// // TODO: understand full meaning of these settings
|
||||
cfg.Consensus.TimeoutPropose = 5000 * time.Millisecond
|
||||
// cfg.Consensus.TimeoutProposeDelta = 500 * time.Millisecond
|
||||
// cfg.Consensus.TimeoutPrevote = 1000 * time.Millisecond
|
||||
// cfg.Consensus.TimeoutPrevoteDelta = 500 * time.Millisecond
|
||||
// cfg.Consensus.TimeoutPrecommit = 1000 * time.Millisecond
|
||||
// cfg.Consensus.TimeoutPrecommitDelta = 500 * time.Millisecond
|
||||
|
||||
// // start new block as soon as 2/3 precommits are received
|
||||
// cfg.Consensus.TimeoutCommit = 0 * time.Second
|
||||
|
||||
cfg.Consensus.CreateEmptyBlocks = false
|
||||
|
||||
// overwrite default pprof listen address
|
||||
cfg.RPC.PprofListenAddress = "localhost:6060"
|
||||
// use previous db backend
|
||||
cfg.DBBackend = "goleveldb"
|
||||
|
||||
return cfg
|
||||
}
|
||||
87
cmd/laconicd/cmd/log.go
Normal file
87
cmd/laconicd/cmd/log.go
Normal file
@ -0,0 +1,87 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
sdk_slog "cosmossdk.io/log/slog"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/lmittmann/tint"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
)
|
||||
|
||||
func createSlogLogger(cfg server.ConfigMap, out io.Writer) (log.Logger, error) {
|
||||
handler, err := createSlogHandler(cfg, out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sdk_slog.NewCustomLogger(slog.New(handler)), nil
|
||||
}
|
||||
|
||||
func createSlogHandler(cfg server.ConfigMap, out io.Writer) (slog.Handler, error) {
|
||||
var (
|
||||
format string
|
||||
noColor bool
|
||||
level string
|
||||
)
|
||||
if v, ok := cfg[flags.FlagLogFormat]; ok {
|
||||
format = v.(string)
|
||||
}
|
||||
if v, ok := cfg[flags.FlagLogNoColor]; ok {
|
||||
noColor = v.(bool)
|
||||
}
|
||||
if v, ok := cfg[flags.FlagLogLevel]; ok {
|
||||
level = v.(string)
|
||||
}
|
||||
|
||||
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.ParseLogLevelWithParser(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 == flags.OutputFormatJSON {
|
||||
handler = slog.NewJSONHandler(out, &slog.HandlerOptions{
|
||||
Level: logLvl,
|
||||
})
|
||||
} else {
|
||||
handler = tint.NewHandler(out, &tint.Options{
|
||||
Level: logLvl,
|
||||
TimeFormat: time.RFC3339Nano,
|
||||
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)
|
||||
}
|
||||
@ -1,26 +1,23 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
cmtcfg "github.com/cometbft/cometbft/config"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
|
||||
"cosmossdk.io/client/v2/autocli"
|
||||
clientv2keyring "cosmossdk.io/client/v2/autocli/keyring"
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/config"
|
||||
clientconfig "github.com/cosmos/cosmos-sdk/client/config"
|
||||
nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
|
||||
"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"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
@ -28,16 +25,19 @@ import (
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app"
|
||||
"git.vdb.to/cerc-io/laconicd/app/params"
|
||||
"git.vdb.to/cerc-io/laconicd/gql"
|
||||
types "git.vdb.to/cerc-io/laconicd/x/types/v1"
|
||||
appconfig "git.vdb.to/cerc-io/laconicd/app/config"
|
||||
)
|
||||
|
||||
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 {
|
||||
// DefaultNodeHome is the default data directory name for the application
|
||||
DefaultNodeHome = ".laconicd"
|
||||
)
|
||||
|
||||
// NewRootCmd creates a new root command for laconicd. It is called once in the main function.
|
||||
func NewRootCmd(args ...string) (*cobra.Command, error) {
|
||||
var (
|
||||
txConfigOpts tx.ConfigOptions
|
||||
autoCliOpts autocli.AppOptions
|
||||
@ -46,13 +46,12 @@ func NewRootCmd() *cobra.Command {
|
||||
)
|
||||
|
||||
if err := depinject.Inject(
|
||||
depinject.Configs(app.AppConfig(),
|
||||
depinject.Configs(app.AppModuleConfig,
|
||||
depinject.Supply(
|
||||
log.NewNopLogger(),
|
||||
),
|
||||
depinject.Provide(
|
||||
ProvideClientContext,
|
||||
ProvideKeyring,
|
||||
),
|
||||
),
|
||||
&txConfigOpts,
|
||||
@ -60,68 +59,34 @@ func NewRootCmd() *cobra.Command {
|
||||
&moduleBasicManager,
|
||||
&clientCtx,
|
||||
); err != nil {
|
||||
panic(err)
|
||||
return nil, 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", params.CoinUnit)
|
||||
|
||||
// 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)
|
||||
},
|
||||
Use: "laconicd",
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true, // prevent usage printing on every error
|
||||
PersistentPreRunE: RootCommandPersistentPreRun(clientCtx, txConfigOpts),
|
||||
}
|
||||
|
||||
initRootCmd(rootCmd, clientCtx.TxConfig, moduleBasicManager)
|
||||
initCtx := initRootCmd(rootCmd, clientCtx.TxConfig, moduleBasicManager)
|
||||
|
||||
nodeCmds := nodeservice.NewNodeCommands()
|
||||
autoCliOpts.ModuleOptions = make(map[string]*autocliv1.ModuleOptions)
|
||||
autoCliOpts.ModuleOptions[nodeCmds.Name()] = nodeCmds.AutoCLIOptions()
|
||||
|
||||
if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
rootCmd.SetArgs(args)
|
||||
|
||||
// Add flags for GQL server.
|
||||
rootCmd = gql.AddGQLFlags(rootCmd)
|
||||
|
||||
return rootCmd
|
||||
// now enhance the subcommand
|
||||
subCmd, _, err := rootCmd.Find(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
initCtx.AddComponents(subCmd, initComponents)
|
||||
return rootCmd, nil
|
||||
}
|
||||
|
||||
func ProvideClientContext(
|
||||
@ -141,7 +106,7 @@ func ProvideClientContext(
|
||||
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)
|
||||
clientCtx, _ = clientconfig.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
|
||||
@ -149,9 +114,10 @@ func ProvideClientContext(
|
||||
clientCtx.HomeDir = ""
|
||||
clientCtx.KeyringDir = ""
|
||||
|
||||
// XXX TODO fix after rebase
|
||||
// Custom LockupAccount type needs to be registered
|
||||
interfaceRegistry.RegisterImplementations((*types.LockupAccountI)(nil), &types.LockupAccount{})
|
||||
interfaceRegistry.RegisterImplementations((*authtypes.GenesisAccount)(nil), &types.LockupAccount{})
|
||||
// interfaceRegistry.RegisterImplementations((*types.LockupAccountI)(nil), &types.LockupAccount{})
|
||||
// interfaceRegistry.RegisterImplementations((*authtypes.GenesisAccount)(nil), &types.LockupAccount{})
|
||||
|
||||
return clientCtx
|
||||
}
|
||||
@ -164,3 +130,61 @@ func ProvideKeyring(clientCtx client.Context, addressCodec address.Codec) (clien
|
||||
|
||||
return keyring.NewAutoCLIKeyring(kb)
|
||||
}
|
||||
|
||||
func RootCommandPersistentPreRun(
|
||||
clientCtx client.Context,
|
||||
txConfigOpts tx.ConfigOptions,
|
||||
) func(*cobra.Command, []string) error {
|
||||
return 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("")
|
||||
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientCtx, err = clientconfig.ReadFromClientConfig(clientCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This needs to go after ReadFromClientConfig, as that function
|
||||
// sets the RPC client needed for SIGN_MODE_TEXTUAL. This sign mode
|
||||
// is only available if the client is online.
|
||||
if !clientCtx.Offline {
|
||||
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
|
||||
}
|
||||
|
||||
appConfig := appconfig.DefaultConfig()
|
||||
cmtConfig := initCometBFTConfig()
|
||||
|
||||
serverCtx, err := server.InterceptConfigsAndCreateContext(
|
||||
cmd, appconfig.DefaultConfigTemplate, appConfig, cmtConfig,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// use slog-based logger to combine with nitro logs
|
||||
logger, err := createSlogLogger(serverCtx.Viper.AllSettings(), cmd.OutOrStdout())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serverCtx.Logger = logger.With(log.ModuleKey, "server")
|
||||
|
||||
return server.SetCmdServerContext(cmd, serverCtx)
|
||||
}
|
||||
}
|
||||
|
||||
67
cmd/laconicd/cmd/root_test.go
Normal file
67
cmd/laconicd/cmd/root_test.go
Normal file
@ -0,0 +1,67 @@
|
||||
package cmd_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, err := cmd.NewRootCmd()
|
||||
require.NoError(t, err)
|
||||
rootCmd.SetArgs([]string{
|
||||
"init", // Test the init cmd
|
||||
"simapp-test", // Moniker
|
||||
fmt.Sprintf("--%s=%s", cli.FlagOverwrite, "true"), // Overwrite genesis.json, in case it already exists
|
||||
})
|
||||
|
||||
require.NoError(t, svrcmd.Execute(rootCmd, "", app.DefaultNodeHome))
|
||||
}
|
||||
|
||||
func TestHomeFlagRegistration(t *testing.T) {
|
||||
homeDir := "/tmp/foo"
|
||||
|
||||
rootCmd, err := cmd.NewRootCmd()
|
||||
require.NoError(t, err)
|
||||
rootCmd.SetArgs([]string{
|
||||
"query",
|
||||
fmt.Sprintf("--%s", flags.FlagHome),
|
||||
homeDir,
|
||||
})
|
||||
|
||||
require.NoError(t, svrcmd.Execute(rootCmd, "", app.DefaultNodeHome))
|
||||
|
||||
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(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:")
|
||||
}
|
||||
}
|
||||
598
cmd/laconicd/cmd/testnet.go
Normal file
598
cmd/laconicd/cmd/testnet.go
Normal file
@ -0,0 +1,598 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
cmtcfg "github.com/cometbft/cometbft/config"
|
||||
cmtconfig "github.com/cometbft/cometbft/config"
|
||||
cmttime "github.com/cometbft/cometbft/types/time"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
"cosmossdk.io/math/unsafe"
|
||||
|
||||
"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/server"
|
||||
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
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"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app"
|
||||
appconfig "git.vdb.to/cerc-io/laconicd/app/config"
|
||||
)
|
||||
|
||||
var (
|
||||
flagNodeDirPrefix = "node-dir-prefix"
|
||||
flagNumValidators = "validator-count"
|
||||
flagOutputDir = "output-dir"
|
||||
flagNodeDaemonHome = "node-daemon-home"
|
||||
flagStartingIPAddress = "starting-ip-address"
|
||||
flagListenIPAddress = "listen-ip-address"
|
||||
flagEnableLogging = "enable-logging"
|
||||
flagGRPCAddress = "grpc.address"
|
||||
flagRPCAddress = "rpc.address"
|
||||
flagAPIAddress = "api.address"
|
||||
flagPrintMnemonic = "print-mnemonic"
|
||||
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
|
||||
}
|
||||
|
||||
type startArgs struct {
|
||||
algo string
|
||||
apiAddress string
|
||||
chainID string
|
||||
enableLogging bool
|
||||
grpcAddress string
|
||||
minGasPrices string
|
||||
numValidators int
|
||||
outputDir string
|
||||
printMnemonic bool
|
||||
rpcAddress string
|
||||
timeoutCommit time.Duration
|
||||
}
|
||||
|
||||
func addTestnetFlagsToCmd(cmd *cobra.Command) {
|
||||
cmd.Flags().IntP(flagNumValidators, "v", 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(server.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")
|
||||
|
||||
// support old flags name for backwards compatibility
|
||||
cmd.Flags().SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
if name == flags.FlagKeyAlgorithm {
|
||||
name = flags.FlagKeyType
|
||||
}
|
||||
|
||||
return pflag.NormalizedName(name)
|
||||
})
|
||||
}
|
||||
|
||||
// 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(mm module.BasicManager, genBalIterator banktypes.GenesisBalancesIterator) *cobra.Command {
|
||||
testnetCmd := &cobra.Command{
|
||||
Use: "testnet",
|
||||
Short: "subcommands for starting or configuring local testnets",
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
}
|
||||
|
||||
testnetCmd.AddCommand(testnetStartCmd())
|
||||
testnetCmd.AddCommand(testnetInitFilesCmd(mm, genBalIterator))
|
||||
|
||||
return testnetCmd
|
||||
}
|
||||
|
||||
// testnetInitFilesCmd returns a cmd to initialize all files for CometBFT testnet and application
|
||||
func testnetInitFilesCmd(mm module.BasicManager, genBalIterator banktypes.GenesisBalancesIterator) *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 := cmtcfg.DefaultConfig()
|
||||
|
||||
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(server.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, genBalIterator, args)
|
||||
},
|
||||
}
|
||||
|
||||
addTestnetFlagsToCmd(cmd)
|
||||
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")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// testnetStartCmd returns a cmd to start multi validator in-process testnet
|
||||
func testnetStartCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "start",
|
||||
Short: "Launch an in-process multi-validator testnet",
|
||||
Long: fmt.Sprintf(`testnet will launch an in-process multi-validator testnet,
|
||||
and generate a directory for each validator populated with necessary
|
||||
configuration files (private validator, genesis, config, etc.).
|
||||
|
||||
Example:
|
||||
%s testnet --validator-count 4 --output-dir ./.testnets
|
||||
`, version.AppName),
|
||||
RunE: func(cmd *cobra.Command, _ []string) (err error) {
|
||||
args := startArgs{}
|
||||
args.outputDir, _ = cmd.Flags().GetString(flagOutputDir)
|
||||
args.chainID, _ = cmd.Flags().GetString(flags.FlagChainID)
|
||||
args.minGasPrices, _ = cmd.Flags().GetString(server.FlagMinGasPrices)
|
||||
args.numValidators, _ = cmd.Flags().GetInt(flagNumValidators)
|
||||
args.algo, _ = cmd.Flags().GetString(flags.FlagKeyType)
|
||||
args.enableLogging, _ = cmd.Flags().GetBool(flagEnableLogging)
|
||||
args.rpcAddress, _ = cmd.Flags().GetString(flagRPCAddress)
|
||||
args.apiAddress, _ = cmd.Flags().GetString(flagAPIAddress)
|
||||
args.grpcAddress, _ = cmd.Flags().GetString(flagGRPCAddress)
|
||||
args.printMnemonic, _ = cmd.Flags().GetBool(flagPrintMnemonic)
|
||||
|
||||
return startTestnet(cmd, args)
|
||||
},
|
||||
}
|
||||
|
||||
addTestnetFlagsToCmd(cmd)
|
||||
cmd.Flags().Bool(flagEnableLogging, false, "Enable INFO logging of CometBFT validator nodes")
|
||||
cmd.Flags().String(flagRPCAddress, "tcp://0.0.0.0:26657", "the RPC address to listen on")
|
||||
cmd.Flags().String(flagAPIAddress, "tcp://0.0.0.0:1317", "the address to listen on for REST API")
|
||||
cmd.Flags().String(flagGRPCAddress, "0.0.0.0:9090", "the gRPC server address to listen on")
|
||||
cmd.Flags().Bool(flagPrintMnemonic, true, "print mnemonic of first validator to stdout for manual testing")
|
||||
return cmd
|
||||
}
|
||||
|
||||
const nodeDirPerm = 0o755
|
||||
|
||||
// initTestnetFiles initializes testnet files for a testnet to be run in a separate process
|
||||
func initTestnetFiles(
|
||||
clientCtx client.Context,
|
||||
cmd *cobra.Command,
|
||||
nodeConfig *cmtconfig.Config,
|
||||
mm module.BasicManager,
|
||||
genBalIterator banktypes.GenesisBalancesIterator,
|
||||
args initArgs,
|
||||
) error {
|
||||
if args.chainID == "" {
|
||||
args.chainID = "chain-" + unsafe.Str(6)
|
||||
}
|
||||
nodeIDs := make([]string, args.numValidators)
|
||||
valPubKeys := make([]cryptotypes.PubKey, args.numValidators)
|
||||
|
||||
appConfig := appconfig.DefaultConfig()
|
||||
appConfig.MinGasPrices = args.minGasPrices
|
||||
appConfig.API.Enable = true
|
||||
appConfig.Telemetry.Enabled = true
|
||||
appConfig.Telemetry.PrometheusRetentionTime = 60
|
||||
appConfig.Telemetry.EnableHostnameLabel = false
|
||||
appConfig.Telemetry.GlobalLabels = [][]string{{"chain_id", args.chainID}}
|
||||
|
||||
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
|
||||
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
|
||||
appConfig.API.Address = fmt.Sprintf("tcp://0.0.0.0:%d", apiPort+portOffset)
|
||||
appConfig.GRPC.Address = fmt.Sprintf("0.0.0.0:%d", grpcPort+portOffset)
|
||||
}
|
||||
|
||||
nodeDirName := fmt.Sprintf("%s%d", args.nodeDirPrefix, i)
|
||||
nodeDir := filepath.Join(args.outputDir, nodeDirName, args.nodeDaemonHome)
|
||||
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)
|
||||
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)
|
||||
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),
|
||||
}
|
||||
|
||||
genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins.Sort()})
|
||||
genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0))
|
||||
|
||||
valAddr := sdk.ValAddress(addr)
|
||||
valStr := valAddr.String()
|
||||
valTokens := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction)
|
||||
createValMsg, err := stakingtypes.NewMsgCreateValidator(
|
||||
valStr,
|
||||
valPubKeys[i],
|
||||
sdk.NewCoin(args.bondTokenDenom, valTokens),
|
||||
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
|
||||
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)
|
||||
|
||||
txFactory := tx.Factory{}
|
||||
txFactory = txFactory.
|
||||
WithChainID(args.chainID).
|
||||
WithMemo(memo).
|
||||
WithKeybase(kb).
|
||||
WithTxConfig(clientCtx.TxConfig)
|
||||
|
||||
if err := tx.Sign(cmd.Context(), 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
|
||||
}
|
||||
|
||||
srvconfig.SetConfigTemplate(appconfig.DefaultConfigTemplate)
|
||||
srvconfig.WriteConfigFile(filepath.Join(nodeDir, "config", "app.toml"), appConfig)
|
||||
}
|
||||
|
||||
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, genBalIterator,
|
||||
rpcPort, p2pPortStart, args.singleMachine,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server.GetServerContextFromCmd(cmd).Viper.Set(flags.FlagHome, nodeConfig.RootDir)
|
||||
|
||||
cmd.PrintErrf("Successfully initialized %d node directories\n", args.numValidators)
|
||||
return nil
|
||||
}
|
||||
|
||||
func initGenFiles(
|
||||
clientCtx client.Context, mm module.BasicManager, chainID string,
|
||||
genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance,
|
||||
genFiles []string, numValidators int,
|
||||
) error {
|
||||
appGenState := mm.DefaultGenesis(clientCtx.Codec)
|
||||
|
||||
// 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 = banktypes.SanitizeGenesisBalances(genBalances)
|
||||
|
||||
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, genBalIterator banktypes.GenesisBalancesIterator,
|
||||
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,
|
||||
genBalIterator,
|
||||
genutiltypes.DefaultMessageValidator,
|
||||
clientCtx.TxConfig.SigningContext().ValidatorAddressCodec(),
|
||||
)
|
||||
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 = server.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)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(file, contents, 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// startTestnet starts an in-process testnet
|
||||
func startTestnet(cmd *cobra.Command, args startArgs) error {
|
||||
networkConfig := network.DefaultConfig(app.NewTestNetworkFixture)
|
||||
|
||||
// Default networkConfig.ChainID is random, and we should only override it if chainID provided
|
||||
// is non-empty
|
||||
if args.chainID != "" {
|
||||
networkConfig.ChainID = args.chainID
|
||||
}
|
||||
networkConfig.SigningAlgo = args.algo
|
||||
networkConfig.MinGasPrices = args.minGasPrices
|
||||
networkConfig.NumValidators = args.numValidators
|
||||
networkConfig.EnableLogging = args.enableLogging
|
||||
networkConfig.RPCAddress = args.rpcAddress
|
||||
networkConfig.APIAddress = args.apiAddress
|
||||
networkConfig.GRPCAddress = args.grpcAddress
|
||||
networkConfig.PrintMnemonic = args.printMnemonic
|
||||
networkConfig.TimeoutCommit = args.timeoutCommit
|
||||
networkLogger := network.NewCLILogger(cmd)
|
||||
|
||||
baseDir := fmt.Sprintf("%s/%s", args.outputDir, networkConfig.ChainID)
|
||||
if _, err := os.Stat(baseDir); !os.IsNotExist(err) {
|
||||
return fmt.Errorf(
|
||||
"testnests directory already exists for chain-id '%s': %s, please remove or select a new --chain-id",
|
||||
networkConfig.ChainID, baseDir)
|
||||
}
|
||||
|
||||
testnet, err := network.New(networkLogger, baseDir, networkConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := testnet.WaitForHeight(1); err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Println("press the Enter Key to terminate")
|
||||
if _, err := fmt.Scanln(); err != nil { // wait for Enter Key
|
||||
return err
|
||||
}
|
||||
testnet.Cleanup()
|
||||
|
||||
return nil
|
||||
}
|
||||
72
cmd/laconicd/cmd/testnet_test.go
Normal file
72
cmd/laconicd/cmd/testnet_test.go
Normal file
@ -0,0 +1,72 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/consensus"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil"
|
||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
)
|
||||
|
||||
func Test_TestnetCmd(t *testing.T) {
|
||||
moduleBasic := module.NewBasicManager(
|
||||
auth.AppModuleBasic{},
|
||||
genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
|
||||
bank.AppModuleBasic{},
|
||||
staking.AppModuleBasic{},
|
||||
distribution.AppModuleBasic{},
|
||||
consensus.AppModuleBasic{},
|
||||
)
|
||||
|
||||
home := t.TempDir()
|
||||
encodingConfig := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, staking.AppModuleBasic{})
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := genutiltest.CreateDefaultCometConfig(home)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = genutiltest.ExecInitCmd(moduleBasic, home, encodingConfig.Codec)
|
||||
require.NoError(t, err)
|
||||
|
||||
serverCtx := server.NewContext(viper.New(), cfg, logger)
|
||||
clientCtx := client.Context{}.
|
||||
WithCodec(encodingConfig.Codec).
|
||||
WithHomeDir(home).
|
||||
WithTxConfig(encodingConfig.TxConfig)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, server.ServerContextKey, serverCtx)
|
||||
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
|
||||
cmd := testnetInitFilesCmd(moduleBasic, banktypes.GenesisBalancesIterator{})
|
||||
cmd.SetArgs([]string{
|
||||
fmt.Sprintf("--%s=test", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--output-dir=%s", home),
|
||||
})
|
||||
err = cmd.ExecuteContext(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
genFile := cfg.GenesisFile()
|
||||
appState, _, err := genutiltypes.GenesisStateFromGenFile(genFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
bankGenState := banktypes.GetGenesisStateFromAppState(encodingConfig.Codec, appState)
|
||||
require.NotEmpty(t, bankGenState.Supply.String())
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -1,22 +1,32 @@
|
||||
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/app/params" // import for side-effects
|
||||
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
|
||||
)
|
||||
|
||||
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(args...)
|
||||
if err != nil {
|
||||
if _, pErr := fmt.Fprintln(os.Stderr, err); pErr != nil {
|
||||
panic(errors.Join(err, pErr))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := svrcmd.Execute(rootCmd, cmd.EnvPrefix, app.DefaultNodeHome); err != nil {
|
||||
if _, pErr := fmt.Fprintln(rootCmd.OutOrStderr(), err); pErr != nil {
|
||||
panic(errors.Join(err, pErr))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
296
go.mod
296
go.mod
@ -1,8 +1,8 @@
|
||||
module git.vdb.to/cerc-io/laconicd
|
||||
|
||||
go 1.21
|
||||
go 1.23.5
|
||||
|
||||
toolchain go1.21.0
|
||||
toolchain go1.23.6
|
||||
|
||||
replace (
|
||||
// Fix upstream GHSA-h395-qcrw-5vmq vulnerability.
|
||||
@ -12,138 +12,192 @@ replace (
|
||||
github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
||||
)
|
||||
|
||||
// DEV
|
||||
replace (
|
||||
cosmossdk.io/client/v2 => ../mod/cosmos-sdk/client/v2
|
||||
cosmossdk.io/log => ../mod/cosmos-sdk/log
|
||||
cosmossdk.io/systemtests => ../mod/cosmos-sdk/systemtests
|
||||
cosmossdk.io/tools/confix => ../mod/cosmos-sdk/tools/confix
|
||||
github.com/cometbft/cometbft => ../mod/cometbft
|
||||
// github.com/cometbft/cometbft/api => ../mod/cometbft/api
|
||||
github.com/cosmos/cosmos-sdk => ../mod/cosmos-sdk
|
||||
)
|
||||
|
||||
// DEV - nitro deps
|
||||
replace (
|
||||
// github.com/ethereum/go-ethereum => ../mod/go-ethereum
|
||||
git.vdb.to/cerc-io/chainsig => ../mod/chainsig
|
||||
github.com/statechannels/go-nitro => ../mod/go-nitro
|
||||
go.dedis.ch/kyber/v3 => ../mod/kyber
|
||||
|
||||
// go.dedis.ch/kyber/v3 => github.com/cerc-io/kyber/v3 v3.0.0-20250728035006-f80208a7f291 // branch dev-3.x
|
||||
)
|
||||
|
||||
require (
|
||||
cosmossdk.io/api v0.7.5
|
||||
cosmossdk.io/client/v2 v2.0.0-beta.1
|
||||
cosmossdk.io/collections v0.4.0
|
||||
cosmossdk.io/core v0.11.1
|
||||
cosmossdk.io/depinject v1.0.0
|
||||
cosmossdk.io/errors v1.0.1
|
||||
cosmossdk.io/log v1.4.1
|
||||
cosmossdk.io/math v1.3.0
|
||||
cosmossdk.io/store v1.1.1
|
||||
cosmossdk.io/tools/confix v0.1.0
|
||||
cosmossdk.io/x/evidence v0.1.1
|
||||
cosmossdk.io/api v0.9.2
|
||||
cosmossdk.io/client/v2 v2.0.0-00010101000000-000000000000
|
||||
cosmossdk.io/collections v1.3.1
|
||||
cosmossdk.io/core v0.11.3
|
||||
cosmossdk.io/depinject v1.2.1
|
||||
cosmossdk.io/errors v1.0.2
|
||||
cosmossdk.io/log v1.6.0
|
||||
cosmossdk.io/math v1.5.3
|
||||
cosmossdk.io/store v1.1.2
|
||||
cosmossdk.io/systemtests v1.2.1
|
||||
cosmossdk.io/tools/confix v0.1.2
|
||||
cosmossdk.io/x/evidence v0.2.0
|
||||
git.vdb.to/cerc-io/chain-signatures v0.1.0
|
||||
github.com/99designs/gqlgen v0.17.22
|
||||
github.com/cometbft/cometbft v0.38.12
|
||||
github.com/cosmos/cosmos-db v1.0.2
|
||||
github.com/cometbft/cometbft v0.38.17
|
||||
github.com/cosmos/cosmos-db v1.1.3
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.5
|
||||
github.com/cosmos/cosmos-sdk v0.50.10
|
||||
github.com/cosmos/cosmos-sdk v0.53.0
|
||||
github.com/cosmos/go-bip39 v1.0.0
|
||||
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.16.1
|
||||
github.com/gibson042/canonicaljson-go v1.0.3
|
||||
github.com/go-chi/chi/v5 v5.0.8
|
||||
github.com/go-chi/chi/v5 v5.2.2
|
||||
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/ipfs/go-cid v0.5.0
|
||||
github.com/ipld/go-ipld-prime v0.21.0
|
||||
github.com/lmittmann/tint v1.1.2
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/pelletier/go-toml/v2 v2.2.4
|
||||
github.com/rs/cors v1.11.1
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/statechannels/go-nitro v0.1.2
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/vektah/gqlparser/v2 v2.5.11
|
||||
golang.org/x/sync v0.8.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237
|
||||
google.golang.org/grpc v1.64.1
|
||||
google.golang.org/protobuf v1.34.2
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.7
|
||||
github.com/spf13/viper v1.20.1
|
||||
github.com/statechannels/go-nitro v0.0.0-00010101000000-000000000000
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
github.com/vektah/gqlparser/v2 v2.5.30
|
||||
go.dedis.ch/kyber/v3 v3.1.0
|
||||
golang.org/x/time v0.10.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a
|
||||
google.golang.org/grpc v1.72.2
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
cosmossdk.io/x/tx v0.13.5 // indirect
|
||||
filippo.io/edwards25519 v1.0.0 // indirect
|
||||
cosmossdk.io/schema v1.1.0 // indirect
|
||||
cosmossdk.io/x/tx v0.14.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/99designs/keyring v1.2.2 // indirect
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||
github.com/DataDog/zstd v1.5.7 // 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.2.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/bgentry/speakeasy v0.2.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.22.0 // indirect
|
||||
github.com/btcsuite/btcd v0.22.0-beta // 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/bytedance/sonic v1.13.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
|
||||
github.com/cockroachdb/errors v1.11.3 // indirect
|
||||
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||
github.com/cockroachdb/pebble v1.1.1 // indirect
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
github.com/cockroachdb/errors v1.12.0 // 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.5 // indirect
|
||||
github.com/cockroachdb/redact v1.1.6 // indirect
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
||||
github.com/cometbft/cometbft-db v0.11.0 // indirect
|
||||
github.com/cometbft/cometbft-db v0.14.1 // indirect
|
||||
github.com/consensys/gnark-crypto v0.18.0 // indirect
|
||||
github.com/cosmos/btcutil v1.0.5 // indirect
|
||||
github.com/cosmos/gogogateway v1.2.0 // indirect
|
||||
github.com/cosmos/iavl v1.2.0 // indirect
|
||||
github.com/cosmos/iavl v1.2.2 // indirect
|
||||
github.com/cosmos/ics23/go v0.11.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/cosmos/ledger-cosmos-go v0.14.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect
|
||||
github.com/creachadair/atomicfile v0.3.7 // indirect
|
||||
github.com/creachadair/tomledit v0.0.27 // indirect
|
||||
github.com/danieljoos/wincred v1.1.2 // 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/deckarep/golang-set/v2 v2.6.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.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/badger/v4 v4.2.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
|
||||
github.com/emicklei/dot v1.6.1 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/emicklei/dot v1.6.2 // indirect
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.0 // indirect
|
||||
github.com/ethereum/go-verkle v0.2.2 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/getsentry/sentry-go v0.27.0 // indirect
|
||||
github.com/go-kit/kit v0.12.0 // indirect
|
||||
github.com/ferranbt/fastssz v0.1.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/getsentry/sentry-go v0.33.0 // indirect
|
||||
github.com/go-kit/kit v0.13.0 // 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/go-viper/mapstructure/v2 v2.3.0 // indirect
|
||||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/googleapis v1.4.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-jwt/jwt/v5 v5.0.0 // indirect
|
||||
github.com/golang/glog v1.2.4 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/flatbuffers v2.0.8+incompatible // indirect
|
||||
github.com/google/go-cmp v0.7.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/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.2 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // 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.3 // 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.2 // 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.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // 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/linxGnu/grocksdb v1.8.14 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/linxGnu/grocksdb v1.9.7 // indirect
|
||||
github.com/manifoldco/promptui v0.9.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mdp/qrterminal/v3 v3.2.1 // 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/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/mtibben/percent v0.2.1 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
@ -154,49 +208,75 @@ require (
|
||||
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.2.2 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.12 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/stun/v2 v2.0.0 // indirect
|
||||
github.com/pion/transport/v2 v2.2.10 // indirect
|
||||
github.com/pion/transport/v3 v3.0.7 // 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.20.1 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/common v0.63.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.12.0 // indirect
|
||||
github.com/rs/zerolog v1.33.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/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/rs/zerolog v1.34.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // 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.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.9.2 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/supranational/blst v0.3.14 // 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.27.7 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
github.com/zondax/hid v0.9.2 // indirect
|
||||
github.com/zondax/ledger-go v0.14.3 // indirect
|
||||
go.etcd.io/bbolt v1.3.10 // 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/mock v0.5.2 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/term v0.23.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gotest.tools/v3 v3.5.1 // indirect
|
||||
lukechampine.com/blake3 v1.2.1 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/arch v0.15.0 // indirect
|
||||
golang.org/x/crypto v0.39.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gotest.tools/v3 v3.5.2 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
nhooyr.io/websocket v1.8.6 // indirect
|
||||
pgregory.net/rapid v1.1.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
pgregory.net/rapid v1.2.0 // indirect
|
||||
rsc.io/qr v0.2.0 // indirect
|
||||
sigs.k8s.io/yaml v1.6.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
|
||||
|
||||
@ -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
19
gql/config.go
Normal 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."`
|
||||
}
|
||||
29
gql/flags.go
29
gql/flags.go
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -12,6 +12,8 @@ import (
|
||||
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(), ®istrytypes.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(), ®istrytypes.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(), ®istrytypes.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(), ®istrytypes.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
@ -1,4 +1,4 @@
|
||||
package gql
|
||||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
|
||||
|
||||
package gql
|
||||
package schema
|
||||
|
||||
type Value interface {
|
||||
IsValue()
|
||||
123
gql/server.go
123
gql/server.go
@ -2,74 +2,117 @@ package gql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/rs/cors"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"git.vdb.to/cerc-io/laconicd/gql/schema"
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
)
|
||||
|
||||
// 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"
|
||||
)
|
||||
|
||||
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) {
|
||||
func New(clientCtx client.Context, cfg server.ConfigMap, logger log.Logger) (*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 := server.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
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
73
gql/util.go
73
gql/util.go
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
20
proto/cerc/nitro/module/v1/module.proto
Normal file
20
proto/cerc/nitro/module/v1/module.proto
Normal file
@ -0,0 +1,20 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cerc.nitro.module.v1;
|
||||
|
||||
import "cosmos/app/v1alpha1/module.proto";
|
||||
|
||||
// Module is the app config object of the module.
|
||||
// Learn more: https://docs.cosmos.network/main/building-modules/depinject
|
||||
message Module {
|
||||
option (cosmos.app.v1alpha1.module) = {
|
||||
go_import : "git.vdb.to/cerc-io/laconicd/x/nitro"
|
||||
};
|
||||
|
||||
// authority defines the custom module authority. If not set, defaults to the
|
||||
// governance module.
|
||||
string authority = 2;
|
||||
|
||||
// TODO LNT address here?
|
||||
string token_address = 3;
|
||||
}
|
||||
33
proto/cerc/nitro/v1/nitro.proto
Normal file
33
proto/cerc/nitro/v1/nitro.proto
Normal file
@ -0,0 +1,33 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cerc.nitro.v1;
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "cosmos/msg/v1/msg.proto";
|
||||
import "cosmos_proto/cosmos.proto";
|
||||
import "gogoproto/gogo.proto";
|
||||
|
||||
option go_package = "git.vdb.to/cerc-io/laconicd/x/nitro/types/v1";
|
||||
|
||||
// Params defines the parameters of the nitro module.
|
||||
message Params {
|
||||
bytes nitro_adjudicator_address = 1;
|
||||
bytes virtual_payment_app_address = 2;
|
||||
bytes consensus_app_address = 3;
|
||||
}
|
||||
|
||||
message PaymentChannel {
|
||||
string channel_id = 1;
|
||||
// TODO
|
||||
}
|
||||
|
||||
message Fund {
|
||||
option (gogoproto.equal) = true;
|
||||
|
||||
string token_address = 1;
|
||||
string amount = 2 [
|
||||
(cosmos_proto.scalar) = "cosmos.Int",
|
||||
(gogoproto.customtype) = "cosmossdk.io/math.Int",
|
||||
(gogoproto.nullable) = false
|
||||
];
|
||||
}
|
||||
10
proto/cerc/nitro/v1/p2p.proto
Normal file
10
proto/cerc/nitro/v1/p2p.proto
Normal 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;
|
||||
}
|
||||
14
proto/cerc/nitro/v1/query.proto
Normal file
14
proto/cerc/nitro/v1/query.proto
Normal file
@ -0,0 +1,14 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cerc.nitro.v1;
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "gogoproto/gogo.proto";
|
||||
import "cosmos/base/v1beta1/coin.proto";
|
||||
import "cosmos/msg/v1/msg.proto";
|
||||
|
||||
option go_package = "git.vdb.to/cerc-io/laconicd/x/nitro/types/v1";
|
||||
|
||||
service Query {
|
||||
|
||||
}
|
||||
139
proto/cerc/nitro/v1/tx.proto
Normal file
139
proto/cerc/nitro/v1/tx.proto
Normal file
@ -0,0 +1,139 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cerc.nitro.v1;
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "gogoproto/gogo.proto";
|
||||
import "cosmos/base/v1beta1/coin.proto";
|
||||
import "cosmos/msg/v1/msg.proto";
|
||||
|
||||
option go_package = "git.vdb.to/cerc-io/laconicd/x/nitro/types/v1";
|
||||
|
||||
// 1. user submits OpenChannel tx (from local relay node)
|
||||
//
|
||||
// 2. tx is not processed; instead first block proposer to pick up tx triggers Nitro
|
||||
// CreateLedgerChannel call (or client makes the call and the tx indicates it was made, then
|
||||
// proposer pushes an event to Nitro?)
|
||||
//
|
||||
// 3. objective is cranked among Nitro nodes over comet p2p
|
||||
//
|
||||
// 4. once complete, block proposer includes actual tx; client can detect update via Event api
|
||||
|
||||
service Msg {
|
||||
option (cosmos.msg.v1.service) = true;
|
||||
|
||||
// TODO: OpenLedgerChannel?
|
||||
rpc OpenChannel(MsgOpenChannel) returns (MsgOpenChannelResponse) {
|
||||
option (google.api.http).post = "/cerc/nitro/v1/open_channel";
|
||||
}
|
||||
|
||||
rpc CloseChannel(MsgCloseChannel) returns (MsgCloseChannelResponse) {
|
||||
option (google.api.http).post = "/cerc/nitro/v1/close_channel";
|
||||
}
|
||||
|
||||
rpc CreatePaymentChannel(MsgCreatePaymentChannel) returns (MsgCreatePaymentChannelResponse) {
|
||||
option (google.api.http).post = "/cerc/nitro/v1/create_payment_channel";
|
||||
}
|
||||
|
||||
rpc ClosePaymentChannel(MsgClosePaymentChannel) returns (MsgClosePaymentChannelResponse) {
|
||||
option (google.api.http).post = "/cerc/nitro/v1/close_payment_channel";
|
||||
}
|
||||
|
||||
rpc Pay(MsgPay) returns (MsgPayResponse) {
|
||||
option (google.api.http).post = "/cerc/nitro/v1/pay";
|
||||
}
|
||||
}
|
||||
|
||||
message MsgOpenChannel {
|
||||
option (cosmos.msg.v1.signer) = "signer";
|
||||
|
||||
// Nitro address of proposing party
|
||||
string nitro_address = 1;
|
||||
|
||||
// Nitro address of counterparty
|
||||
string counterparty = 2;
|
||||
|
||||
// Simplified outcome just includes the funding amount from payer
|
||||
// TODO: review use of coins to represent ETH/ERC20
|
||||
repeated cosmos.base.v1beta1.Coin funds = 3 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
|
||||
// Nitro channel ID
|
||||
string channel_id = 4;
|
||||
|
||||
// Tx signer address is independent of proposer ETH address
|
||||
string signer = 5;
|
||||
}
|
||||
message MsgOpenChannelResponse {}
|
||||
|
||||
message MsgCloseChannel {
|
||||
option (cosmos.msg.v1.signer) = "signer";
|
||||
|
||||
// Nitro channel ID to close
|
||||
string channel_id = 1;
|
||||
|
||||
// Whether to close via challenge (dispute resolution) or cooperative closure
|
||||
bool is_challenge = 2;
|
||||
|
||||
// Laconic address of proposing party
|
||||
string signer = 3;
|
||||
}
|
||||
message MsgCloseChannelResponse {}
|
||||
|
||||
message MsgCreatePaymentChannel {
|
||||
option (cosmos.msg.v1.signer) = "signer";
|
||||
|
||||
// Nitro address of proposing party
|
||||
string nitro_address = 1;
|
||||
|
||||
// Nitro address of counterparty
|
||||
string counterparty = 2;
|
||||
|
||||
// Nitro addresses of intermediaries
|
||||
repeated string intermediaries = 3;
|
||||
|
||||
// Challenge duration for the channel
|
||||
uint32 challenge_duration = 4;
|
||||
|
||||
// Funding amount for the payment channel
|
||||
repeated cosmos.base.v1beta1.Coin funds = 5 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
|
||||
// Nitro channel ID
|
||||
string channel_id = 6;
|
||||
|
||||
// Laconic address of proposing party
|
||||
string signer = 7;
|
||||
}
|
||||
message MsgCreatePaymentChannelResponse {}
|
||||
|
||||
message MsgClosePaymentChannel {
|
||||
option (cosmos.msg.v1.signer) = "signer";
|
||||
|
||||
// Nitro channel ID to close
|
||||
string channel_id = 1;
|
||||
|
||||
// Laconic address of proposing party
|
||||
string signer = 2;
|
||||
}
|
||||
message MsgClosePaymentChannelResponse {}
|
||||
|
||||
message MsgPay {
|
||||
option (cosmos.msg.v1.signer) = "signer";
|
||||
|
||||
// Nitro channel ID through which to send payment
|
||||
string channel_id = 1;
|
||||
|
||||
// Amount to pay
|
||||
cosmos.base.v1beta1.Coin amount = 2 [
|
||||
(gogoproto.nullable) = false
|
||||
];
|
||||
|
||||
// Laconic address of the payer
|
||||
string signer = 3;
|
||||
}
|
||||
message MsgPayResponse {}
|
||||
@ -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\"" ];
|
||||
|
||||
@ -27,7 +27,7 @@ service Query {
|
||||
rpc GetParticipantByNitroAddress(QueryGetParticipantByNitroAddressRequest)
|
||||
returns (QueryGetParticipantByNitroAddressResponse) {
|
||||
option (google.api.http).get =
|
||||
"/cerc/onboarding/v1/participants/{nitro_address}";
|
||||
"/cerc/onboarding/v1/participants-by-nitro/{nitro_address}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
188
scripts/init.sh
188
scripts/init.sh
@ -1,153 +1,105 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
KEY="alice"
|
||||
LACONIC_BIN=${LACONIC_BIN:-laconicd}
|
||||
LACONIC_HOME="${LACONIC_HOME:-$HOME/.laconicd}"
|
||||
|
||||
KEYNAME="node_key"
|
||||
CHAINID=${CHAINID:-"laconic_9000-1"}
|
||||
MONIKER=${MONIKER:-"localtestnet"}
|
||||
KEYRING=${KEYRING:-"test"}
|
||||
DENOM=${DENOM:-"alnt"}
|
||||
BALANCE=${BALANCE:-"1000000000000000000000000000000"} # 10^32 alnt
|
||||
STAKING_AMOUNT=${STAKING_AMOUNT:-"1000000000000000"} # 10^15 alnt
|
||||
MIN_GAS_PRICE=${MIN_GAS_PRICE:-"0.001"}
|
||||
ALLOCATION_AMOUNT=1000000000000000000000000000000 # 10^30 alnt | 10^12 lnt
|
||||
LOGLEVEL=${LOGLEVEL:-"info"}
|
||||
|
||||
P2P_EXTERNAL_PORT=${P2P_EXTERNAL_PORT:-26656}
|
||||
|
||||
input_genesis_file=${GENESIS_FILE}
|
||||
import_private_key=${PRIVATE_KEY}
|
||||
|
||||
if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data" ]; 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/"
|
||||
exit 1
|
||||
}
|
||||
laconicd="$LACONIC_BIN --home=$LACONIC_HOME --log_level=$LOGLEVEL"
|
||||
|
||||
# remove existing daemon and client
|
||||
rm -rf $HOME/.laconicd/*
|
||||
set -e
|
||||
|
||||
if [ -n "`which make`" ]; then
|
||||
make install
|
||||
if [ "$1" == "clean" ]; then
|
||||
echo "Clearing existing data directory in $LACONIC_HOME"
|
||||
rm -rf "$LACONIC_HOME"
|
||||
else
|
||||
echo "Using existing database at $LACONIC_HOME. To replace, run '$(basename $0) clean'"
|
||||
fi
|
||||
|
||||
# Create a new home dir if needed
|
||||
if [[ ! -d "$LACONIC_HOME/data/application.db" ]]; then
|
||||
# Import the node key if passed, or generate one
|
||||
if [[ -n "$import_private_key" ]]; then
|
||||
$laconicd keys import-hex $KEYNAME 'b0b0000000000000000000000000000000000000000000000000000000000000'
|
||||
else
|
||||
printf "y\n" | $laconicd keys add $KEYNAME --keyring-backend $KEYRING --no-backup
|
||||
fi
|
||||
|
||||
laconicd config set client chain-id $CHAINID
|
||||
laconicd config set client keyring-backend $KEYRING
|
||||
# Set moniker and chain-id (Moniker can be anything, chain-id must be an integer)
|
||||
$laconicd init $MONIKER --chain-id $CHAINID --default-denom $DENOM
|
||||
else
|
||||
KEYNAME=$($laconicd keys list --list-names --keyring-backend $KEYRING | head -1)
|
||||
fi
|
||||
|
||||
# if $KEY exists it should be deleted
|
||||
laconicd keys add $KEY --keyring-backend $KEYRING
|
||||
|
||||
# Set moniker and chain-id
|
||||
laconicd init $MONIKER --chain-id $CHAINID --default-denom $DENOM
|
||||
if [[ ! -d "$db_path" ]]; then
|
||||
$laconicd config set client chain-id $CHAINID
|
||||
$laconicd config set client keyring-backend $KEYRING
|
||||
|
||||
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
|
||||
$laconicd genesis validate
|
||||
|
||||
update_comet_config() { # comet config is not supported by confix cli
|
||||
local file="$LACONIC_HOME/config/config.toml"
|
||||
cp -f "$file" "${file}.bak" && tomlq --toml-output ".$1 = $2" "${file}.bak" > "$file"
|
||||
}
|
||||
|
||||
if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then
|
||||
echo "Setting timers for expiry tests."
|
||||
# disable empty blocks
|
||||
update_comet_config consensus.create_empty_blocks 'false'
|
||||
|
||||
update_genesis '.app_state["registry"]["params"]["record_rent_duration"]="60s"'
|
||||
update_genesis '.app_state["registry"]["params"]["authority_grace_period"]="60s"'
|
||||
update_genesis '.app_state["registry"]["params"]["authority_rent_duration"]="60s"'
|
||||
fi
|
||||
# Allow requests from any origin
|
||||
update_comet_config rpc.cors_allowed_origins '["*"]'
|
||||
|
||||
if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then
|
||||
echo "Enabling auction and setting timers."
|
||||
|
||||
update_genesis '.app_state["registry"]["params"]["authority_auction_enabled"]=true'
|
||||
update_genesis '.app_state["registry"]["params"]["authority_rent_duration"]="60s"'
|
||||
update_genesis '.app_state["registry"]["params"]["authority_grace_period"]="300s"'
|
||||
update_genesis '.app_state["registry"]["params"]["authority_auction_commits_duration"]="60s"'
|
||||
update_genesis '.app_state["registry"]["params"]["authority_auction_reveals_duration"]="60s"'
|
||||
fi
|
||||
|
||||
if [[ "$ONBOARDING_ENABLED" == "true" ]]; then
|
||||
echo "Enabling onboarding."
|
||||
|
||||
update_genesis '.app_state["onboarding"]["params"]["onboarding_enabled"]=true'
|
||||
fi
|
||||
|
||||
if [[ "$AUTHORITY_AUCTION_ENABLED" == "true" ]]; then
|
||||
echo "Enabling authority auctions."
|
||||
update_genesis '.app_state["registry"]["params"]["authority_auction_enabled"]=true'
|
||||
fi
|
||||
|
||||
if [[ -n $AUTHORITY_AUCTION_COMMITS_DURATION ]]; then
|
||||
echo "Setting authority_auction_commits_duration to $AUTHORITY_AUCTION_COMMITS_DURATION seconds."
|
||||
update_genesis ".app_state[\"registry\"][\"params\"][\"authority_auction_commits_duration\"]=\"${AUTHORITY_AUCTION_COMMITS_DURATION}s\""
|
||||
fi
|
||||
|
||||
if [[ -n $AUTHORITY_AUCTION_REVEALS_DURATION ]]; then
|
||||
echo "Setting authority_auction_reveals_duration to $AUTHORITY_AUCTION_REVEALS_DURATION seconds."
|
||||
update_genesis ".app_state[\"registry\"][\"params\"][\"authority_auction_reveals_duration\"]=\"${AUTHORITY_AUCTION_REVEALS_DURATION}s\""
|
||||
fi
|
||||
|
||||
if [[ -n $AUTHORITY_GRACE_PERIOD ]]; then
|
||||
echo "Setting authority_grace_period to $AUTHORITY_GRACE_PERIOD seconds."
|
||||
update_genesis ".app_state[\"registry\"][\"params\"][\"authority_grace_period\"]=\"${AUTHORITY_GRACE_PERIOD}s\""
|
||||
fi
|
||||
|
||||
# increase block time (?)
|
||||
update_genesis '.consensus["params"]["block"]["time_iota_ms"]="1000"'
|
||||
|
||||
# Set gas limit in genesis
|
||||
update_genesis '.consensus["params"]["block"]["max_gas"]="10000000"'
|
||||
|
||||
# Set distribution community tax to 1 for disabling staking rewards
|
||||
update_genesis '.app_state["distribution"]["params"]["community_tax"]="1.000000000000000000"'
|
||||
|
||||
echo "Setting high threshold for accepting governance proposal"
|
||||
update_genesis '.app_state["gov"]["params"]["quorum"]="1.000000000000000000"'
|
||||
# Set expedited threshold to 100%
|
||||
update_genesis '.app_state["gov"]["params"]["expedited_threshold"]="1.000000000000000000"'
|
||||
# Set normal threshold to 99% since it needs to be lesser than expedited threshold
|
||||
update_genesis '.app_state["gov"]["params"]["threshold"]="0.990000000000000000"'
|
||||
|
||||
# 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
|
||||
|
||||
# Run this to allow requests from any origin
|
||||
sed -i 's/cors_allowed_origins.*$/cors_allowed_origins = ["*"]/' $HOME/.laconicd/config/config.toml
|
||||
# Set persistent peers
|
||||
update_comet_config p2p.seeds "\"$P2P_PEERS\""
|
||||
update_comet_config p2p.persistent_peers "\"$P2P_PEERS\""
|
||||
update_comet_config p2p.external_address "\"tcp://127.0.0.1:${P2P_EXTERNAL_PORT}\""
|
||||
update_comet_config p2p.addr_book_strict false
|
||||
|
||||
# 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
|
||||
$laconicd config set app telemetry.enable true
|
||||
$laconicd config set app telemetry.prometheus-retention-time 60
|
||||
update_comet_config instrumentation.prometheus true
|
||||
|
||||
# Allocate genesis accounts (cosmos formatted addresses)
|
||||
laconicd genesis add-genesis-account $KEY ${BALANCE}${DENOM} --keyring-backend $KEYRING
|
||||
# Enable validator distsig
|
||||
$laconicd config set app distsig.enable true
|
||||
$laconicd config set app distsig.longterm-key "$KEYNAME"
|
||||
|
||||
# Sign genesis transaction
|
||||
laconicd genesis gentx $KEY $STAKING_AMOUNT$DENOM --keyring-backend $KEYRING --chain-id $CHAINID
|
||||
|
||||
# Collect genesis tx
|
||||
laconicd genesis collect-gentxs
|
||||
|
||||
# Run this to ensure everything worked and that the genesis file is setup correctly
|
||||
laconicd genesis validate
|
||||
# Nitro config, WIP
|
||||
# $laconicd config set app nitro.use-distsig true # TODO
|
||||
$laconicd config set app nitro.eth-key "$KEYNAME"
|
||||
$laconicd config set app nitro.eth-url "$NITRO_ETH_URL"
|
||||
$laconicd config set app nitro.eth-start-block "$NITRO_ETH_START_BLOCK"
|
||||
$laconicd config set app nitro.eth-na-address "'$NITRO_ADJUDICATOR_ADDRESS'"
|
||||
$laconicd config set app nitro.eth-vpa-address "'$VIRTUAL_PAYMENT_APP_ADDRESS'"
|
||||
$laconicd config set app nitro.eth-ca-address "'$CONSENSUS_APP_ADDRESS'"
|
||||
else
|
||||
echo "Using existing database at $HOME/.laconicd. To replace, run '`basename $0` clean'"
|
||||
echo "Using existing database at $LACONIC_HOME."
|
||||
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=$MIN_GAS_PRICE$DENOM \
|
||||
--api.enable \
|
||||
# TODO new pruning config
|
||||
$laconicd start \
|
||||
--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
|
||||
|
||||
120
server/components.go
Normal file
120
server/components.go
Normal file
@ -0,0 +1,120 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"github.com/cometbft/cometbft/node"
|
||||
"github.com/cometbft/cometbft/p2p"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// HasContextKey is implemented by servers that have a dedicated key under which they should be
|
||||
// associated with a context.
|
||||
type HasContextKey interface {
|
||||
ContextKey() string
|
||||
}
|
||||
|
||||
type HasP2PReactors interface {
|
||||
P2PReactors() map[string]p2p.Reactor
|
||||
}
|
||||
|
||||
// maps commands to server components they require
|
||||
var cmdRequirements = map[*cobra.Command][]ServerComponent{}
|
||||
|
||||
// SetRequiredComponents sets required server components for a command
|
||||
func SetRequiredComponents(cmd *cobra.Command, components ...ServerComponent) {
|
||||
for _, c := range components {
|
||||
cmdRequirements[cmd] = append(cmdRequirements[cmd], c)
|
||||
if startmod, ok := c.(HasStartFlags); ok {
|
||||
cmd.Flags().AddFlagSet(startmod.StartCmdFlags())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RequiresComponent(cmd *cobra.Command, c string) bool {
|
||||
components, ok := cmdRequirements[cmd]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, mod := range components {
|
||||
if mod.Name() == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ComponentsCreator func(ConfigMap, client.Context, log.Logger, func(string) bool) ([]ServerComponent, error)
|
||||
|
||||
type ServerAux struct {
|
||||
components []ServerComponent
|
||||
}
|
||||
|
||||
// AddComponents adds hooks to create, start and stop the components returned from the passed
|
||||
// constructor, and ensures they are available on the command context.
|
||||
// It returns a node.Option to additionally configure the CometBFT node.
|
||||
func (s *ServerAux) AddComponents(cmd *cobra.Command, initComponents ComponentsCreator) {
|
||||
needsComponent := func(name string) bool {
|
||||
return RequiresComponent(cmd, name)
|
||||
}
|
||||
|
||||
// manage component lifecycle
|
||||
cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
|
||||
serverCtx := server.GetServerContextFromCmd(cmd)
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.components, err = initComponents(
|
||||
serverCtx.Viper.AllSettings(), clientCtx, serverCtx.Logger, needsComponent,
|
||||
)
|
||||
// add available context keys
|
||||
for _, mod := range s.components {
|
||||
if ckeymod, ok := mod.(HasContextKey); ok {
|
||||
cmdCtx := cmd.Context()
|
||||
if cmdCtx == nil {
|
||||
cmdCtx = context.Background()
|
||||
}
|
||||
cmd.SetContext(context.WithValue(cmdCtx, ckeymod.ContextKey(), mod))
|
||||
}
|
||||
}
|
||||
|
||||
for _, mod := range s.components {
|
||||
if err := mod.Start(cmd.Context()); err != nil {
|
||||
return fmt.Errorf("failed to start server %s: %w", mod.Name(), err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
startFn := cmd.RunE
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
// if we do this in PostRunE, it won't be called if RunE errors
|
||||
defer func() {
|
||||
var err error
|
||||
for _, mod := range s.components {
|
||||
err = errors.Join(err, mod.Stop(cmd.Context()))
|
||||
}
|
||||
if err != nil {
|
||||
cmd.PrintErrln("failed to stop servers:", err)
|
||||
}
|
||||
}()
|
||||
return startFn(cmd, args)
|
||||
}
|
||||
}
|
||||
|
||||
// AddReactors adds p2p Reactors for all configured components to a CometBFT node.
|
||||
// When passed to StartCmdOptions this will be run in start(), after components are initialized in PreRun.
|
||||
func (s *ServerAux) AddReactors(cmt *node.Node) {
|
||||
for _, mod := range s.components {
|
||||
if reactormod, ok := mod.(HasP2PReactors); ok {
|
||||
opt := node.CustomReactors(reactormod.P2PReactors())
|
||||
opt(cmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
65
server/config.go
Normal file
65
server/config.go
Normal file
@ -0,0 +1,65 @@
|
||||
package server
|
||||
|
||||
// The utilities in this file are copied from cosmos-sdk server/v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type ConfigMap map[string]any
|
||||
|
||||
// ReadConfig returns a viper instance of the config file
|
||||
func ReadConfig(configPath string) (*viper.Viper, error) {
|
||||
v := viper.New()
|
||||
v.SetConfigType("toml")
|
||||
v.SetConfigName("config")
|
||||
v.AddConfigPath(configPath)
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return nil, fmt.Errorf("failed to read config: %s: %w", configPath, err)
|
||||
}
|
||||
|
||||
v.SetConfigName("app")
|
||||
if err := v.MergeInConfig(); err != nil {
|
||||
return nil, fmt.Errorf("failed to merge configuration: %w", err)
|
||||
}
|
||||
|
||||
v.WatchConfig()
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// UnmarshalSubConfig unmarshals the given (sub) config from the main config (given as a map) into the target.
|
||||
// If subName is empty, the main config is unmarshaled into the target.
|
||||
func UnmarshalSubConfig(cfg map[string]any, subName string, target any) error {
|
||||
var sub any
|
||||
if subName != "" {
|
||||
if val, ok := cfg[subName]; ok {
|
||||
sub = val
|
||||
}
|
||||
} else {
|
||||
sub = cfg
|
||||
}
|
||||
|
||||
// Create a new decoder with custom decoding options
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
DecodeHook: mapstructure.ComposeDecodeHookFunc(
|
||||
mapstructure.StringToTimeDurationHookFunc(),
|
||||
mapstructure.StringToSliceHookFunc(","),
|
||||
),
|
||||
Result: target,
|
||||
WeaklyTypedInput: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create decoder: %w", err)
|
||||
}
|
||||
|
||||
// Decode the sub-configuration
|
||||
if err := decoder.Decode(sub); err != nil {
|
||||
return fmt.Errorf("failed to decode sub-configuration: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
29
server/distsig/config.go
Normal file
29
server/distsig/config.go
Normal file
@ -0,0 +1,29 @@
|
||||
package distsig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Enable bool `mapstructure:"enable" toml:"enable" comment:"Enable distributed Schnorr signatures"`
|
||||
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{
|
||||
Enable: false,
|
||||
ThresholdRatio: 4. / 7,
|
||||
}
|
||||
}
|
||||
|
||||
func UnmarshalConfig(cfg map[string]any) (*Config, error) {
|
||||
config := DefaultConfig()
|
||||
if err := server.UnmarshalSubConfig(cfg, componentName, config); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal %T: %w", config, err)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
175
server/distsig/distsig_test.go
Normal file
175
server/distsig/distsig_test.go
Normal file
@ -0,0 +1,175 @@
|
||||
package distsig
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"git.vdb.to/cerc-io/chain-signatures/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
19
server/distsig/flags.go
Normal 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
224
server/distsig/keygen.go
Normal 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 }
|
||||
268
server/distsig/manager.go
Normal file
268
server/distsig/manager.go
Normal file
@ -0,0 +1,268 @@
|
||||
package distsig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
cmtcrypto "github.com/cometbft/cometbft/crypto"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
dkg "go.dedis.ch/kyber/v3/share/dkg/rabin"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
|
||||
clientdss "git.vdb.to/cerc-io/chain-signatures/ethdss"
|
||||
"git.vdb.to/cerc-io/chain-signatures/ethschnorr"
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
"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
|
||||
keyring keyring.Keyring
|
||||
|
||||
longtermKey Scalar // only initialized after Start()
|
||||
longtermPubKey cmtcrypto.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, globalConfig server.ConfigMap, kr keyring.Keyring) (*Manager, error) {
|
||||
config, err := UnmarshalConfig(globalConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := &Manager{
|
||||
config: config,
|
||||
keyring: kr,
|
||||
dkgs: make(map[DkgRunID]*dkgRun),
|
||||
sigs: make(map[SigRunID]*sigRun),
|
||||
}
|
||||
m.logger = logger.With(log.ModuleKey, m.Name())
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (*Manager) Name() string { return componentName }
|
||||
|
||||
func (m *Manager) Start(ctx context.Context) error {
|
||||
if !m.config.Enable {
|
||||
m.logger.Info(fmt.Sprintf("%s server is disabled via config", m.Name()))
|
||||
return nil
|
||||
}
|
||||
if m.config.LongtermKey == "" {
|
||||
return fmt.Errorf("missing longterm key")
|
||||
}
|
||||
longtermPrivKey, err := utils.ExtractPrivateKeyByUid(m.keyring, m.config.LongtermKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to extract longterm key: %w", err)
|
||||
}
|
||||
m.longtermKey = suite.Scalar().SetBytes(longtermPrivKey.Bytes())
|
||||
m.longtermPubKey = longtermPrivKey.PubKey()
|
||||
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 (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() cmtcrypto.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.longtermKey, 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.longtermKey,
|
||||
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 (pm PeerMessages) Empty() bool {
|
||||
return pm.dkg == nil && len(pm.dss) == 0
|
||||
}
|
||||
61
server/distsig/signature.go
Normal file
61
server/distsig/signature.go
Normal file
@ -0,0 +1,61 @@
|
||||
package distsig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
clientdss "git.vdb.to/cerc-io/chain-signatures/ethdss"
|
||||
"git.vdb.to/cerc-io/chain-signatures/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()[:8]))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
39
server/distsig/suite.go
Normal file
39
server/distsig/suite.go
Normal file
@ -0,0 +1,39 @@
|
||||
package distsig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.vdb.to/cerc-io/chain-signatures/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()
|
||||
NewScalar = suite.Scalar
|
||||
NewPoint = suite.Point
|
||||
|
||||
// Note: the compressed encoding of pubkeys used by Cosmos SDK and our library (based on chainlink)
|
||||
// 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()
|
||||
}
|
||||
13
server/distsig/utils.go
Normal file
13
server/distsig/utils.go
Normal file
@ -0,0 +1,13 @@
|
||||
package distsig
|
||||
|
||||
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
|
||||
}
|
||||
36
server/gas.go
Normal file
36
server/gas.go
Normal file
@ -0,0 +1,36 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cosmossdk.io/core/gas"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var _ gas.Service = gasService{}
|
||||
|
||||
// Placeholder gas service, in anticipation of future use
|
||||
// https://github.com/cosmos/cosmos-sdk/pull/16310
|
||||
type gasService struct{}
|
||||
|
||||
func NewGasService() gas.Service { return gasService{} }
|
||||
|
||||
func (gasService) GetGasMeter(ctx context.Context) gas.Meter {
|
||||
c := sdk.UnwrapSDKContext(ctx)
|
||||
return c.GasMeter()
|
||||
}
|
||||
|
||||
func (gasService) WithGasMeter(ctx context.Context, meter gas.Meter) context.Context {
|
||||
c := sdk.UnwrapSDKContext(ctx)
|
||||
return c.WithGasMeter(meter)
|
||||
}
|
||||
|
||||
// deprecated https://github.com/cosmos/cosmos-sdk/issues/19793
|
||||
func (gasService) GetBlockGasMeter(context.Context) gas.Meter {
|
||||
return nil
|
||||
}
|
||||
|
||||
// deprecated https://github.com/cosmos/cosmos-sdk/issues/19793
|
||||
func (gasService) WithBlockGasMeter(ctx context.Context, meter gas.Meter) context.Context {
|
||||
return ctx
|
||||
}
|
||||
230
server/nitro/command_utils.go
Normal file
230
server/nitro/command_utils.go
Normal file
@ -0,0 +1,230 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cometbft/cometbft/p2p"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/statechannels/go-nitro/protocols"
|
||||
nitrotypes "github.com/statechannels/go-nitro/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server/relay"
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
)
|
||||
|
||||
const txTimeoutDuration = 5 * time.Second
|
||||
|
||||
func GetServerFromCmd(cmd *cobra.Command) (*Server, error) {
|
||||
s, err := utils.GetFromContext[Server](cmd.Context(), ServerContextKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for !s.Ready() {
|
||||
runtime.Gosched()
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func delayAfterUpdate() {
|
||||
// HACK: delay so remote server status is synced before we return
|
||||
// TODO: correct solution is passing messages with consistency guarantees,
|
||||
// i.e. using txs to pass nitro messages and integrating state into chain storage
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
// waitForObjective waits for an objective to complete or fail using select pattern
|
||||
func waitForObjective[Info any](
|
||||
failedChan <-chan protocols.ObjectiveId,
|
||||
objective protocols.ObjectiveId,
|
||||
updateChan <-chan Info,
|
||||
statusCheck func(Info) bool,
|
||||
) error {
|
||||
for {
|
||||
select {
|
||||
case update := <-updateChan:
|
||||
if statusCheck(update) {
|
||||
delayAfterUpdate()
|
||||
return nil
|
||||
}
|
||||
case failedObjective := <-failedChan:
|
||||
if failedObjective == objective {
|
||||
return fmt.Errorf("objective failed for unspecified reason: %s", objective)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func submitNitroTx(
|
||||
clientCtx client.Context,
|
||||
cmd *cobra.Command,
|
||||
msg MsgWrapper,
|
||||
unordered bool,
|
||||
) error {
|
||||
if msg.SignerField != nil {
|
||||
ac := utils.NewAddressCodec()
|
||||
var err error
|
||||
*msg.SignerField, err = ac.BytesToString(clientCtx.FromAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
factory, err := tx.NewFactoryCLI(clientCtx, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if unordered {
|
||||
deadline := time.Now().Add(txTimeoutDuration)
|
||||
factory = factory.WithUnordered(true).WithTimeoutTimestamp(deadline)
|
||||
}
|
||||
if err := tx.GenerateOrBroadcastTxWithFactory(clientCtx, factory, msg.Msg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupNitroCommand sets up common infrastructure for nitro commands
|
||||
func setupNitroCommand(cmd *cobra.Command) (*client.Context, *Server, func() error, error) {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
s, err := GetServerFromCmd(cmd)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
relayServer, err := relay.GetServerFromCmd(cmd)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
sw, err := connectAsPeer(clientCtx, relayServer, s.P2PReactors())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return &clientCtx, s, sw.Stop, nil
|
||||
}
|
||||
|
||||
// setupNitroQueryCommand sets up infrastructure for nitro query commands (no tx context needed)
|
||||
func setupNitroQueryCommand(cmd *cobra.Command, needp2p bool) (*Server, func() error, error) {
|
||||
s, err := GetServerFromCmd(cmd)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if !needp2p {
|
||||
return s, func() error { return nil }, nil
|
||||
}
|
||||
|
||||
relayServer, err := relay.GetServerFromCmd(cmd)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sw, err := connectAsPeer(clientCtx, relayServer, s.P2PReactors())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return s, sw.Stop, nil
|
||||
}
|
||||
|
||||
// resolveTokens resolves amount and asset address to Nitro funds
|
||||
func resolveTokens(s *Server, amountStr, assetAddr string) (nitrotypes.Funds, error) {
|
||||
var amount *big.Int
|
||||
var asset common.Address
|
||||
|
||||
if assetAddr != "" {
|
||||
// Parse asset address
|
||||
if !common.IsHexAddress(assetAddr) {
|
||||
return nitrotypes.Funds{}, fmt.Errorf("invalid asset address: %s", assetAddr)
|
||||
}
|
||||
asset = common.HexToAddress(assetAddr)
|
||||
|
||||
// A token specified by address must have an integer amount
|
||||
amount = new(big.Int)
|
||||
if _, ok := amount.SetString(amountStr, 10); !ok {
|
||||
return nitrotypes.Funds{}, fmt.Errorf("invalid amount for token %s: %s", assetAddr, amountStr)
|
||||
}
|
||||
if amount.Sign() <= 0 {
|
||||
return nitrotypes.Funds{}, fmt.Errorf("amount must be positive for token %s: %s", assetAddr, amountStr)
|
||||
}
|
||||
} else {
|
||||
// Parse as (known) coins and convert
|
||||
coins, err := sdk.ParseCoinsNormalized(amountStr)
|
||||
if err != nil {
|
||||
return nitrotypes.Funds{}, fmt.Errorf("failed to parse coins: %w", err)
|
||||
}
|
||||
if len(coins) != 1 {
|
||||
return nitrotypes.Funds{}, fmt.Errorf("only one asset is supported")
|
||||
}
|
||||
|
||||
// Convert denomination to token address
|
||||
asset, err = denomToToken(coins[0].Denom)
|
||||
if err != nil {
|
||||
return nitrotypes.Funds{}, err
|
||||
}
|
||||
amount = coins[0].Amount.BigInt()
|
||||
}
|
||||
|
||||
return nitrotypes.Funds{asset: amount}, nil
|
||||
}
|
||||
|
||||
// map denoms to token addresses
|
||||
// TODO nitro should control this mapping, and resolution should happen in the module logic
|
||||
func denomToToken(denom string) (common.Address, error) {
|
||||
_tokens := map[string]common.Address{
|
||||
"eth": {},
|
||||
}
|
||||
token, ok := _tokens[strings.ToLower(denom)]
|
||||
if !ok {
|
||||
return common.Address{}, fmt.Errorf("unknown token %s", denom)
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// connects as a peer to the relay server, initializing the P2P switch
|
||||
func connectAsPeer(
|
||||
clientCtx client.Context, relayServer *relay.Server, reactors map[string]p2p.Reactor,
|
||||
) (*relay.Switch, error) {
|
||||
// initialize the switch using the target's node info
|
||||
status, err := clientCtx.Client.Status(clientCtx.CmdContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeInfo := status.NodeInfo
|
||||
sw, err := relayServer.GetSwitch(clientCtx.ChainID, nodeInfo.ProtocolVersion.Block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating switch: %w", err)
|
||||
}
|
||||
for name, reactor := range reactors {
|
||||
if err := sw.AddReactor(name, reactor); err != nil {
|
||||
return nil, fmt.Errorf("error adding reactor: %w", err)
|
||||
}
|
||||
}
|
||||
if err := sw.Start(); err != nil {
|
||||
return nil, fmt.Errorf("error starting switch: %w", err)
|
||||
}
|
||||
|
||||
peerAddr := p2p.IDAddressString(nodeInfo.ID(), nodeInfo.ListenAddr)
|
||||
// s.logger.Debug("dialing peer", "peer", peerAddr)
|
||||
if err := sw.Dial(peerAddr); err != nil {
|
||||
return nil, fmt.Errorf("error dialing peer: %w", err)
|
||||
}
|
||||
return sw, nil
|
||||
}
|
||||
80
server/nitro/config.go
Normal file
80
server/nitro/config.go
Normal file
@ -0,0 +1,80 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Enable bool `mapstructure:"enable" toml:"enable" comment:"Enable Nitro state channel functionality"`
|
||||
|
||||
EthKey string `mapstructure:"eth-key" toml:"eth-key" comment:"The private key used when interacting with the Ethereum chain and for our identity as a participant in the Nitro protocol."`
|
||||
// UseDistsig bool `mapstructure:"use-distsig" toml:"use-distsig" comment:"Whether to use distributed signatures to authenticate Nitro actions."`
|
||||
|
||||
// EthChainID string
|
||||
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."`
|
||||
|
||||
// TODO: move to module params?
|
||||
EthNaAddress string `mapstructure:"eth-na-address" toml:"eth-na-address" comment:"Ethereum address of the Nitro Adjudicator contract."`
|
||||
EthVpaAddress string `mapstructure:"eth-vpa-address" toml:"eth-vpa-address" comment:"Ethereum address of the Virtual Payment App contract."`
|
||||
EthCaAddress string `mapstructure:"eth-ca-address" toml:"eth-ca-address" comment:"Ethereum address of the Consensus App contract."`
|
||||
|
||||
// P2P Rate Limiting
|
||||
P2PRateLimitEnable bool `mapstructure:"p2p-rate-limit-enable" toml:"p2p-rate-limit-enable" comment:"Enable send-side rate limiting for P2P messages."`
|
||||
P2PRateLimitRate float64 `mapstructure:"p2p-rate-limit-rate" toml:"p2p-rate-limit-rate" comment:"Maximum number of P2P messages per second (e.g., 10.0 for 10 messages/second)."`
|
||||
P2PRateLimitBurst int `mapstructure:"p2p-rate-limit-burst" toml:"p2p-rate-limit-burst" comment:"Maximum burst size for P2P rate limiter."`
|
||||
}
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Enable: true,
|
||||
// UseDistsig: false,
|
||||
// EthURL: "ws://127.0.0.1:8545",
|
||||
|
||||
// Default rate limiting: 10 messages/second with burst of 20
|
||||
P2PRateLimitEnable: true,
|
||||
P2PRateLimitRate: 10.0,
|
||||
P2PRateLimitBurst: 20,
|
||||
}
|
||||
}
|
||||
|
||||
func (c Config) Validate() error {
|
||||
if !c.Enable {
|
||||
return nil
|
||||
}
|
||||
if c.EthKey == "" {
|
||||
return errors.New("nitro.eth-key must be set")
|
||||
}
|
||||
// TODO With distsig enabled, eth-key will be a mutually exclusive setting, and authentication
|
||||
// for signing groups will be done using longterm key
|
||||
//
|
||||
// if c.UseDistsig && c.EthKey != "" {
|
||||
// return errors.New("nitro.eth-key should not be set when distsig is enabled")
|
||||
// }
|
||||
|
||||
// Validate rate limiting config
|
||||
if c.P2PRateLimitEnable {
|
||||
if c.P2PRateLimitRate <= 0 {
|
||||
return errors.New("nitro.p2p-rate-limit-rate must be positive when rate limiting is enabled")
|
||||
}
|
||||
if c.P2PRateLimitBurst <= 0 {
|
||||
return errors.New("nitro.p2p-rate-limit-burst must be positive when rate limiting is enabled")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UnmarshalConfig(cfg map[string]any) (*Config, error) {
|
||||
config := DefaultConfig()
|
||||
if len(cfg) > 0 {
|
||||
if err := server.UnmarshalSubConfig(cfg, serverName, config); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal %T: %w", config, err)
|
||||
}
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
71
server/nitro/config_test.go
Normal file
71
server/nitro/config_test.go
Normal file
@ -0,0 +1,71 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfigValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config Config
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid config with rate limiting",
|
||||
config: Config{
|
||||
Enable: true,
|
||||
EthKey: "test-eth-key",
|
||||
P2PRateLimitEnable: true,
|
||||
P2PRateLimitRate: 10.0,
|
||||
P2PRateLimitBurst: 20,
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid rate - zero",
|
||||
config: Config{
|
||||
Enable: true,
|
||||
EthKey: "test-eth-key",
|
||||
P2PRateLimitEnable: true,
|
||||
P2PRateLimitRate: 0,
|
||||
P2PRateLimitBurst: 20,
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid burst - zero",
|
||||
config: Config{
|
||||
Enable: true,
|
||||
EthKey: "test-eth-key",
|
||||
P2PRateLimitEnable: true,
|
||||
P2PRateLimitRate: 10.0,
|
||||
P2PRateLimitBurst: 0,
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "rate limiting disabled - no validation needed",
|
||||
config: Config{
|
||||
Enable: true,
|
||||
EthKey: "test-eth-key",
|
||||
P2PRateLimitEnable: false,
|
||||
P2PRateLimitRate: 0, // Invalid but should be ignored
|
||||
P2PRateLimitBurst: 0, // Invalid but should be ignored
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.config.Validate()
|
||||
if tt.expectErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
30
server/nitro/flags.go
Normal file
30
server/nitro/flags.go
Normal file
@ -0,0 +1,30 @@
|
||||
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 (
|
||||
FlagEthKey = prefix("eth-key")
|
||||
FlagEthURL = prefix("eth-url")
|
||||
FlagEthStartBlock = prefix("eth-start-block")
|
||||
FlagEthAuthToken = prefix("eth-auth-token")
|
||||
|
||||
// FlagEthNaAddress = prefix("eth-na-address")
|
||||
// FlagEthVpaAddress = prefix("eth-vpa-address")
|
||||
// FlagEthCaAddress = prefix("eth-ca-address")
|
||||
)
|
||||
|
||||
func AddFlags(f *pflag.FlagSet) {
|
||||
f.String(FlagEthKey, "", "name of private key to use when interacting with the Ethereum chain")
|
||||
f.String(FlagEthURL, "ws://127.0.0.1:8545", "URL of the Ethereum node to connect to")
|
||||
f.String(FlagEthAuthToken, "", "bearer token used for auth in requests to the Ethereum chain's RPC endpoint")
|
||||
f.Uint64(FlagEthStartBlock, 0, "Ethereum block number to start listening for Nitro Adjudicator events")
|
||||
}
|
||||
286
server/nitro/p2p.go
Normal file
286
server/nitro/p2p.go
Normal file
@ -0,0 +1,286 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"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"
|
||||
nitrotypes "github.com/statechannels/go-nitro/types"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
const (
|
||||
P2PMessageChannel = byte(0x80)
|
||||
// SigRequestChannel = byte(0x81)
|
||||
|
||||
maxMsgSize = 1024 * 1024
|
||||
msgBufSize = 1000
|
||||
limiterTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
_ p2p.Reactor = (*p2pReactor)(nil)
|
||||
_ nitrop2p.MessageService = (*p2pMsgService)(nil)
|
||||
)
|
||||
|
||||
// p2pReactor handles Nitro P2P messages via CometBFT
|
||||
type p2pReactor struct {
|
||||
p2p.BaseReactor
|
||||
incoming chan nitrop2p.Message
|
||||
outgoing map[p2p.ID]chan nitrop2p.Message
|
||||
sendQueue chan nitrop2p.Message
|
||||
rateLimiter *rate.Limiter
|
||||
config *Config
|
||||
logger log.Logger
|
||||
mtx sync.RWMutex
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
type p2pMsgService struct {
|
||||
id string
|
||||
logger log.Logger
|
||||
reactor *p2pReactor // one reactor per msg service
|
||||
}
|
||||
|
||||
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 }
|
||||
|
||||
// Reactor
|
||||
|
||||
func newReactor(config *Config, logger log.Logger) *p2pReactor {
|
||||
var rateLimiter *rate.Limiter
|
||||
if config.P2PRateLimitEnable {
|
||||
rateLimiter = rate.NewLimiter(rate.Limit(config.P2PRateLimitRate), config.P2PRateLimitBurst)
|
||||
}
|
||||
|
||||
ret := &p2pReactor{
|
||||
incoming: make(chan nitrop2p.Message, msgBufSize),
|
||||
outgoing: make(map[p2p.ID]chan nitrop2p.Message),
|
||||
sendQueue: make(chan nitrop2p.Message, msgBufSize),
|
||||
rateLimiter: rateLimiter,
|
||||
config: config,
|
||||
logger: logger,
|
||||
}
|
||||
ret.BaseReactor = *p2p.NewBaseReactor("nitro-reactor", ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
// StreamDescriptors returns the stream descriptor for Nitro messages.
|
||||
func (r *p2pReactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
return []*p2p.ChannelDescriptor{
|
||||
{
|
||||
ID: P2PMessageChannel,
|
||||
Priority: 5,
|
||||
SendQueueCapacity: 100,
|
||||
RecvBufferCapacity: 1000,
|
||||
RecvMessageCapacity: maxMsgSize,
|
||||
MessageType: &P2PMessage{},
|
||||
},
|
||||
// TODO Nitro peer info channel
|
||||
}
|
||||
}
|
||||
|
||||
// AddPeer begins sending messages to a peer.
|
||||
func (r *p2pReactor) AddPeer(peer p2p.Peer) {
|
||||
if !r.IsRunning() {
|
||||
return
|
||||
}
|
||||
|
||||
peerCh := make(chan nitrop2p.Message, msgBufSize)
|
||||
r.mtx.Lock()
|
||||
r.outgoing[peer.ID()] = peerCh
|
||||
r.mtx.Unlock()
|
||||
|
||||
// Start goroutine to handle sending to this specific peer
|
||||
go r.handlePeer(peer, peerCh)
|
||||
}
|
||||
|
||||
func (r *p2pReactor) handlePeer(peer p2p.Peer, peerCh chan nitrop2p.Message) {
|
||||
logger := r.logger.With("peer", peer)
|
||||
|
||||
defer func() {
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
if _, ok := r.outgoing[peer.ID()]; ok {
|
||||
close(peerCh)
|
||||
delete(r.outgoing, peer.ID())
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
if !peer.IsRunning() || !r.IsRunning() {
|
||||
return
|
||||
}
|
||||
inner_loop:
|
||||
for {
|
||||
select {
|
||||
case msg := <-peerCh:
|
||||
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)
|
||||
return
|
||||
}
|
||||
default:
|
||||
break inner_loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Receive handles an envelope received from any connected peer on any registered channel.
|
||||
func (r *p2pReactor) 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.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))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *p2pReactor) OnStart() error {
|
||||
// Start the single sending goroutine
|
||||
r.wg.Add(1)
|
||||
go r.sendLoop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *p2pReactor) OnStop() { r.close() }
|
||||
|
||||
func (r *p2pReactor) close() {
|
||||
close(r.incoming)
|
||||
close(r.sendQueue)
|
||||
r.wg.Wait() // Wait for sending goroutine to finish
|
||||
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
for id, ch := range r.outgoing {
|
||||
close(ch)
|
||||
delete(r.outgoing, id)
|
||||
}
|
||||
}
|
||||
|
||||
// sendLoop runs in a single goroutine and handles all outgoing messages with rate limiting
|
||||
func (r *p2pReactor) sendLoop() {
|
||||
defer r.wg.Done()
|
||||
|
||||
for msg := range r.sendQueue {
|
||||
// Apply rate limiting if enabled
|
||||
if r.rateLimiter != nil {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), limiterTimeout)
|
||||
if err := r.rateLimiter.Wait(ctx); err != nil {
|
||||
r.logger.Error("Rate limit exceeded, dropping message", "error", err)
|
||||
cancel()
|
||||
continue
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
|
||||
// Send to all connected peers
|
||||
r.mtx.RLock()
|
||||
for peerID, ch := range r.outgoing {
|
||||
select {
|
||||
case ch <- msg:
|
||||
// Message sent successfully
|
||||
default:
|
||||
// Channel is full, log warning but don't block
|
||||
r.logger.Warn("Peer channel full, dropping message", "peer", peerID)
|
||||
}
|
||||
}
|
||||
r.mtx.RUnlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *p2pReactor) send(msg nitrop2p.Message) {
|
||||
select {
|
||||
case r.sendQueue <- msg:
|
||||
// Message queued successfully
|
||||
default:
|
||||
// Send queue is full, log error
|
||||
r.logger.Error("Send queue full, dropping message")
|
||||
}
|
||||
}
|
||||
|
||||
// GetRateLimitStats returns current rate limiting statistics
|
||||
func (r *p2pReactor) GetRateLimitStats() (enabled bool, limit float64, burst int, tokens float64) {
|
||||
if r.rateLimiter == nil {
|
||||
return false, 0, 0, 0
|
||||
}
|
||||
return true, float64(r.rateLimiter.Limit()), r.rateLimiter.Burst(), r.rateLimiter.Tokens()
|
||||
}
|
||||
|
||||
// UpdateRateLimit updates the rate limiting parameters at runtime
|
||||
func (r *p2pReactor) UpdateRateLimit(newRate float64, newBurst int) {
|
||||
if r.rateLimiter != nil {
|
||||
r.rateLimiter.SetLimit(rate.Limit(newRate))
|
||||
r.rateLimiter.SetBurst(newBurst)
|
||||
}
|
||||
}
|
||||
|
||||
// MessageService
|
||||
|
||||
func newMessageService(id string, r *p2pReactor /* , logger log.Logger */) *p2pMsgService {
|
||||
return &p2pMsgService{
|
||||
id: id,
|
||||
reactor: r,
|
||||
// logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *p2pMsgService) P2PMessages() <-chan nitrop2p.Message {
|
||||
return ms.reactor.incoming
|
||||
}
|
||||
|
||||
func (ms *p2pMsgService) Send(p nitrotypes.Participant, m nitrop2p.Message) error {
|
||||
if !ms.reactor.IsRunning() {
|
||||
return errors.New("reactor not running")
|
||||
}
|
||||
|
||||
ms.reactor.send(m)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms *p2pMsgService) Close() error {
|
||||
// the lifecycle of the reactor is managed by cometbft
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms *p2pMsgService) Id() string {
|
||||
return ms.id
|
||||
}
|
||||
317
server/nitro/p2p.pb.go
Normal file
317
server/nitro/p2p.pb.go
Normal file
@ -0,0 +1,317 @@
|
||||
// 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
|
||||
|
||||
// P2PMessage wraps a json-encoded Nitro protocols.Message
|
||||
// TODO: proper proto message?
|
||||
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")
|
||||
)
|
||||
74
server/nitro/p2p_ratelimit_test.go
Normal file
74
server/nitro/p2p_ratelimit_test.go
Normal file
@ -0,0 +1,74 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
nitrop2p "github.com/statechannels/go-nitro/node/engine/messageservice"
|
||||
nitrotypes "github.com/statechannels/go-nitro/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestP2PRateLimit(t *testing.T) {
|
||||
// Test with rate limiting enabled
|
||||
config := &Config{
|
||||
P2PRateLimitEnable: true,
|
||||
P2PRateLimitRate: 2.0, // 2 messages per second
|
||||
P2PRateLimitBurst: 2, // burst of 2
|
||||
}
|
||||
|
||||
reactor := newReactor(config, log.NewNopLogger())
|
||||
|
||||
// Check rate limit stats
|
||||
enabled, limit, burst, tokens := reactor.GetRateLimitStats()
|
||||
assert.True(t, enabled, "Rate limiting should be enabled")
|
||||
assert.Equal(t, 2.0, limit, "Rate limit should be 2.0")
|
||||
assert.Equal(t, 2, burst, "Burst should be 2")
|
||||
assert.Equal(t, float64(2), tokens, "Initial tokens should equal burst size")
|
||||
|
||||
// Test that UpdateRateLimit works
|
||||
reactor.UpdateRateLimit(5.0, 10)
|
||||
enabled, limit, burst, _ = reactor.GetRateLimitStats()
|
||||
assert.True(t, enabled)
|
||||
assert.Equal(t, 5.0, limit)
|
||||
assert.Equal(t, 10, burst)
|
||||
}
|
||||
|
||||
func TestP2PRateLimitDisabled(t *testing.T) {
|
||||
// Test with rate limiting disabled
|
||||
config := &Config{
|
||||
P2PRateLimitEnable: false,
|
||||
}
|
||||
|
||||
reactor := newReactor(config, log.NewNopLogger())
|
||||
|
||||
// Check rate limit stats
|
||||
enabled, limit, burst, tokens := reactor.GetRateLimitStats()
|
||||
assert.False(t, enabled, "Rate limiting should be disabled")
|
||||
assert.Equal(t, 0.0, limit)
|
||||
assert.Equal(t, 0, burst)
|
||||
assert.Equal(t, 0.0, tokens)
|
||||
}
|
||||
|
||||
func TestP2PRateLimitSendBehavior(t *testing.T) {
|
||||
// Test actual send behavior with rate limiting
|
||||
config := &Config{
|
||||
P2PRateLimitEnable: true,
|
||||
P2PRateLimitRate: 1000.0, // High rate for testing
|
||||
P2PRateLimitBurst: 1, // Small burst
|
||||
}
|
||||
|
||||
reactor := newReactor(config, log.NewNopLogger())
|
||||
msgService := newMessageService("test", reactor)
|
||||
|
||||
// Create a dummy participant and message
|
||||
participant, _ := nitrotypes.ParseParticipant("0x0000000000000000000000000000000000000001")
|
||||
message := nitrop2p.Message{}
|
||||
|
||||
// This should return an error because reactor is not running
|
||||
err := msgService.Send(participant, message)
|
||||
|
||||
// We expect an error because reactor is not running
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "reactor not running")
|
||||
}
|
||||
166
server/nitro/protocol.go
Normal file
166
server/nitro/protocol.go
Normal file
@ -0,0 +1,166 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/statechannels/go-nitro/channel/state/outcome"
|
||||
"github.com/statechannels/go-nitro/protocols"
|
||||
nitrotypes "github.com/statechannels/go-nitro/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/x/nitro/types/v1"
|
||||
)
|
||||
|
||||
type MsgWrapper struct {
|
||||
Msg sdk.Msg
|
||||
Objective protocols.ObjectiveId
|
||||
SignerField *string
|
||||
}
|
||||
|
||||
func (s *Server) OpenLedgerChannel(funds nitrotypes.Funds, counterparty nitrotypes.Participant) (*MsgWrapper, error) {
|
||||
// TODO: handle multiple assets
|
||||
if len(funds) != 1 {
|
||||
return nil, errors.New("only one asset is supported")
|
||||
}
|
||||
fund, exit := makeOutcome(s.ethAddress, counterparty, funds)
|
||||
|
||||
r, err := s.node.CreateLedgerChannel(counterparty, 0, exit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.logger.Info("Initiated objective", "id", r.Id)
|
||||
|
||||
// Convert nitrotypes.Funds back to sdk.Coins for the message
|
||||
// Use "token" as a default denomination for now
|
||||
// TODO: nitro will store a mapping of denoms to token addresses
|
||||
// an entry will be added for new denominations upon confirmation of ledger deposit
|
||||
coins := sdk.Coins{sdk.NewCoin("token", math.NewIntFromBigInt(fund.Amount))}
|
||||
|
||||
msg := &v1.MsgOpenChannel{
|
||||
Funds: coins,
|
||||
NitroAddress: s.ethAddress.String(),
|
||||
Counterparty: counterparty.String(),
|
||||
ChannelId: r.ChannelId.String(),
|
||||
}
|
||||
return &MsgWrapper{msg, r.Id, &msg.Signer}, nil
|
||||
}
|
||||
|
||||
func (s *Server) CloseLedgerChannel(channelId nitrotypes.ChannelID, isChallenge bool) (*MsgWrapper, error) {
|
||||
objective, err := s.node.CloseLedgerChannel(channelId, isChallenge)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.logger.Info("Initiated objective", "id", objective)
|
||||
|
||||
msg := &v1.MsgCloseChannel{
|
||||
ChannelId: channelId.String(),
|
||||
IsChallenge: isChallenge,
|
||||
}
|
||||
return &MsgWrapper{msg, objective, &msg.Signer}, nil
|
||||
}
|
||||
|
||||
func (s *Server) CreatePaymentChannel(intermediaries []string, counterpartyString string, challengeDuration uint32, funds nitrotypes.Funds) (*MsgWrapper, error) {
|
||||
// Parse intermediaries
|
||||
var intermediaryParticipants []nitrotypes.Participant
|
||||
for _, addr := range intermediaries {
|
||||
participant, err := nitrotypes.ParseParticipant(addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse intermediary %s: %w", addr, err)
|
||||
}
|
||||
intermediaryParticipants = append(intermediaryParticipants, participant)
|
||||
}
|
||||
|
||||
// Parse counterparty
|
||||
counterparty, err := nitrotypes.ParseParticipant(counterpartyString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse counterparty: %w", err)
|
||||
}
|
||||
|
||||
// TODO: handle multiple assets
|
||||
if len(funds) != 1 {
|
||||
return nil, errors.New("only one asset is supported")
|
||||
}
|
||||
if len(funds) != 1 {
|
||||
return nil, errors.New("only one asset is supported")
|
||||
}
|
||||
fund, exit := makeOutcome(s.ethAddress, counterparty, funds)
|
||||
|
||||
// Create payment channel
|
||||
r, err := s.node.CreatePaymentChannel(intermediaryParticipants, counterparty, challengeDuration, exit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.logger.Info("Initiated payment channel objective", "id", r.Id)
|
||||
|
||||
// Convert nitrotypes.Funds back to sdk.Coins for the message
|
||||
coins := sdk.Coins{sdk.NewCoin("token", math.NewIntFromBigInt(fund.Amount))}
|
||||
|
||||
msg := &v1.MsgCreatePaymentChannel{
|
||||
NitroAddress: s.ethAddress.String(),
|
||||
Counterparty: counterpartyString,
|
||||
Intermediaries: intermediaries,
|
||||
ChallengeDuration: challengeDuration,
|
||||
Funds: coins,
|
||||
ChannelId: r.ChannelId.String(),
|
||||
}
|
||||
return &MsgWrapper{msg, r.Id, &msg.Signer}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ClosePaymentChannel(channelId nitrotypes.ChannelID) (*MsgWrapper, error) {
|
||||
objective, err := s.node.ClosePaymentChannel(channelId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.logger.Info("Initiated payment channel close objective", "id", objective)
|
||||
|
||||
msg := &v1.MsgClosePaymentChannel{
|
||||
ChannelId: channelId.String(),
|
||||
}
|
||||
return &MsgWrapper{msg, objective, &msg.Signer}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Pay(channelId nitrotypes.ChannelID, amount sdk.Coin) (*MsgWrapper, error) {
|
||||
err := s.node.Pay(channelId, amount.Amount.BigInt())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodeAddrStr, err := s.addressCodec.BytesToString(s.nodeAddress())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg := &v1.MsgPay{
|
||||
ChannelId: channelId.String(),
|
||||
Amount: amount,
|
||||
Signer: nodeAddrStr,
|
||||
}
|
||||
return &MsgWrapper{msg, "", &msg.Signer}, nil
|
||||
}
|
||||
|
||||
func makeOutcome(ethAddress, counterparty nitrotypes.Participant, funds nitrotypes.Funds) (nitrotypes.Fund, outcome.Exit) {
|
||||
var fund nitrotypes.Fund
|
||||
for asset, amount := range funds {
|
||||
fund = nitrotypes.Fund{asset, amount}
|
||||
}
|
||||
|
||||
exit := outcome.Exit{
|
||||
outcome.SingleAssetExit{
|
||||
Asset: fund.Asset,
|
||||
Allocations: []outcome.Allocation{
|
||||
{
|
||||
Destination: ethAddress.ToDestination(),
|
||||
Amount: fund.Amount,
|
||||
},
|
||||
{
|
||||
Destination: counterparty.ToDestination(),
|
||||
Amount: big.NewInt(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return fund, exit
|
||||
}
|
||||
194
server/nitro/query.go
Normal file
194
server/nitro/query.go
Normal file
@ -0,0 +1,194 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/spf13/cobra"
|
||||
nitrotypes "github.com/statechannels/go-nitro/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
"git.vdb.to/cerc-io/laconicd/server/relay"
|
||||
)
|
||||
|
||||
func GetChannelCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "get-channel <channel-id>",
|
||||
Short: "Get information about a channel",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Long: "Retrieves detailed information about a specific ledger or payment channel.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
channelId, err := nitrotypes.ParseChannelID(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse channel ID: %w", err)
|
||||
}
|
||||
|
||||
ledger, _ := cmd.Flags().GetBool("ledger")
|
||||
payment, _ := cmd.Flags().GetBool("payment")
|
||||
local, _ := cmd.Flags().GetBool("local")
|
||||
|
||||
if !ledger && !payment {
|
||||
ledger = true
|
||||
}
|
||||
if ledger && payment {
|
||||
return fmt.Errorf("cannot specify both --ledger and --payment flags")
|
||||
}
|
||||
|
||||
s, done, err := setupNitroQueryCommand(cmd, !local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
var output []byte
|
||||
if ledger {
|
||||
info, err := s.node.GetLedgerChannel(channelId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get ledger channel: %w", err)
|
||||
}
|
||||
output, err = json.MarshalIndent(info, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal response: %w", err)
|
||||
}
|
||||
} else {
|
||||
info, err := s.node.GetPaymentChannel(channelId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get payment channel: %w", err)
|
||||
}
|
||||
output, err = json.MarshalIndent(info, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal response: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Bool("ledger", false, "Get ledger channel information")
|
||||
cmd.Flags().Bool("payment", false, "Get payment channel information")
|
||||
cmd.Flags().Bool("local", false, "Query local data only (no P2P connection)")
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ListChannelsCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "list-channels",
|
||||
Short: "List all ledger channels",
|
||||
Args: cobra.NoArgs,
|
||||
Long: "Retrieves information about all ledger channels.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
local, _ := cmd.Flags().GetBool("local")
|
||||
|
||||
s, done, err := setupNitroQueryCommand(cmd, !local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
channels, err := s.node.GetAllLedgerChannels()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get all ledger channels: %w", err)
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(channels, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal response: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Bool("local", false, "Query local data only (no P2P connection)")
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ListPaymentChannelsCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "list-payment-channels <ledger-channel-id>",
|
||||
Short: "List all payment channels for a ledger channel",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Long: "Retrieves all active payment channels associated with a specific ledger channel.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ledgerChannelId, err := nitrotypes.ParseChannelID(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse ledger channel ID: %w", err)
|
||||
}
|
||||
|
||||
local, _ := cmd.Flags().GetBool("local")
|
||||
|
||||
s, done, err := setupNitroQueryCommand(cmd, !local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
channels, err := s.node.GetPaymentChannelsByLedger(ledgerChannelId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get payment channels: %w", err)
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(channels, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal response: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Bool("local", false, "Query local data only (no P2P connection)")
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func IdentityCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "identity",
|
||||
Short: "Get the node identity",
|
||||
Args: cobra.NoArgs,
|
||||
Long: "Retrieves the node's identity. Use --participant for principal ID (default) or --network for network address.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
participant, _ := cmd.Flags().GetBool("participant")
|
||||
network, _ := cmd.Flags().GetBool("network")
|
||||
|
||||
if !participant && !network {
|
||||
participant = true
|
||||
}
|
||||
if participant && network {
|
||||
return fmt.Errorf("cannot specify both --participant and --network flags")
|
||||
}
|
||||
|
||||
s, done, err := setupNitroQueryCommand(cmd, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
if participant {
|
||||
identity := s.node.PrincipalID()
|
||||
fmt.Println(identity.String())
|
||||
} else {
|
||||
identity := s.node.NetworkID()
|
||||
fmt.Println(identity.String())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Bool("participant", false, "Get the principal ID (default)")
|
||||
cmd.Flags().Bool("network", false, "Get the network address")
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
server.SetRequiredComponents(cmd, &Server{})
|
||||
return cmd
|
||||
}
|
||||
210
server/nitro/server.go
Normal file
210
server/nitro/server.go
Normal file
@ -0,0 +1,210 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
|
||||
cmtcrypto "github.com/cometbft/cometbft/crypto"
|
||||
"github.com/cometbft/cometbft/p2p"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/spf13/pflag"
|
||||
nitrocrypto "github.com/statechannels/go-nitro/crypto"
|
||||
"github.com/statechannels/go-nitro/node"
|
||||
"github.com/statechannels/go-nitro/node/engine"
|
||||
"github.com/statechannels/go-nitro/node/engine/chainservice"
|
||||
chainutils "github.com/statechannels/go-nitro/node/engine/chainservice/utils"
|
||||
"github.com/statechannels/go-nitro/node/engine/store"
|
||||
nitrotypes "github.com/statechannels/go-nitro/types"
|
||||
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/log"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
serverName = "nitro"
|
||||
|
||||
ServerContextKey = "server." + serverName
|
||||
)
|
||||
|
||||
// TODO
|
||||
// 1. implement participation as a signing group member:
|
||||
// 1.1. initialize group delegate credentials, with distsig over ABCI
|
||||
// 1.2. bind custodian contract for chain/adjudicator actions
|
||||
// 2. operation to update DKG group members
|
||||
// 3. integrate with onboarding module
|
||||
|
||||
// Server wraps and configures a go-nitro Node.
|
||||
type Server struct {
|
||||
logger log.Logger
|
||||
config *Config
|
||||
node *node.Node
|
||||
storeDir string // path to Nitro store directory
|
||||
reactor *p2pReactor
|
||||
keyring keyring.Keyring
|
||||
addressCodec address.Codec
|
||||
ethAddress nitrotypes.Address
|
||||
nodeKey cmtcrypto.PrivKey
|
||||
// participantID nitrotypes.Participant
|
||||
ready atomic.Bool
|
||||
}
|
||||
|
||||
func New(globalConfig server.ConfigMap, logger log.Logger, kr keyring.Keyring) (*Server, error) {
|
||||
home, _ := globalConfig[flags.FlagHome].(string)
|
||||
cfg, err := UnmarshalConfig(globalConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &Server{
|
||||
config: cfg,
|
||||
storeDir: filepath.Join(home, "nitro"),
|
||||
reactor: newReactor(cfg, logger.With(log.ModuleKey, serverName, "component", "p2p-reactor")),
|
||||
keyring: kr,
|
||||
logger: logger.With(log.ModuleKey, serverName),
|
||||
addressCodec: utils.NewAddressCodec(),
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (*Server) Name() string {
|
||||
return serverName
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
// TODO: pass keyring through context?
|
||||
if err := s.init(s.keyring); err != nil {
|
||||
return err
|
||||
}
|
||||
s.logger.Info("starting Nitro server")
|
||||
s.ready.Store(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Stop(context.Context) error {
|
||||
s.logger.Info("stopping Nitro server")
|
||||
s.ready.Store(false)
|
||||
if s.node != nil {
|
||||
return s.node.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) init(kr keyring.Keyring) error {
|
||||
var (
|
||||
ethkey cmtcrypto.PrivKey
|
||||
err error
|
||||
c = s.config
|
||||
)
|
||||
if c.EthKey != "" {
|
||||
ethkey, err = utils.ExtractPrivateKeyByUid(kr, c.EthKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("eth-key is not set") // should already be caught by Config.Validate
|
||||
}
|
||||
s.nodeKey = ethkey
|
||||
|
||||
storeOpts := store.StoreOpts{
|
||||
UseDurableStore: true,
|
||||
DurableStoreDir: s.storeDir,
|
||||
}
|
||||
chainOpts := chainservice.ChainOpts{
|
||||
ChainUrl: c.EthURL,
|
||||
StartBlockNum: c.EthStartBlock,
|
||||
ChainAuthToken: c.EthAuthToken,
|
||||
ChainPk: hex.EncodeToString(ethkey.Bytes()),
|
||||
}
|
||||
// inject SDK logger into slog, which Nitro uses
|
||||
loggerImpl, ok := s.logger.Impl().(*slog.Logger)
|
||||
if ok {
|
||||
slog.SetDefault(loggerImpl)
|
||||
} else {
|
||||
s.logger.Warn("Logger backend is not slog, cannot set as Nitro logger")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
chainOpts.StartBlockNum = max(storeBlockNum, chainOpts.StartBlockNum)
|
||||
|
||||
contractAddresses := node.ContractAddresses{
|
||||
NaAddress: common.HexToAddress(c.EthNaAddress),
|
||||
VpaAddress: common.HexToAddress(c.EthVpaAddress),
|
||||
CaAddress: common.HexToAddress(c.EthCaAddress),
|
||||
}
|
||||
chainOpts.CreateAdjudicator = chainutils.AdjudicatorCreator(contractAddresses.NaAddress)
|
||||
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.ethAddress = nitrotypes.Address(crypto.PubkeyToAddress(*ethPubkey))
|
||||
|
||||
s.node = node.New(
|
||||
newMessageService("laconicd-p2p-"+s.ethAddress.String(), s.reactor),
|
||||
chain,
|
||||
store,
|
||||
&engine.PermissivePolicy{},
|
||||
nitrocrypto.NewSimpleCredential(ethkey.Bytes()),
|
||||
contractAddresses,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
AddFlags(flags)
|
||||
return flags
|
||||
}
|
||||
|
||||
func (s *Server) Ready() bool {
|
||||
return s.ready.Load()
|
||||
}
|
||||
|
||||
func (s *Server) ContextKey() string {
|
||||
return ServerContextKey
|
||||
}
|
||||
|
||||
func (s *Server) P2PReactors() map[string]p2p.Reactor {
|
||||
return map[string]p2p.Reactor{"NITRO": s.reactor}
|
||||
}
|
||||
|
||||
func (s *Server) nodeAddress() sdk.AccAddress {
|
||||
return sdk.AccAddress(s.nodeKey.PubKey().Address())
|
||||
}
|
||||
326
server/nitro/tx.go
Normal file
326
server/nitro/tx.go
Normal file
@ -0,0 +1,326 @@
|
||||
package nitro
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/statechannels/go-nitro/node/query"
|
||||
nitrotypes "github.com/statechannels/go-nitro/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
"git.vdb.to/cerc-io/laconicd/server/relay"
|
||||
)
|
||||
|
||||
func OpenChannelCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "open-channel <counterparty> <amount>",
|
||||
Short: "Open a ledger channel with the given counterparty",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Long: "Creates a ledger channel with the specified counterparty and funding amount.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
counterparty, err := nitrotypes.ParseParticipant(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse counterparty: %w", err)
|
||||
}
|
||||
|
||||
clientCtx, s, done, err := setupNitroCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
assetAddr, _ := cmd.Flags().GetString("asset")
|
||||
funds, err := resolveTokens(s, args[1], assetAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m, err := s.OpenLedgerChannel(funds, counterparty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = waitForObjective(
|
||||
s.node.FailedObjectives(),
|
||||
m.Objective,
|
||||
s.node.LedgerUpdatedChan(m.Objective.ChannelID()),
|
||||
func(info query.LedgerChannelInfo) bool { return info.Status == query.Open },
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return submitNitroTx(*clientCtx, cmd, *m, false)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String("asset", "", "Ethereum token address (if specified, amount is parsed as decimal without denomination)")
|
||||
AddFlags(cmd.Flags())
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func CloseChannelCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "close-channel <channel-id>",
|
||||
Short: "Close a ledger channel",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Long: "Close a ledger channel. Use --challenge flag for dispute resolution when cooperation fails.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
channelId, err := nitrotypes.ParseChannelID(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse channel ID: %w", err)
|
||||
}
|
||||
|
||||
isChallenge, err := cmd.Flags().GetBool("challenge")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientCtx, s, done, err := setupNitroCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
m, err := s.CloseLedgerChannel(channelId, isChallenge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = waitForObjective(
|
||||
s.node.FailedObjectives(),
|
||||
m.Objective,
|
||||
s.node.LedgerUpdatedChan(channelId),
|
||||
func(info query.LedgerChannelInfo) bool { return info.Status == query.Complete },
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return submitNitroTx(*clientCtx, cmd, *m, false)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Bool("challenge", false, "Close via challenge (dispute resolution) instead of cooperative closure")
|
||||
AddFlags(cmd.Flags())
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func OpenPaymentChannelCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "open-payment-channel <counterparty> <amount> [intermediaries...]",
|
||||
Short: "Open a virtual payment channel",
|
||||
Args: cobra.MinimumNArgs(2),
|
||||
Long: "Creates a virtual payment channel with the specified counterparty and optional intermediaries.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
counterparty := args[0]
|
||||
|
||||
challengeDuration, err := cmd.Flags().GetUint32("challenge-duration")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var intermediaries []string
|
||||
if len(args) > 2 {
|
||||
intermediaries = args[2:]
|
||||
}
|
||||
|
||||
clientCtx, s, done, err := setupNitroCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
assetAddr, _ := cmd.Flags().GetString("asset")
|
||||
funds, err := resolveTokens(s, args[1], assetAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m, err := s.CreatePaymentChannel(intermediaries, counterparty, challengeDuration, funds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = waitForObjective(
|
||||
s.node.FailedObjectives(),
|
||||
m.Objective,
|
||||
s.node.PaymentChannelUpdatedChan(m.Objective.ChannelID()),
|
||||
func(info query.PaymentChannelInfo) bool { return info.Status == query.Open },
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return submitNitroTx(*clientCtx, cmd, *m, false)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String("asset", "", "Ethereum token address (if specified, amount is parsed as decimal without denomination)")
|
||||
cmd.Flags().Uint32("challenge-duration", 0, "Challenge duration for the channel")
|
||||
AddFlags(cmd.Flags())
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ClosePaymentChannelCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "close-payment-channel <channel-id>",
|
||||
Short: "Close a virtual payment channel",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Long: "Close a virtual payment channel with the given channel ID.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
channelId, err := nitrotypes.ParseChannelID(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse channel ID: %w", err)
|
||||
}
|
||||
|
||||
clientCtx, s, done, err := setupNitroCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
m, err := s.ClosePaymentChannel(channelId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = waitForObjective(
|
||||
s.node.FailedObjectives(),
|
||||
m.Objective,
|
||||
s.node.PaymentChannelUpdatedChan(channelId),
|
||||
func(info query.PaymentChannelInfo) bool { return info.Status == query.Complete },
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return submitNitroTx(*clientCtx, cmd, *m, false)
|
||||
},
|
||||
}
|
||||
|
||||
AddFlags(cmd.Flags())
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func PayCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "pay <channel-id> <amount>",
|
||||
Short: "Send a payment through a payment channel",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Long: "Creates and sends a payment voucher through the specified payment channel.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
channelId, err := nitrotypes.ParseChannelID(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse channel ID: %w", err)
|
||||
}
|
||||
|
||||
coins, err := sdk.ParseCoinsNormalized(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse amount: %w", err)
|
||||
}
|
||||
if len(coins) != 1 {
|
||||
return fmt.Errorf("exactly one coin denomination required")
|
||||
}
|
||||
|
||||
clientCtx, s, done, err := setupNitroCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
info, err := s.node.GetPaymentChannel(channelId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
paidSoFar := info.Balance.PaidSoFar.ToInt()
|
||||
expectedAmount := new(big.Int).Add(paidSoFar, coins[0].Amount.BigInt())
|
||||
updateChan := s.node.PaymentChannelUpdatedChan(channelId)
|
||||
|
||||
m, err := s.Pay(channelId, coins[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send payment: %w", err)
|
||||
}
|
||||
|
||||
// TODO: unordered tx for payments: this could break if tx is sent before opening the
|
||||
// channel; think through wrt. state integration
|
||||
if err = submitNitroTx(*clientCtx, cmd, *m, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for info := range updateChan {
|
||||
if expectedAmount.Cmp(info.Balance.PaidSoFar.ToInt()) <= 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
delayAfterUpdate()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
AddFlags(cmd.Flags())
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func CreateVoucherCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "create-voucher <channel-id> <amount>",
|
||||
Short: "Create a payment voucher for a payment channel",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Long: "Creates a signed payment voucher that can be used to redeem payments from the specified channel.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
channelId, err := nitrotypes.ParseChannelID(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse channel ID: %w", err)
|
||||
}
|
||||
|
||||
coins, err := sdk.ParseCoinsNormalized(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse amount: %w", err)
|
||||
}
|
||||
|
||||
if len(coins) != 1 {
|
||||
return fmt.Errorf("exactly one coin denomination required")
|
||||
}
|
||||
amount := coins[0].Amount.BigInt()
|
||||
|
||||
s, done, err := setupNitroQueryCommand(cmd, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
voucher, err := s.node.CreateVoucher(channelId, amount)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create voucher: %w", err)
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(voucher, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal voucher: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
server.SetRequiredComponents(cmd, &Server{}, &relay.Server{})
|
||||
return cmd
|
||||
}
|
||||
23
server/relay/config.go
Normal file
23
server/relay/config.go
Normal file
@ -0,0 +1,23 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// Target string `mapstructure:"target" toml:"target" comment:"The target peer to relay messages to"`
|
||||
}
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
||||
func UnmarshalConfig(cfg map[string]any) (*Config, error) {
|
||||
config := DefaultConfig()
|
||||
if err := server.UnmarshalSubConfig(cfg, serverName, config); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal %T: %w", config, err)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
199
server/relay/server.go
Normal file
199
server/relay/server.go
Normal file
@ -0,0 +1,199 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
cmtcfg "github.com/cometbft/cometbft/config"
|
||||
"github.com/cometbft/cometbft/p2p"
|
||||
"github.com/cometbft/cometbft/p2p/pex"
|
||||
"github.com/cometbft/cometbft/version"
|
||||
cmtversion "github.com/cometbft/cometbft/version"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
)
|
||||
|
||||
const (
|
||||
serverName = "relay"
|
||||
|
||||
ServerContextKey = "server." + serverName
|
||||
)
|
||||
|
||||
// Server is a server component with CometBFT p2p capabilities
|
||||
type Server struct {
|
||||
logger log.Logger
|
||||
config *Config
|
||||
cometConfig *cmtcfg.Config
|
||||
nodeKey *p2p.NodeKey
|
||||
ready atomic.Bool
|
||||
}
|
||||
|
||||
type Switch struct {
|
||||
*p2p.Switch
|
||||
transport *p2p.MultiplexTransport
|
||||
}
|
||||
|
||||
func New(cfg server.ConfigMap, logger log.Logger) (*Server, error) {
|
||||
c, err := UnmarshalConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cometConfig := cmtcfg.DefaultConfig()
|
||||
if err := server.UnmarshalSubConfig(cfg, "", &cometConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Server{
|
||||
config: c,
|
||||
cometConfig: cometConfig,
|
||||
logger: logger.With(log.ModuleKey, serverName),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (*Server) Name() string {
|
||||
return serverName
|
||||
}
|
||||
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
var err error
|
||||
s.nodeKey, err = p2p.LoadOrGenNodeKey(s.cometConfig.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.ready.Store(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Stop(ctx context.Context) error {
|
||||
s.ready.Store(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Config() any {
|
||||
if s.config == nil {
|
||||
return DefaultConfig()
|
||||
}
|
||||
return s.config
|
||||
}
|
||||
|
||||
func (s *Server) Ready() bool {
|
||||
return s.ready.Load()
|
||||
}
|
||||
|
||||
func (s *Server) ContextKey() string {
|
||||
return ServerContextKey
|
||||
}
|
||||
|
||||
func (s *Server) GetSwitch(chainID string, blockVersion uint64) (*Switch, error) {
|
||||
nodeInfo, err := makeNodeInfo(s.cometConfig, s.nodeKey, chainID, blockVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transport := createTransport(s.cometConfig, nodeInfo, s.nodeKey)
|
||||
sw := p2p.NewSwitch(s.cometConfig.P2P, transport, p2p.SwitchPeerFilters())
|
||||
sw.SetNodeInfo(nodeInfo)
|
||||
sw.SetNodeKey(s.nodeKey)
|
||||
return &Switch{sw, transport}, nil
|
||||
}
|
||||
|
||||
func (s *Switch) AddReactor(name string, reactor p2p.Reactor) error {
|
||||
s.Switch.AddReactor(name, reactor)
|
||||
// register the new channels to the nodeInfo
|
||||
ni, ok := s.NodeInfo().(p2p.DefaultNodeInfo)
|
||||
if !ok {
|
||||
return errors.New("Node info is not of type DefaultNodeInfo")
|
||||
}
|
||||
for _, chDesc := range reactor.GetChannels() {
|
||||
if !ni.HasChannel(chDesc.ID) {
|
||||
ni.Channels = append(ni.Channels, chDesc.ID)
|
||||
s.transport.AddChannel(chDesc.ID)
|
||||
}
|
||||
}
|
||||
s.SetNodeInfo(ni)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Switch) Dial(peerAddr string) error {
|
||||
addr, err := p2p.NewNetAddressString(peerAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error resolving net address: %w", err)
|
||||
}
|
||||
err = s.AddPersistentPeers([]string{addr.String()})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error adding persistent peer: %w", err)
|
||||
}
|
||||
return s.DialPeerWithAddress(addr)
|
||||
}
|
||||
|
||||
func makeNodeInfo(
|
||||
config *cmtcfg.Config,
|
||||
nodeKey *p2p.NodeKey,
|
||||
chainID string,
|
||||
blockVersion uint64,
|
||||
) (p2p.DefaultNodeInfo, error) {
|
||||
nodeInfo := p2p.DefaultNodeInfo{
|
||||
ProtocolVersion: p2p.NewProtocolVersion(
|
||||
cmtversion.P2PProtocol,
|
||||
blockVersion,
|
||||
0,
|
||||
),
|
||||
DefaultNodeID: nodeKey.ID(),
|
||||
Network: chainID,
|
||||
Version: version.TMCoreSemVer,
|
||||
Channels: nil, // updated in AddReactor
|
||||
Moniker: config.Moniker,
|
||||
Other: p2p.DefaultNodeInfoOther{
|
||||
RPCAddress: config.RPC.ListenAddress,
|
||||
},
|
||||
}
|
||||
|
||||
if config.P2P.PexReactor {
|
||||
nodeInfo.Channels = append(nodeInfo.Channels, pex.PexChannel)
|
||||
}
|
||||
|
||||
lAddr := config.P2P.ExternalAddress
|
||||
|
||||
if lAddr == "" {
|
||||
lAddr = config.P2P.ListenAddress
|
||||
}
|
||||
|
||||
nodeInfo.ListenAddr = lAddr
|
||||
|
||||
// err := nodeInfo.Validate()
|
||||
return nodeInfo, nil
|
||||
}
|
||||
|
||||
func createTransport(
|
||||
config *cmtcfg.Config,
|
||||
nodeInfo p2p.NodeInfo,
|
||||
nodeKey *p2p.NodeKey,
|
||||
) *p2p.MultiplexTransport {
|
||||
var (
|
||||
mConnConfig = p2p.MConnConfig(config.P2P)
|
||||
transport = p2p.NewMultiplexTransport(nodeInfo, *nodeKey, mConnConfig)
|
||||
connFilters = []p2p.ConnFilterFunc{}
|
||||
)
|
||||
|
||||
if !config.P2P.AllowDuplicateIP {
|
||||
connFilters = append(connFilters, p2p.ConnDuplicateIPFilter())
|
||||
}
|
||||
|
||||
p2p.MultiplexTransportConnFilters(connFilters...)(transport)
|
||||
|
||||
// Limit the number of incoming connections.
|
||||
max := config.P2P.MaxNumInboundPeers
|
||||
p2p.MultiplexTransportMaxIncomingConnections(max)(transport)
|
||||
|
||||
return transport
|
||||
}
|
||||
|
||||
func removeProtocolIfDefined(addr string) string {
|
||||
if strings.Contains(addr, "://") {
|
||||
return strings.Split(addr, "://")[1]
|
||||
}
|
||||
return addr
|
||||
}
|
||||
20
server/relay/util.go
Normal file
20
server/relay/util.go
Normal file
@ -0,0 +1,20 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func GetServerFromCmd(cmd *cobra.Command) (*Server, error) {
|
||||
s, err := utils.GetFromContext[Server](cmd.Context(), ServerContextKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for !s.Ready() {
|
||||
s.logger.Debug("waiting for relay server")
|
||||
runtime.Gosched()
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
29
server/server.go
Normal file
29
server/server.go
Normal file
@ -0,0 +1,29 @@
|
||||
package server
|
||||
|
||||
// The utilities in this file are copied from cosmos-sdk server/v2
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// ServerComponent is a server component that can be started and stopped.
|
||||
type ServerComponent interface {
|
||||
// Name returns the name of the server component.
|
||||
Name() string
|
||||
|
||||
// Start starts the server component.
|
||||
Start(context.Context) error
|
||||
// Stop stops the server component.
|
||||
// Once Stop has been called on a server component, it may not be reused.
|
||||
Stop(context.Context) error
|
||||
}
|
||||
|
||||
// HasStartFlags is a server component that has start flags.
|
||||
type HasStartFlags interface {
|
||||
// StartCmdFlags returns server start flags.
|
||||
// Those flags should be prefixed with the server name.
|
||||
// They are then merged with the server config in one viper instance.
|
||||
StartCmdFlags() *pflag.FlagSet
|
||||
}
|
||||
@ -3,7 +3,6 @@ package keeper_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
|
||||
@ -19,7 +18,7 @@ type KeeperTestSuite struct {
|
||||
|
||||
func (kts *KeeperTestSuite) SetupTest() {
|
||||
err := kts.TestFixture.Setup()
|
||||
assert.Nil(kts.T(), err)
|
||||
kts.Require().NoError(err)
|
||||
|
||||
qr := kts.App.QueryHelper()
|
||||
kts.queryClient = types.NewQueryClient(qr)
|
||||
|
||||
@ -30,7 +30,7 @@ func (kts *KeeperTestSuite) TestGrpcQueryParams() {
|
||||
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().NoError(err)
|
||||
kts.Require().Equal(*(resp.Params), types.DefaultParams())
|
||||
})
|
||||
}
|
||||
@ -59,14 +59,14 @@ func (kts *KeeperTestSuite) TestGrpcGetAuction() {
|
||||
var expectedAuction types.Auction
|
||||
if test.createAuction {
|
||||
auction, _, err := kts.createAuctionAndCommitBid(false)
|
||||
kts.Require().Nil(err)
|
||||
kts.Require().NoError(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().NoError(err)
|
||||
kts.Require().NotNil(resp.GetAuction())
|
||||
kts.Require().EqualExportedValues(expectedAuction, *(resp.GetAuction()))
|
||||
} else {
|
||||
@ -103,7 +103,7 @@ func (kts *KeeperTestSuite) TestGrpcGetAllAuctions() {
|
||||
kts.Run(fmt.Sprintf("Case %s", test.msg), func() {
|
||||
if test.createAuctions {
|
||||
_, _, err := kts.createAuctionAndCommitBid(false)
|
||||
kts.Require().Nil(err)
|
||||
kts.Require().NoError(err)
|
||||
}
|
||||
|
||||
resp, _ := kts.queryClient.Auctions(context.Background(), test.req)
|
||||
@ -153,7 +153,7 @@ func (kts *KeeperTestSuite) TestGrpcGetBids() {
|
||||
|
||||
resp, err := kts.queryClient.GetBids(context.Background(), test.req)
|
||||
if test.createAuction {
|
||||
kts.Require().Nil(err)
|
||||
kts.Require().NoError(err)
|
||||
kts.Require().Equal(test.bidCount, len(resp.GetBids()))
|
||||
} else {
|
||||
kts.Require().NotNil(err)
|
||||
|
||||
@ -3,7 +3,6 @@ package keeper_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
|
||||
@ -19,7 +18,7 @@ type KeeperTestSuite struct {
|
||||
|
||||
func (kts *KeeperTestSuite) SetupTest() {
|
||||
err := kts.TestFixture.Setup()
|
||||
assert.Nil(kts.T(), err)
|
||||
kts.Require().NoError(err)
|
||||
|
||||
qr := kts.App.QueryHelper()
|
||||
kts.queryClient = types.NewQueryClient(qr)
|
||||
|
||||
@ -26,7 +26,7 @@ func (kts *KeeperTestSuite) TestGrpcQueryParams() {
|
||||
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().NoError(err)
|
||||
kts.Require().Equal(*(resp.Params), types.DefaultParams())
|
||||
})
|
||||
}
|
||||
@ -101,7 +101,7 @@ func (kts *KeeperTestSuite) TestGrpcQueryBondByBondId() {
|
||||
}
|
||||
resp, err := kts.queryClient.GetBondById(context.Background(), test.req)
|
||||
if !test.errResponse {
|
||||
kts.Require().Nil(err)
|
||||
kts.Require().NoError(err)
|
||||
kts.Require().NotNil(resp.GetBond())
|
||||
kts.Require().Equal(test.req.Id, resp.GetBond().GetId())
|
||||
} else {
|
||||
@ -148,7 +148,7 @@ func (kts *KeeperTestSuite) TestGrpcGetBondsByOwner() {
|
||||
}
|
||||
resp, err := kts.queryClient.GetBondsByOwner(context.Background(), test.req)
|
||||
if !test.errResponse {
|
||||
kts.Require().Nil(err)
|
||||
kts.Require().NoError(err)
|
||||
kts.Require().NotNil(resp.GetBonds())
|
||||
kts.Require().Equal(test.noOfBonds, len(resp.GetBonds()))
|
||||
} else {
|
||||
@ -184,7 +184,7 @@ func (kts *KeeperTestSuite) TestGrpcGetModuleBalance() {
|
||||
}
|
||||
resp, err := kts.queryClient.GetBondModuleBalance(context.Background(), test.req)
|
||||
if !test.errResponse {
|
||||
kts.Require().Nil(err)
|
||||
kts.Require().NoError(err)
|
||||
kts.Require().NotNil(resp.GetBalance())
|
||||
kts.Require().Equal(resp.GetBalance(), sdk.NewCoins(sdk.NewCoin(params.CoinUnit, math.NewInt(10))))
|
||||
} else {
|
||||
|
||||
@ -3,17 +3,20 @@ package integration_test
|
||||
import (
|
||||
"context"
|
||||
|
||||
runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1"
|
||||
appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1"
|
||||
authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1"
|
||||
bankmodulev1 "cosmossdk.io/api/cosmos/bank/module/v1"
|
||||
"cosmossdk.io/core/appconfig"
|
||||
"cosmossdk.io/core/appmodule"
|
||||
"cosmossdk.io/depinject"
|
||||
"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"
|
||||
@ -21,16 +24,22 @@ import (
|
||||
"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"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
|
||||
auctionmodulev1 "git.vdb.to/cerc-io/laconicd/api/cerc/auction/module/v1"
|
||||
bondmodulev1 "git.vdb.to/cerc-io/laconicd/api/cerc/bond/module/v1"
|
||||
registrymodulev1 "git.vdb.to/cerc-io/laconicd/api/cerc/registry/module/v1"
|
||||
"git.vdb.to/cerc-io/laconicd/app/params"
|
||||
auctionTypes "git.vdb.to/cerc-io/laconicd/x/auction"
|
||||
"git.vdb.to/cerc-io/laconicd/server"
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
)
|
||||
@ -51,108 +60,136 @@ type TestFixture struct {
|
||||
}
|
||||
|
||||
func (tf *TestFixture) Setup() error {
|
||||
keys := storetypes.NewKVStoreKeys(
|
||||
authtypes.StoreKey, banktypes.StoreKey, auctionTypes.StoreKey, bondTypes.StoreKey, registryTypes.StoreKey,
|
||||
logger := log.NewNopLogger()
|
||||
authority := authtypes.NewModuleAddress(govtypes.ModuleName)
|
||||
|
||||
moduleAccPerms := []*authmodulev1.ModuleAccountPermission{
|
||||
{Account: minttypes.ModuleName, Permissions: []string{authtypes.Minter}},
|
||||
{Account: auctiontypes.ModuleName},
|
||||
{Account: auctiontypes.AuctionBurnModuleAccountName},
|
||||
{Account: bondtypes.ModuleName},
|
||||
{Account: registrytypes.ModuleName},
|
||||
{Account: registrytypes.RecordRentModuleAccountName},
|
||||
{Account: registrytypes.AuthorityRentModuleAccountName},
|
||||
}
|
||||
|
||||
moduleConfigs := []*appv1alpha1.ModuleConfig{
|
||||
{
|
||||
Name: runtime.ModuleName,
|
||||
Config: appconfig.WrapAny(&runtimev1alpha1.Module{
|
||||
AppName: "TestApp",
|
||||
BeginBlockers: []string{
|
||||
authtypes.ModuleName,
|
||||
banktypes.ModuleName,
|
||||
auctiontypes.ModuleName,
|
||||
bondtypes.ModuleName,
|
||||
registrytypes.ModuleName,
|
||||
},
|
||||
EndBlockers: []string{
|
||||
auctiontypes.ModuleName,
|
||||
bondtypes.ModuleName,
|
||||
registrytypes.ModuleName,
|
||||
banktypes.ModuleName,
|
||||
authtypes.ModuleName,
|
||||
},
|
||||
InitGenesis: []string{
|
||||
authtypes.ModuleName,
|
||||
banktypes.ModuleName,
|
||||
auctiontypes.ModuleName,
|
||||
bondtypes.ModuleName,
|
||||
registrytypes.ModuleName,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: authtypes.ModuleName,
|
||||
Config: appconfig.WrapAny(&authmodulev1.Module{
|
||||
Bech32Prefix: params.Bech32PrefixAccAddr,
|
||||
ModuleAccountPermissions: moduleAccPerms,
|
||||
EnableUnorderedTransactions: true,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: banktypes.ModuleName,
|
||||
Config: appconfig.WrapAny(&bankmodulev1.Module{}),
|
||||
},
|
||||
{
|
||||
Name: auctiontypes.ModuleName,
|
||||
Config: appconfig.WrapAny(&auctionmodulev1.Module{}),
|
||||
},
|
||||
{
|
||||
Name: bondtypes.ModuleName,
|
||||
Config: appconfig.WrapAny(&bondmodulev1.Module{}),
|
||||
},
|
||||
{
|
||||
Name: registrytypes.ModuleName,
|
||||
Config: appconfig.WrapAny(®istrymodulev1.Module{}),
|
||||
},
|
||||
}
|
||||
|
||||
storeKeys := StoreKeyExtractor{}
|
||||
appConfig := depinject.Configs(
|
||||
appconfig.Compose(&appv1alpha1.Config{
|
||||
Modules: moduleConfigs,
|
||||
}),
|
||||
depinject.Supply(
|
||||
logger,
|
||||
authority,
|
||||
utils.NewAddressCodec(),
|
||||
),
|
||||
depinject.Provide(
|
||||
server.NewGasService,
|
||||
),
|
||||
storeKeys.config(),
|
||||
)
|
||||
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)
|
||||
var (
|
||||
appBuilder *runtime.AppBuilder
|
||||
cdc codec.Codec
|
||||
accountKeeper authkeeper.AccountKeeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
auctionKeeper *auctionkeeper.Keeper
|
||||
bondKeeper *bondkeeper.Keeper
|
||||
registryKeeper registrykeeper.Keeper
|
||||
)
|
||||
if err := depinject.Inject(
|
||||
appConfig,
|
||||
&appBuilder,
|
||||
&cdc,
|
||||
&accountKeeper,
|
||||
&bankKeeper,
|
||||
&auctionKeeper,
|
||||
&bondKeeper,
|
||||
®istryKeeper,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cms := integration.CreateMultiStore(storeKeys, 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: {},
|
||||
modules := map[string]appmodule.AppModule{
|
||||
authtypes.ModuleName: auth.NewAppModule(cdc, accountKeeper, authsims.RandomGenesisAccounts, nil),
|
||||
banktypes.ModuleName: bank.NewAppModule(cdc, bankKeeper, accountKeeper, nil),
|
||||
auctiontypes.ModuleName: auctionmodule.NewAppModule(cdc, auctionKeeper),
|
||||
bondtypes.ModuleName: bondmodule.NewAppModule(cdc, bondKeeper),
|
||||
registrytypes.ModuleName: registrymodule.NewAppModule(cdc, registryKeeper),
|
||||
}
|
||||
|
||||
accountKeeper := authkeeper.NewAccountKeeper(
|
||||
cdc,
|
||||
runtime.NewKVStoreService(keys[authtypes.StoreKey]),
|
||||
authtypes.ProtoBaseAccount,
|
||||
maccPerms,
|
||||
addresscodec.NewBech32Codec(params.Bech32PrefixAccAddr),
|
||||
params.Bech32PrefixAccAddr,
|
||||
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,
|
||||
})
|
||||
|
||||
integrationApp := integration.NewIntegrationApp(newCtx, logger, storeKeys, cdc, modules)
|
||||
sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context())
|
||||
|
||||
// Register MsgServer and QueryServer
|
||||
auctionTypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), auctionkeeper.NewMsgServerImpl(auctionKeeper))
|
||||
auctionTypes.RegisterQueryServer(integrationApp.QueryHelper(), auctionkeeper.NewQueryServerImpl(auctionKeeper))
|
||||
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))
|
||||
|
||||
bondTypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), bondkeeper.NewMsgServerImpl(bondKeeper))
|
||||
bondTypes.RegisterQueryServer(integrationApp.QueryHelper(), bondkeeper.NewQueryServerImpl(bondKeeper))
|
||||
auctionKeeper.Params.Set(sdkCtx, auctiontypes.DefaultParams())
|
||||
bondKeeper.Params.Set(sdkCtx, bondtypes.DefaultParams())
|
||||
registryKeeper.Params.Set(sdkCtx, registrytypes.DefaultParams())
|
||||
|
||||
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.App, tf.SdkCtx, tf.cdc, tf.keys = integrationApp, sdkCtx, cdc, storeKeys
|
||||
tf.AccountKeeper, tf.BankKeeper = accountKeeper, bankKeeper
|
||||
tf.AuctionKeeper, tf.BondKeeper, tf.RegistryKeeper = auctionKeeper, bondKeeper, registryKeeper
|
||||
|
||||
@ -164,3 +201,22 @@ type BondDenomProvider struct{}
|
||||
func (bdp BondDenomProvider) BondDenom(ctx context.Context) (string, error) {
|
||||
return params.CoinUnit, nil
|
||||
}
|
||||
|
||||
// store keys are uniquely constructed by ProvideKVStoreKey when building the app, so we must
|
||||
// extract the keys like this rather than create new ones.
|
||||
type StoreKeyExtractor map[string]*storetypes.KVStoreKey
|
||||
|
||||
func (ske *StoreKeyExtractor) ExtractKey(mkey depinject.ModuleKey, storeKey *storetypes.KVStoreKey) {
|
||||
(*ske)[mkey.Name()] = storeKey
|
||||
}
|
||||
|
||||
func (ske *StoreKeyExtractor) config() depinject.Config {
|
||||
return depinject.Configs(
|
||||
depinject.Supply(ske),
|
||||
depinject.InvokeInModule(banktypes.ModuleName, (*StoreKeyExtractor).ExtractKey),
|
||||
depinject.InvokeInModule(authtypes.ModuleName, (*StoreKeyExtractor).ExtractKey),
|
||||
depinject.InvokeInModule(bondtypes.ModuleName, (*StoreKeyExtractor).ExtractKey),
|
||||
depinject.InvokeInModule(auctiontypes.ModuleName, (*StoreKeyExtractor).ExtractKey),
|
||||
depinject.InvokeInModule(registrytypes.ModuleName, (*StoreKeyExtractor).ExtractKey),
|
||||
)
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import (
|
||||
"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"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app/params"
|
||||
@ -27,18 +26,18 @@ type KeeperTestSuite struct {
|
||||
|
||||
func (kts *KeeperTestSuite) SetupTest() {
|
||||
err := kts.TestFixture.Setup()
|
||||
assert.Nil(kts.T(), err)
|
||||
kts.Require().NoError(err)
|
||||
|
||||
// set default params
|
||||
err = kts.RegistryKeeper.Params.Set(kts.SdkCtx, types.DefaultParams())
|
||||
assert.Nil(kts.T(), err)
|
||||
kts.Require().NoError(err)
|
||||
|
||||
qr := kts.App.QueryHelper()
|
||||
kts.queryClient = types.NewQueryClient(qr)
|
||||
|
||||
// Create a bond
|
||||
bond, err := kts.createBond()
|
||||
assert.Nil(kts.T(), err)
|
||||
kts.Require().NoError(err)
|
||||
kts.bond = *bond
|
||||
}
|
||||
|
||||
|
||||
260
tests/system/auction_grpc_test.go
Normal file
260
tests/system/auction_grpc_test.go
Normal file
@ -0,0 +1,260 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/x/auction"
|
||||
)
|
||||
|
||||
const (
|
||||
randomAuctionId = "randomAuctionId"
|
||||
randomBidderAddress = "randomBidderAddress"
|
||||
randomOwnerAddress = "randomOwnerAddress"
|
||||
)
|
||||
|
||||
func (s *auctionSuite) TestGRPCQueryParams() {
|
||||
reqURL := s.endpointURL("auction/v1/params")
|
||||
|
||||
s.Run("valid request to get auction params", func() {
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(reqURL)
|
||||
require.NoError(err)
|
||||
|
||||
var params auction.QueryParamsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, ¶ms), string(resp))
|
||||
require.Equal(auction.DefaultParams(), *params.GetParams())
|
||||
})
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TestGRPCGetAllAuctions() {
|
||||
reqURL := s.endpointURL("auction/v1/auctions")
|
||||
|
||||
s.createAuction()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
}{
|
||||
{
|
||||
"invalid request",
|
||||
reqURL + "-asdasd",
|
||||
"Not Implemented",
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var auctions auction.QueryAuctionsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &auctions), string(resp))
|
||||
require.NotEmpty(auctions.Auctions.Auctions)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TestGRPCGetAuction() {
|
||||
reqURL := s.endpointURL("auction/v1/auctions/%s")
|
||||
|
||||
auctionId := s.createAuction()
|
||||
s.createBid(auctionId)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
exists bool
|
||||
}{
|
||||
{
|
||||
"nonexistent auction",
|
||||
fmt.Sprintf(reqURL, randomAuctionId),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
fmt.Sprintf(reqURL, auctionId),
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.exists {
|
||||
var auction auction.QueryGetAuctionResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &auction), string(resp))
|
||||
require.Equal(auctionId, auction.Auction.Id)
|
||||
} else {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, "not found", tc.url)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TestGRPCGetBids() {
|
||||
reqURL := s.endpointURL("auction/v1/bids/%s")
|
||||
|
||||
auctionId := s.createAuction()
|
||||
s.createBid(auctionId)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
exists bool
|
||||
}{
|
||||
{
|
||||
"nonexistent auction",
|
||||
fmt.Sprintf(reqURL, randomAuctionId),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
fmt.Sprintf(reqURL, auctionId),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
var bids auction.QueryGetBidsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &bids), string(resp))
|
||||
if tc.exists {
|
||||
require.Equal(auctionId, bids.Bids[0].AuctionId)
|
||||
} else {
|
||||
require.Empty(bids.Bids)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TestGRPCGetBid() {
|
||||
reqURL := s.endpointURL("auction/v1/bids/%s/%s")
|
||||
bidderAddress := s.cli().GetKeyAddr(s.bidderAccount)
|
||||
|
||||
auctionId := s.createAuction()
|
||||
s.createBid(auctionId)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
exists bool
|
||||
}{
|
||||
{
|
||||
"nonexistent auction",
|
||||
fmt.Sprintf(reqURL, randomAuctionId, bidderAddress),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"nonexistent bidder",
|
||||
fmt.Sprintf(reqURL, auctionId, randomBidderAddress),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
fmt.Sprintf(reqURL, auctionId, bidderAddress),
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.exists {
|
||||
var bid auction.QueryGetBidResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &bid), string(resp))
|
||||
require.Equal(auctionId, bid.Bid.AuctionId)
|
||||
} else {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, "not found", tc.url)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TestGRPCGetAuctionsByOwner() {
|
||||
reqURL := s.endpointURL("auction/v1/by-owner/%s")
|
||||
ownerAddress := s.cli().GetKeyAddr(s.ownerAccount)
|
||||
|
||||
auctionId := s.createAuction()
|
||||
s.createBid(auctionId)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
exists bool
|
||||
}{
|
||||
{
|
||||
"nonexistent owner",
|
||||
fmt.Sprintf(reqURL, randomOwnerAddress),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
fmt.Sprintf(reqURL, ownerAddress),
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
var auctions auction.QueryAuctionsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &auctions), string(resp))
|
||||
if tc.exists {
|
||||
require.Equal(auctionId, auctions.Auctions.Auctions[0].Id)
|
||||
} else {
|
||||
require.Empty(auctions.Auctions.Auctions)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TestGRPCQueryBalance() {
|
||||
reqURL := s.endpointURL("auction/v1/balance")
|
||||
|
||||
s.Run("valid request", func() {
|
||||
require := s.Require()
|
||||
|
||||
auctionId := s.createAuction()
|
||||
s.createBid(auctionId)
|
||||
|
||||
resp, err := testutil.GetRequest(reqURL)
|
||||
require.NoError(err)
|
||||
|
||||
var response auction.QueryGetAuctionModuleBalanceResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
require.NotEmpty(response.GetBalance())
|
||||
})
|
||||
}
|
||||
162
tests/system/auction_test.go
Normal file
162
tests/system/auction_test.go
Normal file
@ -0,0 +1,162 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/x/auction"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
const (
|
||||
sampleCommitTime = "90s"
|
||||
sampleRevealTime = "5s"
|
||||
placeholderAuctionId = "placeholder_auction_id"
|
||||
)
|
||||
|
||||
type auctionSuite struct {
|
||||
testSuite
|
||||
|
||||
ownerAccount string
|
||||
bidderAccount string
|
||||
defaultAuctionId string
|
||||
}
|
||||
|
||||
func TestAuction(t *testing.T) {
|
||||
suite.Run(t, new(auctionSuite))
|
||||
}
|
||||
|
||||
func (s *auctionSuite) SetupTest() {
|
||||
s.resetChain()
|
||||
|
||||
s.ownerAccount = s.account(0)
|
||||
s.bidderAccount = s.account(1)
|
||||
|
||||
Sut.StartChain(s.T())
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TearDownTest() {
|
||||
s.cleanupBidFiles()
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TestQueryList() {
|
||||
sr := s.Require()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
createAuction bool
|
||||
}{
|
||||
{
|
||||
"when no auctions exist",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"after creating an auction",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
s.Run(test.name, func() {
|
||||
if test.createAuction {
|
||||
s.createAuction()
|
||||
}
|
||||
|
||||
out := s.cli().CustomQuery("q", "auction", "list")
|
||||
var response auction.QueryAuctionsResponse
|
||||
sr.NoError(s.codec.UnmarshalJSON([]byte(out), &response), out)
|
||||
if test.createAuction {
|
||||
sr.NotEmpty(response.Auctions.Auctions)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *auctionSuite) TestTxCommitBid() {
|
||||
auctionId := s.createAuction()
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
"with missing args",
|
||||
[]string{auctionId},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"with zero bid",
|
||||
[]string{auctionId, ("0" + s.bondDenom)},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"with invalid auction",
|
||||
[]string{"fake", ("200" + s.bondDenom)},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"with valid args",
|
||||
[]string{auctionId, ("200" + s.bondDenom)},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
s.Run(test.name, func() {
|
||||
cmd := []string{
|
||||
"tx", "auction", "commit-bid",
|
||||
}
|
||||
cmd = append(cmd, test.args...)
|
||||
s.runTx(cmd, test.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *auctionSuite) createAuction() string {
|
||||
require := s.Require()
|
||||
|
||||
cmd := []string{
|
||||
"tx", "auction", "create",
|
||||
sampleCommitTime,
|
||||
sampleRevealTime,
|
||||
"10" + s.bondDenom,
|
||||
"10" + s.bondDenom,
|
||||
"--kind", auction.AuctionKindVickrey,
|
||||
"--minimum-bid", "100" + s.bondDenom,
|
||||
"--max-price", "0" + s.bondDenom,
|
||||
"--num-providers", "0",
|
||||
}
|
||||
s.runTx(cmd, false)
|
||||
|
||||
out := s.cli().CustomQuery("q", "auction", "list")
|
||||
var response auction.QueryAuctionsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON([]byte(out), &response), out)
|
||||
return response.Auctions.Auctions[0].Id
|
||||
}
|
||||
|
||||
func (s *auctionSuite) createBid(auctionId string) {
|
||||
cmd := []string{
|
||||
"tx", "auction", "commit-bid",
|
||||
auctionId,
|
||||
"200" + s.bondDenom,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.bidderAccount),
|
||||
}
|
||||
s.runTx(cmd, false)
|
||||
}
|
||||
|
||||
func (s *auctionSuite) cleanupBidFiles() {
|
||||
matches, err := filepath.Glob(fmt.Sprintf("%s-*.json", s.bidderAccount))
|
||||
if err != nil {
|
||||
s.T().Errorf("Error matching bidder files: %v\n", err)
|
||||
}
|
||||
|
||||
for _, match := range matches {
|
||||
err := os.Remove(match)
|
||||
if err != nil {
|
||||
s.T().Errorf("Error removing bidder file: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
168
tests/system/bond_grpc_test.go
Normal file
168
tests/system/bond_grpc_test.go
Normal file
@ -0,0 +1,168 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/x/bond"
|
||||
)
|
||||
|
||||
func (s *bondSuite) TestGRPCGetParams() {
|
||||
reqURL := s.endpointURL("bond/v1/params")
|
||||
|
||||
var params bond.QueryParamsResponse
|
||||
resp, err := testutil.GetRequest(reqURL)
|
||||
require.NoError(s.T(), err)
|
||||
require.NoError(s.T(), s.codec.UnmarshalJSON(resp, ¶ms))
|
||||
|
||||
require.Equal(s.T(), bond.DefaultParams().MaxBondAmount, params.GetParams().MaxBondAmount)
|
||||
}
|
||||
|
||||
func (s *bondSuite) TestGRPCGetBond() {
|
||||
reqURL := s.endpointURL("bond/v1/bonds")
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
prerun func()
|
||||
}{
|
||||
{
|
||||
"invalid request with headers",
|
||||
reqURL + "asdasdas",
|
||||
"Not Implemented",
|
||||
func() {},
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
func() { s.createBond() },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
tc.prerun()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, string(resp))
|
||||
} else {
|
||||
var bonds bond.QueryBondsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &bonds), string(resp))
|
||||
require.NotEmpty(bonds.GetBonds())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *bondSuite) TestGRPCGetBondsByOwner() {
|
||||
reqURL := s.endpointURL("bond/v1/by-owner/%s")
|
||||
accountAddress := s.cli().GetKeyAddr(s.account(0))
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
url string
|
||||
err bool
|
||||
prerun func()
|
||||
}{
|
||||
{
|
||||
"empty list",
|
||||
fmt.Sprintf(reqURL, "asdasd"),
|
||||
true,
|
||||
func() {},
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
fmt.Sprintf(reqURL, accountAddress),
|
||||
false,
|
||||
func() { s.createBond() },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
tc.prerun()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
var bonds bond.QueryGetBondsByOwnerResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &bonds))
|
||||
if tc.err {
|
||||
require.Empty(bonds.GetBonds())
|
||||
} else {
|
||||
bondsList := bonds.GetBonds()
|
||||
require.NotEmpty(bondsList)
|
||||
require.Equal(accountAddress, bondsList[0].GetOwner())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *bondSuite) TestGRPCGetBondById() {
|
||||
reqURL := s.endpointURL("bond/v1/bonds/%s")
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
url string
|
||||
err bool
|
||||
prerun func() string
|
||||
}{
|
||||
{
|
||||
"invalid request",
|
||||
reqURL,
|
||||
true,
|
||||
func() string { return "asdadad" },
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
false,
|
||||
func() string { return s.createBond() },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
bondId := tc.prerun()
|
||||
tc.url = fmt.Sprintf(reqURL, bondId)
|
||||
|
||||
var bond bond.QueryGetBondByIdResponse
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
if tc.err {
|
||||
require.Error(s.codec.UnmarshalJSON(resp, &bond))
|
||||
} else {
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &bond))
|
||||
require.Equal(bondId, bond.GetBond().GetId())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *bondSuite) TestGRPCGetBondModuleBalance() {
|
||||
reqURL := s.endpointURL("bond/v1/balance")
|
||||
|
||||
s.createBond()
|
||||
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(reqURL)
|
||||
require.NoError(err)
|
||||
|
||||
var response bond.QueryGetBondModuleBalanceResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response))
|
||||
require.False(response.GetBalance().IsZero())
|
||||
}
|
||||
96
tests/system/bond_test.go
Normal file
96
tests/system/bond_test.go
Normal file
@ -0,0 +1,96 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/x/bond"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type bondSuite struct {
|
||||
testSuite
|
||||
}
|
||||
|
||||
func TestBonds(t *testing.T) {
|
||||
suite.Run(t, new(bondSuite))
|
||||
}
|
||||
|
||||
func (s *bondSuite) SetupTest() {
|
||||
s.resetChain()
|
||||
Sut.StartChain(s.T())
|
||||
}
|
||||
|
||||
func (s *bondSuite) TestQueryList() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
prerun func()
|
||||
}{
|
||||
{
|
||||
"create and get bond lists",
|
||||
nil,
|
||||
func() { s.createBond() },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
tc.prerun()
|
||||
out := s.cli().CustomQuery("q", "bond", "list")
|
||||
s.Require().NotEmpty(gjson.Get(out, "bonds").Array(), out)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *bondSuite) TestTxCreateBond() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
"without deposit",
|
||||
[]string{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"create bond",
|
||||
[]string{
|
||||
"10" + s.bondDenom,
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := append([]string{"tx", "bond", "create"}, tc.args...)
|
||||
s.runTx(cmd, tc.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *bondSuite) createBond() string {
|
||||
return createBond(&s.testSuite)
|
||||
}
|
||||
|
||||
// free function for use in other suites
|
||||
func createBond(s *testSuite) string {
|
||||
require := s.Require()
|
||||
|
||||
cli := s.cli()
|
||||
cmd := []string{
|
||||
"tx", "bond", "create", ("1000000" + s.bondDenom),
|
||||
}
|
||||
s.runTx(cmd, false)
|
||||
|
||||
raw := cli.CustomQuery("q", "bond", "list")
|
||||
var queryResponse bond.QueryBondsResponse
|
||||
require.NoError(json.Unmarshal([]byte(raw), &queryResponse))
|
||||
bonds := queryResponse.GetBonds()
|
||||
require.NotEmpty(bonds)
|
||||
|
||||
return bonds[0].GetId()
|
||||
}
|
||||
55
tests/system/main_test.go
Normal file
55
tests/system/main_test.go
Normal file
@ -0,0 +1,55 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/systemtests"
|
||||
)
|
||||
|
||||
var (
|
||||
Sut *systemtests.SystemUnderTest
|
||||
|
||||
verbose bool
|
||||
nodesCount = flag.Int("nodes", 4, "number of nodes in the cluster")
|
||||
blockTime = 3 * time.Second // expected time between blocks
|
||||
// txTimeout = 10 * time.Second // timeout for transactions to be included in a block
|
||||
txTimeout = 10 * time.Minute // timeout for transactions to be included in a block
|
||||
|
||||
workDir string
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// sdk systemtests expects this to be set for v2 server/runtime
|
||||
os.Setenv("COSMOS_BUILD_OPTIONS", "v2")
|
||||
|
||||
flag.BoolVar(&verbose, "verbose", false, "verbose output")
|
||||
flag.Parse()
|
||||
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
workDir = dir
|
||||
if verbose {
|
||||
println("Work dir: ", workDir)
|
||||
}
|
||||
|
||||
Sut = systemtests.NewSystemUnderTest("laconicd", verbose, *nodesCount, blockTime)
|
||||
// Sut.SetTestnetInitializer(initer)
|
||||
|
||||
Sut.SetupChain() // setup chain and keyring
|
||||
|
||||
// run tests
|
||||
exitCode := m.Run()
|
||||
|
||||
// postprocess
|
||||
Sut.StopChain()
|
||||
if verbose || exitCode != 0 {
|
||||
Sut.PrintBuffer()
|
||||
}
|
||||
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
452
tests/system/nitro_test.go
Normal file
452
tests/system/nitro_test.go
Normal file
@ -0,0 +1,452 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
nitrocrypto "github.com/statechannels/go-nitro/crypto"
|
||||
chainutils "github.com/statechannels/go-nitro/node/chain"
|
||||
"github.com/statechannels/go-nitro/node/query"
|
||||
"github.com/statechannels/go-nitro/node_test"
|
||||
nitrotypes "github.com/statechannels/go-nitro/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
systest "cosmossdk.io/systemtests"
|
||||
)
|
||||
|
||||
var (
|
||||
ethChainPort = "8546"
|
||||
ethChainUrl = "ws://127.0.0.1:8546"
|
||||
)
|
||||
|
||||
type nitroSuite struct {
|
||||
testSuite
|
||||
|
||||
tokenDenom string
|
||||
ethChainOpts *node_test.LocalChainOptions
|
||||
|
||||
alice, bob nitrocrypto.Credential
|
||||
intermediaries []nitrocrypto.Credential
|
||||
}
|
||||
|
||||
func TestNitro(t *testing.T) {
|
||||
suite.Run(t, new(nitroSuite))
|
||||
}
|
||||
|
||||
func (s *nitroSuite) SetupSuite() {
|
||||
s.testSuite.SetupSuite()
|
||||
|
||||
s.tokenDenom = "eth"
|
||||
|
||||
// Set up Ethereum test chain
|
||||
// TODO: use anvil for better self-containment
|
||||
ethChainOpts := node_test.ExternalHardhatChainOptions(s.T())
|
||||
ethChainOpts.ChainUrl = ethChainUrl
|
||||
aliceKey := ethChainOpts.ChainPks[0]
|
||||
bobKey := ethChainOpts.ChainPks[1]
|
||||
s.ethChainOpts = ethChainOpts
|
||||
|
||||
ethChain, err := node_test.ConnectLocalChain(ethChainOpts, nitrotypes.BytesFromHex(aliceKey))
|
||||
s.Require().NoError(err)
|
||||
s.T().Cleanup(func() { s.NoError(ethChain.Close()) })
|
||||
|
||||
s.alice = nitrocrypto.NewSimpleCredential(nitrotypes.BytesFromHex(aliceKey))
|
||||
s.bob = nitrocrypto.NewSimpleCredential(nitrotypes.BytesFromHex(bobKey))
|
||||
for _, pk := range ethChainOpts.ChainPks {
|
||||
creds := nitrocrypto.NewSimpleCredential(nitrotypes.BytesFromHex(pk))
|
||||
s.intermediaries = append(s.intermediaries, creds)
|
||||
}
|
||||
|
||||
s.configureEthChain()
|
||||
// TODO when using intermediaries, set more validator node pks here
|
||||
s.setValidatorNitroKeys(s.ethChainOpts.ChainPks[1])
|
||||
}
|
||||
|
||||
func (s *nitroSuite) SetupTest() {
|
||||
s.resetChain()
|
||||
|
||||
s.setClientKeys(s.ethChainOpts.ChainPks[0])
|
||||
|
||||
Sut.StartChain(s.T())
|
||||
}
|
||||
|
||||
func (s *nitroSuite) SetupSubTest() { s.SetupTest() }
|
||||
|
||||
func (s *nitroSuite) configureEthChain() {
|
||||
cas, err := chainutils.LoadEnvContractAddresses()
|
||||
s.Require().NoError(err)
|
||||
|
||||
cmds := [][]string{
|
||||
{"config", "set", "app", "nitro.eth-na-address", "'" + cas.NaAddress.String() + "'"},
|
||||
{"config", "set", "app", "nitro.eth-vpa-address", "'" + cas.VpaAddress.String() + "'"},
|
||||
{"config", "set", "app", "nitro.eth-ca-address", "'" + cas.CaAddress.String() + "'"},
|
||||
{"config", "set", "app", "nitro.eth-url", ethChainUrl},
|
||||
}
|
||||
_ = Sut.ForEachNodeExecAndWait(s.T(), cmds...)
|
||||
for _, cmd := range cmds {
|
||||
cmd = append(cmd, "--home", s.clientHome())
|
||||
_ = systest.MustRunShellCmd(s.T(), Sut.ExecBinary(), cmd...)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nitroSuite) TestTxOpenChannel() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
"missing args",
|
||||
[]string{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"missing amount",
|
||||
[]string{s.bob.AsParticipant().String()},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
[]string{s.bob.AsParticipant().String(), "10" + s.tokenDenom},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := append([]string{"tx", "nitro", "open-channel"}, tc.args...)
|
||||
s.runTx(cmd, tc.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nitroSuite) TestTxCloseChannel() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
err bool
|
||||
setup func() []string
|
||||
}{
|
||||
{
|
||||
"missing args",
|
||||
[]string{},
|
||||
true,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"invalid channel",
|
||||
[]string{"invalid-channel-id"},
|
||||
true,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid channel",
|
||||
nil,
|
||||
false,
|
||||
func() []string { return s.setupLedgerChannel("10") },
|
||||
},
|
||||
// {
|
||||
// "valid channel with challenge",
|
||||
// []string{"--challenge"},
|
||||
// false,
|
||||
// func() []string { return s.setupLedgerChannel("10") },
|
||||
// },
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := []string{"tx", "nitro", "close-channel"}
|
||||
if tc.setup != nil {
|
||||
cmd = append(cmd, tc.setup()...)
|
||||
}
|
||||
cmd = append(cmd, tc.args...)
|
||||
s.runTx(cmd, tc.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nitroSuite) TestTxOpenPaymentChannel() {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
err bool
|
||||
setup func() []string
|
||||
}{
|
||||
{
|
||||
"missing args",
|
||||
[]string{},
|
||||
true,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"missing amount",
|
||||
[]string{s.bob.AsParticipant().String()},
|
||||
true,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"zero hops",
|
||||
[]string{s.bob.AsParticipant().String(), "10" + s.tokenDenom},
|
||||
false,
|
||||
func() []string { s.setupLedgerChannel("20"); return nil },
|
||||
},
|
||||
// { // TODO open n-hop ledger channels
|
||||
// "one hop",
|
||||
// []string{"10" + s.tokenDenom, s.bob.AsParticipant().String(), s.intermediaries[0].String()},
|
||||
// false,
|
||||
// setupLedgerChannelForPaymentChannel,
|
||||
// },
|
||||
// { // TODO use a different counterparty, cannot have duplicate channels
|
||||
// "direct channel with challenge duration",
|
||||
// []string{"10" + s.tokenDenom, s.bob.AsParticipant().String(), "--challenge-duration", "100"},
|
||||
// false,
|
||||
// setupLedgerChannelForPaymentChannel,
|
||||
// },
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := []string{"tx", "nitro", "open-payment-channel"}
|
||||
if tc.setup != nil {
|
||||
tc.setup()
|
||||
}
|
||||
cmd = append(cmd, tc.args...)
|
||||
s.runTx(cmd, tc.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nitroSuite) TestTxClosePaymentChannel() {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
err bool
|
||||
setup func() []string
|
||||
}{
|
||||
{
|
||||
"missing args",
|
||||
[]string{},
|
||||
true,
|
||||
nil,
|
||||
},
|
||||
// { // TODO use different counterparty
|
||||
// "invalid channel ID",
|
||||
// []string{"invalid-channel-id"},
|
||||
// true,
|
||||
// setupLedgerChannel,
|
||||
// },
|
||||
{
|
||||
"zero hops",
|
||||
nil,
|
||||
false,
|
||||
func() []string {
|
||||
s.setupLedgerChannel("20")
|
||||
return s.setupPaymentChannel("10")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := []string{"tx", "nitro", "close-payment-channel"}
|
||||
if tc.setup != nil {
|
||||
cmd = append(cmd, tc.setup()...)
|
||||
}
|
||||
cmd = append(cmd, tc.args...)
|
||||
s.runTx(cmd, tc.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nitroSuite) TestTxPay() {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
error bool
|
||||
setup func() []string
|
||||
paid *big.Int
|
||||
}{
|
||||
{
|
||||
name: "missing args",
|
||||
error: true,
|
||||
},
|
||||
{
|
||||
name: "invalid channel ID",
|
||||
args: []string{"invalid-channel-id", "10" + s.tokenDenom},
|
||||
error: true,
|
||||
},
|
||||
{
|
||||
name: "invalid amount format",
|
||||
args: []string{"0x0102030000000000000000000000000000000000000000000000000000000000", "invalid-amount"},
|
||||
error: true,
|
||||
},
|
||||
{
|
||||
name: "nonexistent channel",
|
||||
args: []string{"0x0102030000000000000000000000000000000000000000000000000000000000", "5" + s.tokenDenom},
|
||||
error: true,
|
||||
},
|
||||
{
|
||||
name: "valid payment",
|
||||
args: []string{"10" + s.tokenDenom},
|
||||
setup: func() []string {
|
||||
s.setupLedgerChannel("100")
|
||||
return s.setupPaymentChannel("50")
|
||||
},
|
||||
paid: big.NewInt(10),
|
||||
},
|
||||
// {
|
||||
// "insufficient funds",
|
||||
// []string{"10" + s.tokenDenom},
|
||||
// false,
|
||||
// func() []string {
|
||||
// s.setupLedgerChannel("100")
|
||||
// return s.setupPaymentChannel("50")
|
||||
// },
|
||||
// },
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
var channelId string
|
||||
|
||||
cmd := []string{"tx", "nitro", "pay"}
|
||||
if tc.setup != nil {
|
||||
setupArgs := tc.setup()
|
||||
cmd = append(cmd, setupArgs...)
|
||||
|
||||
if !tc.error && len(setupArgs) > 0 {
|
||||
channelId = setupArgs[0]
|
||||
}
|
||||
}
|
||||
cmd = append(cmd, tc.args...)
|
||||
s.runTx(cmd, tc.error)
|
||||
|
||||
// Check balance change for successful payments
|
||||
if channelId != "" {
|
||||
balance := s.getChannelBalance(channelId)
|
||||
s.Require().Equal(tc.paid, balance.PaidSoFar.ToInt())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nitroSuite) TestFullPaymentFlow() {
|
||||
s.Run("complete payment lifecycle", func() {
|
||||
// Open ledger and payment channels
|
||||
ledgerChannel := s.setupLedgerChannel("100")[0]
|
||||
paymentChannel := s.setupPaymentChannel("50")[0]
|
||||
|
||||
// Verify initial balance
|
||||
s.Require().Equal("0", s.getChannelBalance(paymentChannel).PaidSoFar.ToInt().String())
|
||||
|
||||
// Make payments: 5 + 10 + 15 = 30
|
||||
s.runTx([]string{"tx", "nitro", "pay", paymentChannel, "5" + s.tokenDenom}, false)
|
||||
s.runTx([]string{"tx", "nitro", "pay", paymentChannel, "10" + s.tokenDenom}, false)
|
||||
s.runTx([]string{"tx", "nitro", "pay", paymentChannel, "15" + s.tokenDenom}, false)
|
||||
|
||||
// Verify final balance
|
||||
finalBalance := s.getChannelBalance(paymentChannel)
|
||||
s.Require().Equal("30", finalBalance.PaidSoFar.ToInt().String())
|
||||
s.Require().Equal("20", finalBalance.RemainingFunds.ToInt().String())
|
||||
|
||||
// Close channels in correct order
|
||||
s.runTx([]string{"tx", "nitro", "close-payment-channel", paymentChannel}, false)
|
||||
s.runTx([]string{"tx", "nitro", "close-channel", ledgerChannel}, false)
|
||||
})
|
||||
|
||||
s.Run("insufficient funds scenario", func() {
|
||||
s.setupLedgerChannel("20")
|
||||
paymentChannel := s.setupPaymentChannel("10")[0]
|
||||
|
||||
s.runTx([]string{"tx", "nitro", "pay", paymentChannel, "5" + s.tokenDenom}, false)
|
||||
s.runTx([]string{"tx", "nitro", "pay", paymentChannel, "10" + s.tokenDenom}, true) // insufficient funds
|
||||
s.runTx([]string{"tx", "nitro", "pay", paymentChannel, "5" + s.tokenDenom}, false)
|
||||
|
||||
// Verify all funds used
|
||||
balance := s.getChannelBalance(paymentChannel)
|
||||
s.Require().Equal("10", balance.PaidSoFar.ToInt().String())
|
||||
s.Require().Equal("0", balance.RemainingFunds.ToInt().String())
|
||||
})
|
||||
|
||||
s.Run("invalid closure order", func() {
|
||||
// Open both channels
|
||||
ledgerChannel := s.setupLedgerChannel("50")[0]
|
||||
paymentChannel := s.setupPaymentChannel("30")[0]
|
||||
|
||||
// Make a payment
|
||||
s.runTx([]string{"tx", "nitro", "pay", paymentChannel, "10" + s.tokenDenom}, false)
|
||||
|
||||
// Try to close ledger channel before payment channel - should fail
|
||||
s.runTx([]string{"tx", "nitro", "close-channel", ledgerChannel}, true)
|
||||
|
||||
// Correct order should work
|
||||
s.runTx([]string{"tx", "nitro", "close-payment-channel", paymentChannel}, false)
|
||||
s.runTx([]string{"tx", "nitro", "close-channel", ledgerChannel}, false)
|
||||
})
|
||||
}
|
||||
|
||||
// setupLedgerChannel creates a ledger channel and returns the channel ID as args
|
||||
func (s *nitroSuite) setupLedgerChannel(amount string) []string {
|
||||
openCmd := []string{"tx", "nitro", "open-channel", s.bob.AsParticipant().String(), amount + s.tokenDenom}
|
||||
txhash := s.runTx(openCmd, false)
|
||||
return []string{s.getChannelIdFromTx(txhash)}
|
||||
}
|
||||
|
||||
// setupPaymentChannel creates a ledger channel and payment channel, returns payment channel ID as args
|
||||
func (s *nitroSuite) setupPaymentChannel(amount string) []string {
|
||||
openPcCmd := []string{"tx", "nitro", "open-payment-channel", s.bob.AsParticipant().String(), amount + s.tokenDenom}
|
||||
txhash := s.runTx(openPcCmd, false)
|
||||
return []string{s.getChannelIdFromTx(txhash)}
|
||||
}
|
||||
|
||||
// getChannelIdFromTx opens a channel and extracts the channel ID from the transaction result
|
||||
func (s *nitroSuite) getChannelIdFromTx(txHash string) string {
|
||||
txDetails := s.cli().CustomQuery("query", "tx", txHash)
|
||||
|
||||
// find channel_id in any event's attributes
|
||||
channelId := gjson.Get(txDetails, "events.#.attributes.#(key==\"channel_id\").value|0")
|
||||
s.Require().True(channelId.Exists(), "channel_id not found in transaction events")
|
||||
|
||||
return channelId.String()
|
||||
}
|
||||
|
||||
func (s *nitroSuite) getChannelBalance(channelId string) query.PaymentChannelBalance {
|
||||
channelInfo := s.cli().CustomQuery(
|
||||
s.withNitroQueryFlags("q", "nitro", "get-channel", "--payment", channelId)...,
|
||||
)
|
||||
|
||||
var info query.PaymentChannelInfo
|
||||
err := json.Unmarshal([]byte(channelInfo), &info)
|
||||
s.Require().NoError(err, "could not parse PaymentChannelInfo: %s", channelInfo)
|
||||
return info.Balance
|
||||
}
|
||||
|
||||
func (s *nitroSuite) withNitroQueryFlags(cmd ...string) []string {
|
||||
return append(cmd, "--home", s.clientHome())
|
||||
}
|
||||
|
||||
func (s *nitroSuite) Test_Hang() {
|
||||
hang := os.Getenv("HANG")
|
||||
if hang == "" {
|
||||
s.T().Skip("Placeholder to run the validator nodes and hang for manual testing")
|
||||
}
|
||||
|
||||
if hang == "ledger" || hang == "payment" {
|
||||
s.setupLedgerChannel("20")
|
||||
}
|
||||
if hang == "payment" {
|
||||
s.setupPaymentChannel("10")
|
||||
}
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
<-c
|
||||
}
|
||||
389
tests/system/registry_grpc_test.go
Normal file
389
tests/system/registry_grpc_test.go
Normal file
@ -0,0 +1,389 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/x/registry"
|
||||
)
|
||||
|
||||
const badPath = "/asdasd"
|
||||
|
||||
func (s *registrySuite) TestGRPCQueryParams() {
|
||||
reqURL := s.endpointURL("registry/v1/params")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
}{
|
||||
{
|
||||
"invalid request",
|
||||
reqURL + badPath,
|
||||
"Not Implemented",
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var response registry.QueryParamsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
|
||||
params := registry.DefaultParams()
|
||||
s.updateParams(¶ms)
|
||||
require.Equal(params.String(), response.GetParams().String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) TestGRPCQueryWhoIs() {
|
||||
reqURL := s.endpointURL("registry/v1/whois/%s")
|
||||
authorityName := "QueryWhoIS"
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
prerun func(string)
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
"Not Implemented",
|
||||
func(string) {},
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
func(name string) { s.reserveName(name) },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
tc.prerun(authorityName)
|
||||
url := fmt.Sprintf(tc.url, authorityName)
|
||||
|
||||
resp, err := testutil.GetRequest(url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var response registry.QueryWhoisResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
require.Equal(registry.AuthorityActive, response.GetNameAuthority().Status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) TestGRPCQueryLookup() {
|
||||
reqURL := s.endpointURL("registry/v1/lookup")
|
||||
authorityName := "QueryLookUp"
|
||||
|
||||
s.createNameRecord(authorityName)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
"Not Implemented",
|
||||
},
|
||||
{
|
||||
"nonexistent LRN",
|
||||
fmt.Sprintf(reqURL+"?lrn=lrn://%s/", "nonexistent"),
|
||||
"not found",
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
fmt.Sprintf(reqURL+"?lrn=lrn://%s/", authorityName),
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var response registry.QueryLookupLrnResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
require.NotEmpty(response.Name.Latest.Id)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) TestGRPCQueryListRecords() {
|
||||
reqURL := s.endpointURL("registry/v1/records")
|
||||
bondId := s.bondId
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
prerun func(string)
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
"not found",
|
||||
func(string) {},
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
func(id string) { s.createRecord(id) },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
tc.prerun(bondId)
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var response registry.QueryRecordsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
require.NotEmpty(response.GetRecords())
|
||||
require.Equal(bondId, response.GetRecords()[0].GetBondId())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) TestGRPCQueryGetRecordById() {
|
||||
reqURL := s.endpointURL("registry/v1/records/%s")
|
||||
bondId := s.bondId
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
prerun func(string) string
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
"not found",
|
||||
func(string) string { return "" },
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
func(id string) string {
|
||||
require := s.Require()
|
||||
|
||||
// create a record and get the id
|
||||
s.createRecord(id)
|
||||
out := s.cli().CustomQuery("q", "registry", "list")
|
||||
var response registry.QueryRecordsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON([]byte(out), &response), out)
|
||||
require.NotEmpty(response.GetRecords())
|
||||
|
||||
return response.GetRecords()[0].Id
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
recordId := tc.prerun(bondId)
|
||||
url := fmt.Sprintf(tc.url, recordId)
|
||||
|
||||
resp, err := testutil.GetRequest(url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var response registry.QueryGetRecordResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
record := response.GetRecord()
|
||||
require.NotEmpty(record.GetId())
|
||||
require.Equal(recordId, record.GetId())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) TestGRPCQueryGetRecordByBondId() {
|
||||
reqURL := s.endpointURL("registry/v1/records-by-bond-id/%s")
|
||||
bondId := s.bondId
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
prerun func(string)
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
"Not Implemented",
|
||||
func(string) {},
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
func(id string) { s.createRecord(id) },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
tc.prerun(bondId)
|
||||
url := fmt.Sprintf(tc.url, bondId)
|
||||
|
||||
resp, err := testutil.GetRequest(url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var response registry.QueryGetRecordsByBondIdResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
records := response.GetRecords()
|
||||
require.NotEmpty(records)
|
||||
require.Equal(bondId, records[0].GetBondId())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) TestGRPCQueryGetRegistryModuleBalance() {
|
||||
reqURL := s.endpointURL("registry/v1/balance")
|
||||
bondId := s.bondId
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
prerun func(string)
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
"Not Implemented",
|
||||
func(string) {},
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
func(id string) { s.createRecord(id) },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
tc.prerun(bondId)
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var response registry.QueryGetRegistryModuleBalanceResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
require.NotEmpty(response.GetBalances())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) TestGRPCQueryNamesList() {
|
||||
reqURL := s.endpointURL("registry/v1/names")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
errmsg string
|
||||
prerun func(string)
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
"Not Implemented",
|
||||
func(string) {},
|
||||
},
|
||||
{
|
||||
"valid request",
|
||||
reqURL,
|
||||
"",
|
||||
func(name string) { s.createNameRecord(name) },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
require := s.Require()
|
||||
|
||||
tc.prerun("ListNameRecords")
|
||||
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.errmsg != "" {
|
||||
message := gjson.Get(string(resp), "message").String()
|
||||
require.Contains(message, tc.errmsg, tc.url)
|
||||
} else {
|
||||
var response registry.QueryNameRecordsResponse
|
||||
require.NoError(s.codec.UnmarshalJSON(resp, &response), string(resp))
|
||||
require.NotEmpty(response.GetNames())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
157
tests/system/registry_test.go
Normal file
157
tests/system/registry_test.go
Normal file
@ -0,0 +1,157 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
// accounts "github.com/cosmos/cosmos-sdk/x/accounts/v1"
|
||||
"cosmossdk.io/math"
|
||||
systest "cosmossdk.io/systemtests"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
// nitro "git.vdb.to/cerc-io/laconicd/x/nitro/v1"
|
||||
"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 registrySuite struct {
|
||||
testSuite
|
||||
|
||||
accountAddress string
|
||||
bondId string
|
||||
}
|
||||
|
||||
func TestRegistry(t *testing.T) {
|
||||
suite.Run(t, new(registrySuite))
|
||||
}
|
||||
|
||||
func (s *registrySuite) SetupTest() {
|
||||
s.resetChain()
|
||||
|
||||
Sut.ModifyGenesisJSON(s.T(), UpdateGenesisRegistry(s))
|
||||
s.accountAddress = s.cli().GetKeyAddr(s.account(0))
|
||||
|
||||
Sut.StartChain(s.T())
|
||||
s.bondId = createBond(&s.testSuite)
|
||||
}
|
||||
|
||||
func (s *registrySuite) TestTxSetRecord() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
"request with invalid payload file arg",
|
||||
[]string{"bad-file", s.bondId},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"success",
|
||||
[]string{recordFilePath, s.bondId},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := []string{"tx", "registry", "set"}
|
||||
cmd = append(cmd, tc.args...)
|
||||
s.runTx(cmd, tc.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testSuite) updateParams(params *registry.Params) {
|
||||
params.RecordRent = sdk.NewCoin(s.bondDenom, math.NewInt(1000))
|
||||
params.RecordRentDuration = 10 * time.Second
|
||||
|
||||
params.AuthorityRent = sdk.NewCoin(s.bondDenom, math.NewInt(1000))
|
||||
params.AuthorityGracePeriod = 10 * time.Second
|
||||
|
||||
params.AuthorityAuctionCommitFee = sdk.NewCoin(s.bondDenom, math.NewInt(100))
|
||||
params.AuthorityAuctionRevealFee = sdk.NewCoin(s.bondDenom, math.NewInt(100))
|
||||
params.AuthorityAuctionMinimumBid = sdk.NewCoin(s.bondDenom, math.NewInt(500))
|
||||
}
|
||||
|
||||
func UpdateGenesisRegistry(s *registrySuite) systest.GenesisMutator {
|
||||
require := s.Require()
|
||||
|
||||
return func(genesis []byte) []byte {
|
||||
var regState registry.GenesisState
|
||||
raw := gjson.Get(string(genesis), "app_state.registry").String()
|
||||
require.NoError(s.codec.UnmarshalJSON([]byte(raw), ®State))
|
||||
|
||||
s.updateParams(®State.Params)
|
||||
regStateBz, err := s.codec.MarshalJSON(®State)
|
||||
require.NoError(err)
|
||||
genesis, err = sjson.SetRawBytes(genesis, "app_state.registry", regStateBz)
|
||||
require.NoError(err)
|
||||
|
||||
// // add consensus-controlled module account(s)
|
||||
// bondinitmsg, err := codectypes.NewAnyWithValue(&nitro.MsgInitAccount{})
|
||||
// require.NoError(s.T(), err)
|
||||
// var accountsState accounts.GenesisState
|
||||
// raw = gjson.Get(string(genesis), "app_state.accounts").String()
|
||||
// require.NoError(s.T(), cdc.UnmarshalJSON([]byte(raw), &accountsState))
|
||||
// accountsState.InitAccountMsgs = []*accounts.MsgInit{
|
||||
// {
|
||||
// Sender: accountAddress,
|
||||
// AccountType: "nitro",
|
||||
// Message: bondinitmsg,
|
||||
// },
|
||||
// }
|
||||
// accountsStateBz, err := cdc.MarshalJSON(&accountsState)
|
||||
// require.NoError(s.T(), err)
|
||||
// genesis, err = sjson.SetRawBytes(genesis, "app_state.accounts", accountsStateBz)
|
||||
// require.NoError(s.T(), err)
|
||||
|
||||
return genesis
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) reserveName(authorityName string) {
|
||||
cmd := []string{
|
||||
"tx", "registry", "reserve-authority", authorityName, s.accountAddress,
|
||||
}
|
||||
s.runTx(cmd, false)
|
||||
}
|
||||
|
||||
func (s *registrySuite) createNameRecord(authorityName string) {
|
||||
for _, cmd := range [][]string{
|
||||
// reserve name authority
|
||||
{"tx", "registry", "reserve-authority", authorityName, s.accountAddress},
|
||||
// add bond-id to name authority
|
||||
{"tx", "registry", "authority-bond", authorityName, s.bondId},
|
||||
// create actual name record
|
||||
{"tx", "registry", "set-name", fmt.Sprintf("lrn://%s/", authorityName), "test_hello_cid"},
|
||||
} {
|
||||
s.runTx(cmd, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *registrySuite) createRecord(bondId string) {
|
||||
s.T().Helper()
|
||||
cmd := []string{
|
||||
"tx", "registry", "set", recordFilePath, bondId,
|
||||
}
|
||||
s.runTx(cmd, false)
|
||||
}
|
||||
170
tests/system/suite_test.go
Normal file
170
tests/system/suite_test.go
Normal file
@ -0,0 +1,170 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
systest "cosmossdk.io/systemtests"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app/params"
|
||||
)
|
||||
|
||||
type testSuite struct {
|
||||
suite.Suite
|
||||
|
||||
codec codec.Codec
|
||||
accountNamePrefix string
|
||||
fees string
|
||||
bondDenom string
|
||||
|
||||
clientEthKey string
|
||||
validatorEthKey string
|
||||
}
|
||||
|
||||
func (s *testSuite) SetupSuite() {
|
||||
s.codec = codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
|
||||
s.accountNamePrefix = "node" // from testnet (--node-dir-prefix)
|
||||
s.fees = "1" + params.CoinUnit
|
||||
s.bondDenom = sdk.DefaultBondDenom
|
||||
|
||||
s.validatorEthKey = "validator-eth-key"
|
||||
s.clientEthKey = "client-eth-key"
|
||||
|
||||
// configure the validators and client
|
||||
commonInitCommands := [][]string{
|
||||
{"config", "set", "client", "chain-id", "testing"},
|
||||
{"config", "set", "client", "keyring-backend", "test"},
|
||||
}
|
||||
|
||||
// disable nitro on validators by default
|
||||
Sut.ForEachNodeExecAndWait(s.T(), append(commonInitCommands,
|
||||
[]string{"config", "set", "app", "nitro.enable", "false"},
|
||||
)...)
|
||||
|
||||
clientInitCommands := append(commonInitCommands,
|
||||
[]string{"config", "set", "app", "nitro.eth-key", s.clientEthKey},
|
||||
)
|
||||
for _, cmd := range clientInitCommands {
|
||||
cmd = append(cmd, "--home", s.clientHome())
|
||||
_ = systest.MustRunShellCmd(s.T(), Sut.ExecBinary(), cmd...)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testSuite) setValidatorNitroKeys(keys ...string) {
|
||||
Sut.WithEachNodeHome(func(i int, home string) {
|
||||
var cmds [][]string
|
||||
// TODO: complete and enable distsig
|
||||
// []string{"config", "set", "app", "distsig.enable", "true"},
|
||||
// []string{"config", "set", "app", "distsig.longterm-key", s.validatorNitroKey},
|
||||
// []string{"config", "set", "app", "nitro.use-distsig", "true"},
|
||||
|
||||
if i < len(keys) {
|
||||
// configure validator as a payment channel (individual) counterparty
|
||||
cmds = [][]string{
|
||||
{"config", "set", "app", "nitro.enable", "true"},
|
||||
|
||||
{"keys", "import-hex", s.validatorEthKey, keys[i]},
|
||||
{"config", "set", "app", "nitro.eth-key", s.validatorEthKey},
|
||||
}
|
||||
}
|
||||
|
||||
for _, cmd := range cmds {
|
||||
systest.MustRunShellCmd(s.T(), Sut.ExecBinary(), append(cmd, "--home", home)...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// note: keys have to be created after ResetChain, which clears the keyring
|
||||
func (s *testSuite) setClientKeys(ethKey string) {
|
||||
commands := [][]string{
|
||||
{"keys", "import-hex", s.clientEthKey, ethKey},
|
||||
}
|
||||
for _, cmd := range commands {
|
||||
cmd = append(cmd, "--home", s.clientHome())
|
||||
_ = systest.MustRunShellCmd(s.T(), Sut.ExecBinary(), cmd...)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testSuite) resetChain() {
|
||||
Sut.ResetChain(s.T())
|
||||
// clear the nitro data dirs
|
||||
Sut.WithEachNodeHome(func(i int, home string) {
|
||||
_ = os.RemoveAll(filepath.Join(home, "nitro"))
|
||||
|
||||
})
|
||||
_ = os.RemoveAll(filepath.Join(s.clientHome(), "nitro"))
|
||||
}
|
||||
|
||||
func (s *testSuite) account(i int) string {
|
||||
return fmt.Sprintf("%s%d", s.accountNamePrefix, i)
|
||||
}
|
||||
|
||||
// the home dir systemtests uses to run client commands
|
||||
func (s *testSuite) clientHome() string {
|
||||
return filepath.Join(workDir, "testnet")
|
||||
}
|
||||
|
||||
func (s *testSuite) endpointURL(endpoint string) string {
|
||||
return fmt.Sprintf("%s/cerc/%s", Sut.APIAddress(), endpoint)
|
||||
}
|
||||
|
||||
func (s *testSuite) cli() *systest.CLIWrapper {
|
||||
cli := systest.NewCLIWrapper(s.T(), Sut, verbose).
|
||||
WithRunStderr(os.Stderr)
|
||||
return &cli
|
||||
}
|
||||
|
||||
func (s *testSuite) assertWithStderr(asserter systest.RunErrorAssert) systest.RunErrorAssert {
|
||||
return func(t assert.TestingT, err error, msgAndArgs ...any) bool {
|
||||
if asserter(t, err, msgAndArgs...) {
|
||||
return true
|
||||
}
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
if stderr := exitError.Stderr; len(stderr) > 0 {
|
||||
defer t.Errorf("stderr: %s", stderr)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testSuite) runTx(cmd []string, err bool) string {
|
||||
s.T().Helper()
|
||||
cli := s.cli()
|
||||
asserter := assert.NoError
|
||||
if err {
|
||||
asserter = assert.Error
|
||||
}
|
||||
// don't use Run(), it will clobber our custom --home
|
||||
out := cli.
|
||||
WithRunErrorMatcher(s.assertWithStderr(asserter)).
|
||||
RunCommandWithArgs(s.withTxFlags(cmd)...)
|
||||
if err {
|
||||
return ""
|
||||
}
|
||||
txResult, committed := cli.AwaitTxCommitted(out, txTimeout)
|
||||
s.Require().True(committed)
|
||||
systest.RequireTxSuccess(s.T(), txResult)
|
||||
txHash := gjson.Get(out, "txhash")
|
||||
s.Require().True(txHash.Exists(), "txhash not found in output: %s", out)
|
||||
return txHash.String()
|
||||
}
|
||||
|
||||
func (s *testSuite) withTxFlags(cmd []string) []string {
|
||||
cmd = s.cli().WithTXFlags(cmd...)
|
||||
return append(cmd, []string{
|
||||
"--from", s.account(0),
|
||||
"--fees", s.fees,
|
||||
}...)
|
||||
}
|
||||
11
testutil/keyring.go
Normal file
11
testutil/keyring.go
Normal file
@ -0,0 +1,11 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
modtestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
|
||||
)
|
||||
|
||||
func NewKeyring() keyring.Keyring {
|
||||
encCfg := modtestutil.MakeTestEncodingConfig()
|
||||
return keyring.NewInMemory(encCfg.Codec)
|
||||
}
|
||||
54
utils/address.go
Normal file
54
utils/address.go
Normal file
@ -0,0 +1,54 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"cosmossdk.io/core/address"
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
|
||||
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
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 NewValidatorAddressCodec() runtime.ValidatorAddressCodec {
|
||||
return addressCodec{
|
||||
Codec: addresscodec.NewBech32Codec(params.Bech32PrefixValAddr),
|
||||
}
|
||||
}
|
||||
|
||||
func NewConsensusAddressCodec() runtime.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
|
||||
}
|
||||
18
utils/cmd.go
Normal file
18
utils/cmd.go
Normal file
@ -0,0 +1,18 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func GetFromContext[T any](ctx context.Context, key string) (*T, error) {
|
||||
if v := ctx.Value(key); v != nil {
|
||||
val, ok := v.(*T)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("context value of wrong type; expected %T, got %T", new(T), v)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
return nil, errors.New("key not found in context: " + key)
|
||||
}
|
||||
@ -1,29 +1,39 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/core/gas"
|
||||
"cosmossdk.io/log"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func CtxWithCustomKVGasConfig(ctx *sdk.Context) *sdk.Context {
|
||||
updatedCtx := ctx.WithKVGasConfig(storetypes.GasConfig{
|
||||
HasCost: 0,
|
||||
DeleteCost: 0,
|
||||
ReadCostFlat: 0,
|
||||
ReadCostPerByte: 0,
|
||||
WriteCostFlat: 0,
|
||||
WriteCostPerByte: 0,
|
||||
IterNextCostFlat: 0,
|
||||
})
|
||||
const RefundModuleGasDescriptor = "laconic module gas refund"
|
||||
|
||||
return &updatedCtx
|
||||
// WithCustomGasConfig returns a context with a zero-cost gas config, and a function to log all consumed gas.
|
||||
//
|
||||
// Note: as planned in server/v2, the gas meter will not be available on the STF-provided context
|
||||
// during tx execution, and must be accessed via gas.Service instead. This arg is a placeholder
|
||||
// to ensure modules using this include the gas service in anticipation of that change.
|
||||
// https://github.com/cosmos/cosmos-sdk/pull/16310
|
||||
func WithCustomGasConfig(ctx context.Context, _ gas.Service) (context.Context, func(log.Logger, string)) {
|
||||
c := sdk.UnwrapSDKContext(ctx)
|
||||
meter := c.GasMeter()
|
||||
|
||||
startGas := meter.GasConsumed()
|
||||
logGas := func(logger log.Logger, method string) {
|
||||
endGas := meter.GasConsumed()
|
||||
meter.RefundGas(endGas-startGas, RefundModuleGasDescriptor)
|
||||
LogTxGasConsumed(meter, logger, method)
|
||||
}
|
||||
|
||||
// Set a zero-cost gas config on the returned context
|
||||
return c.WithKVGasConfig(storetypes.GasConfig{}), logGas
|
||||
}
|
||||
|
||||
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.GasConsumed()
|
||||
logger.Info("tx executed", "method", method, "gas_consumed", fmt.Sprintf("%d", gasConsumed))
|
||||
}
|
||||
|
||||
79
utils/keys.go
Normal file
79
utils/keys.go
Normal file
@ -0,0 +1,79 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"cosmossdk.io/core/address"
|
||||
sdkerrors "cosmossdk.io/errors"
|
||||
cmtcrypto "github.com/cometbft/cometbft/crypto"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
sdkcrypto "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// cosmos-sdk crypto/keyring/record.go:138
|
||||
func extractPrivKeyFromLocal(rl *keyring.Record_Local) (cmtcrypto.PrivKey, error) {
|
||||
if rl.PrivKey == nil {
|
||||
return nil, keyring.ErrPrivKeyNotAvailable
|
||||
}
|
||||
|
||||
priv, ok := rl.PrivKey.GetCachedValue().(sdkcrypto.PrivKey)
|
||||
if !ok {
|
||||
return nil, sdkerrors.Wrap(keyring.ErrCastAny, "PrivKey")
|
||||
}
|
||||
return &PrivKey{priv}, nil
|
||||
}
|
||||
|
||||
func ExtractPrivateKey(r *keyring.Record) (cmtcrypto.PrivKey, error) {
|
||||
local := r.GetLocal()
|
||||
if local == nil {
|
||||
return nil, keyring.ErrPrivKeyExtr
|
||||
}
|
||||
return extractPrivKeyFromLocal(local)
|
||||
}
|
||||
|
||||
func ExtractPrivateKeyByUid(kr keyring.Keyring, uid string) (cmtcrypto.PrivKey, error) {
|
||||
r, err := kr.Key(uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ExtractPrivateKey(r)
|
||||
}
|
||||
|
||||
// GetKeyRecord tries to get a key by either address or uid
|
||||
func GetKeyRecord(kr keyring.Keyring, from string, ac address.Codec) (*keyring.Record, error) {
|
||||
var k *keyring.Record
|
||||
addr, err := ac.StringToBytes(from)
|
||||
if err == nil {
|
||||
k, err = kr.KeyByAddress(sdk.AccAddress(addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
k, err = kr.Key(from)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// PrivKey wraps the SDK PrivKey type to satisfy cometbft/crypto.PrivKey
|
||||
type PrivKey struct{ sdkcrypto.PrivKey }
|
||||
|
||||
func (k PrivKey) PubKey() cmtcrypto.PubKey { return PubKey{k.PrivKey.PubKey()} }
|
||||
|
||||
func (k PrivKey) Equals(other cmtcrypto.PrivKey) bool {
|
||||
if otherPk, ok := other.(*PrivKey); ok {
|
||||
return k.PrivKey.Equals(otherPk.PrivKey)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// PubKey wraps the SDK PubKey type to satisfy cometbft/crypto.PubKey
|
||||
type PubKey struct{ sdkcrypto.PubKey }
|
||||
|
||||
func (k PubKey) Equals(other cmtcrypto.PubKey) bool {
|
||||
if otherPk, ok := other.(*PubKey); ok {
|
||||
return k.PubKey.Equals(otherPk.PubKey)
|
||||
}
|
||||
return false
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user