Merge pull request #130 from tendermint/feature/tags-in-deliver-tx

Tags in DeliverTx response
This commit is contained in:
Ethan Buchman 2017-11-27 22:41:57 +00:00 committed by GitHub
commit 460c045fcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1022 additions and 914 deletions

View File

@ -13,3 +13,7 @@ indent_style = tab
[*.sh] [*.sh]
indent_style = tab indent_style = tab
[*.proto]
indent_style = space
indent_size = 2

View File

@ -1,5 +1,18 @@
# Changelog # Changelog
## 0.8.0 (TBD)
BREAKING CHANGES:
- [client] all XxxSync methods now return (ResponseXxx, error)
- [types] Application: all methods now take RequestXxx and return (ResponseXxx, error).
- Except `CheckTx`/`DeliverTx`, which takes a `tx []byte` argument.
- Except `Commit`, which takes no arguments.
- [types] removed Result
FEATURES:
- [types] added Tags field to ResponseDeliverTx
- [types] added Gas and Fee fields to ResponseCheckTx
## 0.7.1 (November 14, 2017) ## 0.7.1 (November 14, 2017)
IMPROVEMENTS: IMPROVEMENTS:

21
Dockerfile.develop Normal file
View File

@ -0,0 +1,21 @@
FROM golang:latest
RUN mkdir -p /go/src/github.com/tendermint/abci
WORKDIR /go/src/github.com/tendermint/abci
COPY Makefile /go/src/github.com/tendermint/abci/
# see make protoc for details on ldconfig
RUN make install_protoc && ldconfig
# killall is used in tests
RUN apt-get update && apt-get install -y \
psmisc \
&& rm -rf /var/lib/apt/lists/*
COPY glide.yaml /go/src/github.com/tendermint/abci/
COPY glide.lock /go/src/github.com/tendermint/abci/
RUN make get_vendor_deps
COPY . /go/src/github.com/tendermint/abci

View File

@ -1,18 +1,29 @@
GOTOOLS = \ GOTOOLS = \
github.com/mitchellh/gox \ github.com/mitchellh/gox \
github.com/Masterminds/glide \ github.com/Masterminds/glide \
github.com/alecthomas/gometalinter github.com/alecthomas/gometalinter \
github.com/ckaznocha/protoc-gen-lint
all: protoc install test all: install test
PACKAGES=$(shell go list ./... | grep -v '/vendor/') PACKAGES=$(shell go list ./... | grep -v '/vendor/')
install-protoc: install_protoc:
# Download: https://github.com/google/protobuf/releases # https://github.com/google/protobuf/releases
curl -L https://github.com/google/protobuf/releases/download/v3.4.1/protobuf-cpp-3.4.1.tar.gz | tar xvz && \
cd protobuf-3.4.1 && \
DIST_LANG=cpp ./configure && \
make && \
make install && \
cd .. && \
rm -rf protobuf-3.4.1
go get github.com/golang/protobuf/protoc-gen-go go get github.com/golang/protobuf/protoc-gen-go
protoc: protoc:
@ protoc --go_out=plugins=grpc:. types/*.proto ## On "error while loading shared libraries: libprotobuf.so.14: cannot open shared object file: No such file or directory"
## ldconfig (may require sudo)
## https://stackoverflow.com/a/25518702
protoc --go_out=plugins=grpc:. types/*.proto
install: install:
@ go install ./cmd/... @ go install ./cmd/...
@ -24,17 +35,22 @@ dist:
@ bash scripts/dist.sh @ bash scripts/dist.sh
@ bash scripts/publish.sh @ bash scripts/publish.sh
# test.sh requires that we run the installed cmds, must not be out of date test:
test: install @ find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \;
find . -path ./vendor -prune -o -name *.sock -exec rm {} \; @ echo "==> Running go test"
@ go test $(PACKAGES) @ go test $(PACKAGES)
@ bash tests/test.sh
test_race:
@ find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \;
@ echo "==> Running go test --race"
@go test -v -race $(PACKAGES)
test_integrations:
@ bash test.sh
fmt: fmt:
@ go fmt ./... @ go fmt ./...
test_integrations: get_vendor_deps install test
get_deps: get_deps:
@ go get -d $(PACKAGES) @ go get -d $(PACKAGES)
@ -47,10 +63,12 @@ get_vendor_deps:
metalinter: tools metalinter: tools
@gometalinter --install @gometalinter --install
protoc --lint_out=. types/*.proto
gometalinter --vendor --deadline=600s --enable-all --disable=lll ./... gometalinter --vendor --deadline=600s --enable-all --disable=lll ./...
metalinter_test: tools metalinter_test: tools
@gometalinter --install @gometalinter --install
# protoc --lint_out=. types/*.proto
gometalinter --vendor --deadline=600s --disable-all \ gometalinter --vendor --deadline=600s --disable-all \
--enable=maligned \ --enable=maligned \
--enable=deadcode \ --enable=deadcode \
@ -79,4 +97,10 @@ metalinter_test: tools
#--enable=unparam \ #--enable=unparam \
#--enable=vet \ #--enable=vet \
.PHONY: all build test fmt get_deps tools build-docker:
docker build -t "tendermint/abci-dev" -f Dockerfile.develop .
run-docker:
docker run -it --rm -v "$PWD:/go/src/github.com/tendermint/abci" -w "/go/src/github.com/tendermint/abci" "tendermint/abci-dev" /bin/bash
.PHONY: all build test fmt get_deps tools protoc install_protoc build-docker run-docker

View File

@ -91,6 +91,7 @@ Here, we describe the requests and responses as function arguments and return va
* `Code (uint32)`: Response code * `Code (uint32)`: Response code
* `Data ([]byte)`: Result bytes, if any * `Data ([]byte)`: Result bytes, if any
* `Log (string)`: Debug or error message * `Log (string)`: Debug or error message
* `Tags ([]*KVPair)`: Optional tags for indexing
* __Usage__:<br/> * __Usage__:<br/>
Append and run a transaction. If the transaction is valid, returns CodeType.OK Append and run a transaction. If the transaction is valid, returns CodeType.OK
@ -101,6 +102,8 @@ Here, we describe the requests and responses as function arguments and return va
* `Code (uint32)`: Response code * `Code (uint32)`: Response code
* `Data ([]byte)`: Result bytes, if any * `Data ([]byte)`: Result bytes, if any
* `Log (string)`: Debug or error message * `Log (string)`: Debug or error message
* `Gas (uint64)`: Amount of gas consumed by transaction
* `Fee (uint64)`: Fee paid by transaction
* __Usage__:<br/> * __Usage__:<br/>
Validate a mempool transaction, prior to broadcasting or proposing. This message should not mutate the main state, but application Validate a mempool transaction, prior to broadcasting or proposing. This message should not mutate the main state, but application
developers may want to keep a separate CheckTx state that gets reset upon Commit. developers may want to keep a separate CheckTx state that gets reset upon Commit.

View File

@ -12,11 +12,11 @@ checkout:
- rm -rf $REPO - rm -rf $REPO
- mkdir -p $HOME/.go_workspace/src/github.com/$CIRCLE_PROJECT_USERNAME - mkdir -p $HOME/.go_workspace/src/github.com/$CIRCLE_PROJECT_USERNAME
- mv $HOME/$CIRCLE_PROJECT_REPONAME $REPO - mv $HOME/$CIRCLE_PROJECT_REPONAME $REPO
# - git submodule sync - go version
# - git submodule update --init # use submodules
test: test:
override: override:
- "go version" - cd $REPO && make get_vendor_deps && make metalinter_test && make test_integrations
- "cd $REPO && make get_vendor_deps && make metalinter_test" post:
- "cd $REPO && make test_integrations" - cd "$REPO" && bash <(curl -s https://codecov.io/bash) -f coverage.txt
- cd "$REPO" && mv coverage.txt "${CIRCLE_ARTIFACTS}"

View File

@ -8,6 +8,11 @@ import (
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
) )
// Client defines an interface for an ABCI client.
// All `Async` methods return a `ReqRes` object.
// All `Sync` methods return the appropriate protobuf ResponseXxx struct and an error.
// Note these are client errors, eg. ABCI socket connectivity issues.
// Application-related errors are reflected in response via ABCI error codes and logs.
type Client interface { type Client interface {
cmn.Service cmn.Service
@ -17,28 +22,26 @@ type Client interface {
FlushAsync() *ReqRes FlushAsync() *ReqRes
EchoAsync(msg string) *ReqRes EchoAsync(msg string) *ReqRes
InfoAsync(types.RequestInfo) *ReqRes InfoAsync(types.RequestInfo) *ReqRes
SetOptionAsync(key string, value string) *ReqRes SetOptionAsync(types.RequestSetOption) *ReqRes
DeliverTxAsync(tx []byte) *ReqRes DeliverTxAsync(tx []byte) *ReqRes
CheckTxAsync(tx []byte) *ReqRes CheckTxAsync(tx []byte) *ReqRes
QueryAsync(types.RequestQuery) *ReqRes QueryAsync(types.RequestQuery) *ReqRes
CommitAsync() *ReqRes CommitAsync() *ReqRes
FlushSync() error
EchoSync(msg string) (res types.Result)
InfoSync(types.RequestInfo) (resInfo types.ResponseInfo, err error)
SetOptionSync(key string, value string) (res types.Result)
DeliverTxSync(tx []byte) (res types.Result)
CheckTxSync(tx []byte) (res types.Result)
QuerySync(types.RequestQuery) (resQuery types.ResponseQuery, err error)
CommitSync() (res types.Result)
InitChainAsync(types.RequestInitChain) *ReqRes InitChainAsync(types.RequestInitChain) *ReqRes
BeginBlockAsync(types.RequestBeginBlock) *ReqRes BeginBlockAsync(types.RequestBeginBlock) *ReqRes
EndBlockAsync(height uint64) *ReqRes EndBlockAsync(types.RequestEndBlock) *ReqRes
InitChainSync(types.RequestInitChain) (err error) FlushSync() error
BeginBlockSync(types.RequestBeginBlock) (err error) EchoSync(msg string) (*types.ResponseEcho, error)
EndBlockSync(height uint64) (resEndBlock types.ResponseEndBlock, err error) InfoSync(types.RequestInfo) (*types.ResponseInfo, error)
SetOptionSync(types.RequestSetOption) (*types.ResponseSetOption, error)
DeliverTxSync(tx []byte) (*types.ResponseDeliverTx, error)
CheckTxSync(tx []byte) (*types.ResponseCheckTx, error)
QuerySync(types.RequestQuery) (*types.ResponseQuery, error)
CommitSync() (*types.ResponseCommit, error)
InitChainSync(types.RequestInitChain) (*types.ResponseInitChain, error)
BeginBlockSync(types.RequestBeginBlock) (*types.ResponseBeginBlock, error)
EndBlockSync(types.RequestEndBlock) (*types.ResponseEndBlock, error)
} }
//---------------------------------------- //----------------------------------------

View File

@ -6,6 +6,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/pkg/errors"
context "golang.org/x/net/context" context "golang.org/x/net/context"
grpc "google.golang.org/grpc" grpc "google.golang.org/grpc"
@ -13,6 +14,8 @@ import (
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
) )
var _ Client = (*grpcClient)(nil)
// A stripped copy of the remoteClient that makes // A stripped copy of the remoteClient that makes
// synchronous calls using grpc // synchronous calls using grpc
type grpcClient struct { type grpcClient struct {
@ -101,7 +104,7 @@ func (cli *grpcClient) StopForError(err error) {
func (cli *grpcClient) Error() error { func (cli *grpcClient) Error() error {
cli.mtx.Lock() cli.mtx.Lock()
defer cli.mtx.Unlock() defer cli.mtx.Unlock()
return cli.err return errors.Wrap(cli.err, types.HumanCode(types.CodeType_InternalError))
} }
// Set listener for all responses // Set listener for all responses
@ -147,8 +150,8 @@ func (cli *grpcClient) InfoAsync(params types.RequestInfo) *ReqRes {
return cli.finishAsyncCall(req, &types.Response{&types.Response_Info{res}}) return cli.finishAsyncCall(req, &types.Response{&types.Response_Info{res}})
} }
func (cli *grpcClient) SetOptionAsync(key string, value string) *ReqRes { func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption) *ReqRes {
req := types.ToRequestSetOption(key, value) req := types.ToRequestSetOption(params)
res, err := cli.client.SetOption(context.Background(), req.GetSetOption(), grpc.FailFast(true)) res, err := cli.client.SetOption(context.Background(), req.GetSetOption(), grpc.FailFast(true))
if err != nil { if err != nil {
cli.StopForError(err) cli.StopForError(err)
@ -210,8 +213,8 @@ func (cli *grpcClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes {
return cli.finishAsyncCall(req, &types.Response{&types.Response_BeginBlock{res}}) return cli.finishAsyncCall(req, &types.Response{&types.Response_BeginBlock{res}})
} }
func (cli *grpcClient) EndBlockAsync(height uint64) *ReqRes { func (cli *grpcClient) EndBlockAsync(params types.RequestEndBlock) *ReqRes {
req := types.ToRequestEndBlock(height) req := types.ToRequestEndBlock(params)
res, err := cli.client.EndBlock(context.Background(), req.GetEndBlock(), grpc.FailFast(true)) res, err := cli.client.EndBlock(context.Background(), req.GetEndBlock(), grpc.FailFast(true))
if err != nil { if err != nil {
cli.StopForError(err) cli.StopForError(err)
@ -240,104 +243,59 @@ func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response)
return reqres return reqres
} }
func (cli *grpcClient) checkErrGetResult() types.Result {
if err := cli.Error(); err != nil {
// StopForError should already have been called if error is set
return types.ErrInternalError.SetLog(err.Error())
}
return types.Result{}
}
//---------------------------------------- //----------------------------------------
func (cli *grpcClient) EchoSync(msg string) (res types.Result) {
reqres := cli.EchoAsync(msg)
if res := cli.checkErrGetResult(); res.IsErr() {
return res
}
resp := reqres.Response.GetEcho()
return types.NewResultOK([]byte(resp.Message), "")
}
func (cli *grpcClient) FlushSync() error { func (cli *grpcClient) FlushSync() error {
return nil return nil
} }
func (cli *grpcClient) InfoSync(req types.RequestInfo) (resInfo types.ResponseInfo, err error) { func (cli *grpcClient) EchoSync(msg string) (*types.ResponseEcho, error) {
reqres := cli.EchoAsync(msg)
// StopForError should already have been called if error is set
return reqres.Response.GetEcho(), cli.Error()
}
func (cli *grpcClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
reqres := cli.InfoAsync(req) reqres := cli.InfoAsync(req)
if err = cli.Error(); err != nil { return reqres.Response.GetInfo(), cli.Error()
return resInfo, err
}
if info := reqres.Response.GetInfo(); info != nil {
return *info, nil
}
return resInfo, nil
} }
func (cli *grpcClient) SetOptionSync(key string, value string) (res types.Result) { func (cli *grpcClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
reqres := cli.SetOptionAsync(key, value) reqres := cli.SetOptionAsync(req)
if res := cli.checkErrGetResult(); res.IsErr() { return reqres.Response.GetSetOption(), cli.Error()
return res
}
resp := reqres.Response.GetSetOption()
return types.Result{Code: OK, Data: nil, Log: resp.Log}
} }
func (cli *grpcClient) DeliverTxSync(tx []byte) (res types.Result) { func (cli *grpcClient) DeliverTxSync(tx []byte) (*types.ResponseDeliverTx, error) {
reqres := cli.DeliverTxAsync(tx) reqres := cli.DeliverTxAsync(tx)
if res := cli.checkErrGetResult(); res.IsErr() { return reqres.Response.GetDeliverTx(), cli.Error()
return res
}
resp := reqres.Response.GetDeliverTx()
return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log}
} }
func (cli *grpcClient) CheckTxSync(tx []byte) (res types.Result) { func (cli *grpcClient) CheckTxSync(tx []byte) (*types.ResponseCheckTx, error) {
reqres := cli.CheckTxAsync(tx) reqres := cli.CheckTxAsync(tx)
if res := cli.checkErrGetResult(); res.IsErr() { return reqres.Response.GetCheckTx(), cli.Error()
return res
}
resp := reqres.Response.GetCheckTx()
return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log}
} }
func (cli *grpcClient) QuerySync(reqQuery types.RequestQuery) (resQuery types.ResponseQuery, err error) { func (cli *grpcClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) {
reqres := cli.QueryAsync(reqQuery) reqres := cli.QueryAsync(req)
if err = cli.Error(); err != nil { return reqres.Response.GetQuery(), cli.Error()
return resQuery, err
}
if resQuery_ := reqres.Response.GetQuery(); resQuery_ != nil {
return *resQuery_, nil
}
return resQuery, nil
} }
func (cli *grpcClient) CommitSync() (res types.Result) { func (cli *grpcClient) CommitSync() (*types.ResponseCommit, error) {
reqres := cli.CommitAsync() reqres := cli.CommitAsync()
if res := cli.checkErrGetResult(); res.IsErr() { return reqres.Response.GetCommit(), cli.Error()
return res
}
resp := reqres.Response.GetCommit()
return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log}
} }
func (cli *grpcClient) InitChainSync(params types.RequestInitChain) (err error) { func (cli *grpcClient) InitChainSync(params types.RequestInitChain) (*types.ResponseInitChain, error) {
cli.InitChainAsync(params) reqres := cli.InitChainAsync(params)
return cli.Error() return reqres.Response.GetInitChain(), cli.Error()
} }
func (cli *grpcClient) BeginBlockSync(params types.RequestBeginBlock) (err error) { func (cli *grpcClient) BeginBlockSync(params types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
cli.BeginBlockAsync(params) reqres := cli.BeginBlockAsync(params)
return cli.Error() return reqres.Response.GetBeginBlock(), cli.Error()
} }
func (cli *grpcClient) EndBlockSync(height uint64) (resEndBlock types.ResponseEndBlock, err error) { func (cli *grpcClient) EndBlockSync(params types.RequestEndBlock) (*types.ResponseEndBlock, error) {
reqres := cli.EndBlockAsync(height) reqres := cli.EndBlockAsync(params)
if err := cli.Error(); err != nil { return reqres.Response.GetEndBlock(), cli.Error()
return resEndBlock, err
}
if blk := reqres.Response.GetEndBlock(); blk != nil {
return *blk, nil
}
return resEndBlock, nil
} }

View File

@ -7,6 +7,8 @@ import (
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
) )
var _ Client = (*localClient)(nil)
type localClient struct { type localClient struct {
cmn.BaseService cmn.BaseService
mtx *sync.Mutex mtx *sync.Mutex
@ -51,21 +53,21 @@ func (app *localClient) EchoAsync(msg string) *ReqRes {
func (app *localClient) InfoAsync(req types.RequestInfo) *ReqRes { func (app *localClient) InfoAsync(req types.RequestInfo) *ReqRes {
app.mtx.Lock() app.mtx.Lock()
resInfo := app.Application.Info(req) res := app.Application.Info(req)
app.mtx.Unlock() app.mtx.Unlock()
return app.callback( return app.callback(
types.ToRequestInfo(req), types.ToRequestInfo(req),
types.ToResponseInfo(resInfo), types.ToResponseInfo(res),
) )
} }
func (app *localClient) SetOptionAsync(key string, value string) *ReqRes { func (app *localClient) SetOptionAsync(req types.RequestSetOption) *ReqRes {
app.mtx.Lock() app.mtx.Lock()
log := app.Application.SetOption(key, value) res := app.Application.SetOption(req)
app.mtx.Unlock() app.mtx.Unlock()
return app.callback( return app.callback(
types.ToRequestSetOption(key, value), types.ToRequestSetOption(req),
types.ToResponseSetOption(log), types.ToResponseSetOption(res),
) )
} }
@ -75,7 +77,7 @@ func (app *localClient) DeliverTxAsync(tx []byte) *ReqRes {
app.mtx.Unlock() app.mtx.Unlock()
return app.callback( return app.callback(
types.ToRequestDeliverTx(tx), types.ToRequestDeliverTx(tx),
types.ToResponseDeliverTx(res.Code, res.Data, res.Log), types.ToResponseDeliverTx(res),
) )
} }
@ -85,17 +87,17 @@ func (app *localClient) CheckTxAsync(tx []byte) *ReqRes {
app.mtx.Unlock() app.mtx.Unlock()
return app.callback( return app.callback(
types.ToRequestCheckTx(tx), types.ToRequestCheckTx(tx),
types.ToResponseCheckTx(res.Code, res.Data, res.Log), types.ToResponseCheckTx(res),
) )
} }
func (app *localClient) QueryAsync(reqQuery types.RequestQuery) *ReqRes { func (app *localClient) QueryAsync(req types.RequestQuery) *ReqRes {
app.mtx.Lock() app.mtx.Lock()
resQuery := app.Application.Query(reqQuery) res := app.Application.Query(req)
app.mtx.Unlock() app.mtx.Unlock()
return app.callback( return app.callback(
types.ToRequestQuery(reqQuery), types.ToRequestQuery(req),
types.ToResponseQuery(resQuery), types.ToResponseQuery(res),
) )
} }
@ -105,38 +107,38 @@ func (app *localClient) CommitAsync() *ReqRes {
app.mtx.Unlock() app.mtx.Unlock()
return app.callback( return app.callback(
types.ToRequestCommit(), types.ToRequestCommit(),
types.ToResponseCommit(res.Code, res.Data, res.Log), types.ToResponseCommit(res),
) )
} }
func (app *localClient) InitChainAsync(params types.RequestInitChain) *ReqRes { func (app *localClient) InitChainAsync(req types.RequestInitChain) *ReqRes {
app.mtx.Lock() app.mtx.Lock()
app.Application.InitChain(params) res := app.Application.InitChain(req)
reqRes := app.callback( reqRes := app.callback(
types.ToRequestInitChain(params), types.ToRequestInitChain(req),
types.ToResponseInitChain(), types.ToResponseInitChain(res),
) )
app.mtx.Unlock() app.mtx.Unlock()
return reqRes return reqRes
} }
func (app *localClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes { func (app *localClient) BeginBlockAsync(req types.RequestBeginBlock) *ReqRes {
app.mtx.Lock() app.mtx.Lock()
app.Application.BeginBlock(params) res := app.Application.BeginBlock(req)
app.mtx.Unlock() app.mtx.Unlock()
return app.callback( return app.callback(
types.ToRequestBeginBlock(params), types.ToRequestBeginBlock(req),
types.ToResponseBeginBlock(), types.ToResponseBeginBlock(res),
) )
} }
func (app *localClient) EndBlockAsync(height uint64) *ReqRes { func (app *localClient) EndBlockAsync(req types.RequestEndBlock) *ReqRes {
app.mtx.Lock() app.mtx.Lock()
resEndBlock := app.Application.EndBlock(height) res := app.Application.EndBlock(req)
app.mtx.Unlock() app.mtx.Unlock()
return app.callback( return app.callback(
types.ToRequestEndBlock(height), types.ToRequestEndBlock(req),
types.ToResponseEndBlock(resEndBlock), types.ToResponseEndBlock(res),
) )
} }
@ -146,71 +148,71 @@ func (app *localClient) FlushSync() error {
return nil return nil
} }
func (app *localClient) EchoSync(msg string) (res types.Result) { func (app *localClient) EchoSync(msg string) (*types.ResponseEcho, error) {
return types.OK.SetData([]byte(msg)) return &types.ResponseEcho{msg}, nil
} }
func (app *localClient) InfoSync(req types.RequestInfo) (resInfo types.ResponseInfo, err error) { func (app *localClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
app.mtx.Lock() app.mtx.Lock()
defer app.mtx.Unlock() res := app.Application.Info(req)
resInfo = app.Application.Info(req)
return resInfo, nil
}
func (app *localClient) SetOptionSync(key string, value string) (res types.Result) {
app.mtx.Lock()
log := app.Application.SetOption(key, value)
app.mtx.Unlock() app.mtx.Unlock()
return types.OK.SetLog(log) return &res, nil
} }
func (app *localClient) DeliverTxSync(tx []byte) (res types.Result) { func (app *localClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
app.mtx.Lock() app.mtx.Lock()
res = app.Application.DeliverTx(tx) res := app.Application.SetOption(req)
app.mtx.Unlock() app.mtx.Unlock()
return res return &res, nil
} }
func (app *localClient) CheckTxSync(tx []byte) (res types.Result) { func (app *localClient) DeliverTxSync(tx []byte) (*types.ResponseDeliverTx, error) {
app.mtx.Lock() app.mtx.Lock()
res = app.Application.CheckTx(tx) res := app.Application.DeliverTx(tx)
app.mtx.Unlock() app.mtx.Unlock()
return res return &res, nil
} }
func (app *localClient) QuerySync(reqQuery types.RequestQuery) (resQuery types.ResponseQuery, err error) { func (app *localClient) CheckTxSync(tx []byte) (*types.ResponseCheckTx, error) {
app.mtx.Lock() app.mtx.Lock()
resQuery = app.Application.Query(reqQuery) res := app.Application.CheckTx(tx)
app.mtx.Unlock() app.mtx.Unlock()
return resQuery, nil return &res, nil
} }
func (app *localClient) CommitSync() (res types.Result) { func (app *localClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) {
app.mtx.Lock() app.mtx.Lock()
res = app.Application.Commit() res := app.Application.Query(req)
app.mtx.Unlock() app.mtx.Unlock()
return res return &res, nil
} }
func (app *localClient) InitChainSync(params types.RequestInitChain) (err error) { func (app *localClient) CommitSync() (*types.ResponseCommit, error) {
app.mtx.Lock() app.mtx.Lock()
app.Application.InitChain(params) res := app.Application.Commit()
app.mtx.Unlock() app.mtx.Unlock()
return nil return &res, nil
} }
func (app *localClient) BeginBlockSync(params types.RequestBeginBlock) (err error) { func (app *localClient) InitChainSync(req types.RequestInitChain) (*types.ResponseInitChain, error) {
app.mtx.Lock() app.mtx.Lock()
app.Application.BeginBlock(params) res := app.Application.InitChain(req)
app.mtx.Unlock() app.mtx.Unlock()
return nil return &res, nil
} }
func (app *localClient) EndBlockSync(height uint64) (resEndBlock types.ResponseEndBlock, err error) { func (app *localClient) BeginBlockSync(req types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
app.mtx.Lock() app.mtx.Lock()
resEndBlock = app.Application.EndBlock(height) res := app.Application.BeginBlock(req)
app.mtx.Unlock() app.mtx.Unlock()
return resEndBlock, nil return &res, nil
}
func (app *localClient) EndBlockSync(req types.RequestEndBlock) (*types.ResponseEndBlock, error) {
app.mtx.Lock()
res := app.Application.EndBlock(req)
app.mtx.Unlock()
return &res, nil
} }
//------------------------------------------------------- //-------------------------------------------------------

View File

@ -3,26 +3,23 @@ package abcicli
import ( import (
"bufio" "bufio"
"container/list" "container/list"
"errors"
"fmt" "fmt"
"net" "net"
"reflect" "reflect"
"sync" "sync"
"time" "time"
"github.com/pkg/errors"
"github.com/tendermint/abci/types" "github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
) )
const (
OK = types.CodeType_OK
LOG = ""
)
const reqQueueSize = 256 // TODO make configurable const reqQueueSize = 256 // TODO make configurable
// const maxResponseSize = 1048576 // 1MB TODO make configurable // const maxResponseSize = 1048576 // 1MB TODO make configurable
const flushThrottleMS = 20 // Don't wait longer than... const flushThrottleMS = 20 // Don't wait longer than...
var _ Client = (*socketClient)(nil)
// This is goroutine-safe, but users should beware that // This is goroutine-safe, but users should beware that
// the application in general is not meant to be interfaced // the application in general is not meant to be interfaced
// with concurrent callers. // with concurrent callers.
@ -114,7 +111,7 @@ func (cli *socketClient) StopForError(err error) {
func (cli *socketClient) Error() error { func (cli *socketClient) Error() error {
cli.mtx.Lock() cli.mtx.Lock()
defer cli.mtx.Unlock() defer cli.mtx.Unlock()
return cli.err return errors.Wrap(cli.err, types.HumanCode(types.CodeType_InternalError))
} }
// Set listener for all responses // Set listener for all responses
@ -237,8 +234,8 @@ func (cli *socketClient) InfoAsync(req types.RequestInfo) *ReqRes {
return cli.queueRequest(types.ToRequestInfo(req)) return cli.queueRequest(types.ToRequestInfo(req))
} }
func (cli *socketClient) SetOptionAsync(key string, value string) *ReqRes { func (cli *socketClient) SetOptionAsync(req types.RequestSetOption) *ReqRes {
return cli.queueRequest(types.ToRequestSetOption(key, value)) return cli.queueRequest(types.ToRequestSetOption(req))
} }
func (cli *socketClient) DeliverTxAsync(tx []byte) *ReqRes { func (cli *socketClient) DeliverTxAsync(tx []byte) *ReqRes {
@ -249,133 +246,95 @@ func (cli *socketClient) CheckTxAsync(tx []byte) *ReqRes {
return cli.queueRequest(types.ToRequestCheckTx(tx)) return cli.queueRequest(types.ToRequestCheckTx(tx))
} }
func (cli *socketClient) QueryAsync(reqQuery types.RequestQuery) *ReqRes { func (cli *socketClient) QueryAsync(req types.RequestQuery) *ReqRes {
return cli.queueRequest(types.ToRequestQuery(reqQuery)) return cli.queueRequest(types.ToRequestQuery(req))
} }
func (cli *socketClient) CommitAsync() *ReqRes { func (cli *socketClient) CommitAsync() *ReqRes {
return cli.queueRequest(types.ToRequestCommit()) return cli.queueRequest(types.ToRequestCommit())
} }
func (cli *socketClient) InitChainAsync(params types.RequestInitChain) *ReqRes { func (cli *socketClient) InitChainAsync(req types.RequestInitChain) *ReqRes {
return cli.queueRequest(types.ToRequestInitChain(params)) return cli.queueRequest(types.ToRequestInitChain(req))
} }
func (cli *socketClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes { func (cli *socketClient) BeginBlockAsync(req types.RequestBeginBlock) *ReqRes {
return cli.queueRequest(types.ToRequestBeginBlock(params)) return cli.queueRequest(types.ToRequestBeginBlock(req))
} }
func (cli *socketClient) EndBlockAsync(height uint64) *ReqRes { func (cli *socketClient) EndBlockAsync(req types.RequestEndBlock) *ReqRes {
return cli.queueRequest(types.ToRequestEndBlock(height)) return cli.queueRequest(types.ToRequestEndBlock(req))
} }
//---------------------------------------- //----------------------------------------
func (cli *socketClient) EchoSync(msg string) (res types.Result) {
reqres := cli.queueRequest(types.ToRequestEcho(msg))
cli.FlushSync()
if err := cli.Error(); err != nil {
return types.ErrInternalError.SetLog(err.Error())
}
resp := reqres.Response.GetEcho()
return types.Result{Code: OK, Data: []byte(resp.Message)}
}
func (cli *socketClient) FlushSync() error { func (cli *socketClient) FlushSync() error {
reqRes := cli.queueRequest(types.ToRequestFlush()) reqRes := cli.queueRequest(types.ToRequestFlush())
if err := cli.Error(); err != nil { if err := cli.Error(); err != nil {
return types.ErrInternalError.SetLog(err.Error()) return err
} }
reqRes.Wait() // NOTE: if we don't flush the queue, its possible to get stuck here reqRes.Wait() // NOTE: if we don't flush the queue, its possible to get stuck here
return cli.Error() return cli.Error()
} }
func (cli *socketClient) InfoSync(req types.RequestInfo) (resInfo types.ResponseInfo, err error) { func (cli *socketClient) EchoSync(msg string) (*types.ResponseEcho, error) {
reqres := cli.queueRequest(types.ToRequestEcho(msg))
cli.FlushSync()
return reqres.Response.GetEcho(), cli.Error()
}
func (cli *socketClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
reqres := cli.queueRequest(types.ToRequestInfo(req)) reqres := cli.queueRequest(types.ToRequestInfo(req))
cli.FlushSync() cli.FlushSync()
if err := cli.Error(); err != nil { return reqres.Response.GetInfo(), cli.Error()
return resInfo, err
}
if resInfo_ := reqres.Response.GetInfo(); resInfo_ != nil {
return *resInfo_, nil
}
return resInfo, nil
} }
func (cli *socketClient) SetOptionSync(key string, value string) (res types.Result) { func (cli *socketClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
reqres := cli.queueRequest(types.ToRequestSetOption(key, value)) reqres := cli.queueRequest(types.ToRequestSetOption(req))
cli.FlushSync() cli.FlushSync()
if err := cli.Error(); err != nil { return reqres.Response.GetSetOption(), cli.Error()
return types.ErrInternalError.SetLog(err.Error())
}
resp := reqres.Response.GetSetOption()
return types.Result{Code: OK, Data: nil, Log: resp.Log}
} }
func (cli *socketClient) DeliverTxSync(tx []byte) (res types.Result) { func (cli *socketClient) DeliverTxSync(tx []byte) (*types.ResponseDeliverTx, error) {
reqres := cli.queueRequest(types.ToRequestDeliverTx(tx)) reqres := cli.queueRequest(types.ToRequestDeliverTx(tx))
cli.FlushSync() cli.FlushSync()
if err := cli.Error(); err != nil { return reqres.Response.GetDeliverTx(), cli.Error()
return types.ErrInternalError.SetLog(err.Error())
}
resp := reqres.Response.GetDeliverTx()
return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log}
} }
func (cli *socketClient) CheckTxSync(tx []byte) (res types.Result) { func (cli *socketClient) CheckTxSync(tx []byte) (*types.ResponseCheckTx, error) {
reqres := cli.queueRequest(types.ToRequestCheckTx(tx)) reqres := cli.queueRequest(types.ToRequestCheckTx(tx))
cli.FlushSync() cli.FlushSync()
if err := cli.Error(); err != nil { return reqres.Response.GetCheckTx(), cli.Error()
return types.ErrInternalError.SetLog(err.Error())
}
resp := reqres.Response.GetCheckTx()
return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log}
} }
func (cli *socketClient) QuerySync(reqQuery types.RequestQuery) (resQuery types.ResponseQuery, err error) { func (cli *socketClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) {
reqres := cli.queueRequest(types.ToRequestQuery(reqQuery)) reqres := cli.queueRequest(types.ToRequestQuery(req))
cli.FlushSync() cli.FlushSync()
if err := cli.Error(); err != nil { return reqres.Response.GetQuery(), cli.Error()
return resQuery, err
}
if resQuery_ := reqres.Response.GetQuery(); resQuery_ != nil {
return *resQuery_, nil
}
return resQuery, nil
} }
func (cli *socketClient) CommitSync() (res types.Result) { func (cli *socketClient) CommitSync() (*types.ResponseCommit, error) {
reqres := cli.queueRequest(types.ToRequestCommit()) reqres := cli.queueRequest(types.ToRequestCommit())
cli.FlushSync() cli.FlushSync()
if err := cli.Error(); err != nil { return reqres.Response.GetCommit(), cli.Error()
return types.ErrInternalError.SetLog(err.Error())
}
resp := reqres.Response.GetCommit()
return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log}
} }
func (cli *socketClient) InitChainSync(params types.RequestInitChain) (err error) { func (cli *socketClient) InitChainSync(req types.RequestInitChain) (*types.ResponseInitChain, error) {
cli.queueRequest(types.ToRequestInitChain(params)) reqres := cli.queueRequest(types.ToRequestInitChain(req))
cli.FlushSync() cli.FlushSync()
return cli.Error() return reqres.Response.GetInitChain(), cli.Error()
} }
func (cli *socketClient) BeginBlockSync(params types.RequestBeginBlock) (err error) { func (cli *socketClient) BeginBlockSync(req types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
cli.queueRequest(types.ToRequestBeginBlock(params)) reqres := cli.queueRequest(types.ToRequestBeginBlock(req))
cli.FlushSync() cli.FlushSync()
return cli.Error() return reqres.Response.GetBeginBlock(), cli.Error()
} }
func (cli *socketClient) EndBlockSync(height uint64) (resEndBlock types.ResponseEndBlock, err error) { func (cli *socketClient) EndBlockSync(req types.RequestEndBlock) (*types.ResponseEndBlock, error) {
reqres := cli.queueRequest(types.ToRequestEndBlock(height)) reqres := cli.queueRequest(types.ToRequestEndBlock(req))
cli.FlushSync() cli.FlushSync()
if err := cli.Error(); err != nil { return reqres.Response.GetEndBlock(), cli.Error()
return resEndBlock, err
}
if blk := reqres.Response.GetEndBlock(); blk != nil {
return *blk, nil
}
return resEndBlock, nil
} }
//---------------------------------------- //----------------------------------------

View File

@ -96,10 +96,10 @@ var RootCmd = &cobra.Command{
}, },
} }
func Execute() { func Execute() error {
addGlobalFlags() addGlobalFlags()
addCommands() addCommands()
RootCmd.Execute() return RootCmd.Execute()
} }
func addGlobalFlags() { func addGlobalFlags() {
@ -294,7 +294,7 @@ func cmdBatch(cmd *cobra.Command, args []string) error {
} }
pArgs := persistentArgs(line) pArgs := persistentArgs(line)
out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() // nolint: gas
if err != nil { if err != nil {
return err return err
} }
@ -316,7 +316,7 @@ func cmdConsole(cmd *cobra.Command, args []string) error {
} }
pArgs := persistentArgs(line) pArgs := persistentArgs(line)
out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() // nolint: gas
if err != nil { if err != nil {
return err return err
} }
@ -327,9 +327,12 @@ func cmdConsole(cmd *cobra.Command, args []string) error {
// Have the application echo a message // Have the application echo a message
func cmdEcho(cmd *cobra.Command, args []string) error { func cmdEcho(cmd *cobra.Command, args []string) error {
resEcho := client.EchoSync(args[0]) res, err := client.EchoSync(args[0])
if err != nil {
return err
}
printResponse(cmd, args, response{ printResponse(cmd, args, response{
Data: resEcho.Data, Data: []byte(res.Message),
}) })
return nil return nil
} }
@ -340,21 +343,25 @@ func cmdInfo(cmd *cobra.Command, args []string) error {
if len(args) == 1 { if len(args) == 1 {
version = args[0] version = args[0]
} }
resInfo, err := client.InfoSync(types.RequestInfo{version}) res, err := client.InfoSync(types.RequestInfo{version})
if err != nil { if err != nil {
return err return err
} }
printResponse(cmd, args, response{ printResponse(cmd, args, response{
Data: []byte(resInfo.Data), Data: []byte(res.Data),
}) })
return nil return nil
} }
// Set an option on the application // Set an option on the application
func cmdSetOption(cmd *cobra.Command, args []string) error { func cmdSetOption(cmd *cobra.Command, args []string) error {
resSetOption := client.SetOptionSync(args[0], args[1]) key, val := args[0], args[1]
res, err := client.SetOptionSync(types.RequestSetOption{key, val})
if err != nil {
return err
}
printResponse(cmd, args, response{ printResponse(cmd, args, response{
Log: resSetOption.Log, Log: res.Log,
}) })
return nil return nil
} }
@ -365,7 +372,10 @@ func cmdDeliverTx(cmd *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
res := client.DeliverTxSync(txBytes) res, err := client.DeliverTxSync(txBytes)
if err != nil {
return err
}
printResponse(cmd, args, response{ printResponse(cmd, args, response{
Code: res.Code, Code: res.Code,
Data: res.Data, Data: res.Data,
@ -380,7 +390,10 @@ func cmdCheckTx(cmd *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
res := client.CheckTxSync(txBytes) res, err := client.CheckTxSync(txBytes)
if err != nil {
return err
}
printResponse(cmd, args, response{ printResponse(cmd, args, response{
Code: res.Code, Code: res.Code,
Data: res.Data, Data: res.Data,
@ -391,7 +404,10 @@ func cmdCheckTx(cmd *cobra.Command, args []string) error {
// Get application Merkle root hash // Get application Merkle root hash
func cmdCommit(cmd *cobra.Command, args []string) error { func cmdCommit(cmd *cobra.Command, args []string) error {
res := client.CommitSync() res, err := client.CommitSync()
if err != nil {
return err
}
printResponse(cmd, args, response{ printResponse(cmd, args, response{
Code: res.Code, Code: res.Code,
Data: res.Data, Data: res.Data,

View File

@ -1,5 +1,14 @@
package main package main
import (
"fmt"
"os"
)
func main() { func main() {
Execute() err := Execute()
if err != nil {
fmt.Print(err)
os.Exit(1)
}
} }

View File

@ -1,65 +0,0 @@
package main
import (
"flag"
"os"
"github.com/tendermint/abci/server"
"github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
)
func main() {
addrPtr := flag.String("addr", "tcp://0.0.0.0:46658", "Listen address")
abciPtr := flag.String("abci", "socket", "socket | grpc")
flag.Parse()
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
// Start the listener
srv, err := server.NewServer(*addrPtr, *abciPtr, NewChainAwareApplication())
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}
srv.SetLogger(logger.With("module", "abci-server"))
if _, err := srv.Start(); err != nil {
logger.Error(err.Error())
os.Exit(1)
}
// Wait forever
cmn.TrapSignal(func() {
// Cleanup
srv.Stop()
})
}
type ChainAwareApplication struct {
types.BaseApplication
beginCount int
endCount int
}
func NewChainAwareApplication() *ChainAwareApplication {
return &ChainAwareApplication{}
}
func (app *ChainAwareApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
return types.ResponseQuery{
Value: []byte(cmn.Fmt("%d,%d", app.beginCount, app.endCount)),
}
}
func (app *ChainAwareApplication) BeginBlock(reqBeginBlock types.RequestBeginBlock) {
app.beginCount++
}
func (app *ChainAwareApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) {
app.endCount++
return
}

View File

@ -1,57 +0,0 @@
package main
import (
"strconv"
"strings"
"testing"
abcicli "github.com/tendermint/abci/client"
"github.com/tendermint/abci/server"
"github.com/tendermint/abci/types"
"github.com/tendermint/tmlibs/log"
)
func TestChainAware(t *testing.T) {
app := NewChainAwareApplication()
// Start the listener
srv, err := server.NewServer("unix://test.sock", "socket", app)
if err != nil {
t.Fatal(err)
}
srv.SetLogger(log.TestingLogger().With("module", "abci-server"))
if _, err := srv.Start(); err != nil {
t.Fatal(err.Error())
}
defer srv.Stop()
// Connect to the socket
client := abcicli.NewSocketClient("unix://test.sock", false)
client.SetLogger(log.TestingLogger().With("module", "abci-client"))
if _, err := client.Start(); err != nil {
t.Fatalf("Error starting socket client: %v", err.Error())
}
defer client.Stop()
n := uint64(5)
hash := []byte("fake block hash")
header := &types.Header{}
for i := uint64(0); i < n; i++ {
client.BeginBlockSync(types.RequestBeginBlock{hash, header})
client.EndBlockSync(i)
client.CommitSync()
}
r := app.Query(types.RequestQuery{})
spl := strings.Split(string(r.Value), ",")
if len(spl) != 2 {
t.Fatal("expected %d,%d ; got %s", n, n, string(r.Value))
}
beginCount, _ := strconv.Atoi(spl[0])
endCount, _ := strconv.Atoi(spl[1])
if uint64(beginCount) != n {
t.Fatalf("expected beginCount of %d, got %d", n, beginCount)
} else if uint64(endCount) != n {
t.Fatalf("expected endCount of %d, got %d", n, endCount)
}
}

View File

@ -2,6 +2,7 @@ package counter
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
"github.com/tendermint/abci/types" "github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
@ -23,52 +24,61 @@ func (app *CounterApplication) Info(req types.RequestInfo) types.ResponseInfo {
return types.ResponseInfo{Data: cmn.Fmt("{\"hashes\":%v,\"txs\":%v}", app.hashCount, app.txCount)} return types.ResponseInfo{Data: cmn.Fmt("{\"hashes\":%v,\"txs\":%v}", app.hashCount, app.txCount)}
} }
func (app *CounterApplication) SetOption(key string, value string) (log string) { func (app *CounterApplication) SetOption(req types.RequestSetOption) types.ResponseSetOption {
key, value := req.Key, req.Value
if key == "serial" && value == "on" { if key == "serial" && value == "on" {
app.serial = true app.serial = true
} }
return "" return types.ResponseSetOption{}
} }
func (app *CounterApplication) DeliverTx(tx []byte) types.Result { func (app *CounterApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {
if app.serial { if app.serial {
if len(tx) > 8 { if len(tx) > 8 {
return types.ErrEncodingError.SetLog(cmn.Fmt("Max tx size is 8 bytes, got %d", len(tx))) return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Max tx size is 8 bytes, got %d", len(tx))}
} }
tx8 := make([]byte, 8) tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(tx):], tx) copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8) txValue := binary.BigEndian.Uint64(tx8)
if txValue != uint64(app.txCount) { if txValue != uint64(app.txCount) {
return types.ErrBadNonce.SetLog(cmn.Fmt("Invalid nonce. Expected %v, got %v", app.txCount, txValue)) return types.ResponseDeliverTx{
Code: types.CodeType_BadNonce,
Log: fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue)}
} }
} }
app.txCount++ app.txCount++
return types.OK return types.ResponseDeliverTx{Code: types.CodeType_OK}
} }
func (app *CounterApplication) CheckTx(tx []byte) types.Result { func (app *CounterApplication) CheckTx(tx []byte) types.ResponseCheckTx {
if app.serial { if app.serial {
if len(tx) > 8 { if len(tx) > 8 {
return types.ErrEncodingError.SetLog(cmn.Fmt("Max tx size is 8 bytes, got %d", len(tx))) return types.ResponseCheckTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Max tx size is 8 bytes, got %d", len(tx))}
} }
tx8 := make([]byte, 8) tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(tx):], tx) copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8) txValue := binary.BigEndian.Uint64(tx8)
if txValue < uint64(app.txCount) { if txValue < uint64(app.txCount) {
return types.ErrBadNonce.SetLog(cmn.Fmt("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue)) return types.ResponseCheckTx{
Code: types.CodeType_BadNonce,
Log: fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue)}
} }
} }
return types.OK return types.ResponseCheckTx{Code: types.CodeType_OK}
} }
func (app *CounterApplication) Commit() types.Result { func (app *CounterApplication) Commit() (resp types.ResponseCommit) {
app.hashCount++ app.hashCount++
if app.txCount == 0 { if app.txCount == 0 {
return types.OK return types.ResponseCommit{Code: types.CodeType_OK}
} }
hash := make([]byte, 8) hash := make([]byte, 8)
binary.BigEndian.PutUint64(hash, uint64(app.txCount)) binary.BigEndian.PutUint64(hash, uint64(app.txCount))
return types.NewResultOK(hash, "") return types.ResponseCommit{Code: types.CodeType_OK, Data: hash}
} }
func (app *CounterApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery { func (app *CounterApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery {

View File

@ -1,15 +1,17 @@
package dummy package dummy
import ( import (
"fmt"
"strings" "strings"
"github.com/tendermint/abci/types" "github.com/tendermint/abci/types"
wire "github.com/tendermint/go-wire" wire "github.com/tendermint/go-wire"
"github.com/tendermint/iavl" "github.com/tendermint/iavl"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
) )
var _ types.Application = (*DummyApplication)(nil)
type DummyApplication struct { type DummyApplication struct {
types.BaseApplication types.BaseApplication
@ -22,25 +24,25 @@ func NewDummyApplication() *DummyApplication {
} }
func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())} return types.ResponseInfo{Data: fmt.Sprintf("{\"size\":%v}", app.state.Size())}
} }
// tx is either "key=value" or just arbitrary bytes // tx is either "key=value" or just arbitrary bytes
func (app *DummyApplication) DeliverTx(tx []byte) types.Result { func (app *DummyApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {
parts := strings.Split(string(tx), "=") parts := strings.Split(string(tx), "=")
if len(parts) == 2 { if len(parts) == 2 {
app.state.Set([]byte(parts[0]), []byte(parts[1])) app.state.Set([]byte(parts[0]), []byte(parts[1]))
} else { } else {
app.state.Set(tx, tx) app.state.Set(tx, tx)
} }
return types.OK return types.ResponseDeliverTx{Code: types.CodeType_OK}
} }
func (app *DummyApplication) CheckTx(tx []byte) types.Result { func (app *DummyApplication) CheckTx(tx []byte) types.ResponseCheckTx {
return types.OK return types.ResponseCheckTx{Code: types.CodeType_OK}
} }
func (app *DummyApplication) Commit() types.Result { func (app *DummyApplication) Commit() types.ResponseCommit {
// Save a new version // Save a new version
var hash []byte var hash []byte
var err error var err error
@ -55,7 +57,7 @@ func (app *DummyApplication) Commit() types.Result {
} }
} }
return types.NewResultOK(hash, "") return types.ResponseCommit{Code: types.CodeType_OK, Data: hash}
} }
func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {

View File

@ -93,7 +93,7 @@ func TestPersistentDummyInfo(t *testing.T) {
Height: uint64(height), Height: uint64(height),
} }
dummy.BeginBlock(types.RequestBeginBlock{hash, header}) dummy.BeginBlock(types.RequestBeginBlock{hash, header})
dummy.EndBlock(height) dummy.EndBlock(types.RequestEndBlock{header.Height})
dummy.Commit() dummy.Commit()
resInfo = dummy.Info(types.RequestInfo{}) resInfo = dummy.Info(types.RequestInfo{})
@ -182,7 +182,7 @@ func makeApplyBlock(t *testing.T, dummy types.Application, heightInt int, diff [
t.Fatal(r) t.Fatal(r)
} }
} }
resEndBlock := dummy.EndBlock(height) resEndBlock := dummy.EndBlock(types.RequestEndBlock{header.Height})
dummy.Commit() dummy.Commit()
valsEqual(t, diff, resEndBlock.Diffs) valsEqual(t, diff, resEndBlock.Diffs)
@ -281,10 +281,12 @@ func runClientTests(t *testing.T, client abcicli.Client) {
} }
func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) { func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) {
ar := app.DeliverTxSync(tx) ar, err := app.DeliverTxSync(tx)
require.NoError(t, err)
require.False(t, ar.IsErr(), ar) require.False(t, ar.IsErr(), ar)
// repeating tx doesn't raise error // repeating tx doesn't raise error
ar = app.DeliverTxSync(tx) ar, err = app.DeliverTxSync(tx)
require.NoError(t, err)
require.False(t, ar.IsErr(), ar) require.False(t, ar.IsErr(), ar)
// make sure query is fine // make sure query is fine

View File

@ -3,6 +3,7 @@ package dummy
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"fmt"
"strconv" "strconv"
"strings" "strings"
@ -20,6 +21,8 @@ const (
//----------------------------------------- //-----------------------------------------
var _ types.Application = (*PersistentDummyApplication)(nil)
type PersistentDummyApplication struct { type PersistentDummyApplication struct {
app *DummyApplication app *DummyApplication
@ -49,19 +52,19 @@ func (app *PersistentDummyApplication) SetLogger(l log.Logger) {
app.logger = l app.logger = l
} }
func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { func (app *PersistentDummyApplication) Info(req types.RequestInfo) types.ResponseInfo {
resInfo = app.app.Info(req) res := app.app.Info(req)
resInfo.LastBlockHeight = app.app.state.LatestVersion() res.LastBlockHeight = app.app.state.LatestVersion()
resInfo.LastBlockAppHash = app.app.state.Hash() res.LastBlockAppHash = app.app.state.Hash()
return resInfo return res
} }
func (app *PersistentDummyApplication) SetOption(key string, value string) (log string) { func (app *PersistentDummyApplication) SetOption(req types.RequestSetOption) types.ResponseSetOption {
return app.app.SetOption(key, value) return app.app.SetOption(req)
} }
// tx is either "val:pubkey/power" or "key=value" or just arbitrary bytes // tx is either "val:pubkey/power" or "key=value" or just arbitrary bytes
func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result { func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {
// if it starts with "val:", update the validator set // if it starts with "val:", update the validator set
// format is "val:pubkey/power" // format is "val:pubkey/power"
if isValidatorTx(tx) { if isValidatorTx(tx) {
@ -74,12 +77,12 @@ func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result {
return app.app.DeliverTx(tx) return app.app.DeliverTx(tx)
} }
func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result { func (app *PersistentDummyApplication) CheckTx(tx []byte) types.ResponseCheckTx {
return app.app.CheckTx(tx) return app.app.CheckTx(tx)
} }
// Commit will panic if InitChain was not called // Commit will panic if InitChain was not called
func (app *PersistentDummyApplication) Commit() types.Result { func (app *PersistentDummyApplication) Commit() types.ResponseCommit {
// Save a new version for next height // Save a new version for next height
height := app.app.state.LatestVersion() + 1 height := app.app.state.LatestVersion() + 1
@ -93,7 +96,7 @@ func (app *PersistentDummyApplication) Commit() types.Result {
} }
app.logger.Info("Commit block", "height", height, "root", appHash) app.logger.Info("Commit block", "height", height, "root", appHash)
return types.NewResultOK(appHash, "") return types.ResponseCommit{Code: types.CodeType_OK, Data: appHash}
} }
func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery { func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery {
@ -101,23 +104,25 @@ func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.
} }
// Save the validators in the merkle tree // Save the validators in the merkle tree
func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) { func (app *PersistentDummyApplication) InitChain(req types.RequestInitChain) types.ResponseInitChain {
for _, v := range params.Validators { for _, v := range req.Validators {
r := app.updateValidator(v) r := app.updateValidator(v)
if r.IsErr() { if r.IsErr() {
app.logger.Error("Error updating validators", "r", r) app.logger.Error("Error updating validators", "r", r)
} }
} }
return types.ResponseInitChain{}
} }
// Track the block hash and header information // Track the block hash and header information
func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) { func (app *PersistentDummyApplication) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock {
// reset valset changes // reset valset changes
app.changes = make([]*types.Validator, 0) app.changes = make([]*types.Validator, 0)
return types.ResponseBeginBlock{}
} }
// Update the validator set // Update the validator set
func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) { func (app *PersistentDummyApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock {
return types.ResponseEndBlock{Diffs: app.changes} return types.ResponseEndBlock{Diffs: app.changes}
} }
@ -148,30 +153,38 @@ func isValidatorTx(tx []byte) bool {
} }
// format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx // format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx
func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result { func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.ResponseDeliverTx {
tx = tx[len(ValidatorSetChangePrefix):] tx = tx[len(ValidatorSetChangePrefix):]
//get the pubkey and power //get the pubkey and power
pubKeyAndPower := strings.Split(string(tx), "/") pubKeyAndPower := strings.Split(string(tx), "/")
if len(pubKeyAndPower) != 2 { if len(pubKeyAndPower) != 2 {
return types.ErrEncodingError.SetLog(cmn.Fmt("Expected 'pubkey/power'. Got %v", pubKeyAndPower)) return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Expected 'pubkey/power'. Got %v", pubKeyAndPower)}
} }
pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1] pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1]
// decode the pubkey, ensuring its go-crypto encoded // decode the pubkey, ensuring its go-crypto encoded
pubkey, err := hex.DecodeString(pubkeyS) pubkey, err := hex.DecodeString(pubkeyS)
if err != nil { if err != nil {
return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%s) is invalid hex", pubkeyS)) return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Pubkey (%s) is invalid hex", pubkeyS)}
} }
_, err = crypto.PubKeyFromBytes(pubkey) _, err = crypto.PubKeyFromBytes(pubkey)
if err != nil { if err != nil {
return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%X) is invalid go-crypto encoded", pubkey)) return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Pubkey (%X) is invalid go-crypto encoded", pubkey)}
} }
// decode the power // decode the power
power, err := strconv.Atoi(powerS) power, err := strconv.Atoi(powerS)
if err != nil { if err != nil {
return types.ErrEncodingError.SetLog(cmn.Fmt("Power (%s) is not an int", powerS)) return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Power (%s) is not an int", powerS)}
} }
// update // update
@ -179,19 +192,23 @@ func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result {
} }
// add, update, or remove a validator // add, update, or remove a validator
func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types.Result { func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types.ResponseDeliverTx {
key := []byte("val:" + string(v.PubKey)) key := []byte("val:" + string(v.PubKey))
if v.Power == 0 { if v.Power == 0 {
// remove validator // remove validator
if !app.app.state.Has(key) { if !app.app.state.Has(key) {
return types.ErrUnauthorized.SetLog(cmn.Fmt("Cannot remove non-existent validator %X", key)) return types.ResponseDeliverTx{
Code: types.CodeType_Unauthorized,
Log: fmt.Sprintf("Cannot remove non-existent validator %X", key)}
} }
app.app.state.Remove(key) app.app.state.Remove(key)
} else { } else {
// add or update validator // add or update validator
value := bytes.NewBuffer(make([]byte, 0)) value := bytes.NewBuffer(make([]byte, 0))
if err := types.WriteMessage(v, value); err != nil { if err := types.WriteMessage(v, value); err != nil {
return types.ErrInternalError.SetLog(cmn.Fmt("Error encoding validator: %v", err)) return types.ResponseDeliverTx{
Code: types.CodeType_InternalError,
Log: fmt.Sprintf("Error encoding validator: %v", err)}
} }
app.app.state.Set(key, value.Bytes()) app.app.state.Set(key, value.Bytes())
} }
@ -199,5 +216,5 @@ func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types
// we only update the changes array if we successfully updated the tree // we only update the changes array if we successfully updated the tree
app.changes = append(app.changes, v) app.changes = append(app.changes, v)
return types.OK return types.ResponseDeliverTx{Code: types.CodeType_OK}
} }

View File

@ -56,13 +56,17 @@ func (s *SocketServer) OnStart() error {
func (s *SocketServer) OnStop() { func (s *SocketServer) OnStop() {
s.BaseService.OnStop() s.BaseService.OnStop()
s.listener.Close() if err := s.listener.Close(); err != nil {
s.Logger.Error("Error closing listener", "err", err)
}
s.connsMtx.Lock() s.connsMtx.Lock()
defer s.connsMtx.Unlock() defer s.connsMtx.Unlock()
for id, conn := range s.conns { for id, conn := range s.conns {
delete(s.conns, id) delete(s.conns, id)
conn.Close() if err := conn.Close(); err != nil {
s.Logger.Error("Error closing connection", "id", id, "conn", conn, "err", err)
}
} }
} }
@ -168,33 +172,32 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types
case *types.Request_Flush: case *types.Request_Flush:
responses <- types.ToResponseFlush() responses <- types.ToResponseFlush()
case *types.Request_Info: case *types.Request_Info:
resInfo := s.app.Info(*r.Info) res := s.app.Info(*r.Info)
responses <- types.ToResponseInfo(resInfo) responses <- types.ToResponseInfo(res)
case *types.Request_SetOption: case *types.Request_SetOption:
so := r.SetOption res := s.app.SetOption(*r.SetOption)
logStr := s.app.SetOption(so.Key, so.Value) responses <- types.ToResponseSetOption(res)
responses <- types.ToResponseSetOption(logStr)
case *types.Request_DeliverTx: case *types.Request_DeliverTx:
res := s.app.DeliverTx(r.DeliverTx.Tx) res := s.app.DeliverTx(r.DeliverTx.Tx)
responses <- types.ToResponseDeliverTx(res.Code, res.Data, res.Log) responses <- types.ToResponseDeliverTx(res)
case *types.Request_CheckTx: case *types.Request_CheckTx:
res := s.app.CheckTx(r.CheckTx.Tx) res := s.app.CheckTx(r.CheckTx.Tx)
responses <- types.ToResponseCheckTx(res.Code, res.Data, res.Log) responses <- types.ToResponseCheckTx(res)
case *types.Request_Commit: case *types.Request_Commit:
res := s.app.Commit() res := s.app.Commit()
responses <- types.ToResponseCommit(res.Code, res.Data, res.Log) responses <- types.ToResponseCommit(res)
case *types.Request_Query: case *types.Request_Query:
resQuery := s.app.Query(*r.Query) res := s.app.Query(*r.Query)
responses <- types.ToResponseQuery(resQuery) responses <- types.ToResponseQuery(res)
case *types.Request_InitChain: case *types.Request_InitChain:
s.app.InitChain(*r.InitChain) res := s.app.InitChain(*r.InitChain)
responses <- types.ToResponseInitChain() responses <- types.ToResponseInitChain(res)
case *types.Request_BeginBlock: case *types.Request_BeginBlock:
s.app.BeginBlock(*r.BeginBlock) res := s.app.BeginBlock(*r.BeginBlock)
responses <- types.ToResponseBeginBlock() responses <- types.ToResponseBeginBlock(res)
case *types.Request_EndBlock: case *types.Request_EndBlock:
resEndBlock := s.app.EndBlock(r.EndBlock.Height) res := s.app.EndBlock(*r.EndBlock)
responses <- types.ToResponseEndBlock(resEndBlock) responses <- types.ToResponseEndBlock(res)
default: default:
responses <- types.ToResponseException("Unknown request") responses <- types.ToResponseException("Unknown request")
} }

19
test.sh Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -e
echo "" > coverage.txt
echo "==> Running unit tests"
for d in $(go list ./... | grep -v vendor); do
go test -race -coverprofile=profile.out -covermode=atomic "$d"
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done
echo "==> Running integration tests (./tests)"
find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \;
# tests/test.sh requires that we run the installed cmds, must not be out of date
make install
bash tests/test.sh

View File

@ -23,7 +23,7 @@ func startApp(abciApp string) *process.Process {
os.Stdout, os.Stdout,
) )
if err != nil { if err != nil {
panic("running abci_app: " + err.Error()) panicf("running abci_app: %v", err)
} }
// TODO a better way to handle this? // TODO a better way to handle this?
@ -41,57 +41,63 @@ func startClient(abciType string) abcicli.Client {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
client.SetLogger(logger.With("module", "abcicli")) client.SetLogger(logger.With("module", "abcicli"))
if _, err := client.Start(); err != nil { if _, err := client.Start(); err != nil {
panic("connecting to abci_app: " + err.Error()) panicf("connecting to abci_app: %v", err.Error())
} }
return client return client
} }
func setOption(client abcicli.Client, key, value string) { func setOption(client abcicli.Client, key, value string) {
res := client.SetOptionSync(key, value) _, err := client.SetOptionSync(types.RequestSetOption{key, value})
_, _, log := res.Code, res.Data, res.Log if err != nil {
if res.IsErr() { panicf("setting %v=%v: \nerr: %v", key, value, err)
panic(fmt.Sprintf("setting %v=%v: \nlog: %v", key, value, log))
} }
} }
func commit(client abcicli.Client, hashExp []byte) { func commit(client abcicli.Client, hashExp []byte) {
res := client.CommitSync() res, err := client.CommitSync()
_, data, _ := res.Code, res.Data, res.Log if err != nil {
panicf("client error: %v", err)
}
if res.IsErr() { if res.IsErr() {
panic(fmt.Sprintf("committing err %v\n", res)) panicf("committing err %v\n", res)
} }
if !bytes.Equal(res.Data, hashExp) { if !bytes.Equal(res.Data, hashExp) {
panic(fmt.Sprintf("Commit hash was unexpected. Got %X expected %X", panicf("Commit hash was unexpected. Got %X expected %X", res.Data, hashExp)
data, hashExp))
} }
} }
func deliverTx(client abcicli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) { func deliverTx(client abcicli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) {
res := client.DeliverTxSync(txBytes) res, err := client.DeliverTxSync(txBytes)
code, data, log := res.Code, res.Data, res.Log if err != nil {
if code != codeExp { panicf("client error: %v", err)
panic(fmt.Sprintf("DeliverTx response code was unexpected. Got %v expected %v. Log: %v",
code, codeExp, log))
} }
if !bytes.Equal(data, dataExp) { if res.Code != codeExp {
panic(fmt.Sprintf("DeliverTx response data was unexpected. Got %X expected %X", panicf("DeliverTx response code was unexpected. Got %v expected %v. Log: %v", res.Code, codeExp, res.Log)
data, dataExp)) }
if !bytes.Equal(res.Data, dataExp) {
panicf("DeliverTx response data was unexpected. Got %X expected %X", res.Data, dataExp)
} }
} }
/*func checkTx(client abcicli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) { /*func checkTx(client abcicli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) {
res := client.CheckTxSync(txBytes) res, err := client.CheckTxSync(txBytes)
code, data, log := res.Code, res.Data, res.Log if err != nil {
panicf("client error: %v", err)
}
if res.IsErr() { if res.IsErr() {
panic(fmt.Sprintf("checking tx %X: %v\nlog: %v", txBytes, log)) panicf("checking tx %X: %v\nlog: %v", txBytes, res.Log)
} }
if code != codeExp { if res.Code != codeExp {
panic(fmt.Sprintf("CheckTx response code was unexpected. Got %v expected %v. Log: %v", panicf("CheckTx response code was unexpected. Got %v expected %v. Log: %v",
code, codeExp, log)) res.Code, codeExp, res.Log)
} }
if !bytes.Equal(data, dataExp) { if !bytes.Equal(res.Data, dataExp) {
panic(fmt.Sprintf("CheckTx response data was unexpected. Got %X expected %X", panicf("CheckTx response data was unexpected. Got %X expected %X",
data, dataExp)) res.Data, dataExp)
} }
}*/ }*/
func panicf(format string, a ...interface{}) {
panic(fmt.Sprintf(format, a...))
}

View File

@ -5,22 +5,24 @@ import (
) )
// Application is an interface that enables any finite, deterministic state machine // Application is an interface that enables any finite, deterministic state machine
// to be driven by a blockchain-based replication engine via the ABCI // to be driven by a blockchain-based replication engine via the ABCI.
// All methods take a RequestXxx argument and return a ResponseXxx argument,
// except CheckTx/DeliverTx, which take `tx []byte`, and `Commit`, which takes nothing.
type Application interface { type Application interface {
// Info/Query Connection // Info/Query Connection
Info(RequestInfo) ResponseInfo // Return application info Info(RequestInfo) ResponseInfo // Return application info
SetOption(key string, value string) (log string) // Set application option SetOption(RequestSetOption) ResponseSetOption // Set application option
Query(RequestQuery) ResponseQuery // Query for state Query(RequestQuery) ResponseQuery // Query for state
// Mempool Connection // Mempool Connection
CheckTx(tx []byte) Result // Validate a tx for the mempool CheckTx(tx []byte) ResponseCheckTx // Validate a tx for the mempool
// Consensus Connection // Consensus Connection
InitChain(RequestInitChain) // Initialize blockchain with validators and other info from TendermintCore InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain with validators and other info from TendermintCore
BeginBlock(RequestBeginBlock) // Signals the beginning of a block BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block
DeliverTx(tx []byte) Result // Deliver a tx for full processing DeliverTx(tx []byte) ResponseDeliverTx // Deliver a tx for full processing
EndBlock(height uint64) ResponseEndBlock // Signals the end of a block, returns changes to the validator set EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set
Commit() Result // Commit the state and return the application Merkle root hash Commit() ResponseCommit // Commit the state and return the application Merkle root hash
} }
//------------------------------------ //------------------------------------
@ -43,45 +45,46 @@ func (app *GRPCApplication) Flush(ctx context.Context, req *RequestFlush) (*Resp
} }
func (app *GRPCApplication) Info(ctx context.Context, req *RequestInfo) (*ResponseInfo, error) { func (app *GRPCApplication) Info(ctx context.Context, req *RequestInfo) (*ResponseInfo, error) {
resInfo := app.app.Info(*req) res := app.app.Info(*req)
return &resInfo, nil return &res, nil
} }
func (app *GRPCApplication) SetOption(ctx context.Context, req *RequestSetOption) (*ResponseSetOption, error) { func (app *GRPCApplication) SetOption(ctx context.Context, req *RequestSetOption) (*ResponseSetOption, error) {
return &ResponseSetOption{app.app.SetOption(req.Key, req.Value)}, nil res := app.app.SetOption(*req)
return &res, nil
} }
func (app *GRPCApplication) DeliverTx(ctx context.Context, req *RequestDeliverTx) (*ResponseDeliverTx, error) { func (app *GRPCApplication) DeliverTx(ctx context.Context, req *RequestDeliverTx) (*ResponseDeliverTx, error) {
r := app.app.DeliverTx(req.Tx) res := app.app.DeliverTx(req.Tx)
return &ResponseDeliverTx{r.Code, r.Data, r.Log}, nil return &res, nil
} }
func (app *GRPCApplication) CheckTx(ctx context.Context, req *RequestCheckTx) (*ResponseCheckTx, error) { func (app *GRPCApplication) CheckTx(ctx context.Context, req *RequestCheckTx) (*ResponseCheckTx, error) {
r := app.app.CheckTx(req.Tx) res := app.app.CheckTx(req.Tx)
return &ResponseCheckTx{r.Code, r.Data, r.Log}, nil return &res, nil
} }
func (app *GRPCApplication) Query(ctx context.Context, req *RequestQuery) (*ResponseQuery, error) { func (app *GRPCApplication) Query(ctx context.Context, req *RequestQuery) (*ResponseQuery, error) {
resQuery := app.app.Query(*req) res := app.app.Query(*req)
return &resQuery, nil return &res, nil
} }
func (app *GRPCApplication) Commit(ctx context.Context, req *RequestCommit) (*ResponseCommit, error) { func (app *GRPCApplication) Commit(ctx context.Context, req *RequestCommit) (*ResponseCommit, error) {
r := app.app.Commit() res := app.app.Commit()
return &ResponseCommit{r.Code, r.Data, r.Log}, nil return &res, nil
} }
func (app *GRPCApplication) InitChain(ctx context.Context, req *RequestInitChain) (*ResponseInitChain, error) { func (app *GRPCApplication) InitChain(ctx context.Context, req *RequestInitChain) (*ResponseInitChain, error) {
app.app.InitChain(*req) res := app.app.InitChain(*req)
return &ResponseInitChain{}, nil // NOTE: empty return return &res, nil
} }
func (app *GRPCApplication) BeginBlock(ctx context.Context, req *RequestBeginBlock) (*ResponseBeginBlock, error) { func (app *GRPCApplication) BeginBlock(ctx context.Context, req *RequestBeginBlock) (*ResponseBeginBlock, error) {
app.app.BeginBlock(*req) res := app.app.BeginBlock(*req)
return &ResponseBeginBlock{}, nil // NOTE: empty return return &res, nil
} }
func (app *GRPCApplication) EndBlock(ctx context.Context, req *RequestEndBlock) (*ResponseEndBlock, error) { func (app *GRPCApplication) EndBlock(ctx context.Context, req *RequestEndBlock) (*ResponseEndBlock, error) {
resEndBlock := app.app.EndBlock(req.Height) res := app.app.EndBlock(*req)
return &resEndBlock, nil return &res, nil
} }

View File

@ -7,36 +7,38 @@ func NewBaseApplication() *BaseApplication {
return &BaseApplication{} return &BaseApplication{}
} }
func (app *BaseApplication) Info(req RequestInfo) (resInfo ResponseInfo) { func (BaseApplication) Info(req RequestInfo) ResponseInfo {
return return ResponseInfo{}
} }
func (app *BaseApplication) SetOption(key string, value string) (log string) { func (BaseApplication) SetOption(req RequestSetOption) ResponseSetOption {
return "" return ResponseSetOption{}
} }
func (app *BaseApplication) DeliverTx(tx []byte) Result { func (BaseApplication) DeliverTx(tx []byte) ResponseDeliverTx {
return NewResultOK(nil, "") return ResponseDeliverTx{Code: CodeType_OK}
} }
func (app *BaseApplication) CheckTx(tx []byte) Result { func (BaseApplication) CheckTx(tx []byte) ResponseCheckTx {
return NewResultOK(nil, "") return ResponseCheckTx{Code: CodeType_OK}
} }
func (app *BaseApplication) Commit() Result { func (BaseApplication) Commit() ResponseCommit {
return NewResultOK([]byte("nil"), "") return ResponseCommit{Code: CodeType_OK, Data: []byte("nil")}
} }
func (app *BaseApplication) Query(req RequestQuery) (resQuery ResponseQuery) { func (BaseApplication) Query(req RequestQuery) ResponseQuery {
return return ResponseQuery{Code: CodeType_OK}
} }
func (app *BaseApplication) InitChain(req RequestInitChain) { func (BaseApplication) InitChain(req RequestInitChain) ResponseInitChain {
return ResponseInitChain{}
} }
func (app *BaseApplication) BeginBlock(req RequestBeginBlock) { func (BaseApplication) BeginBlock(req RequestBeginBlock) ResponseBeginBlock {
return ResponseBeginBlock{}
} }
func (app *BaseApplication) EndBlock(height uint64) (resEndBlock ResponseEndBlock) { func (BaseApplication) EndBlock(req RequestEndBlock) ResponseEndBlock {
return return ResponseEndBlock{}
} }

View File

@ -1,3 +1,37 @@
package types package types
var (
code2string = map[CodeType]string{
CodeType_InternalError: "Internal error",
CodeType_EncodingError: "Encoding error",
CodeType_BadNonce: "Error bad nonce",
CodeType_Unauthorized: "Unauthorized",
CodeType_InsufficientFunds: "Insufficient funds",
CodeType_UnknownRequest: "Unknown request",
CodeType_BaseDuplicateAddress: "Error (base) duplicate address",
CodeType_BaseEncodingError: "Error (base) encoding error",
CodeType_BaseInsufficientFees: "Error (base) insufficient fees",
CodeType_BaseInsufficientFunds: "Error (base) insufficient funds",
CodeType_BaseInsufficientGasPrice: "Error (base) insufficient gas price",
CodeType_BaseInvalidInput: "Error (base) invalid input",
CodeType_BaseInvalidOutput: "Error (base) invalid output",
CodeType_BaseInvalidPubKey: "Error (base) invalid pubkey",
CodeType_BaseInvalidSequence: "Error (base) invalid sequence",
CodeType_BaseInvalidSignature: "Error (base) invalid signature",
CodeType_BaseUnknownAddress: "Error (base) unknown address",
CodeType_BaseUnknownPlugin: "Error (base) unknown plugin",
CodeType_BaseUnknownPubKey: "Error (base) unknown pubkey",
}
)
func (c CodeType) IsOK() bool { return c == CodeType_OK } func (c CodeType) IsOK() bool { return c == CodeType_OK }
// HumanCode transforms code into a more humane format, such as "Internal error" instead of 0.
func HumanCode(code CodeType) string {
s, ok := code2string[code]
if !ok {
return "Unknown code"
}
return s
}

12
types/code_test.go Normal file
View File

@ -0,0 +1,12 @@
package types
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestHumanCode(t *testing.T) {
assert.Equal(t, "Internal error", HumanCode(CodeType_InternalError))
assert.Equal(t, "Unknown code", HumanCode(-1))
}

View File

@ -1,26 +0,0 @@
package types
var (
OK = NewResultOK(nil, "")
ErrInternalError = NewError(CodeType_InternalError, "Internal error")
ErrEncodingError = NewError(CodeType_EncodingError, "Encoding error")
ErrBadNonce = NewError(CodeType_BadNonce, "Error bad nonce")
ErrUnauthorized = NewError(CodeType_Unauthorized, "Unauthorized")
ErrInsufficientFunds = NewError(CodeType_InsufficientFunds, "Insufficient funds")
ErrUnknownRequest = NewError(CodeType_UnknownRequest, "Unknown request")
ErrBaseDuplicateAddress = NewError(CodeType_BaseDuplicateAddress, "Error (base) duplicate address")
ErrBaseEncodingError = NewError(CodeType_BaseEncodingError, "Error (base) encoding error")
ErrBaseInsufficientFees = NewError(CodeType_BaseInsufficientFees, "Error (base) insufficient fees")
ErrBaseInsufficientFunds = NewError(CodeType_BaseInsufficientFunds, "Error (base) insufficient funds")
ErrBaseInsufficientGasPrice = NewError(CodeType_BaseInsufficientGasPrice, "Error (base) insufficient gas price")
ErrBaseInvalidInput = NewError(CodeType_BaseInvalidInput, "Error (base) invalid input")
ErrBaseInvalidOutput = NewError(CodeType_BaseInvalidOutput, "Error (base) invalid output")
ErrBaseInvalidPubKey = NewError(CodeType_BaseInvalidPubKey, "Error (base) invalid pubkey")
ErrBaseInvalidSequence = NewError(CodeType_BaseInvalidSequence, "Error (base) invalid sequence")
ErrBaseInvalidSignature = NewError(CodeType_BaseInvalidSignature, "Error (base) invalid signature")
ErrBaseUnknownAddress = NewError(CodeType_BaseUnknownAddress, "Error (base) unknown address")
ErrBaseUnknownPlugin = NewError(CodeType_BaseUnknownPlugin, "Error (base) unknown plugin")
ErrBaseUnknownPubKey = NewError(CodeType_BaseUnknownPubKey, "Error (base) unknown pubkey")
)

View File

@ -4,7 +4,7 @@ import (
"io" "io"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/tendermint/go-wire" wire "github.com/tendermint/go-wire"
) )
func ToRequestEcho(message string) *Request { func ToRequestEcho(message string) *Request {
@ -25,21 +25,21 @@ func ToRequestInfo(req RequestInfo) *Request {
} }
} }
func ToRequestSetOption(key string, value string) *Request { func ToRequestSetOption(req RequestSetOption) *Request {
return &Request{ return &Request{
Value: &Request_SetOption{&RequestSetOption{key, value}}, Value: &Request_SetOption{&req},
} }
} }
func ToRequestDeliverTx(txBytes []byte) *Request { func ToRequestDeliverTx(tx []byte) *Request {
return &Request{ return &Request{
Value: &Request_DeliverTx{&RequestDeliverTx{txBytes}}, Value: &Request_DeliverTx{&RequestDeliverTx{tx}},
} }
} }
func ToRequestCheckTx(txBytes []byte) *Request { func ToRequestCheckTx(tx []byte) *Request {
return &Request{ return &Request{
Value: &Request_CheckTx{&RequestCheckTx{txBytes}}, Value: &Request_CheckTx{&RequestCheckTx{tx}},
} }
} }
@ -67,9 +67,9 @@ func ToRequestBeginBlock(req RequestBeginBlock) *Request {
} }
} }
func ToRequestEndBlock(height uint64) *Request { func ToRequestEndBlock(req RequestEndBlock) *Request {
return &Request{ return &Request{
Value: &Request_EndBlock{&RequestEndBlock{height}}, Value: &Request_EndBlock{&req},
} }
} }
@ -93,57 +93,57 @@ func ToResponseFlush() *Response {
} }
} }
func ToResponseInfo(resInfo ResponseInfo) *Response { func ToResponseInfo(res ResponseInfo) *Response {
return &Response{ return &Response{
Value: &Response_Info{&resInfo}, Value: &Response_Info{&res},
} }
} }
func ToResponseSetOption(log string) *Response { func ToResponseSetOption(res ResponseSetOption) *Response {
return &Response{ return &Response{
Value: &Response_SetOption{&ResponseSetOption{log}}, Value: &Response_SetOption{&res},
} }
} }
func ToResponseDeliverTx(code CodeType, data []byte, log string) *Response { func ToResponseDeliverTx(res ResponseDeliverTx) *Response {
return &Response{ return &Response{
Value: &Response_DeliverTx{&ResponseDeliverTx{code, data, log}}, Value: &Response_DeliverTx{&res},
} }
} }
func ToResponseCheckTx(code CodeType, data []byte, log string) *Response { func ToResponseCheckTx(res ResponseCheckTx) *Response {
return &Response{ return &Response{
Value: &Response_CheckTx{&ResponseCheckTx{code, data, log}}, Value: &Response_CheckTx{&res},
} }
} }
func ToResponseCommit(code CodeType, data []byte, log string) *Response { func ToResponseCommit(res ResponseCommit) *Response {
return &Response{ return &Response{
Value: &Response_Commit{&ResponseCommit{code, data, log}}, Value: &Response_Commit{&res},
} }
} }
func ToResponseQuery(resQuery ResponseQuery) *Response { func ToResponseQuery(res ResponseQuery) *Response {
return &Response{ return &Response{
Value: &Response_Query{&resQuery}, Value: &Response_Query{&res},
} }
} }
func ToResponseInitChain() *Response { func ToResponseInitChain(res ResponseInitChain) *Response {
return &Response{ return &Response{
Value: &Response_InitChain{&ResponseInitChain{}}, Value: &Response_InitChain{&res},
} }
} }
func ToResponseBeginBlock() *Response { func ToResponseBeginBlock(res ResponseBeginBlock) *Response {
return &Response{ return &Response{
Value: &Response_BeginBlock{&ResponseBeginBlock{}}, Value: &Response_BeginBlock{&res},
} }
} }
func ToResponseEndBlock(resEndBlock ResponseEndBlock) *Response { func ToResponseEndBlock(res ResponseEndBlock) *Response {
return &Response{ return &Response{
Value: &Response_EndBlock{&resEndBlock}, Value: &Response_EndBlock{&res},
} }
} }

View File

@ -6,114 +6,47 @@ import (
"github.com/tendermint/go-wire/data" "github.com/tendermint/go-wire/data"
) )
// Result is a common result object for ABCI calls. // IsErr returns true if Code is something other than OK.
// CONTRACT: a zero Result is OK. func (r ResponseCheckTx) IsErr() bool {
type Result struct { return r.Code != CodeType_OK
Code CodeType `json:"code"`
Data data.Bytes `json:"data"`
Log string `json:"log"` // Can be non-deterministic
} }
func NewResult(code CodeType, data []byte, log string) Result { // Error implements error interface by formatting response as string.
return Result{ func (r ResponseCheckTx) Error() string {
Code: code, return fmtError(r.Code, r.Log)
Data: data, }
Log: log,
} // IsErr returns true if Code is something other than OK.
} func (r ResponseDeliverTx) IsErr() bool {
return r.Code != CodeType_OK
func (res Result) IsOK() bool { }
return res.Code == CodeType_OK
} // Error implements error interface by formatting response as string.
func (r ResponseDeliverTx) Error() string {
func (res Result) IsErr() bool { return fmtError(r.Code, r.Log)
return res.Code != CodeType_OK }
}
// IsErr returns true if Code is something other than OK.
func (res Result) IsSameCode(compare Result) bool { func (r ResponseCommit) IsErr() bool {
return res.Code == compare.Code return r.Code != CodeType_OK
} }
func (res Result) Error() string { // Error implements error interface by formatting response as string.
return fmt.Sprintf("ABCI{code:%v, data:%X, log:%v}", res.Code, res.Data, res.Log) func (r ResponseCommit) Error() string {
} return fmtError(r.Code, r.Log)
}
func (res Result) String() string {
return fmt.Sprintf("ABCI{code:%v, data:%X, log:%v}", res.Code, res.Data, res.Log) func fmtError(code CodeType, log string) string {
} codeAsStr, ok := code2string[code]
if ok {
func (res Result) PrependLog(log string) Result { return fmt.Sprintf("%s (%d): %s", codeAsStr, code, log)
return Result{ } else {
Code: res.Code, return fmt.Sprintf("Unknown error (%d): %s", code, log)
Data: res.Data,
Log: log + ";" + res.Log,
}
}
func (res Result) AppendLog(log string) Result {
return Result{
Code: res.Code,
Data: res.Data,
Log: res.Log + ";" + log,
}
}
func (res Result) SetLog(log string) Result {
return Result{
Code: res.Code,
Data: res.Data,
Log: log,
}
}
func (res Result) SetData(data []byte) Result {
return Result{
Code: res.Code,
Data: data,
Log: res.Log,
}
}
//----------------------------------------
// NOTE: if data == nil and log == "", same as zero Result.
func NewResultOK(data []byte, log string) Result {
return Result{
Code: CodeType_OK,
Data: data,
Log: log,
}
}
func NewError(code CodeType, log string) Result {
return Result{
Code: code,
Log: log,
}
}
//----------------------------------------
// Convenience methods for turning the
// pb type into one using data.Bytes
// Convert ResponseCheckTx to standard Result
func (r *ResponseCheckTx) Result() Result {
return Result{
Code: r.Code,
Data: r.Data,
Log: r.Log,
}
}
// Convert ResponseDeliverTx to standard Result
func (r *ResponseDeliverTx) Result() Result {
return Result{
Code: r.Code,
Data: r.Data,
Log: r.Log,
} }
} }
// ResultQuery is a wrapper around ResponseQuery using data.Bytes instead of
// raw byte slices.
type ResultQuery struct { type ResultQuery struct {
Code CodeType `json:"code"` Code CodeType `json:"code"`
Index int64 `json:"index"` Index int64 `json:"index"`
@ -124,6 +57,7 @@ type ResultQuery struct {
Log string `json:"log"` Log string `json:"log"`
} }
// Result converts response query to ResultQuery.
func (r *ResponseQuery) Result() *ResultQuery { func (r *ResponseQuery) Result() *ResultQuery {
return &ResultQuery{ return &ResultQuery{
Code: r.Code, Code: r.Code,
@ -135,3 +69,13 @@ func (r *ResponseQuery) Result() *ResultQuery {
Log: r.Log, Log: r.Log,
} }
} }
// IsErr returns true if Code is something other than OK.
func (r *ResultQuery) IsErr() bool {
return r.Code != CodeType_OK
}
// Error implements error interface by formatting result as string.
func (r *ResultQuery) Error() string {
return fmtError(r.Code, r.Log)
}

76
types/result_test.go Normal file
View File

@ -0,0 +1,76 @@
package types
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestResultQuery(t *testing.T) {
orig := &ResponseQuery{
Code: CodeType_OK,
Index: 0,
Key: []byte("hello"),
Value: []byte("world"),
Height: 1,
}
res := orig.Result()
assert.False(t, res.IsErr())
orig = &ResponseQuery{
Code: CodeType_BadNonce,
Index: 0,
Key: []byte("hello"),
Value: []byte("world"),
Height: 1,
Log: "bad",
}
res = orig.Result()
assert.True(t, res.IsErr())
assert.Equal(t, "Error bad nonce (3): bad", res.Error())
}
func TestResponseDeliverTx(t *testing.T) {
res := ResponseDeliverTx{
Code: CodeType_OK,
Data: []byte("Victor Mancha"),
}
assert.False(t, res.IsErr())
res = ResponseDeliverTx{
Code: CodeType_InternalError,
Log: "bad",
}
assert.True(t, res.IsErr())
assert.Equal(t, "Internal error (1): bad", res.Error())
}
func TestResponseCheckTx(t *testing.T) {
res := ResponseCheckTx{
Code: CodeType_OK,
Data: []byte("Talos"),
}
assert.False(t, res.IsErr())
res = ResponseCheckTx{
Code: CodeType_InternalError,
Log: "bad",
}
assert.True(t, res.IsErr())
assert.Equal(t, "Internal error (1): bad", res.Error())
}
func TestResponseCommit(t *testing.T) {
res := ResponseCommit{
Code: CodeType_OK,
Data: []byte("Old Lace"),
}
assert.False(t, res.IsErr())
res = ResponseCommit{
Code: CodeType_Unauthorized,
Log: "bad",
}
assert.True(t, res.IsErr())
assert.Equal(t, "Unauthorized (4): bad", res.Error())
}

View File

@ -38,7 +38,9 @@ It has these top-level messages:
BlockID BlockID
PartSetHeader PartSetHeader
Validator Validator
KVPair
*/ */
//nolint: gas
package types package types
import proto "github.com/golang/protobuf/proto" import proto "github.com/golang/protobuf/proto"
@ -169,6 +171,27 @@ func (x CodeType) String() string {
} }
func (CodeType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (CodeType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type KVPair_Type int32
const (
KVPair_STRING KVPair_Type = 0
KVPair_INT KVPair_Type = 1
)
var KVPair_Type_name = map[int32]string{
0: "STRING",
1: "INT",
}
var KVPair_Type_value = map[string]int32{
"STRING": 0,
"INT": 1,
}
func (x KVPair_Type) String() string {
return proto.EnumName(KVPair_Type_name, int32(x))
}
func (KVPair_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{29, 0} }
type Request struct { type Request struct {
// Types that are valid to be assigned to Value: // Types that are valid to be assigned to Value:
// *Request_Echo // *Request_Echo
@ -1297,9 +1320,10 @@ func (m *ResponseSetOption) GetLog() string {
} }
type ResponseDeliverTx struct { type ResponseDeliverTx struct {
Code CodeType `protobuf:"varint,1,opt,name=code,enum=types.CodeType" json:"code,omitempty"` Code CodeType `protobuf:"varint,1,opt,name=code,enum=types.CodeType" json:"code,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
Log string `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"` Log string `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"`
Tags []*KVPair `protobuf:"bytes,4,rep,name=tags" json:"tags,omitempty"`
} }
func (m *ResponseDeliverTx) Reset() { *m = ResponseDeliverTx{} } func (m *ResponseDeliverTx) Reset() { *m = ResponseDeliverTx{} }
@ -1328,10 +1352,19 @@ func (m *ResponseDeliverTx) GetLog() string {
return "" return ""
} }
func (m *ResponseDeliverTx) GetTags() []*KVPair {
if m != nil {
return m.Tags
}
return nil
}
type ResponseCheckTx struct { type ResponseCheckTx struct {
Code CodeType `protobuf:"varint,1,opt,name=code,enum=types.CodeType" json:"code,omitempty"` Code CodeType `protobuf:"varint,1,opt,name=code,enum=types.CodeType" json:"code,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
Log string `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"` Log string `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"`
Gas uint64 `protobuf:"varint,4,opt,name=gas" json:"gas,omitempty"`
Fee uint64 `protobuf:"varint,5,opt,name=fee" json:"fee,omitempty"`
} }
func (m *ResponseCheckTx) Reset() { *m = ResponseCheckTx{} } func (m *ResponseCheckTx) Reset() { *m = ResponseCheckTx{} }
@ -1360,6 +1393,20 @@ func (m *ResponseCheckTx) GetLog() string {
return "" return ""
} }
func (m *ResponseCheckTx) GetGas() uint64 {
if m != nil {
return m.Gas
}
return 0
}
func (m *ResponseCheckTx) GetFee() uint64 {
if m != nil {
return m.Fee
}
return 0
}
type ResponseQuery struct { type ResponseQuery struct {
Code CodeType `protobuf:"varint,1,opt,name=code,enum=types.CodeType" json:"code,omitempty"` Code CodeType `protobuf:"varint,1,opt,name=code,enum=types.CodeType" json:"code,omitempty"`
Index int64 `protobuf:"varint,2,opt,name=index" json:"index,omitempty"` Index int64 `protobuf:"varint,2,opt,name=index" json:"index,omitempty"`
@ -1640,6 +1687,46 @@ func (m *Validator) GetPower() uint64 {
return 0 return 0
} }
type KVPair struct {
Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
ValueType KVPair_Type `protobuf:"varint,2,opt,name=value_type,json=valueType,enum=types.KVPair_Type" json:"value_type,omitempty"`
ValueString string `protobuf:"bytes,3,opt,name=value_string,json=valueString" json:"value_string,omitempty"`
ValueInt int64 `protobuf:"varint,4,opt,name=value_int,json=valueInt" json:"value_int,omitempty"`
}
func (m *KVPair) Reset() { *m = KVPair{} }
func (m *KVPair) String() string { return proto.CompactTextString(m) }
func (*KVPair) ProtoMessage() {}
func (*KVPair) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} }
func (m *KVPair) GetKey() string {
if m != nil {
return m.Key
}
return ""
}
func (m *KVPair) GetValueType() KVPair_Type {
if m != nil {
return m.ValueType
}
return KVPair_STRING
}
func (m *KVPair) GetValueString() string {
if m != nil {
return m.ValueString
}
return ""
}
func (m *KVPair) GetValueInt() int64 {
if m != nil {
return m.ValueInt
}
return 0
}
func init() { func init() {
proto.RegisterType((*Request)(nil), "types.Request") proto.RegisterType((*Request)(nil), "types.Request")
proto.RegisterType((*RequestEcho)(nil), "types.RequestEcho") proto.RegisterType((*RequestEcho)(nil), "types.RequestEcho")
@ -1670,7 +1757,9 @@ func init() {
proto.RegisterType((*BlockID)(nil), "types.BlockID") proto.RegisterType((*BlockID)(nil), "types.BlockID")
proto.RegisterType((*PartSetHeader)(nil), "types.PartSetHeader") proto.RegisterType((*PartSetHeader)(nil), "types.PartSetHeader")
proto.RegisterType((*Validator)(nil), "types.Validator") proto.RegisterType((*Validator)(nil), "types.Validator")
proto.RegisterType((*KVPair)(nil), "types.KVPair")
proto.RegisterEnum("types.CodeType", CodeType_name, CodeType_value) proto.RegisterEnum("types.CodeType", CodeType_name, CodeType_value)
proto.RegisterEnum("types.KVPair_Type", KVPair_Type_name, KVPair_Type_value)
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -2078,107 +2167,115 @@ var _ABCIApplication_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("types/types.proto", fileDescriptor0) } func init() { proto.RegisterFile("types/types.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 1625 bytes of a gzipped FileDescriptorProto // 1755 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x59, 0x6f, 0xdb, 0xc6, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x49, 0x6f, 0xdb, 0xce,
0x16, 0x36, 0xb5, 0xeb, 0xd8, 0x96, 0xe9, 0xb1, 0x6c, 0xcb, 0xba, 0xf7, 0x21, 0xe0, 0x45, 0x6e, 0x15, 0x37, 0x25, 0x6a, 0x7b, 0x96, 0x65, 0x7a, 0x2c, 0xdb, 0xb2, 0xd2, 0x43, 0xc2, 0x22, 0x8d,
0xec, 0xdc, 0xdc, 0xa4, 0x70, 0x90, 0x22, 0x6e, 0x8a, 0x02, 0xde, 0x62, 0x0b, 0x41, 0x13, 0x97, 0x9d, 0xa6, 0x4e, 0xeb, 0x20, 0x45, 0xdc, 0x14, 0x05, 0xbc, 0xc5, 0x16, 0x82, 0x3a, 0x2e, 0xed,
0x59, 0x5e, 0x5a, 0x54, 0xa0, 0xc9, 0x91, 0xc4, 0x5a, 0x9a, 0x61, 0xc8, 0xa1, 0x23, 0xf7, 0x37, 0xe4, 0xd2, 0x83, 0x40, 0x8b, 0x23, 0x69, 0x6a, 0x69, 0xc8, 0x90, 0x43, 0x47, 0xee, 0xa9, 0xbd,
0xe4, 0xbd, 0x3f, 0xa1, 0xef, 0x05, 0xfa, 0x17, 0x0a, 0x74, 0x5f, 0x7e, 0x51, 0x31, 0x0b, 0x57, 0xe7, 0xde, 0x8f, 0x50, 0xa0, 0xc7, 0x02, 0xfd, 0x0a, 0x05, 0xfe, 0xfb, 0xf2, 0x89, 0xfe, 0x98,
0x93, 0x41, 0x1f, 0xf2, 0x22, 0xf0, 0x6c, 0x33, 0x73, 0xce, 0x9c, 0xf3, 0x9d, 0x33, 0x82, 0x55, 0x85, 0xab, 0xa9, 0xe0, 0x7f, 0xc8, 0x85, 0x98, 0xb7, 0xcd, 0xbc, 0x99, 0x79, 0xef, 0xf7, 0x1e,
0x76, 0xe5, 0xe1, 0xe0, 0x9e, 0xf8, 0xbd, 0xeb, 0xf9, 0x94, 0x51, 0x54, 0x17, 0x84, 0xf1, 0x43, 0x07, 0x56, 0xd8, 0xad, 0x87, 0x83, 0xa7, 0xe2, 0xbb, 0xe3, 0xf9, 0x2e, 0x73, 0x51, 0x45, 0x10,
0x0d, 0x9a, 0x26, 0x7e, 0x1d, 0xe2, 0x80, 0xa1, 0x6d, 0xa8, 0x61, 0x7b, 0x42, 0x7b, 0xda, 0x0d, 0xe6, 0xff, 0x75, 0xa8, 0x59, 0xf8, 0x7d, 0x88, 0x03, 0x86, 0xb6, 0x40, 0xc7, 0x83, 0xb1, 0xdb,
0x6d, 0x7b, 0x71, 0x17, 0xdd, 0x95, 0xea, 0x4a, 0x7a, 0x6c, 0x4f, 0xe8, 0xe9, 0x82, 0x29, 0x34, 0xd1, 0xee, 0x6b, 0x5b, 0x8b, 0xbb, 0x68, 0x47, 0xaa, 0x2b, 0xe9, 0xf1, 0x60, 0xec, 0x9e, 0x2e,
0xd0, 0xff, 0xa0, 0x3e, 0x9a, 0x86, 0xc1, 0xa4, 0x57, 0x11, 0xaa, 0x6b, 0x59, 0xd5, 0xc7, 0x5c, 0x58, 0x42, 0x03, 0xfd, 0x1a, 0x2a, 0xc3, 0x49, 0x18, 0x8c, 0x3b, 0x25, 0xa1, 0xba, 0x9a, 0x55,
0x74, 0xba, 0x60, 0x4a, 0x1d, 0xbe, 0xac, 0x4b, 0x46, 0xb4, 0x57, 0x2d, 0x5a, 0x76, 0x40, 0x46, 0x7d, 0xc5, 0x45, 0xa7, 0x0b, 0x96, 0xd4, 0xe1, 0xd3, 0x12, 0x3a, 0x74, 0x3b, 0xe5, 0xa2, 0x69,
0x62, 0x59, 0xae, 0x81, 0x1e, 0x02, 0x04, 0x98, 0x0d, 0xa9, 0xc7, 0x5c, 0x4a, 0x7a, 0x35, 0xa1, 0x7b, 0x74, 0x28, 0xa6, 0xe5, 0x1a, 0xe8, 0x05, 0x40, 0x80, 0x59, 0xdf, 0xf5, 0x18, 0x71, 0x69,
0xbf, 0x99, 0xd5, 0x7f, 0x8e, 0xd9, 0x33, 0x21, 0x3e, 0x5d, 0x30, 0xdb, 0x41, 0x44, 0x70, 0x4b, 0x47, 0x17, 0xfa, 0x1b, 0x59, 0xfd, 0x0b, 0xcc, 0xde, 0x08, 0xf1, 0xe9, 0x82, 0xd5, 0x08, 0x22,
0x07, 0x4f, 0xdd, 0x4b, 0xec, 0x0f, 0xd9, 0xbc, 0x57, 0x2f, 0xb2, 0x3c, 0x92, 0xf2, 0x17, 0x73, 0x82, 0x5b, 0x3a, 0x78, 0x42, 0x6e, 0xb0, 0xdf, 0x67, 0xb3, 0x4e, 0xa5, 0xc8, 0xf2, 0x48, 0xca,
0x6e, 0xe9, 0x44, 0x04, 0xda, 0x85, 0x96, 0x3d, 0xc1, 0xf6, 0x05, 0xb7, 0x6b, 0x08, 0xbb, 0xf5, 0x2f, 0x67, 0xdc, 0xd2, 0x89, 0x08, 0xb4, 0x0b, 0xf5, 0xc1, 0x18, 0x0f, 0xae, 0xb9, 0x5d, 0x55,
0xac, 0xdd, 0x21, 0x97, 0x0a, 0xab, 0xa6, 0x2d, 0x3f, 0xd1, 0x5d, 0x68, 0xd8, 0x74, 0x36, 0x73, 0xd8, 0xad, 0x65, 0xed, 0x0e, 0xb9, 0x54, 0x58, 0xd5, 0x06, 0x72, 0x88, 0x76, 0xa0, 0x3a, 0x70,
0x59, 0xaf, 0x29, 0x2c, 0xba, 0x39, 0x0b, 0x21, 0x3b, 0x5d, 0x30, 0x95, 0x16, 0x0f, 0xd7, 0xeb, 0xa7, 0x53, 0xc2, 0x3a, 0x35, 0x61, 0xd1, 0xce, 0x59, 0x08, 0xd9, 0xe9, 0x82, 0xa5, 0xb4, 0xf8,
0x10, 0xfb, 0x57, 0xbd, 0x56, 0x51, 0xb8, 0x3e, 0xe3, 0x22, 0x1e, 0x2e, 0xa1, 0xc3, 0x5d, 0x71, 0x71, 0xbd, 0x0f, 0xb1, 0x7f, 0xdb, 0xa9, 0x17, 0x1d, 0xd7, 0x5f, 0xb8, 0x88, 0x1f, 0x97, 0xd0,
0x89, 0xcb, 0x86, 0xf6, 0xc4, 0x72, 0x49, 0xaf, 0x5d, 0xe4, 0xca, 0x80, 0xb8, 0xec, 0x90, 0x8b, 0xe1, 0x5b, 0x21, 0x94, 0xb0, 0xfe, 0x60, 0x6c, 0x13, 0xda, 0x69, 0x14, 0x6d, 0xa5, 0x47, 0x09,
0xb9, 0x2b, 0x6e, 0x44, 0xa0, 0x47, 0xb0, 0x78, 0x8e, 0xc7, 0x2e, 0x19, 0x9e, 0x4f, 0xa9, 0x7d, 0x3b, 0xe4, 0x62, 0xbe, 0x15, 0x12, 0x11, 0xe8, 0x25, 0x2c, 0x5e, 0xe1, 0x11, 0xa1, 0xfd, 0xab,
0xd1, 0x03, 0x61, 0xda, 0xcb, 0x9a, 0x1e, 0x70, 0x85, 0x03, 0x2e, 0x3f, 0x5d, 0x30, 0xe1, 0x3c, 0x89, 0x3b, 0xb8, 0xee, 0x80, 0x30, 0xed, 0x64, 0x4d, 0x0f, 0xb8, 0xc2, 0x01, 0x97, 0x9f, 0x2e,
0xa6, 0xd0, 0x03, 0x68, 0x63, 0xe2, 0x28, 0xd3, 0x45, 0x61, 0xba, 0x91, 0xcb, 0x00, 0xe2, 0x44, 0x58, 0x70, 0x15, 0x53, 0xe8, 0x39, 0x34, 0x30, 0x75, 0x94, 0xe9, 0xa2, 0x30, 0x5d, 0xcf, 0x45,
0x86, 0x2d, 0xac, 0xbe, 0x0f, 0x9a, 0x50, 0xbf, 0xb4, 0xa6, 0x21, 0x36, 0x6e, 0xc1, 0x62, 0x2a, 0x00, 0x75, 0x22, 0xc3, 0x3a, 0x56, 0xe3, 0x83, 0x1a, 0x54, 0x6e, 0xec, 0x49, 0x88, 0xcd, 0x47,
0x53, 0x50, 0x0f, 0x9a, 0x33, 0x1c, 0x04, 0xd6, 0x18, 0x8b, 0x74, 0x6a, 0x9b, 0x11, 0x69, 0x74, 0xb0, 0x98, 0x8a, 0x14, 0xd4, 0x81, 0xda, 0x14, 0x07, 0x81, 0x3d, 0xc2, 0x22, 0x9c, 0x1a, 0x56,
0x60, 0x29, 0x9d, 0x27, 0x29, 0x43, 0x9e, 0x0b, 0xdc, 0xf0, 0x12, 0xfb, 0x01, 0x4f, 0x00, 0x65, 0x44, 0x9a, 0x2d, 0x68, 0xa6, 0xe3, 0x24, 0x65, 0xc8, 0x63, 0x81, 0x1b, 0xde, 0x60, 0x3f, 0xe0,
0xa8, 0x48, 0xe3, 0x23, 0xd0, 0xf3, 0x49, 0x80, 0x74, 0xa8, 0x5e, 0xe0, 0x2b, 0xa5, 0xc9, 0x3f, 0x01, 0xa0, 0x0c, 0x15, 0x69, 0xfe, 0x01, 0x8c, 0x7c, 0x10, 0x20, 0x03, 0xca, 0xd7, 0xf8, 0x56,
0x51, 0x57, 0x1d, 0x48, 0xa4, 0x66, 0xdb, 0x54, 0xa7, 0x33, 0x62, 0xdb, 0x38, 0x0d, 0x50, 0x07, 0x69, 0xf2, 0x21, 0x6a, 0x2b, 0x87, 0x44, 0x68, 0x36, 0x2c, 0xe5, 0x9d, 0x19, 0xdb, 0xc6, 0x61,
0x2a, 0x6c, 0x2e, 0x4c, 0x97, 0xcc, 0x0a, 0x9b, 0x1b, 0x37, 0xa0, 0x93, 0xbd, 0xf2, 0x6b, 0x1a, 0x80, 0x5a, 0x50, 0x62, 0x33, 0x61, 0xda, 0xb4, 0x4a, 0x6c, 0x66, 0xde, 0x87, 0x56, 0xf6, 0xca,
0x4e, 0x7c, 0x74, 0x71, 0x67, 0x08, 0x41, 0xcd, 0xb1, 0x98, 0xa5, 0x34, 0xc4, 0x37, 0xe7, 0x79, 0xef, 0x68, 0x38, 0xb1, 0xeb, 0xe2, 0xce, 0x10, 0x02, 0xdd, 0xb1, 0x99, 0xad, 0x34, 0xc4, 0x98,
0x16, 0x9b, 0xa8, 0xed, 0xc5, 0x37, 0xda, 0x80, 0xc6, 0x04, 0xbb, 0xe3, 0x09, 0x13, 0x35, 0x50, 0xf3, 0x3c, 0x9b, 0x8d, 0xd5, 0xf2, 0x62, 0x8c, 0xd6, 0xa1, 0x3a, 0xc6, 0x64, 0x34, 0x66, 0x22,
0x33, 0x15, 0xc5, 0xcf, 0xea, 0xf9, 0xf4, 0x12, 0x8b, 0x54, 0x6f, 0x99, 0x92, 0x30, 0x56, 0x60, 0x07, 0x74, 0x4b, 0x51, 0xdc, 0x57, 0xcf, 0x77, 0x6f, 0xb0, 0x08, 0xf5, 0xba, 0x25, 0x09, 0x73,
0x39, 0x93, 0x48, 0xc6, 0x51, 0x7c, 0xf8, 0xf8, 0xe2, 0xd1, 0x07, 0x00, 0x97, 0xd6, 0xd4, 0x75, 0x19, 0x96, 0x32, 0x81, 0x64, 0x1e, 0xc5, 0xce, 0xc7, 0x17, 0x8f, 0x7e, 0x0b, 0x70, 0x63, 0x4f,
0x2c, 0x46, 0xfd, 0xa0, 0xa7, 0xdd, 0xa8, 0x6e, 0x2f, 0xee, 0xea, 0xea, 0xbe, 0x5e, 0x45, 0x02, 0x88, 0x63, 0x33, 0xd7, 0x0f, 0x3a, 0xda, 0xfd, 0xf2, 0xd6, 0xe2, 0xae, 0xa1, 0xee, 0xeb, 0x5d,
0x33, 0xa5, 0x63, 0x3c, 0x85, 0xd5, 0x6b, 0x39, 0xc0, 0x4f, 0x3b, 0xb1, 0x82, 0x49, 0xe4, 0x01, 0x24, 0xb0, 0x52, 0x3a, 0xe6, 0x19, 0xac, 0xdc, 0x89, 0x01, 0xee, 0xed, 0xd8, 0x0e, 0xc6, 0xd1,
0xff, 0x46, 0x37, 0xf9, 0x69, 0x2d, 0x07, 0xfb, 0xaa, 0xba, 0x97, 0xd5, 0xb2, 0xa7, 0x82, 0x69, 0x0e, 0xf8, 0x18, 0x3d, 0xe4, 0xde, 0xda, 0x0e, 0xf6, 0x55, 0x76, 0x2f, 0xa9, 0x69, 0x4f, 0x05,
0x2a, 0xa1, 0xb1, 0x03, 0x2b, 0xb9, 0xc4, 0x48, 0xf9, 0xa9, 0xa5, 0xfd, 0x34, 0xde, 0xd6, 0xa1, 0xd3, 0x52, 0x42, 0x73, 0x1b, 0x96, 0x73, 0x81, 0x91, 0xda, 0xa7, 0x96, 0xde, 0xa7, 0xf9, 0xb1,
0x65, 0xe2, 0xc0, 0xa3, 0x24, 0xc0, 0xe8, 0x21, 0xb4, 0xf1, 0xdc, 0xc6, 0xb2, 0xc6, 0xb5, 0x5c, 0x02, 0x75, 0x0b, 0x07, 0x9e, 0x4b, 0x03, 0x8c, 0x5e, 0x40, 0x03, 0xcf, 0x06, 0x58, 0xe6, 0xb8,
0x8e, 0x4a, 0x9d, 0xe3, 0x48, 0xce, 0xf3, 0x3b, 0x56, 0x46, 0x3b, 0x0a, 0x9f, 0xf2, 0xa0, 0xa3, 0x96, 0x8b, 0x51, 0xa9, 0x73, 0x1c, 0xc9, 0x79, 0x7c, 0xc7, 0xca, 0x68, 0x5b, 0xe1, 0x53, 0x1e,
0x8c, 0xd2, 0x00, 0x75, 0x27, 0x02, 0xa8, 0x6a, 0xae, 0x40, 0xa5, 0x6e, 0x0e, 0xa1, 0x76, 0x14, 0x74, 0x94, 0x51, 0x1a, 0xa0, 0x9e, 0x44, 0x00, 0x55, 0xce, 0x25, 0xa8, 0xd4, 0xcd, 0x21, 0xd4,
0x42, 0xd5, 0x0a, 0x17, 0xce, 0x40, 0xd4, 0x5e, 0x06, 0xa2, 0xea, 0x85, 0xc7, 0x2f, 0xc1, 0xa8, 0xb6, 0x42, 0x28, 0xbd, 0x70, 0xe2, 0x0c, 0x44, 0xed, 0x65, 0x20, 0xaa, 0x52, 0xe8, 0xfe, 0x1c,
0xbd, 0x0c, 0x46, 0x35, 0x0a, 0x4d, 0x4b, 0x40, 0xea, 0x7e, 0x0a, 0xa4, 0x9a, 0xb9, 0xda, 0x94, 0x8c, 0xda, 0xcb, 0x60, 0x54, 0xb5, 0xd0, 0x74, 0x0e, 0x48, 0x3d, 0x4b, 0x81, 0x54, 0x2d, 0x97,
0x86, 0x05, 0x28, 0x75, 0x2f, 0x46, 0xa9, 0x56, 0x0e, 0xd7, 0x94, 0x49, 0x1e, 0xa6, 0xee, 0x44, 0x9b, 0xd2, 0xb0, 0x00, 0xa5, 0x9e, 0xc6, 0x28, 0x55, 0xcf, 0xe1, 0x9a, 0x32, 0xc9, 0xc3, 0xd4,
0x30, 0xd5, 0x2e, 0x0c, 0x5a, 0x0e, 0xa7, 0xf6, 0x32, 0x38, 0x05, 0x85, 0xee, 0x94, 0x00, 0xd5, 0x93, 0x08, 0xa6, 0x1a, 0x85, 0x87, 0x96, 0xc3, 0xa9, 0xbd, 0x0c, 0x4e, 0x41, 0xe1, 0x76, 0xe6,
0xc7, 0x59, 0xa0, 0x92, 0x68, 0xb3, 0x95, 0xb3, 0x2d, 0x45, 0xaa, 0x0f, 0xd3, 0x48, 0xb5, 0x94, 0x00, 0xd5, 0x1f, 0xb3, 0x40, 0x25, 0xd1, 0x66, 0x33, 0x67, 0x3b, 0x17, 0xa9, 0x7e, 0x9f, 0x46,
0xc3, 0x47, 0x95, 0x0b, 0xef, 0x84, 0xaa, 0x1d, 0x5e, 0x09, 0xb9, 0x4c, 0xe3, 0xb5, 0x88, 0x7d, 0xaa, 0x66, 0x0e, 0x1f, 0x55, 0x2c, 0x7c, 0x12, 0xaa, 0xb6, 0x79, 0x26, 0xe4, 0x22, 0x8d, 0xe7,
0x9f, 0xfa, 0x0a, 0x4b, 0x24, 0x61, 0x6c, 0xf3, 0x8a, 0x4f, 0xf2, 0xeb, 0x1d, 0xb0, 0x26, 0xaa, 0x22, 0xf6, 0x7d, 0xd7, 0x57, 0x58, 0x22, 0x09, 0x73, 0x8b, 0x67, 0x7c, 0x12, 0x5f, 0x9f, 0x80,
0x36, 0x95, 0x5d, 0xc6, 0x37, 0x5a, 0x62, 0x2b, 0x90, 0x2d, 0x8d, 0x16, 0x6d, 0x85, 0x16, 0x29, 0x35, 0x91, 0xb5, 0xa9, 0xe8, 0x32, 0xff, 0xa5, 0x25, 0xb6, 0x02, 0xd9, 0xd2, 0x68, 0xd1, 0x50,
0xb4, 0xab, 0x64, 0xd0, 0x0e, 0xdd, 0x86, 0xd5, 0xa9, 0x15, 0x30, 0xe9, 0xe6, 0x30, 0x03, 0x1f, 0x68, 0x91, 0x42, 0xbb, 0x52, 0x06, 0xed, 0xd0, 0x63, 0x58, 0x99, 0xd8, 0x01, 0x93, 0xdb, 0xec,
0x2b, 0x5c, 0x20, 0xfd, 0x93, 0x38, 0xf2, 0x7f, 0x58, 0x4b, 0xe9, 0x5a, 0x9e, 0x37, 0x14, 0x45, 0x67, 0xe0, 0x63, 0x99, 0x0b, 0xe4, 0xfe, 0x24, 0x8e, 0xfc, 0x06, 0x56, 0x53, 0xba, 0xb6, 0xe7,
0x5d, 0x13, 0x45, 0xad, 0xc7, 0xda, 0xfb, 0x9e, 0x77, 0x6a, 0x05, 0x13, 0xe3, 0x66, 0xe2, 0x7f, 0xf5, 0x45, 0x52, 0xeb, 0x22, 0xa9, 0x8d, 0x58, 0x7b, 0xdf, 0xf3, 0x4e, 0xed, 0x60, 0x6c, 0x3e,
0x06, 0x49, 0xa7, 0x74, 0x1c, 0x21, 0xe9, 0x94, 0x8e, 0x8d, 0x2f, 0x13, 0xb5, 0x04, 0x34, 0xff, 0x4c, 0xf6, 0x9f, 0x41, 0xd2, 0x89, 0x3b, 0x8a, 0x90, 0x74, 0xe2, 0x8e, 0xcc, 0x7f, 0x6a, 0x89,
0x03, 0x35, 0x9b, 0x3a, 0xd2, 0xfb, 0xce, 0xee, 0x8a, 0x8a, 0xfb, 0x21, 0x75, 0xf0, 0x8b, 0x2b, 0x5e, 0x82, 0x9a, 0xbf, 0x04, 0x7d, 0xe0, 0x3a, 0x72, 0xfb, 0xad, 0xdd, 0x65, 0x75, 0xf0, 0x87,
0x0f, 0x9b, 0x42, 0x18, 0x7b, 0x5a, 0x49, 0xe1, 0xa2, 0x5a, 0xbf, 0x9a, 0xac, 0xff, 0x05, 0x07, 0xae, 0x83, 0x2f, 0x6f, 0x3d, 0x6c, 0x09, 0x61, 0xbc, 0xd5, 0x52, 0x0a, 0x18, 0xd5, 0x02, 0xe5,
0x90, 0x4c, 0xf6, 0xbe, 0xcf, 0xd5, 0xbf, 0xd3, 0x92, 0x0b, 0x91, 0x68, 0xfd, 0x8f, 0x16, 0xef, 0x78, 0x01, 0xf4, 0x00, 0x74, 0x66, 0x8f, 0x82, 0x8e, 0x2e, 0xd0, 0x2b, 0x82, 0x99, 0xd7, 0xef,
0x42, 0xdd, 0x25, 0x0e, 0x9e, 0x8b, 0xd5, 0xab, 0xa6, 0x24, 0xa2, 0x36, 0x53, 0x15, 0x3b, 0x66, 0xce, 0x6d, 0xe2, 0x5b, 0x42, 0x64, 0xfe, 0x43, 0xe3, 0x28, 0x93, 0x09, 0xf1, 0xcf, 0xe9, 0x81,
0xdb, 0x8c, 0x0c, 0xb2, 0x24, 0x14, 0xa0, 0xd3, 0x91, 0x00, 0x86, 0x25, 0x53, 0x12, 0x29, 0x58, 0x01, 0xe5, 0x91, 0x1d, 0x88, 0x83, 0xd2, 0x2d, 0x3e, 0xe4, 0x9c, 0x21, 0xc6, 0x22, 0xb1, 0x75,
0x6c, 0x64, 0xe0, 0x5f, 0x1d, 0xba, 0x99, 0x1c, 0xfa, 0x73, 0xde, 0x82, 0xd2, 0xd5, 0xf9, 0x3e, 0x8b, 0x0f, 0xcd, 0xff, 0x6a, 0xc9, 0xcd, 0x4a, 0xd8, 0xff, 0x59, 0x0e, 0xb4, 0xa1, 0x42, 0xa8,
0x23, 0xb2, 0x96, 0xdc, 0x67, 0x5c, 0x97, 0x46, 0x17, 0xd0, 0xf5, 0x82, 0x93, 0xad, 0x36, 0x5b, 0x83, 0x67, 0xc2, 0x83, 0xb2, 0x25, 0x89, 0xa8, 0x5e, 0x95, 0x85, 0x57, 0xd9, 0x7a, 0x25, 0x6f,
0x4a, 0xe8, 0xbf, 0x50, 0x77, 0xdc, 0xd1, 0xa8, 0xbc, 0xd9, 0x48, 0xb1, 0xf1, 0x6d, 0x05, 0x1a, 0x4b, 0x12, 0xaa, 0x32, 0xb8, 0x43, 0xe1, 0x48, 0xd3, 0x92, 0x44, 0x0a, 0x5f, 0xab, 0x99, 0x3a,
0xb2, 0x55, 0xa0, 0x2d, 0x0e, 0x5b, 0x96, 0x4b, 0x86, 0xae, 0x13, 0x95, 0x8b, 0xa0, 0x07, 0x4e, 0xa2, 0x36, 0x56, 0x4b, 0xee, 0xee, 0xaf, 0xbc, 0x96, 0xa5, 0xd3, 0xfc, 0x33, 0x9e, 0x9a, 0xb9,
0x2a, 0x26, 0x95, 0x4c, 0x4c, 0x10, 0xd4, 0x98, 0x3b, 0xc3, 0x2a, 0xd3, 0xc5, 0x37, 0xda, 0x84, 0x9a, 0xc4, 0x45, 0x9c, 0xe0, 0x66, 0x1b, 0xd0, 0xdd, 0xcc, 0x95, 0x35, 0x3b, 0x9b, 0x93, 0xe8,
0x26, 0x09, 0x67, 0x43, 0x36, 0x0f, 0x44, 0xb4, 0x6b, 0x66, 0x83, 0x84, 0xb3, 0x17, 0xf3, 0x00, 0x57, 0x50, 0x71, 0xc8, 0x70, 0x38, 0xbf, 0x6a, 0x49, 0xb1, 0xf9, 0xef, 0x12, 0x54, 0x65, 0xcd,
0xed, 0xc2, 0x72, 0x2a, 0xef, 0x5d, 0x47, 0xe1, 0x71, 0x47, 0x1d, 0x4d, 0x9c, 0x7b, 0x70, 0x64, 0x41, 0x9b, 0x1c, 0xff, 0x6c, 0x42, 0xfb, 0xc4, 0x89, 0xf2, 0x4e, 0xd0, 0x3d, 0x27, 0x75, 0x26,
0x2e, 0xc6, 0x15, 0x30, 0x70, 0xd0, 0x36, 0x88, 0x82, 0x18, 0x4a, 0xcc, 0x93, 0x85, 0xd2, 0x10, 0xa5, 0xcc, 0x99, 0x20, 0xd0, 0x19, 0x99, 0x62, 0x95, 0x32, 0x62, 0x8c, 0x36, 0xa0, 0x46, 0xc3,
0x71, 0xeb, 0x70, 0xbe, 0x02, 0x45, 0xde, 0x07, 0xff, 0x05, 0x6d, 0x1e, 0x49, 0xa9, 0xd2, 0x14, 0x69, 0x9f, 0xcd, 0xa2, 0x2b, 0xaf, 0xd2, 0x70, 0x7a, 0x39, 0x0b, 0xd0, 0x2e, 0x2c, 0xa5, 0x12,
0x2a, 0x2d, 0xce, 0x10, 0xc2, 0x5b, 0xb0, 0x92, 0xf4, 0x56, 0xa9, 0xd2, 0x92, 0xab, 0x24, 0x6c, 0x88, 0x38, 0x0a, 0xd8, 0x5b, 0xca, 0x35, 0xe1, 0x77, 0xef, 0xc8, 0x5a, 0x8c, 0x53, 0xa9, 0xe7,
0xa1, 0xb8, 0x05, 0xad, 0xb8, 0x20, 0xdb, 0x42, 0xa3, 0x69, 0xa9, 0x3a, 0x1c, 0x40, 0x53, 0x1d, 0xa0, 0x2d, 0x10, 0x99, 0xd5, 0x97, 0xe0, 0x29, 0x33, 0xae, 0x2a, 0xce, 0xad, 0xc5, 0xf9, 0x0a,
0xb1, 0xb0, 0x0f, 0xdf, 0x86, 0xba, 0x67, 0xf9, 0x2c, 0x50, 0xfd, 0x2e, 0x82, 0xe3, 0x33, 0xcb, 0x5d, 0x79, 0x41, 0xbd, 0x07, 0x0d, 0x7e, 0x92, 0x52, 0xa5, 0x26, 0x54, 0xea, 0x9c, 0x21, 0x84,
0xe7, 0x03, 0x90, 0xea, 0xc6, 0x52, 0xc5, 0xd8, 0x83, 0xe5, 0x0c, 0x9f, 0x67, 0x22, 0xa3, 0xcc, 0x8f, 0x60, 0x39, 0x29, 0xd2, 0x52, 0xa5, 0x2e, 0x67, 0x49, 0xd8, 0x42, 0x71, 0x13, 0xea, 0x71,
0x9a, 0xaa, 0x4e, 0x2c, 0x89, 0x78, 0x9b, 0x4a, 0xb2, 0x8d, 0xb1, 0x07, 0xed, 0xf8, 0x0e, 0xf9, 0x66, 0x37, 0x84, 0x46, 0xcd, 0x56, 0x09, 0xdd, 0x83, 0x9a, 0x72, 0xb1, 0xb0, 0xa0, 0x3f, 0x86,
0xb5, 0x78, 0xe1, 0xf9, 0x13, 0x35, 0x52, 0x2d, 0x99, 0x8a, 0x12, 0x89, 0x4d, 0xdf, 0xa8, 0x91, 0x8a, 0x67, 0xfb, 0x2c, 0x50, 0x85, 0x33, 0xc2, 0xf5, 0x73, 0xdb, 0xe7, 0x9d, 0x94, 0x2a, 0xeb,
0xa0, 0x66, 0x4a, 0xe2, 0xf6, 0xf7, 0x75, 0x68, 0x45, 0xa9, 0x88, 0x1a, 0x50, 0x79, 0xf6, 0x44, 0x52, 0xc5, 0xdc, 0x83, 0xa5, 0x0c, 0x9f, 0x47, 0x22, 0x73, 0x99, 0x3d, 0x51, 0x25, 0x5d, 0x12,
0x5f, 0x40, 0xab, 0xb0, 0x3c, 0x20, 0x0c, 0xfb, 0xc4, 0x9a, 0x1e, 0x73, 0x0c, 0xd5, 0x35, 0xce, 0xf1, 0x32, 0xa5, 0x64, 0x19, 0x73, 0x0f, 0x1a, 0xf1, 0x1d, 0xf2, 0x6b, 0xf1, 0xc2, 0xab, 0xd7,
0x3a, 0x26, 0x36, 0x75, 0x5c, 0x32, 0x96, 0xac, 0x0a, 0x5a, 0x82, 0xd6, 0x81, 0xe5, 0x3c, 0xa5, 0xaa, 0x37, 0x6b, 0x5a, 0x8a, 0x12, 0x81, 0xed, 0x7e, 0x50, 0xbd, 0x85, 0x6e, 0x49, 0xc2, 0xfc,
0xc4, 0xc6, 0x7a, 0x15, 0xe9, 0xb0, 0xf4, 0x92, 0x58, 0x21, 0x9b, 0x50, 0xdf, 0xfd, 0x1a, 0x3b, 0x8f, 0x06, 0x55, 0x99, 0xf7, 0x05, 0x1d, 0xdd, 0xef, 0x44, 0xab, 0x13, 0xe2, 0x3e, 0x77, 0x5b,
0x7a, 0x0d, 0xad, 0xc3, 0xea, 0x80, 0x04, 0xe1, 0x68, 0xe4, 0xda, 0x2e, 0x26, 0xec, 0x71, 0x48, 0xd8, 0xb5, 0xe2, 0xbf, 0x08, 0x69, 0xb4, 0x23, 0x42, 0xb8, 0x21, 0xb4, 0xf8, 0x10, 0x3d, 0x80,
0x9c, 0x40, 0xaf, 0x23, 0x04, 0x9d, 0x97, 0xe4, 0x82, 0xd0, 0x37, 0x44, 0xcd, 0x1e, 0x7a, 0x03, 0xa6, 0x34, 0x09, 0x98, 0x4f, 0x68, 0x14, 0xbc, 0x8b, 0x82, 0x77, 0x21, 0x58, 0xfc, 0x52, 0xa4,
0xf5, 0xa0, 0x7b, 0x60, 0x05, 0xf8, 0x28, 0xf4, 0xa6, 0xae, 0x6d, 0x31, 0xbc, 0xef, 0x38, 0x3e, 0x0a, 0xa1, 0x4c, 0x44, 0x43, 0xd9, 0xaa, 0x0b, 0x46, 0x8f, 0x32, 0xf3, 0x1e, 0xe8, 0x62, 0x1e,
0x0e, 0x02, 0x1d, 0xf3, 0x45, 0xb8, 0x24, 0xbb, 0xf7, 0x28, 0x32, 0xc8, 0xac, 0x8f, 0x71, 0xa0, 0x80, 0xea, 0xc5, 0xa5, 0xd5, 0x3b, 0x3b, 0x31, 0x16, 0x50, 0x0d, 0xca, 0xbd, 0xb3, 0x4b, 0x43,
0x8f, 0xd1, 0x16, 0xac, 0x5f, 0x93, 0x88, 0x9d, 0x27, 0xe8, 0xdf, 0xd0, 0xcb, 0x8b, 0x4e, 0xac, 0x7b, 0xfc, 0xbf, 0x0a, 0xd4, 0xa3, 0xbc, 0x41, 0x55, 0x28, 0xbd, 0x79, 0x6d, 0x2c, 0xa0, 0x15,
0xe0, 0xcc, 0x77, 0x6d, 0xac, 0xbb, 0xa8, 0x0b, 0xba, 0x94, 0x8a, 0xdb, 0x1f, 0x10, 0x2f, 0x64, 0x58, 0xea, 0x51, 0x86, 0x7d, 0x6a, 0x4f, 0x8e, 0x79, 0xe5, 0x30, 0x34, 0xce, 0x3a, 0xa6, 0x03,
0xfa, 0x57, 0xd1, 0xfe, 0x8a, 0xfb, 0x2c, 0x64, 0x9c, 0x7d, 0x91, 0x63, 0x9f, 0x89, 0x08, 0xeb, 0xd7, 0x21, 0x74, 0x24, 0x59, 0x25, 0xd4, 0x84, 0xfa, 0x81, 0xed, 0x9c, 0xb9, 0x74, 0x80, 0x8d,
0x53, 0xb4, 0x09, 0x6b, 0x29, 0xf6, 0x73, 0xee, 0x1f, 0x8f, 0xce, 0x2c, 0x39, 0xaf, 0x14, 0xb8, 0x32, 0x32, 0xa0, 0xf9, 0x96, 0xda, 0x21, 0x1b, 0xbb, 0x3e, 0xf9, 0x3b, 0x76, 0x0c, 0x1d, 0xad,
0x63, 0x62, 0xb1, 0xd0, 0xc7, 0x3a, 0x41, 0x1b, 0x80, 0xb8, 0x44, 0x85, 0x24, 0x72, 0x9c, 0x46, 0xc1, 0x4a, 0x8f, 0x06, 0xe1, 0x70, 0x48, 0x06, 0x04, 0x53, 0xf6, 0x2a, 0xa4, 0x4e, 0x60, 0x54,
0x3b, 0x28, 0xbe, 0xda, 0xc1, 0xcb, 0xb3, 0xa7, 0xe1, 0xd8, 0x25, 0xfa, 0x6b, 0xb4, 0x0e, 0xfa, 0x10, 0x82, 0xd6, 0x5b, 0x7a, 0x4d, 0xdd, 0x0f, 0x54, 0x75, 0x5c, 0x46, 0x15, 0x75, 0xa0, 0x7d,
0x09, 0xbd, 0x54, 0xdc, 0x63, 0xc2, 0x5c, 0x76, 0xa5, 0xff, 0xa8, 0xa1, 0x2e, 0xac, 0x24, 0xec, 0x60, 0x07, 0xf8, 0x28, 0xf4, 0x26, 0x64, 0x60, 0x33, 0xbc, 0xef, 0x38, 0x3e, 0x0e, 0x02, 0x03,
0x13, 0x9f, 0x86, 0x9e, 0xfe, 0x93, 0x86, 0x36, 0x01, 0x25, 0xdc, 0x33, 0x9f, 0x7a, 0x34, 0xb0, 0xf3, 0x49, 0xb8, 0x24, 0xbb, 0xf6, 0x30, 0x32, 0xc8, 0xcc, 0x8f, 0x71, 0x60, 0x8c, 0xd0, 0x26,
0xa6, 0xfa, 0xcf, 0x1a, 0xda, 0x80, 0xd5, 0x13, 0x7a, 0x19, 0xdf, 0x82, 0x34, 0xf8, 0x25, 0x32, 0xac, 0xdd, 0x91, 0x88, 0x95, 0xc7, 0xe8, 0x17, 0xd0, 0xc9, 0x8b, 0x4e, 0xec, 0xe0, 0xdc, 0x27,
0x88, 0xf9, 0x9f, 0xe2, 0xd9, 0x39, 0xf6, 0xf5, 0x5f, 0x35, 0xb4, 0x05, 0xdd, 0xb4, 0x20, 0x5e, 0x03, 0x6c, 0x10, 0xd4, 0x06, 0x43, 0x4a, 0x45, 0xa8, 0xf6, 0xa8, 0x17, 0x32, 0xe3, 0x6f, 0xd1,
0xeb, 0x37, 0x4d, 0x9d, 0x28, 0x16, 0xbd, 0xa2, 0x0c, 0xeb, 0xbf, 0x47, 0x6c, 0x15, 0x07, 0xb5, 0xfa, 0x8a, 0xfb, 0x26, 0x64, 0x9c, 0x7d, 0x9d, 0x63, 0x9f, 0x8b, 0x70, 0x30, 0x26, 0x68, 0x03,
0xd0, 0x1f, 0x1a, 0x5a, 0x83, 0x4e, 0xc2, 0x16, 0xba, 0x7f, 0x6a, 0xa8, 0x0f, 0xeb, 0x19, 0xa6, 0x56, 0x53, 0xec, 0x0b, 0xbe, 0x3f, 0x7e, 0x3a, 0xd3, 0xc4, 0x5f, 0x29, 0x20, 0x23, 0x6a, 0xb3,
0x4b, 0xc6, 0x67, 0x3c, 0x69, 0xf5, 0xbf, 0xb4, 0xdd, 0xb7, 0x75, 0x58, 0xd9, 0x3f, 0x38, 0x1c, 0xd0, 0xc7, 0x06, 0x45, 0xeb, 0x80, 0xb8, 0x44, 0x1d, 0x49, 0xb4, 0x71, 0x37, 0x5a, 0x41, 0xf1,
0xec, 0x7b, 0x72, 0x03, 0xde, 0xff, 0xee, 0x41, 0x4d, 0x74, 0xf8, 0x82, 0x67, 0x6f, 0xbf, 0x68, 0xd5, 0x0a, 0x5e, 0x9e, 0x3d, 0x09, 0x47, 0x84, 0x1a, 0xef, 0xd1, 0x1a, 0x18, 0x27, 0xee, 0x8d,
0xd4, 0x44, 0xbb, 0x50, 0x17, 0x8d, 0x1e, 0x15, 0xbd, 0x7e, 0xfb, 0x85, 0x13, 0x27, 0xdf, 0x44, 0xe2, 0x1e, 0x53, 0x46, 0xd8, 0xad, 0xf1, 0x85, 0x86, 0xda, 0xb0, 0x9c, 0xb0, 0x4f, 0x7c, 0x37,
0x8e, 0x02, 0xd7, 0x1f, 0xc1, 0xfd, 0xa2, 0xb1, 0x13, 0x7d, 0x02, 0xed, 0xa4, 0x45, 0x97, 0x3d, 0xf4, 0x8c, 0x2f, 0x35, 0xb4, 0x01, 0x28, 0xe1, 0x9e, 0xfb, 0xae, 0xe7, 0x06, 0xf6, 0xc4, 0xf8,
0x85, 0xfb, 0xa5, 0x03, 0x28, 0xb7, 0x4f, 0x7a, 0x77, 0xd9, 0x83, 0xb8, 0x5f, 0x3a, 0x85, 0xa2, 0x4a, 0x43, 0xeb, 0xb0, 0x72, 0xe2, 0xde, 0xc4, 0xb7, 0x20, 0x0d, 0xbe, 0x8e, 0x0c, 0x62, 0xfe,
0x87, 0xd0, 0x8c, 0x7a, 0x73, 0xf1, 0xb3, 0xb8, 0x5f, 0x32, 0x88, 0xf2, 0xf0, 0xc8, 0xb6, 0x5b, 0x9f, 0xf1, 0xf4, 0x0a, 0xfb, 0xc6, 0x37, 0x1a, 0xda, 0x84, 0x76, 0x5a, 0x10, 0xcf, 0xf5, 0xad,
0xf4, 0xda, 0xed, 0x17, 0xce, 0x96, 0xe8, 0x01, 0x34, 0x54, 0xdb, 0x2b, 0x7c, 0x51, 0xf7, 0x8b, 0xa6, 0x3c, 0x8a, 0x45, 0xef, 0x5c, 0x86, 0x8d, 0xef, 0x22, 0xb6, 0x3a, 0x07, 0x35, 0xd1, 0xf7,
0x27, 0x58, 0xee, 0x64, 0xf2, 0x30, 0x2a, 0x7b, 0x2a, 0xf7, 0x4b, 0x67, 0x53, 0xb4, 0x0f, 0x90, 0x1a, 0x5a, 0x85, 0x56, 0xc2, 0x16, 0xba, 0x3f, 0x68, 0xa8, 0x0b, 0x6b, 0x19, 0x26, 0xa1, 0xa3,
0x7a, 0x12, 0x95, 0x3e, 0x98, 0xfb, 0xe5, 0x13, 0x2a, 0x7a, 0x04, 0xad, 0xe4, 0x15, 0x54, 0xfc, 0x73, 0x9e, 0x61, 0xc6, 0x8f, 0xda, 0xee, 0xc7, 0x0a, 0x2c, 0xef, 0x1f, 0x1c, 0xf6, 0xf6, 0x3d,
0x6c, 0xee, 0x97, 0x0d, 0xa9, 0xe7, 0x0d, 0xf1, 0x8f, 0xcc, 0xfd, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xb9, 0x00, 0xaf, 0xfa, 0x4f, 0x41, 0x17, 0x7d, 0x4d, 0xc1, 0xcf, 0x7e, 0xb7, 0xa8, 0xc1, 0x46,
0xff, 0xbd, 0xb6, 0xa5, 0xad, 0xa6, 0x11, 0x00, 0x00, 0xbb, 0x50, 0x11, 0xed, 0x0d, 0x2a, 0xfa, 0xe7, 0xef, 0x16, 0xf6, 0xd9, 0x7c, 0x11, 0xd9, 0x00,
0xdd, 0xfd, 0xf5, 0xef, 0x16, 0x35, 0xdb, 0xe8, 0x4f, 0xd0, 0x48, 0x1a, 0x93, 0x79, 0x0f, 0x00,
0xdd, 0xb9, 0x6d, 0x37, 0xb7, 0x4f, 0x1a, 0x96, 0x79, 0xcf, 0x00, 0xdd, 0xb9, 0xbd, 0x37, 0x7a,
0x01, 0xb5, 0xa8, 0xd9, 0x28, 0x7e, 0x0c, 0xe8, 0xce, 0x69, 0xbf, 0xf9, 0xf1, 0xc8, 0x1e, 0xa1,
0xe8, 0x1f, 0xbf, 0x5b, 0xd8, 0x51, 0xa3, 0xe7, 0x50, 0x55, 0x35, 0xba, 0xf0, 0x1d, 0xa1, 0x5b,
0xdc, 0xb7, 0xf3, 0x4d, 0x26, 0xbf, 0x83, 0xf3, 0x1e, 0x08, 0xba, 0x73, 0x3b, 0x72, 0xb4, 0x0f,
0x90, 0xfa, 0x11, 0x9c, 0xfb, 0x4c, 0xd0, 0x9d, 0xdf, 0x97, 0xa3, 0x97, 0x50, 0x4f, 0xfe, 0xfd,
0x8a, 0x1f, 0x0b, 0xba, 0xf3, 0x5a, 0xf3, 0xab, 0xaa, 0x78, 0x87, 0x7a, 0xf6, 0x53, 0x00, 0x00,
0x00, 0xff, 0xff, 0x3c, 0xa1, 0xc6, 0x00, 0x9c, 0x12, 0x00, 0x00,
} }

View File

@ -7,42 +7,42 @@ package types;
// Code types // Code types
enum CodeType { enum CodeType {
OK = 0; OK = 0;
// General response codes, 0 ~ 99 // General response codes, 0 ~ 99
InternalError = 1; InternalError = 1;
EncodingError = 2; EncodingError = 2;
BadNonce = 3; BadNonce = 3;
Unauthorized = 4; Unauthorized = 4;
InsufficientFunds = 5; InsufficientFunds = 5;
UnknownRequest = 6; UnknownRequest = 6;
// Reserved for basecoin, 100 ~ 199 // Reserved for basecoin, 100 ~ 199
BaseDuplicateAddress = 101; BaseDuplicateAddress = 101;
BaseEncodingError = 102; BaseEncodingError = 102;
BaseInsufficientFees = 103; BaseInsufficientFees = 103;
BaseInsufficientFunds = 104; BaseInsufficientFunds = 104;
BaseInsufficientGasPrice = 105; BaseInsufficientGasPrice = 105;
BaseInvalidInput = 106; BaseInvalidInput = 106;
BaseInvalidOutput = 107; BaseInvalidOutput = 107;
BaseInvalidPubKey = 108; BaseInvalidPubKey = 108;
BaseInvalidSequence = 109; BaseInvalidSequence = 109;
BaseInvalidSignature = 110; BaseInvalidSignature = 110;
BaseUnknownAddress = 111; BaseUnknownAddress = 111;
BaseUnknownPubKey = 112; BaseUnknownPubKey = 112;
BaseUnknownPlugin = 113; BaseUnknownPlugin = 113;
// Reserved for governance, 200 ~ 299 // Reserved for governance, 200 ~ 299
GovUnknownEntity = 201; GovUnknownEntity = 201;
GovUnknownGroup = 202; GovUnknownGroup = 202;
GovUnknownProposal = 203; GovUnknownProposal = 203;
GovDuplicateGroup = 204; GovDuplicateGroup = 204;
GovDuplicateMember = 205; GovDuplicateMember = 205;
GovDuplicateProposal = 206; GovDuplicateProposal = 206;
GovDuplicateVote = 207; GovDuplicateVote = 207;
GovInvalidMember = 208; GovInvalidMember = 208;
GovInvalidVote = 209; GovInvalidVote = 209;
GovInvalidVotingPower = 210; GovInvalidVotingPower = 210;
} }
@ -50,66 +50,66 @@ enum CodeType {
// Request types // Request types
message Request { message Request {
oneof value{ oneof value{
RequestEcho echo = 1; RequestEcho echo = 1;
RequestFlush flush = 2; RequestFlush flush = 2;
RequestInfo info = 3; RequestInfo info = 3;
RequestSetOption set_option = 4; RequestSetOption set_option = 4;
RequestDeliverTx deliver_tx = 5; RequestDeliverTx deliver_tx = 5;
RequestCheckTx check_tx = 6; RequestCheckTx check_tx = 6;
RequestCommit commit = 7; RequestCommit commit = 7;
RequestQuery query = 8; RequestQuery query = 8;
RequestInitChain init_chain = 9; RequestInitChain init_chain = 9;
RequestBeginBlock begin_block = 10; RequestBeginBlock begin_block = 10;
RequestEndBlock end_block = 11; RequestEndBlock end_block = 11;
} }
} }
message RequestEcho { message RequestEcho {
string message = 1; string message = 1;
} }
message RequestFlush { message RequestFlush {
} }
message RequestInfo { message RequestInfo {
string version = 1; string version = 1;
} }
message RequestSetOption{ message RequestSetOption{
string key = 1; string key = 1;
string value = 2; string value = 2;
} }
message RequestDeliverTx{ message RequestDeliverTx{
bytes tx = 1; bytes tx = 1;
} }
message RequestCheckTx{ message RequestCheckTx{
bytes tx = 1; bytes tx = 1;
} }
message RequestQuery{ message RequestQuery{
bytes data = 1; bytes data = 1;
string path = 2; string path = 2;
uint64 height = 3; uint64 height = 3;
bool prove = 4; bool prove = 4;
} }
message RequestCommit{ message RequestCommit{
} }
message RequestInitChain{ message RequestInitChain{
repeated Validator validators = 1; repeated Validator validators = 1;
} }
message RequestBeginBlock{ message RequestBeginBlock{
bytes hash = 1; bytes hash = 1;
Header header = 2; Header header = 2;
} }
message RequestEndBlock{ message RequestEndBlock{
uint64 height = 1; uint64 height = 1;
} }
//---------------------------------------- //----------------------------------------
@ -117,70 +117,73 @@ message RequestEndBlock{
message Response { message Response {
oneof value{ oneof value{
ResponseException exception = 1; ResponseException exception = 1;
ResponseEcho echo = 2; ResponseEcho echo = 2;
ResponseFlush flush = 3; ResponseFlush flush = 3;
ResponseInfo info = 4; ResponseInfo info = 4;
ResponseSetOption set_option = 5; ResponseSetOption set_option = 5;
ResponseDeliverTx deliver_tx = 6; ResponseDeliverTx deliver_tx = 6;
ResponseCheckTx check_tx = 7; ResponseCheckTx check_tx = 7;
ResponseCommit commit = 8; ResponseCommit commit = 8;
ResponseQuery query = 9; ResponseQuery query = 9;
ResponseInitChain init_chain = 10; ResponseInitChain init_chain = 10;
ResponseBeginBlock begin_block = 11; ResponseBeginBlock begin_block = 11;
ResponseEndBlock end_block = 12; ResponseEndBlock end_block = 12;
} }
} }
message ResponseException{ message ResponseException{
string error = 1; string error = 1;
} }
message ResponseEcho { message ResponseEcho {
string message = 1; string message = 1;
} }
message ResponseFlush{ message ResponseFlush{
} }
message ResponseInfo { message ResponseInfo {
string data = 1; string data = 1;
string version = 2; string version = 2;
uint64 last_block_height = 3; uint64 last_block_height = 3;
bytes last_block_app_hash = 4; bytes last_block_app_hash = 4;
} }
message ResponseSetOption{ message ResponseSetOption{
string log = 1; string log = 1;
} }
message ResponseDeliverTx{ message ResponseDeliverTx{
CodeType code = 1; CodeType code = 1;
bytes data = 2; bytes data = 2;
string log = 3; string log = 3;
repeated KVPair tags = 4;
} }
message ResponseCheckTx{ message ResponseCheckTx{
CodeType code = 1; CodeType code = 1;
bytes data = 2; bytes data = 2;
string log = 3; string log = 3;
uint64 gas = 4;
uint64 fee = 5;
} }
message ResponseQuery{ message ResponseQuery{
CodeType code = 1; CodeType code = 1;
int64 index = 2; int64 index = 2;
bytes key = 3; bytes key = 3;
bytes value = 4; bytes value = 4;
bytes proof = 5; bytes proof = 5;
uint64 height = 6; uint64 height = 6;
string log = 7; string log = 7;
} }
message ResponseCommit{ message ResponseCommit{
CodeType code = 1; CodeType code = 1;
bytes data = 2; bytes data = 2;
string log = 3; string log = 3;
} }
@ -191,52 +194,66 @@ message ResponseBeginBlock{
} }
message ResponseEndBlock{ message ResponseEndBlock{
repeated Validator diffs = 1; repeated Validator diffs = 1;
} }
//---------------------------------------- //----------------------------------------
// Blockchain Types // Blockchain Types
message Header { message Header {
string chain_id = 1; string chain_id = 1;
uint64 height = 2; uint64 height = 2;
uint64 time = 3; uint64 time = 3;
uint64 num_txs = 4; uint64 num_txs = 4;
BlockID last_block_id = 5; BlockID last_block_id = 5;
bytes last_commit_hash = 6; bytes last_commit_hash = 6;
bytes data_hash = 7; bytes data_hash = 7;
bytes validators_hash = 8; bytes validators_hash = 8;
bytes app_hash = 9; bytes app_hash = 9;
} }
message BlockID { message BlockID {
bytes hash = 1; bytes hash = 1;
PartSetHeader parts = 2; PartSetHeader parts = 2;
} }
message PartSetHeader { message PartSetHeader {
uint64 total = 1; uint64 total = 1;
bytes hash = 2; bytes hash = 2;
} }
message Validator { message Validator {
bytes pubKey = 1; bytes pubKey = 1;
uint64 power = 2; uint64 power = 2;
}
//----------------------------------------
// Abstract types
message KVPair {
string key = 1;
enum Type {
STRING = 0;
INT = 1;
}
Type value_type = 2;
string value_string = 3;
int64 value_int = 4;
} }
//---------------------------------------- //----------------------------------------
// Service Definition // Service Definition
service ABCIApplication { service ABCIApplication {
rpc Echo(RequestEcho) returns (ResponseEcho) ; rpc Echo(RequestEcho) returns (ResponseEcho) ;
rpc Flush(RequestFlush) returns (ResponseFlush); rpc Flush(RequestFlush) returns (ResponseFlush);
rpc Info(RequestInfo) returns (ResponseInfo); rpc Info(RequestInfo) returns (ResponseInfo);
rpc SetOption(RequestSetOption) returns (ResponseSetOption); rpc SetOption(RequestSetOption) returns (ResponseSetOption);
rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx); rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx);
rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx); rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx);
rpc Query(RequestQuery) returns (ResponseQuery); rpc Query(RequestQuery) returns (ResponseQuery);
rpc Commit(RequestCommit) returns (ResponseCommit); rpc Commit(RequestCommit) returns (ResponseCommit);
rpc InitChain(RequestInitChain) returns (ResponseInitChain); rpc InitChain(RequestInitChain) returns (ResponseInitChain);
rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock); rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock);
rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock); rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock);
} }