Browse Source

Merge pull request #36 from tendermint/develop

v0.3.0, for Tendermint v0.8.0
pull/1780/head
Ethan Buchman 8 years ago
committed by GitHub
parent
commit
068afb5b7f
60 changed files with 1647 additions and 660 deletions
  1. +1
    -1
      LICENSE
  2. +2
    -2
      Makefile
  3. +24
    -20
      README.md
  4. +9
    -9
      client/client.go
  5. +36
    -29
      client/grpc_client.go
  6. +25
    -25
      client/local_client.go
  7. +2
    -2
      client/log.go
  8. +36
    -27
      client/socket_client.go
  9. +123
    -56
      cmd/abci-cli/tmsp-cli.go
  10. +5
    -4
      cmd/counter/main.go
  11. +15
    -4
      cmd/dummy/main.go
  12. +76
    -0
      example/chain_aware/chain_aware_app.go
  13. +54
    -0
      example/chain_aware/chain_aware_test.go
  14. +22
    -16
      example/counter/counter.go
  15. +31
    -0
      example/dummy/README.md
  16. +16
    -10
      example/dummy/dummy.go
  17. +203
    -0
      example/dummy/dummy_test.go
  18. +7
    -0
      example/dummy/log.go
  19. +229
    -0
      example/dummy/persistent_dummy.go
  20. +24
    -24
      example/example_test.go
  21. +1
    -1
      example/js/README.md
  22. +4
    -4
      example/nil/nil_app.go
  23. +0
    -0
      example/python/abci/__init__.py
  24. +3
    -3
      example/python/abci/msg.py
  25. +0
    -0
      example/python/abci/reader.py
  26. +2
    -2
      example/python/abci/server.py
  27. +0
    -0
      example/python/abci/wire.py
  28. +6
    -6
      example/python/app.py
  29. +0
    -0
      example/python3/abci/__init__.py
  30. +3
    -3
      example/python3/abci/msg.py
  31. +0
    -0
      example/python3/abci/reader.py
  32. +2
    -2
      example/python3/abci/server.py
  33. +0
    -0
      example/python3/abci/wire.py
  34. +6
    -6
      example/python3/app.py
  35. +25
    -18
      glide.lock
  36. +6
    -1
      glide.yaml
  37. +8
    -8
      server/grpc_server.go
  38. +1
    -1
      server/log.go
  39. +1
    -1
      server/server.go
  40. +19
    -16
      server/socket_server.go
  41. +1
    -1
      tests/benchmarks/parallel/parallel.go
  42. +1
    -1
      tests/benchmarks/simple/simple.go
  43. +17
    -16
      tests/test_app/app.go
  44. +19
    -19
      tests/test_app/main.go
  45. +5
    -5
      tests/test_app/test.sh
  46. +10
    -0
      tests/test_cli/ex1.abci
  47. +32
    -0
      tests/test_cli/ex1.abci.out
  48. +0
    -10
      tests/test_cli/ex1.tmsp
  49. +0
    -31
      tests/test_cli/ex1.tmsp.out
  50. +3
    -3
      tests/test_cli/ex2.abci
  51. +5
    -5
      tests/test_cli/ex2.abci.out
  52. +5
    -3
      tests/test_cli/test.sh
  53. +1
    -1
      testutil/messages.go
  54. +13
    -12
      types/application.go
  55. +10
    -10
      types/messages.go
  56. +1
    -1
      types/result.go
  57. +412
    -230
      types/types.pb.go
  58. +37
    -11
      types/types.proto
  59. +41
    -0
      types/validators.go
  60. +7
    -0
      types/version.go

+ 1
- 1
LICENSE View File

@ -1,4 +1,4 @@
Tendermint TMSP
Tendermint ABCI
Copyright (C) 2015 Tendermint


+ 2
- 2
Makefile View File

@ -2,13 +2,13 @@
all: protoc test install
NOVENDOR = go list github.com/tendermint/tmsp/... | grep -v /vendor/
NOVENDOR = go list github.com/tendermint/abci/... | grep -v /vendor/
protoc:
protoc --go_out=plugins=grpc:. types/*.proto
install:
go install github.com/tendermint/tmsp/cmd/...
go install github.com/tendermint/abci/cmd/...
test:
go test `${NOVENDOR}`


+ 24
- 20
README.md View File

@ -1,37 +1,37 @@
# Tendermint Socket Protocol (TMSP)
# Tendermint Socket Protocol (ABCI)
[![CircleCI](https://circleci.com/gh/tendermint/tmsp.svg?style=svg)](https://circleci.com/gh/tendermint/tmsp)
[![CircleCI](https://circleci.com/gh/tendermint/abci.svg?style=svg)](https://circleci.com/gh/tendermint/abci)
Blockchains are a system for creating shared multi-master application state.
**TMSP** is a socket protocol enabling a blockchain consensus engine, running in one process,
**ABCI** is a socket protocol enabling a blockchain consensus engine, running in one process,
to manage a blockchain application state, running in another.
For more information on TMSP, motivations, and tutorials, please visit [our blog post](https://tendermint.com/blog/tmsp-the-tendermint-socket-protocol).
For more information on ABCI, motivations, and tutorials, please visit [our blog post](https://tendermint.com/blog/abci-the-tendermint-socket-protocol).
Other implementations:
* [cpp-tmsp](https://github.com/mdyring/cpp-tmsp) by Martin Dyring-Andersen
* [js-tmsp](https://github.com/tendermint/js-tmsp)
* [jTMSP](https://github.com/jTMSP/) for Java
* [cpp-abci](https://github.com/mdyring/cpp-abci) by Martin Dyring-Andersen
* [js-abci](https://github.com/tendermint/js-abci)
* [jABCI](https://github.com/jABCI/) for Java
## Contents
This repository holds a number of important pieces:
- `types/types.proto`
- the protobuf file defining TMSP message types, and the optional grpc interface.
- the protobuf file defining ABCI message types, and the optional grpc interface.
- to build, run `make protoc`
- see `protoc --help` and [the grpc docs](https://www.grpc.io/docs) for examples and details of other languages
- golang implementation of TMSP client and server
- golang implementation of ABCI client and server
- two implementations:
- asynchronous, ordered message passing over unix or tcp;
- messages are serialized using protobuf and length prefixed
- grpc
- TendermintCore runs a client, and the application runs a server
- `cmd/tmsp-cli`
- command line tool wrapping the client for probing/testing a TMSP application
- use `tmsp-cli --version` to get the TMSP version
- `cmd/abci-cli`
- command line tool wrapping the client for probing/testing a ABCI application
- use `abci-cli --version` to get the ABCI version
- examples:
- the `cmd/counter` application, which illustrates nonce checking in txs
@ -42,15 +42,15 @@ This repository holds a number of important pieces:
Since this is a streaming protocol, all messages are encoded with a length-prefix followed by the message encoded in Protobuf3. Protobuf3 doesn't have an official length-prefix standard, so we use our own. The first byte represents the length of the big-endian encoded length.
For example, if the Protobuf3 encoded TMSP message is `0xDEADBEEF` (4 bytes), the length-prefixed message is `0x0104DEADBEEF`. If the Protobuf3 encoded TMSP message is 65535 bytes long, the length-prefixed message would be like `0x02FFFF...`.
For example, if the Protobuf3 encoded ABCI message is `0xDEADBEEF` (4 bytes), the length-prefixed message is `0x0104DEADBEEF`. If the Protobuf3 encoded ABCI message is 65535 bytes long, the length-prefixed message would be like `0x02FFFF...`.
Note this prefixing does not apply for grpc.
## Message types
TMSP requests/responses are simple Protobuf messages. Check out the [schema file](https://github.com/tendermint/tmsp/blob/master/types/types.proto).
ABCI requests/responses are simple Protobuf messages. Check out the [schema file](https://github.com/tendermint/abci/blob/master/types/types.proto).
#### AppendTx
#### DeliverTx
* __Arguments__:
* `Data ([]byte)`: The request transaction bytes
* __Returns__:
@ -68,7 +68,11 @@ TMSP requests/responses are simple Protobuf messages. Check out the [schema fil
* `Data ([]byte)`: Result bytes, if any
* `Log (string)`: Debug or error message
* __Usage__:<br/>
Validate a transaction. This message should not mutate the state.
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.
CheckTx can happen interspersed with DeliverTx, but they happen on different connections - CheckTx from the mempool connection, and DeliverTx from the consensus connection. During Commit, the mempool is locked, so you can reset the mempool state to the latest state after running all those delivertxs, and then the mempool will re run whatever txs it has against that latest mempool stte
Transactions are first run through CheckTx before broadcast to peers in the mempool layer.
You can make CheckTx semi-stateful and clear the state upon `Commit` or `BeginBlock`,
to allow for dependent sequences of transactions in the same block.
@ -118,7 +122,7 @@ TMSP requests/responses are simple Protobuf messages. Check out the [schema fil
* __Arguments__:
* `Height (uint64)`: The block height that is starting
* __Usage__:<br/>
Signals the beginning of a new block. Called prior to any AppendTxs.
Signals the beginning of a new block. Called prior to any DeliverTxs.
#### EndBlock
* __Arguments__:
@ -144,8 +148,8 @@ TMSP requests/responses are simple Protobuf messages. Check out the [schema fil
##### Jan 23th, 2016
* Added CheckTx/Query TMSP message types
* Added Result/Log fields to AppendTx/CheckTx/SetOption
* Added CheckTx/Query ABCI message types
* Added Result/Log fields to DeliverTx/CheckTx/SetOption
* Removed Listener messages
* Removed Code from ResponseSetOption and ResponseGetHash
* Made examples BigEndian
@ -156,4 +160,4 @@ TMSP requests/responses are simple Protobuf messages. Check out the [schema fil
##### Jan 8th, 2016
* Tendermint/TMSP now comes to consensus on the order first before AppendTx.
* Tendermint/ABCI now comes to consensus on the order first before DeliverTx.

+ 9
- 9
client/client.go View File

@ -1,11 +1,11 @@
package tmspcli
package abcicli
import (
"fmt"
"sync"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
type Client interface {
@ -18,27 +18,27 @@ type Client interface {
EchoAsync(msg string) *ReqRes
InfoAsync() *ReqRes
SetOptionAsync(key string, value string) *ReqRes
AppendTxAsync(tx []byte) *ReqRes
DeliverTxAsync(tx []byte) *ReqRes
CheckTxAsync(tx []byte) *ReqRes
QueryAsync(tx []byte) *ReqRes
CommitAsync() *ReqRes
FlushSync() error
EchoSync(msg string) (res types.Result)
InfoSync() (res types.Result)
InfoSync() (resInfo types.ResponseInfo, err error)
SetOptionSync(key string, value string) (res types.Result)
AppendTxSync(tx []byte) (res types.Result)
DeliverTxSync(tx []byte) (res types.Result)
CheckTxSync(tx []byte) (res types.Result)
QuerySync(tx []byte) (res types.Result)
CommitSync() (res types.Result)
InitChainAsync(validators []*types.Validator) *ReqRes
BeginBlockAsync(height uint64) *ReqRes
BeginBlockAsync(hash []byte, header *types.Header) *ReqRes
EndBlockAsync(height uint64) *ReqRes
InitChainSync(validators []*types.Validator) (err error)
BeginBlockSync(height uint64) (err error)
EndBlockSync(height uint64) (changedValidators []*types.Validator, err error)
BeginBlockSync(hash []byte, header *types.Header) (err error)
EndBlockSync(height uint64) (resEndBlock types.ResponseEndBlock, err error)
}
//----------------------------------------
@ -50,7 +50,7 @@ func NewClient(addr, transport string, mustConnect bool) (client Client, err err
case "grpc":
client, err = NewGRPCClient(addr, mustConnect)
default:
err = fmt.Errorf("Unknown tmsp transport %s", transport)
err = fmt.Errorf("Unknown abci transport %s", transport)
}
return


+ 36
- 29
client/grpc_client.go View File

@ -1,4 +1,4 @@
package tmspcli
package abcicli
import (
"net"
@ -9,16 +9,16 @@ import (
grpc "google.golang.org/grpc"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
// A stripped copy of the remoteClient that makes
// synchronous calls using grpc
type grpcClient struct {
QuitService
BaseService
mustConnect bool
client types.TMSPApplicationClient
client types.ABCIApplicationClient
mtx sync.Mutex
addr string
@ -31,7 +31,7 @@ func NewGRPCClient(addr string, mustConnect bool) (*grpcClient, error) {
addr: addr,
mustConnect: mustConnect,
}
cli.QuitService = *NewQuitService(nil, "grpcClient", cli)
cli.BaseService = *NewBaseService(nil, "grpcClient", cli)
_, err := cli.Start() // Just start it, it's confusing for callers to remember to start.
return cli, err
}
@ -41,7 +41,7 @@ func dialerFunc(addr string, timeout time.Duration) (net.Conn, error) {
}
func (cli *grpcClient) OnStart() error {
cli.QuitService.OnStart()
cli.BaseService.OnStart()
RETRY_LOOP:
for {
@ -50,13 +50,13 @@ RETRY_LOOP:
if cli.mustConnect {
return err
} else {
log.Warn(Fmt("tmsp.grpcClient failed to connect to %v. Retrying...\n", cli.addr))
log.Warn(Fmt("abci.grpcClient failed to connect to %v. Retrying...\n", cli.addr))
time.Sleep(time.Second * 3)
continue RETRY_LOOP
}
}
client := types.NewTMSPApplicationClient(conn)
client := types.NewABCIApplicationClient(conn)
ENSURE_CONNECTED:
for {
@ -73,7 +73,7 @@ RETRY_LOOP:
}
func (cli *grpcClient) OnStop() {
cli.QuitService.OnStop()
cli.BaseService.OnStop()
cli.mtx.Lock()
defer cli.mtx.Unlock()
// TODO: how to close conn? its not a net.Conn and grpc doesn't expose a Close()
@ -93,7 +93,7 @@ func (cli *grpcClient) StopForError(err error) {
}
cli.mtx.Unlock()
log.Warn(Fmt("Stopping tmsp.grpcClient for error: %v", err.Error()))
log.Warn(Fmt("Stopping abci.grpcClient for error: %v", err.Error()))
cli.Stop()
}
@ -155,13 +155,13 @@ func (cli *grpcClient) SetOptionAsync(key string, value string) *ReqRes {
return cli.finishAsyncCall(req, &types.Response{&types.Response_SetOption{res}})
}
func (cli *grpcClient) AppendTxAsync(tx []byte) *ReqRes {
req := types.ToRequestAppendTx(tx)
res, err := cli.client.AppendTx(context.Background(), req.GetAppendTx(), grpc.FailFast(true))
func (cli *grpcClient) DeliverTxAsync(tx []byte) *ReqRes {
req := types.ToRequestDeliverTx(tx)
res, err := cli.client.DeliverTx(context.Background(), req.GetDeliverTx(), grpc.FailFast(true))
if err != nil {
cli.StopForError(err)
}
return cli.finishAsyncCall(req, &types.Response{&types.Response_AppendTx{res}})
return cli.finishAsyncCall(req, &types.Response{&types.Response_DeliverTx{res}})
}
func (cli *grpcClient) CheckTxAsync(tx []byte) *ReqRes {
@ -200,8 +200,8 @@ func (cli *grpcClient) InitChainAsync(validators []*types.Validator) *ReqRes {
return cli.finishAsyncCall(req, &types.Response{&types.Response_InitChain{res}})
}
func (cli *grpcClient) BeginBlockAsync(height uint64) *ReqRes {
req := types.ToRequestBeginBlock(height)
func (cli *grpcClient) BeginBlockAsync(hash []byte, header *types.Header) *ReqRes {
req := types.ToRequestBeginBlock(hash, header)
res, err := cli.client.BeginBlock(context.Background(), req.GetBeginBlock(), grpc.FailFast(true))
if err != nil {
cli.StopForError(err)
@ -262,13 +262,16 @@ func (cli *grpcClient) FlushSync() error {
return nil
}
func (cli *grpcClient) InfoSync() (res types.Result) {
func (cli *grpcClient) InfoSync() (resInfo types.ResponseInfo, err error) {
reqres := cli.InfoAsync()
if res := cli.checkErrGetResult(); res.IsErr() {
return res
if err = cli.Error(); err != nil {
return resInfo, err
}
if resInfo_ := reqres.Response.GetInfo(); resInfo_ != nil {
return *resInfo_, nil
} else {
return resInfo, nil
}
resp := reqres.Response.GetInfo()
return types.NewResultOK([]byte(resp.Info), LOG)
}
func (cli *grpcClient) SetOptionSync(key string, value string) (res types.Result) {
@ -280,12 +283,12 @@ func (cli *grpcClient) SetOptionSync(key string, value string) (res types.Result
return types.Result{Code: OK, Data: nil, Log: resp.Log}
}
func (cli *grpcClient) AppendTxSync(tx []byte) (res types.Result) {
reqres := cli.AppendTxAsync(tx)
func (cli *grpcClient) DeliverTxSync(tx []byte) (res types.Result) {
reqres := cli.DeliverTxAsync(tx)
if res := cli.checkErrGetResult(); res.IsErr() {
return res
}
resp := reqres.Response.GetAppendTx()
resp := reqres.Response.GetDeliverTx()
return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log}
}
@ -321,15 +324,19 @@ func (cli *grpcClient) InitChainSync(validators []*types.Validator) (err error)
return cli.Error()
}
func (cli *grpcClient) BeginBlockSync(height uint64) (err error) {
cli.BeginBlockAsync(height)
func (cli *grpcClient) BeginBlockSync(hash []byte, header *types.Header) (err error) {
cli.BeginBlockAsync(hash, header)
return cli.Error()
}
func (cli *grpcClient) EndBlockSync(height uint64) (validators []*types.Validator, err error) {
func (cli *grpcClient) EndBlockSync(height uint64) (resEndBlock types.ResponseEndBlock, err error) {
reqres := cli.EndBlockAsync(height)
if err := cli.Error(); err != nil {
return nil, err
return resEndBlock, err
}
if resEndBlock_ := reqres.Response.GetEndBlock(); resEndBlock_ != nil {
return *resEndBlock_, nil
} else {
return resEndBlock, nil
}
return reqres.Response.GetEndBlock().Diffs, nil
}

+ 25
- 25
client/local_client.go View File

@ -1,10 +1,10 @@
package tmspcli
package abcicli
import (
"sync"
. "github.com/tendermint/go-common"
types "github.com/tendermint/tmsp/types"
types "github.com/tendermint/abci/types"
)
type localClient struct {
@ -51,11 +51,11 @@ func (app *localClient) EchoAsync(msg string) *ReqRes {
func (app *localClient) InfoAsync() *ReqRes {
app.mtx.Lock()
info := app.Application.Info()
resInfo := app.Application.Info()
app.mtx.Unlock()
return app.callback(
types.ToRequestInfo(),
types.ToResponseInfo(info),
types.ToResponseInfo(resInfo),
)
}
@ -69,13 +69,13 @@ func (app *localClient) SetOptionAsync(key string, value string) *ReqRes {
)
}
func (app *localClient) AppendTxAsync(tx []byte) *ReqRes {
func (app *localClient) DeliverTxAsync(tx []byte) *ReqRes {
app.mtx.Lock()
res := app.Application.AppendTx(tx)
res := app.Application.DeliverTx(tx)
app.mtx.Unlock()
return app.callback(
types.ToRequestAppendTx(tx),
types.ToResponseAppendTx(res.Code, res.Data, res.Log),
types.ToRequestDeliverTx(tx),
types.ToResponseDeliverTx(res.Code, res.Data, res.Log),
)
}
@ -122,28 +122,28 @@ func (app *localClient) InitChainAsync(validators []*types.Validator) *ReqRes {
return reqRes
}
func (app *localClient) BeginBlockAsync(height uint64) *ReqRes {
func (app *localClient) BeginBlockAsync(hash []byte, header *types.Header) *ReqRes {
app.mtx.Lock()
if bcApp, ok := app.Application.(types.BlockchainAware); ok {
bcApp.BeginBlock(height)
bcApp.BeginBlock(hash, header)
}
app.mtx.Unlock()
return app.callback(
types.ToRequestBeginBlock(height),
types.ToRequestBeginBlock(hash, header),
types.ToResponseBeginBlock(),
)
}
func (app *localClient) EndBlockAsync(height uint64) *ReqRes {
app.mtx.Lock()
var validators []*types.Validator
var resEndBlock types.ResponseEndBlock
if bcApp, ok := app.Application.(types.BlockchainAware); ok {
validators = bcApp.EndBlock(height)
resEndBlock = bcApp.EndBlock(height)
}
app.mtx.Unlock()
return app.callback(
types.ToRequestEndBlock(height),
types.ToResponseEndBlock(validators),
types.ToResponseEndBlock(resEndBlock),
)
}
@ -157,11 +157,11 @@ func (app *localClient) EchoSync(msg string) (res types.Result) {
return types.OK.SetData([]byte(msg))
}
func (app *localClient) InfoSync() (res types.Result) {
func (app *localClient) InfoSync() (resInfo types.ResponseInfo, err error) {
app.mtx.Lock()
info := app.Application.Info()
app.mtx.Unlock()
return types.OK.SetData([]byte(info))
defer app.mtx.Unlock()
resInfo = app.Application.Info()
return resInfo, nil
}
func (app *localClient) SetOptionSync(key string, value string) (res types.Result) {
@ -171,9 +171,9 @@ func (app *localClient) SetOptionSync(key string, value string) (res types.Resul
return types.OK.SetLog(log)
}
func (app *localClient) AppendTxSync(tx []byte) (res types.Result) {
func (app *localClient) DeliverTxSync(tx []byte) (res types.Result) {
app.mtx.Lock()
res = app.Application.AppendTx(tx)
res = app.Application.DeliverTx(tx)
app.mtx.Unlock()
return res
}
@ -208,22 +208,22 @@ func (app *localClient) InitChainSync(validators []*types.Validator) (err error)
return nil
}
func (app *localClient) BeginBlockSync(height uint64) (err error) {
func (app *localClient) BeginBlockSync(hash []byte, header *types.Header) (err error) {
app.mtx.Lock()
if bcApp, ok := app.Application.(types.BlockchainAware); ok {
bcApp.BeginBlock(height)
bcApp.BeginBlock(hash, header)
}
app.mtx.Unlock()
return nil
}
func (app *localClient) EndBlockSync(height uint64) (changedValidators []*types.Validator, err error) {
func (app *localClient) EndBlockSync(height uint64) (resEndBlock types.ResponseEndBlock, err error) {
app.mtx.Lock()
if bcApp, ok := app.Application.(types.BlockchainAware); ok {
changedValidators = bcApp.EndBlock(height)
resEndBlock = bcApp.EndBlock(height)
}
app.mtx.Unlock()
return changedValidators, nil
return resEndBlock, nil
}
//-------------------------------------------------------


+ 2
- 2
client/log.go View File

@ -1,7 +1,7 @@
package tmspcli
package abcicli
import (
"github.com/tendermint/go-logger"
)
var log = logger.New("module", "tmspcli")
var log = logger.New("module", "abcicli")

+ 36
- 27
client/socket_client.go View File

@ -1,4 +1,4 @@
package tmspcli
package abcicli
import (
"bufio"
@ -11,7 +11,7 @@ import (
"time"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
const (
@ -27,7 +27,7 @@ const flushThrottleMS = 20 // Don't wait longer than...
// the application in general is not meant to be interfaced
// with concurrent callers.
type socketClient struct {
QuitService
BaseService
reqQueue chan *ReqRes
flushTimer *ThrottleTimer
@ -52,14 +52,14 @@ func NewSocketClient(addr string, mustConnect bool) (*socketClient, error) {
reqSent: list.New(),
resCb: nil,
}
cli.QuitService = *NewQuitService(nil, "socketClient", cli)
cli.BaseService = *NewBaseService(nil, "socketClient", cli)
_, err := cli.Start() // Just start it, it's confusing for callers to remember to start.
return cli, err
}
func (cli *socketClient) OnStart() error {
cli.QuitService.OnStart()
cli.BaseService.OnStart()
var err error
var conn net.Conn
@ -70,7 +70,7 @@ RETRY_LOOP:
if cli.mustConnect {
return err
} else {
log.Warn(Fmt("tmsp.socketClient failed to connect to %v. Retrying...", cli.addr))
log.Warn(Fmt("abci.socketClient failed to connect to %v. Retrying...", cli.addr))
time.Sleep(time.Second * 3)
continue RETRY_LOOP
}
@ -86,7 +86,7 @@ RETRY_LOOP:
}
func (cli *socketClient) OnStop() {
cli.QuitService.OnStop()
cli.BaseService.OnStop()
cli.mtx.Lock()
defer cli.mtx.Unlock()
@ -109,7 +109,7 @@ func (cli *socketClient) StopForError(err error) {
}
cli.mtx.Unlock()
log.Warn(Fmt("Stopping tmsp.socketClient for error: %v", err.Error()))
log.Warn(Fmt("Stopping abci.socketClient for error: %v", err.Error()))
cli.Stop()
}
@ -140,7 +140,7 @@ func (cli *socketClient) sendRequestsRoutine(conn net.Conn) {
default:
// Probably will fill the buffer, or retry later.
}
case <-cli.QuitService.Quit:
case <-cli.BaseService.Quit:
return
case reqres := <-cli.reqQueue:
cli.willSendReq(reqres)
@ -243,8 +243,8 @@ func (cli *socketClient) SetOptionAsync(key string, value string) *ReqRes {
return cli.queueRequest(types.ToRequestSetOption(key, value))
}
func (cli *socketClient) AppendTxAsync(tx []byte) *ReqRes {
return cli.queueRequest(types.ToRequestAppendTx(tx))
func (cli *socketClient) DeliverTxAsync(tx []byte) *ReqRes {
return cli.queueRequest(types.ToRequestDeliverTx(tx))
}
func (cli *socketClient) CheckTxAsync(tx []byte) *ReqRes {
@ -263,8 +263,8 @@ func (cli *socketClient) InitChainAsync(validators []*types.Validator) *ReqRes {
return cli.queueRequest(types.ToRequestInitChain(validators))
}
func (cli *socketClient) BeginBlockAsync(height uint64) *ReqRes {
return cli.queueRequest(types.ToRequestBeginBlock(height))
func (cli *socketClient) BeginBlockAsync(hash []byte, header *types.Header) *ReqRes {
return cli.queueRequest(types.ToRequestBeginBlock(hash, header))
}
func (cli *socketClient) EndBlockAsync(height uint64) *ReqRes {
@ -292,14 +292,17 @@ func (cli *socketClient) FlushSync() error {
return cli.Error()
}
func (cli *socketClient) InfoSync() (res types.Result) {
func (cli *socketClient) InfoSync() (resInfo types.ResponseInfo, err error) {
reqres := cli.queueRequest(types.ToRequestInfo())
cli.FlushSync()
if err := cli.Error(); err != nil {
return types.ErrInternalError.SetLog(err.Error())
return resInfo, err
}
if resInfo_ := reqres.Response.GetInfo(); resInfo_ != nil {
return *resInfo_, nil
} else {
return resInfo, nil
}
resp := reqres.Response.GetInfo()
return types.Result{Code: OK, Data: []byte(resp.Info), Log: LOG}
}
func (cli *socketClient) SetOptionSync(key string, value string) (res types.Result) {
@ -312,13 +315,13 @@ func (cli *socketClient) SetOptionSync(key string, value string) (res types.Resu
return types.Result{Code: OK, Data: nil, Log: resp.Log}
}
func (cli *socketClient) AppendTxSync(tx []byte) (res types.Result) {
reqres := cli.queueRequest(types.ToRequestAppendTx(tx))
func (cli *socketClient) DeliverTxSync(tx []byte) (res types.Result) {
reqres := cli.queueRequest(types.ToRequestDeliverTx(tx))
cli.FlushSync()
if err := cli.Error(); err != nil {
return types.ErrInternalError.SetLog(err.Error())
}
resp := reqres.Response.GetAppendTx()
resp := reqres.Response.GetDeliverTx()
return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log}
}
@ -361,8 +364,8 @@ func (cli *socketClient) InitChainSync(validators []*types.Validator) (err error
return nil
}
func (cli *socketClient) BeginBlockSync(height uint64) (err error) {
cli.queueRequest(types.ToRequestBeginBlock(height))
func (cli *socketClient) BeginBlockSync(hash []byte, header *types.Header) (err error) {
cli.queueRequest(types.ToRequestBeginBlock(hash, header))
cli.FlushSync()
if err := cli.Error(); err != nil {
return err
@ -370,13 +373,17 @@ func (cli *socketClient) BeginBlockSync(height uint64) (err error) {
return nil
}
func (cli *socketClient) EndBlockSync(height uint64) (validators []*types.Validator, err error) {
func (cli *socketClient) EndBlockSync(height uint64) (resEndBlock types.ResponseEndBlock, err error) {
reqres := cli.queueRequest(types.ToRequestEndBlock(height))
cli.FlushSync()
if err := cli.Error(); err != nil {
return nil, err
return resEndBlock, err
}
if resEndBlock_ := reqres.Response.GetEndBlock(); resEndBlock_ != nil {
return *resEndBlock_, nil
} else {
return resEndBlock, nil
}
return reqres.Response.GetEndBlock().Diffs, nil
}
//----------------------------------------
@ -422,8 +429,8 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) {
_, ok = res.Value.(*types.Response_Info)
case *types.Request_SetOption:
_, ok = res.Value.(*types.Response_SetOption)
case *types.Request_AppendTx:
_, ok = res.Value.(*types.Response_AppendTx)
case *types.Request_DeliverTx:
_, ok = res.Value.(*types.Response_DeliverTx)
case *types.Request_CheckTx:
_, ok = res.Value.(*types.Response_CheckTx)
case *types.Request_Commit:
@ -432,6 +439,8 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) {
_, ok = res.Value.(*types.Response_Query)
case *types.Request_InitChain:
_, ok = res.Value.(*types.Response_InitChain)
case *types.Request_BeginBlock:
_, ok = res.Value.(*types.Response_BeginBlock)
case *types.Request_EndBlock:
_, ok = res.Value.(*types.Response_EndBlock)
}


cmd/tmsp-cli/tmsp-cli.go → cmd/abci-cli/tmsp-cli.go View File


+ 5
- 4
cmd/counter/main.go View File

@ -4,20 +4,20 @@ import (
"flag"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/example/counter"
"github.com/tendermint/tmsp/server"
"github.com/tendermint/abci/example/counter"
"github.com/tendermint/abci/server"
)
func main() {
addrPtr := flag.String("addr", "tcp://0.0.0.0:46658", "Listen address")
tmspPtr := flag.String("tmsp", "socket", "TMSP server: socket | grpc")
abciPtr := flag.String("abci", "socket", "ABCI server: socket | grpc")
serialPtr := flag.Bool("serial", false, "Enforce incrementing (serial) txs")
flag.Parse()
app := counter.NewCounterApplication(*serialPtr)
// Start the listener
_, err := server.NewServer(*addrPtr, *tmspPtr, app)
srv, err := server.NewServer(*addrPtr, *abciPtr, app)
if err != nil {
Exit(err.Error())
}
@ -25,6 +25,7 @@ func main() {
// Wait forever
TrapSignal(func() {
// Cleanup
srv.Stop()
})
}

+ 15
- 4
cmd/dummy/main.go View File

@ -4,18 +4,28 @@ import (
"flag"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/example/dummy"
"github.com/tendermint/tmsp/server"
"github.com/tendermint/abci/example/dummy"
"github.com/tendermint/abci/server"
"github.com/tendermint/abci/types"
)
func main() {
addrPtr := flag.String("addr", "tcp://0.0.0.0:46658", "Listen address")
tmspPtr := flag.String("tmsp", "socket", "socket | grpc")
abciPtr := flag.String("abci", "socket", "socket | grpc")
persistencePtr := flag.String("persist", "", "directory to use for a database")
flag.Parse()
// Create the application - in memory or persisted to disk
var app types.Application
if *persistencePtr == "" {
app = dummy.NewDummyApplication()
} else {
app = dummy.NewPersistentDummyApplication(*persistencePtr)
}
// Start the listener
_, err := server.NewServer(*addrPtr, *tmspPtr, dummy.NewDummyApplication())
srv, err := server.NewServer(*addrPtr, *abciPtr, app)
if err != nil {
Exit(err.Error())
}
@ -23,6 +33,7 @@ func main() {
// Wait forever
TrapSignal(func() {
// Cleanup
srv.Stop()
})
}

+ 76
- 0
example/chain_aware/chain_aware_app.go View File

@ -0,0 +1,76 @@
package main
import (
"flag"
. "github.com/tendermint/go-common"
"github.com/tendermint/abci/server"
"github.com/tendermint/abci/types"
)
func main() {
addrPtr := flag.String("addr", "tcp://0.0.0.0:46658", "Listen address")
abciPtr := flag.String("abci", "socket", "socket | grpc")
flag.Parse()
// Start the listener
srv, err := server.NewServer(*addrPtr, *abciPtr, NewChainAwareApplication())
if err != nil {
Exit(err.Error())
}
// Wait forever
TrapSignal(func() {
// Cleanup
srv.Stop()
})
}
type ChainAwareApplication struct {
beginCount int
endCount int
}
func NewChainAwareApplication() *ChainAwareApplication {
return &ChainAwareApplication{}
}
func (app *ChainAwareApplication) Info() types.ResponseInfo {
return types.ResponseInfo{}
}
func (app *ChainAwareApplication) SetOption(key string, value string) (log string) {
return ""
}
func (app *ChainAwareApplication) DeliverTx(tx []byte) types.Result {
return types.NewResultOK(nil, "")
}
func (app *ChainAwareApplication) CheckTx(tx []byte) types.Result {
return types.NewResultOK(nil, "")
}
func (app *ChainAwareApplication) Commit() types.Result {
return types.NewResultOK([]byte("nil"), "")
}
func (app *ChainAwareApplication) Query(query []byte) types.Result {
return types.NewResultOK([]byte(Fmt("%d,%d", app.beginCount, app.endCount)), "")
}
func (app *ChainAwareApplication) BeginBlock(hash []byte, header *types.Header) {
app.beginCount += 1
return
}
func (app *ChainAwareApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) {
app.endCount += 1
return
}
func (app *ChainAwareApplication) InitChain(vals []*types.Validator) {
return
}

+ 54
- 0
example/chain_aware/chain_aware_test.go View File

@ -0,0 +1,54 @@
package main
import (
"strconv"
"strings"
"testing"
. "github.com/tendermint/go-common"
"github.com/tendermint/abci/client"
"github.com/tendermint/abci/server"
"github.com/tendermint/abci/types"
)
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)
}
defer srv.Stop()
// Connect to the socket
client, err := abcicli.NewSocketClient("unix://test.sock", false)
if err != nil {
Exit(Fmt("Error starting socket client: %v", err.Error()))
}
client.Start()
defer client.Stop()
n := uint64(5)
hash := []byte("fake block hash")
header := &types.Header{}
for i := uint64(0); i < n; i++ {
client.BeginBlockSync(hash, header)
client.EndBlockSync(i)
client.CommitSync()
}
r := app.Query(nil)
spl := strings.Split(string(r.Data), ",")
if len(spl) != 2 {
t.Fatal("expected %d,%d ; got %s", n, n, string(r.Data))
}
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)
}
}

+ 22
- 16
example/counter/counter.go View File

@ -2,10 +2,9 @@ package counter
import (
"encoding/binary"
"fmt"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
type CounterApplication struct {
@ -18,8 +17,8 @@ func NewCounterApplication(serial bool) *CounterApplication {
return &CounterApplication{serial: serial}
}
func (app *CounterApplication) Info() string {
return Fmt("hashes:%v, txs:%v", app.hashCount, app.txCount)
func (app *CounterApplication) Info() types.ResponseInfo {
return types.ResponseInfo{Data: Fmt("{\"hashes\":%v,\"txs\":%v}", app.hashCount, app.txCount)}
}
func (app *CounterApplication) SetOption(key string, value string) (log string) {
@ -29,17 +28,16 @@ func (app *CounterApplication) SetOption(key string, value string) (log string)
return ""
}
func (app *CounterApplication) AppendTx(tx []byte) types.Result {
func (app *CounterApplication) DeliverTx(tx []byte) types.Result {
if app.serial {
if len(tx) > 8 {
return types.ErrEncodingError.SetLog(Fmt("Max tx size is 8 bytes, got %d", len(tx)))
}
tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue != uint64(app.txCount) {
return types.Result{
Code: types.CodeType_BadNonce,
Data: nil,
Log: fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue),
}
return types.ErrBadNonce.SetLog(Fmt("Invalid nonce. Expected %v, got %v", app.txCount, txValue))
}
}
app.txCount += 1
@ -48,15 +46,14 @@ func (app *CounterApplication) AppendTx(tx []byte) types.Result {
func (app *CounterApplication) CheckTx(tx []byte) types.Result {
if app.serial {
if len(tx) > 8 {
return types.ErrEncodingError.SetLog(Fmt("Max tx size is 8 bytes, got %d", len(tx)))
}
tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue < uint64(app.txCount) {
return types.Result{
Code: types.CodeType_BadNonce,
Data: nil,
Log: fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue),
}
return types.ErrBadNonce.SetLog(Fmt("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue))
}
}
return types.OK
@ -75,5 +72,14 @@ func (app *CounterApplication) Commit() types.Result {
}
func (app *CounterApplication) Query(query []byte) types.Result {
return types.NewResultOK(nil, fmt.Sprintf("Query is not supported"))
queryStr := string(query)
switch queryStr {
case "hash":
return types.NewResultOK(nil, Fmt("%v", app.hashCount))
case "tx":
return types.NewResultOK(nil, Fmt("%v", app.txCount))
}
return types.ErrUnknownRequest.SetLog(Fmt("Invalid nonce. Expected hash or tx, got %v", queryStr))
}

+ 31
- 0
example/dummy/README.md View File

@ -0,0 +1,31 @@
# Dummy
There are two app's here: the DummyApplication and the PersistentDummyApplication.
## DummyApplication
The DummyApplication is a simple merkle key-value store.
Transactions of the form `key=value` are stored as key-value pairs in the tree.
Transactions without an `=` sign set the value to the key.
The app has no replay protection (other than what the mempool provides).
## PersistentDummyApplication
The PersistentDummyApplication wraps the DummyApplication
and provides two additional features:
1) persistence of state across app restarts (using Tendermint's ABCI-Handshake mechanism)
2) validator set changes
The state is persisted in leveldb along with the last block committed,
and the Handshake allows any necessary blocks to be replayed.
Validator set changes are effected using the following transaction format:
```
val:pubkey1/power1,addr2/power2,addr3/power3"
```
where `power1` is the new voting power for the validator with `pubkey1` (possibly a new one).
There is no sybil protection against new validators joining.
Validators can be removed by setting their power to `0`.

+ 16
- 10
example/dummy/dummy.go View File

@ -1,11 +1,13 @@
package dummy
import (
"encoding/hex"
"strings"
. "github.com/tendermint/go-common"
"github.com/tendermint/go-merkle"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/go-wire"
"github.com/tendermint/abci/types"
)
type DummyApplication struct {
@ -13,15 +15,12 @@ type DummyApplication struct {
}
func NewDummyApplication() *DummyApplication {
state := merkle.NewIAVLTree(
0,
nil,
)
state := merkle.NewIAVLTree(0, nil)
return &DummyApplication{state: state}
}
func (app *DummyApplication) Info() string {
return Fmt("size:%v", app.state.Size())
func (app *DummyApplication) Info() (resInfo types.ResponseInfo) {
return types.ResponseInfo{Data: Fmt("{\"size\":%v}", app.state.Size())}
}
func (app *DummyApplication) SetOption(key string, value string) (log string) {
@ -29,7 +28,7 @@ func (app *DummyApplication) SetOption(key string, value string) (log string) {
}
// tx is either "key=value" or just arbitrary bytes
func (app *DummyApplication) AppendTx(tx []byte) types.Result {
func (app *DummyApplication) DeliverTx(tx []byte) types.Result {
parts := strings.Split(string(tx), "=")
if len(parts) == 2 {
app.state.Set([]byte(parts[0]), []byte(parts[1]))
@ -50,6 +49,13 @@ func (app *DummyApplication) Commit() types.Result {
func (app *DummyApplication) Query(query []byte) types.Result {
index, value, exists := app.state.Get(query)
resStr := Fmt("Index=%v value=%v exists=%v", index, string(value), exists)
return types.NewResultOK([]byte(resStr), "")
queryResult := QueryResult{index, string(value), hex.EncodeToString(value), exists}
return types.NewResultOK(wire.JSONBytes(queryResult), "")
}
type QueryResult struct {
Index int `json:"index"`
Value string `json:"value"`
ValueHex string `json:"valueHex"`
Exists bool `json:"exists"`
}

+ 203
- 0
example/dummy/dummy_test.go View File

@ -0,0 +1,203 @@
package dummy
import (
"bytes"
"io/ioutil"
"sort"
"testing"
. "github.com/tendermint/go-common"
"github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire"
"github.com/tendermint/abci/types"
)
func testDummy(t *testing.T, dummy types.Application, tx []byte, key, value string) {
if r := dummy.DeliverTx(tx); r.IsErr() {
t.Fatal(r)
}
if r := dummy.DeliverTx(tx); r.IsErr() {
t.Fatal(r)
}
r := dummy.Query([]byte(key))
if r.IsErr() {
t.Fatal(r)
}
q := new(QueryResult)
if err := wire.ReadJSONBytes(r.Data, q); err != nil {
t.Fatal(err)
}
if q.Value != value {
t.Fatalf("Got %s, expected %s", q.Value, value)
}
}
func TestDummyKV(t *testing.T) {
dummy := NewDummyApplication()
key := "abc"
value := key
tx := []byte(key)
testDummy(t, dummy, tx, key, value)
value = "def"
tx = []byte(key + "=" + value)
testDummy(t, dummy, tx, key, value)
}
func TestPersistentDummyKV(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO
if err != nil {
t.Fatal(err)
}
dummy := NewPersistentDummyApplication(dir)
key := "abc"
value := key
tx := []byte(key)
testDummy(t, dummy, tx, key, value)
value = "def"
tx = []byte(key + "=" + value)
testDummy(t, dummy, tx, key, value)
}
func TestPersistentDummyInfo(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO
if err != nil {
t.Fatal(err)
}
dummy := NewPersistentDummyApplication(dir)
height := uint64(0)
resInfo := dummy.Info()
if resInfo.LastBlockHeight != height {
t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
}
// make and apply block
height = uint64(1)
hash := []byte("foo")
header := &types.Header{
Height: uint64(height),
}
dummy.BeginBlock(hash, header)
dummy.EndBlock(height)
dummy.Commit()
resInfo = dummy.Info()
if resInfo.LastBlockHeight != height {
t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
}
}
// add a validator, remove a validator, update a validator
func TestValSetChanges(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO
if err != nil {
t.Fatal(err)
}
dummy := NewPersistentDummyApplication(dir)
// init with some validators
total := 10
nInit := 5
vals := make([]*types.Validator, total)
for i := 0; i < total; i++ {
pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(Fmt("test%d", i))).PubKey().Bytes()
power := RandInt()
vals[i] = &types.Validator{pubkey, uint64(power)}
}
// iniitalize with the first nInit
dummy.InitChain(vals[:nInit])
vals1, vals2 := vals[:nInit], dummy.Validators()
valsEqual(t, vals1, vals2)
var v1, v2, v3 *types.Validator
// add some validators
v1, v2 = vals[nInit], vals[nInit+1]
diff := []*types.Validator{v1, v2}
tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power)
tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power)
makeApplyBlock(t, dummy, 1, diff, tx1, tx2)
vals1, vals2 = vals[:nInit+2], dummy.Validators()
valsEqual(t, vals1, vals2)
// remove some validators
v1, v2, v3 = vals[nInit-2], vals[nInit-1], vals[nInit]
v1.Power = 0
v2.Power = 0
v3.Power = 0
diff = []*types.Validator{v1, v2, v3}
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power)
tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power)
makeApplyBlock(t, dummy, 2, diff, tx1, tx2, tx3)
vals1 = append(vals[:nInit-2], vals[nInit+1])
vals2 = dummy.Validators()
valsEqual(t, vals1, vals2)
// update some validators
v1 = vals[0]
if v1.Power == 5 {
v1.Power = 6
} else {
v1.Power = 5
}
diff = []*types.Validator{v1}
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
makeApplyBlock(t, dummy, 3, diff, tx1)
vals1 = append([]*types.Validator{v1}, vals1[1:len(vals1)]...)
vals2 = dummy.Validators()
valsEqual(t, vals1, vals2)
}
func makeApplyBlock(t *testing.T, dummy types.Application, heightInt int, diff []*types.Validator, txs ...[]byte) {
// make and apply block
height := uint64(heightInt)
hash := []byte("foo")
header := &types.Header{
Height: height,
}
dummyChain := dummy.(types.BlockchainAware) // hmm...
dummyChain.BeginBlock(hash, header)
for _, tx := range txs {
if r := dummy.DeliverTx(tx); r.IsErr() {
t.Fatal(r)
}
}
resEndBlock := dummyChain.EndBlock(height)
dummy.Commit()
valsEqual(t, diff, resEndBlock.Diffs)
}
// order doesn't matter
func valsEqual(t *testing.T, vals1, vals2 []*types.Validator) {
if len(vals1) != len(vals2) {
t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1))
}
sort.Sort(types.Validators(vals1))
sort.Sort(types.Validators(vals2))
for i, v1 := range vals1 {
v2 := vals2[i]
if !bytes.Equal(v1.PubKey, v2.PubKey) ||
v1.Power != v2.Power {
t.Fatalf("vals dont match at index %d. got %X/%d , expected %X/%d", i, v2.PubKey, v2.Power, v1.PubKey, v1.Power)
}
}
}

+ 7
- 0
example/dummy/log.go View File

@ -0,0 +1,7 @@
package dummy
import (
"github.com/tendermint/go-logger"
)
var log = logger.New("module", "dummy")

+ 229
- 0
example/dummy/persistent_dummy.go View File

@ -0,0 +1,229 @@
package dummy
import (
"bytes"
"encoding/hex"
"strconv"
"strings"
. "github.com/tendermint/go-common"
dbm "github.com/tendermint/go-db"
"github.com/tendermint/go-merkle"
"github.com/tendermint/go-wire"
"github.com/tendermint/abci/types"
)
const (
ValidatorSetChangePrefix string = "val:"
)
//-----------------------------------------
type PersistentDummyApplication struct {
app *DummyApplication
db dbm.DB
// latest received
// TODO: move to merkle tree?
blockHeader *types.Header
// validator set
changes []*types.Validator
}
func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication {
db := dbm.NewDB("dummy", "leveldb", dbDir)
lastBlock := LoadLastBlock(db)
stateTree := merkle.NewIAVLTree(0, db)
stateTree.Load(lastBlock.AppHash)
log.Notice("Loaded state", "block", lastBlock.Height, "root", stateTree.Hash())
return &PersistentDummyApplication{
app: &DummyApplication{state: stateTree},
db: db,
}
}
func (app *PersistentDummyApplication) Info() (resInfo types.ResponseInfo) {
resInfo = app.app.Info()
lastBlock := LoadLastBlock(app.db)
resInfo.LastBlockHeight = lastBlock.Height
resInfo.LastBlockAppHash = lastBlock.AppHash
return resInfo
}
func (app *PersistentDummyApplication) SetOption(key string, value string) (log string) {
return app.app.SetOption(key, value)
}
// tx is either "key=value" or just arbitrary bytes
func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result {
// if it starts with "val:", update the validator set
// format is "val:pubkey/power"
if isValidatorTx(tx) {
// update validators in the merkle tree
// and in app.changes
return app.execValidatorTx(tx)
}
// otherwise, update the key-value store
return app.app.DeliverTx(tx)
}
func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result {
return app.app.CheckTx(tx)
}
func (app *PersistentDummyApplication) Commit() types.Result {
// Save
appHash := app.app.state.Save()
log.Info("Saved state", "root", appHash)
lastBlock := LastBlockInfo{
Height: app.blockHeader.Height,
AppHash: appHash, // this hash will be in the next block header
}
SaveLastBlock(app.db, lastBlock)
return types.NewResultOK(appHash, "")
}
func (app *PersistentDummyApplication) Query(query []byte) types.Result {
return app.app.Query(query)
}
// Save the validators in the merkle tree
func (app *PersistentDummyApplication) InitChain(validators []*types.Validator) {
for _, v := range validators {
r := app.updateValidator(v)
if r.IsErr() {
log.Error("Error updating validators", "r", r)
}
}
}
// Track the block hash and header information
func (app *PersistentDummyApplication) BeginBlock(hash []byte, header *types.Header) {
// update latest block info
app.blockHeader = header
// reset valset changes
app.changes = make([]*types.Validator, 0)
}
// Update the validator set
func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) {
return types.ResponseEndBlock{Diffs: app.changes}
}
//-----------------------------------------
// persist the last block info
var lastBlockKey = []byte("lastblock")
type LastBlockInfo struct {
Height uint64
AppHash []byte
}
// Get the last block from the db
func LoadLastBlock(db dbm.DB) (lastBlock LastBlockInfo) {
buf := db.Get(lastBlockKey)
if len(buf) != 0 {
r, n, err := bytes.NewReader(buf), new(int), new(error)
wire.ReadBinaryPtr(&lastBlock, r, 0, n, err)
if *err != nil {
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
Exit(Fmt("Data has been corrupted or its spec has changed: %v\n", *err))
}
// TODO: ensure that buf is completely read.
}
return lastBlock
}
func SaveLastBlock(db dbm.DB, lastBlock LastBlockInfo) {
log.Notice("Saving block", "height", lastBlock.Height, "root", lastBlock.AppHash)
buf, n, err := new(bytes.Buffer), new(int), new(error)
wire.WriteBinary(lastBlock, buf, n, err)
if *err != nil {
// TODO
PanicCrisis(*err)
}
db.Set(lastBlockKey, buf.Bytes())
}
//---------------------------------------------
// update validators
func (app *PersistentDummyApplication) Validators() (validators []*types.Validator) {
app.app.state.Iterate(func(key, value []byte) bool {
if isValidatorTx(key) {
validator := new(types.Validator)
err := types.ReadMessage(bytes.NewBuffer(value), validator)
if err != nil {
panic(err)
}
validators = append(validators, validator)
}
return false
})
return
}
func MakeValSetChangeTx(pubkey []byte, power uint64) []byte {
return []byte(Fmt("val:%X/%d", pubkey, power))
}
func isValidatorTx(tx []byte) bool {
if strings.HasPrefix(string(tx), ValidatorSetChangePrefix) {
return true
}
return false
}
// format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx
func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result {
tx = tx[len(ValidatorSetChangePrefix):]
pubKeyAndPower := strings.Split(string(tx), "/")
if len(pubKeyAndPower) != 2 {
return types.ErrEncodingError.SetLog(Fmt("Expected 'pubkey/power'. Got %v", pubKeyAndPower))
}
pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1]
pubkey, err := hex.DecodeString(pubkeyS)
if err != nil {
return types.ErrEncodingError.SetLog(Fmt("Pubkey (%s) is invalid hex", pubkeyS))
}
power, err := strconv.Atoi(powerS)
if err != nil {
return types.ErrEncodingError.SetLog(Fmt("Power (%s) is not an int", powerS))
}
// update
return app.updateValidator(&types.Validator{pubkey, uint64(power)})
}
// add, update, or remove a validator
func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types.Result {
key := []byte("val:" + string(v.PubKey))
if v.Power == 0 {
// remove validator
if !app.app.state.Has(key) {
return types.ErrUnauthorized.SetLog(Fmt("Cannot remove non-existent validator %X", key))
}
app.app.state.Remove(key)
} else {
// add or update validator
value := bytes.NewBuffer(make([]byte, 0))
if err := types.WriteMessage(v, value); err != nil {
return types.ErrInternalError.SetLog(Fmt("Error encoding validator: %v", err))
}
app.app.state.Set(key, value.Bytes())
}
// we only update the changes array if we succesfully updated the tree
app.changes = append(app.changes, v)
return types.OK
}

+ 24
- 24
example/example_test.go View File

@ -11,11 +11,11 @@ import (
"google.golang.org/grpc"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/client"
"github.com/tendermint/tmsp/example/dummy"
nilapp "github.com/tendermint/tmsp/example/nil"
"github.com/tendermint/tmsp/server"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/client"
"github.com/tendermint/abci/example/dummy"
nilapp "github.com/tendermint/abci/example/nil"
"github.com/tendermint/abci/server"
"github.com/tendermint/abci/types"
)
func TestDummy(t *testing.T) {
@ -35,7 +35,7 @@ func TestGRPC(t *testing.T) {
func testStream(t *testing.T, app types.Application) {
numAppendTxs := 200000
numDeliverTxs := 200000
// Start the listener
server, err := server.NewSocketServer("unix://test.sock", app)
@ -45,7 +45,7 @@ func testStream(t *testing.T, app types.Application) {
defer server.Stop()
// Connect to the socket
client, err := tmspcli.NewSocketClient("unix://test.sock", false)
client, err := abcicli.NewSocketClient("unix://test.sock", false)
if err != nil {
Exit(Fmt("Error starting socket client: %v", err.Error()))
}
@ -57,15 +57,15 @@ func testStream(t *testing.T, app types.Application) {
client.SetResponseCallback(func(req *types.Request, res *types.Response) {
// Process response
switch r := res.Value.(type) {
case *types.Response_AppendTx:
case *types.Response_DeliverTx:
counter += 1
if r.AppendTx.Code != types.CodeType_OK {
t.Error("AppendTx failed with ret_code", r.AppendTx.Code)
if r.DeliverTx.Code != types.CodeType_OK {
t.Error("DeliverTx failed with ret_code", r.DeliverTx.Code)
}
if counter > numAppendTxs {
t.Fatalf("Too many AppendTx responses. Got %d, expected %d", counter, numAppendTxs)
if counter > numDeliverTxs {
t.Fatalf("Too many DeliverTx responses. Got %d, expected %d", counter, numDeliverTxs)
}
if counter == numAppendTxs {
if counter == numDeliverTxs {
go func() {
time.Sleep(time.Second * 2) // Wait for a bit to allow counter overflow
close(done)
@ -80,9 +80,9 @@ func testStream(t *testing.T, app types.Application) {
})
// Write requests
for counter := 0; counter < numAppendTxs; counter++ {
for counter := 0; counter < numDeliverTxs; counter++ {
// Send request
reqRes := client.AppendTxAsync([]byte("test"))
reqRes := client.DeliverTxAsync([]byte("test"))
_ = reqRes
// check err ?
@ -108,7 +108,7 @@ func dialerFunc(addr string, timeout time.Duration) (net.Conn, error) {
func testGRPCSync(t *testing.T, app *types.GRPCApplication) {
numAppendTxs := 2000
numDeliverTxs := 2000
// Start the listener
server, err := server.NewGRPCServer("unix://test.sock", app)
@ -124,24 +124,24 @@ func testGRPCSync(t *testing.T, app *types.GRPCApplication) {
}
defer conn.Close()
client := types.NewTMSPApplicationClient(conn)
client := types.NewABCIApplicationClient(conn)
// Write requests
for counter := 0; counter < numAppendTxs; counter++ {
for counter := 0; counter < numDeliverTxs; counter++ {
// Send request
response, err := client.AppendTx(context.Background(), &types.RequestAppendTx{[]byte("test")})
response, err := client.DeliverTx(context.Background(), &types.RequestDeliverTx{[]byte("test")})
if err != nil {
t.Fatalf("Error in GRPC AppendTx: %v", err.Error())
t.Fatalf("Error in GRPC DeliverTx: %v", err.Error())
}
counter += 1
if response.Code != types.CodeType_OK {
t.Error("AppendTx failed with ret_code", response.Code)
t.Error("DeliverTx failed with ret_code", response.Code)
}
if counter > numAppendTxs {
t.Fatal("Too many AppendTx responses")
if counter > numDeliverTxs {
t.Fatal("Too many DeliverTx responses")
}
t.Log("response", counter)
if counter == numAppendTxs {
if counter == numDeliverTxs {
go func() {
time.Sleep(time.Second * 2) // Wait for a bit to allow counter overflow
}()


+ 1
- 1
example/js/README.md View File

@ -1 +1 @@
This example has been moved here: https://github.com/tendermint/js-tmsp/tree/master/example
This example has been moved here: https://github.com/tendermint/js-abci/tree/master/example

+ 4
- 4
example/nil/nil_app.go View File

@ -1,7 +1,7 @@
package nilapp
import (
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
type NilApplication struct {
@ -11,15 +11,15 @@ func NewNilApplication() *NilApplication {
return &NilApplication{}
}
func (app *NilApplication) Info() string {
return "nil"
func (app *NilApplication) Info() (resInfo types.ResponseInfo) {
return
}
func (app *NilApplication) SetOption(key string, value string) (log string) {
return ""
}
func (app *NilApplication) AppendTx(tx []byte) types.Result {
func (app *NilApplication) DeliverTx(tx []byte) types.Result {
return types.NewResultOK(nil, "")
}


example/python/tmsp/__init__.py → example/python/abci/__init__.py View File


example/python/tmsp/msg.py → example/python/abci/msg.py View File


example/python/tmsp/reader.py → example/python/abci/reader.py View File


example/python/tmsp/server.py → example/python/abci/server.py View File


example/python/tmsp/wire.py → example/python/abci/wire.py View File


+ 6
- 6
example/python/app.py View File

@ -1,8 +1,8 @@
import sys
from tmsp.wire import hex2bytes, decode_big_endian, encode_big_endian
from tmsp.server import TMSPServer
from tmsp.reader import BytesBuffer
from abci.wire import hex2bytes, decode_big_endian, encode_big_endian
from abci.server import ABCIServer
from abci.reader import BytesBuffer
class CounterApplication():
@ -24,7 +24,7 @@ class CounterApplication():
self.serial = True
return 0
def append_tx(self, txBytes):
def deliver_tx(self, txBytes):
if self.serial:
txByteArray = bytearray(txBytes)
if len(txBytes) >= 2 and txBytes[:2] == "0x":
@ -75,8 +75,8 @@ if __name__ == '__main__':
print "too many arguments"
quit()
print 'TMSP Demo APP (Python)'
print 'ABCI Demo APP (Python)'
app = CounterApplication()
server = TMSPServer(app, port)
server = ABCIServer(app, port)
server.main_loop()

example/python3/tmsp/__init__.py → example/python3/abci/__init__.py View File


example/python3/tmsp/msg.py → example/python3/abci/msg.py View File


example/python3/tmsp/reader.py → example/python3/abci/reader.py View File


example/python3/tmsp/server.py → example/python3/abci/server.py View File


example/python3/tmsp/wire.py → example/python3/abci/wire.py View File


+ 6
- 6
example/python3/app.py View File

@ -1,8 +1,8 @@
import sys
from tmsp.wire import hex2bytes, decode_big_endian, encode_big_endian
from tmsp.server import TMSPServer
from tmsp.reader import BytesBuffer
from abci.wire import hex2bytes, decode_big_endian, encode_big_endian
from abci.server import ABCIServer
from abci.reader import BytesBuffer
class CounterApplication():
@ -24,7 +24,7 @@ class CounterApplication():
self.serial = True
return 0
def append_tx(self, txBytes):
def deliver_tx(self, txBytes):
if self.serial:
txByteArray = bytearray(txBytes)
if len(txBytes) >= 2 and txBytes[:2] == "0x":
@ -75,8 +75,8 @@ if __name__ == '__main__':
print("too many arguments")
quit()
print('TMSP Demo APP (Python)')
print('ABCI Demo APP (Python)')
app = CounterApplication()
server = TMSPServer(app, port)
server = ABCIServer(app, port)
server.main_loop()

+ 25
- 18
glide.lock View File

@ -1,26 +1,26 @@
hash: 65769cd1c6d94a9733e9109e1bd7004f31b8df60c6d2cd47d9d8aecb9a94ffc2
updated: 2016-11-15T14:05:15.057591061-05:00
hash: c050dfd4a6af84ab490a78c1580ac74caf42ed00799de7017d2ee325b806f77e
updated: 2017-01-12T21:19:13.812049926-05:00
imports:
- name: github.com/btcsuite/btcd
version: d9a674e1b7bc09d0830d6986c71cf5f535d753c3
version: 153dca5c1e4b5d1ea1523592495e5bedfa503391
subpackages:
- btcec
- name: github.com/btcsuite/fastsha256
version: 637e656429416087660c84436a2a035d69d54e2e
- name: github.com/go-stack/stack
version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82
- name: github.com/golang/protobuf
version: da116c3771bf4a398a43f44e069195ef1c9688ef
version: 8ee79997227bf9b34611aee7946ae64735e6fd93
subpackages:
- proto
- name: github.com/golang/snappy
version: d9eb7a3d35ec988b8585d4a0068e462c27d28380
- name: github.com/jmhodges/levigo
version: c42d9e0ca023e2198120196f842701bb4c55d7b9
- name: github.com/mattn/go-colorable
version: d228849504861217f796da67fae4f6e347643f15
- name: github.com/mattn/go-isatty
version: 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8
version: 30a891c33c7cde7b02a981314b4228ec99380cca
- name: github.com/syndtr/goleveldb
version: 6b4daa5362b502898ddf367c5c11deb9e7a5c727
version: 23851d93a2292dcc56e71a18ec9e0624d84a0f65
subpackages:
- leveldb
- leveldb/cache
@ -40,27 +40,27 @@ imports:
- edwards25519
- extra25519
- name: github.com/tendermint/go-common
version: 1c62bb6dadc6269aeecad5f9e7b153d950a54362
version: 70e694ee76f09058ea38c9ba81b4aa621bd54df1
- name: github.com/tendermint/go-crypto
version: 4b11d62bdb324027ea01554e5767b71174680ba0
- name: github.com/tendermint/go-db
version: 31fdd21c7eaeed53e0ea7ca597fb1e960e2988a5
version: 2645626c33d8702739e52a61a55d705c2dfe4530
- name: github.com/tendermint/go-logger
version: cefb3a45c0bf3c493a04e9bcd9b1540528be59f2
- name: github.com/tendermint/go-merkle
version: 05042c6ab9cad51d12e4cecf717ae68e3b1409a8
version: 2979c7eb8aa020fa1cf203654907dbb889703888
- name: github.com/tendermint/go-process
version: ba01cfbb58d446673beff17e72883cb49c835fb9
version: 7f507d69fa4c13b34e7a17ff5c87d1eaaa759145
- name: github.com/tendermint/go-wire
version: 287d8caeae91d21686340f5f87170560531681e6
version: 2f3b7aafe21c80b19b6ee3210ecb3e3d07c7a471
- name: github.com/tendermint/log15
version: ae0f3d6450da9eac7074b439c8e1c3cabf0d5ce6
subpackages:
- term
- name: github.com/urfave/cli
version: b4f4786f378c0c1d3336b5bb798094b166edf5a9
version: 8ef3805c9de2519805c3f060524b695bba2cd715
- name: golang.org/x/crypto
version: 9477e0b78b9ac3d0b03822fd95422e2fe07627cd
version: 7c6cc321c680f03b9ef0764448e780704f486b51
subpackages:
- nacl/secretbox
- openpgp/armor
@ -69,7 +69,7 @@ imports:
- ripemd160
- salsa20/salsa
- name: golang.org/x/net
version: cac22060de4e495155959e69adcb4b45763ccb10
version: 60c41d1de8da134c05b7b40154a9a82bf5b7edb9
subpackages:
- context
- http2
@ -79,11 +79,18 @@ imports:
- lex/httplex
- trace
- name: golang.org/x/sys
version: b699b7032584f0953262cb2788a0ca19bb494703
version: d75a52659825e75fff6158388dddc6a5b04f9ba5
subpackages:
- unix
- name: golang.org/x/text
version: 44f4f658a783b0cee41fe0a23b8fc91d9c120558
subpackages:
- secure/bidirule
- transform
- unicode/bidi
- unicode/norm
- name: google.golang.org/grpc
version: 0d9891286aca15aeb2b0a73be9f5946c3cfefa85
version: 50955793b0183f9de69bd78e2ec251cf20aab121
subpackages:
- codes
- credentials


+ 6
- 1
glide.yaml View File

@ -1,13 +1,18 @@
package: github.com/tendermint/tmsp
package: github.com/tendermint/abci
import:
- package: github.com/golang/protobuf
subpackages:
- proto
- package: github.com/tendermint/go-common
version: develop
- package: github.com/tendermint/go-crypto
- package: github.com/tendermint/go-logger
- package: github.com/tendermint/go-db
version: develop
- package: github.com/tendermint/go-merkle
version: develop
- package: github.com/tendermint/go-process
version: develop
- package: github.com/tendermint/go-wire
- package: github.com/urfave/cli
- package: golang.org/x/net


+ 8
- 8
server/grpc_server.go View File

@ -7,23 +7,23 @@ import (
"google.golang.org/grpc"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
// var maxNumberConnections = 2
type GRPCServer struct {
QuitService
BaseService
proto string
addr string
listener net.Listener
server *grpc.Server
app types.TMSPApplicationServer
app types.ABCIApplicationServer
}
func NewGRPCServer(protoAddr string, app types.TMSPApplicationServer) (Service, error) {
func NewGRPCServer(protoAddr string, app types.ABCIApplicationServer) (Service, error) {
parts := strings.SplitN(protoAddr, "://", 2)
proto, addr := parts[0], parts[1]
s := &GRPCServer{
@ -32,25 +32,25 @@ func NewGRPCServer(protoAddr string, app types.TMSPApplicationServer) (Service,
listener: nil,
app: app,
}
s.QuitService = *NewQuitService(nil, "TMSPServer", s)
s.BaseService = *NewBaseService(nil, "ABCIServer", s)
_, err := s.Start() // Just start it
return s, err
}
func (s *GRPCServer) OnStart() error {
s.QuitService.OnStart()
s.BaseService.OnStart()
ln, err := net.Listen(s.proto, s.addr)
if err != nil {
return err
}
s.listener = ln
s.server = grpc.NewServer()
types.RegisterTMSPApplicationServer(s.server, s.app)
types.RegisterABCIApplicationServer(s.server, s.app)
go s.server.Serve(s.listener)
return nil
}
func (s *GRPCServer) OnStop() {
s.QuitService.OnStop()
s.BaseService.OnStop()
s.server.Stop()
}

+ 1
- 1
server/log.go View File

@ -4,4 +4,4 @@ import (
"github.com/tendermint/go-logger"
)
var log = logger.New("module", "tmsp-server")
var log = logger.New("module", "abci-server")

+ 1
- 1
server/server.go View File

@ -4,7 +4,7 @@ import (
"fmt"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
func NewServer(protoAddr, transport string, app types.Application) (Service, error) {


+ 19
- 16
server/socket_server.go View File

@ -9,13 +9,13 @@ import (
"sync"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
// var maxNumberConnections = 2
type SocketServer struct {
QuitService
BaseService
proto string
addr string
@ -39,13 +39,13 @@ func NewSocketServer(protoAddr string, app types.Application) (Service, error) {
app: app,
conns: make(map[int]net.Conn),
}
s.QuitService = *NewQuitService(nil, "TMSPServer", s)
s.BaseService = *NewBaseService(nil, "ABCIServer", s)
_, err := s.Start() // Just start it
return s, err
}
func (s *SocketServer) OnStart() error {
s.QuitService.OnStart()
s.BaseService.OnStart()
ln, err := net.Listen(s.proto, s.addr)
if err != nil {
return err
@ -56,7 +56,7 @@ func (s *SocketServer) OnStart() error {
}
func (s *SocketServer) OnStop() {
s.QuitService.OnStop()
s.BaseService.OnStop()
s.listener.Close()
s.connsMtx.Lock()
@ -168,15 +168,15 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types
case *types.Request_Flush:
responses <- types.ToResponseFlush()
case *types.Request_Info:
data := s.app.Info()
responses <- types.ToResponseInfo(data)
resInfo := s.app.Info()
responses <- types.ToResponseInfo(resInfo)
case *types.Request_SetOption:
so := r.SetOption
logStr := s.app.SetOption(so.Key, so.Value)
responses <- types.ToResponseSetOption(logStr)
case *types.Request_AppendTx:
res := s.app.AppendTx(r.AppendTx.Tx)
responses <- types.ToResponseAppendTx(res.Code, res.Data, res.Log)
case *types.Request_DeliverTx:
res := s.app.DeliverTx(r.DeliverTx.Tx)
responses <- types.ToResponseDeliverTx(res.Code, res.Data, res.Log)
case *types.Request_CheckTx:
res := s.app.CheckTx(r.CheckTx.Tx)
responses <- types.ToResponseCheckTx(res.Code, res.Data, res.Log)
@ -189,16 +189,19 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types
case *types.Request_InitChain:
if app, ok := s.app.(types.BlockchainAware); ok {
app.InitChain(r.InitChain.Validators)
responses <- types.ToResponseInitChain()
} else {
responses <- types.ToResponseInitChain()
}
responses <- types.ToResponseInitChain()
case *types.Request_BeginBlock:
if app, ok := s.app.(types.BlockchainAware); ok {
app.BeginBlock(r.BeginBlock.Hash, r.BeginBlock.Header)
}
responses <- types.ToResponseBeginBlock()
case *types.Request_EndBlock:
if app, ok := s.app.(types.BlockchainAware); ok {
validators := app.EndBlock(r.EndBlock.Height)
responses <- types.ToResponseEndBlock(validators)
resEndBlock := app.EndBlock(r.EndBlock.Height)
responses <- types.ToResponseEndBlock(resEndBlock)
} else {
responses <- types.ToResponseEndBlock(nil)
responses <- types.ToResponseEndBlock(types.ResponseEndBlock{})
}
default:
responses <- types.ToResponseException("Unknown request")


+ 1
- 1
tests/benchmarks/parallel/parallel.go View File

@ -6,7 +6,7 @@ import (
//"encoding/hex"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
func main() {


+ 1
- 1
tests/benchmarks/simple/simple.go View File

@ -9,7 +9,7 @@ import (
//"encoding/hex"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
func main() {


+ 17
- 16
tests/test_app/app.go View File

@ -7,23 +7,24 @@ import (
. "github.com/tendermint/go-common"
"github.com/tendermint/go-process"
"github.com/tendermint/tmsp/client"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/client"
"github.com/tendermint/abci/types"
)
//----------------------------------------
func StartApp(tmspApp string) *process.Process {
func StartApp(abciApp string) *process.Process {
// Start the app
//outBuf := NewBufferCloser(nil)
proc, err := process.StartProcess("tmsp_app",
proc, err := process.StartProcess("abci_app",
"",
"bash",
[]string{"-c", tmspApp},
[]string{"-c", abciApp},
nil,
os.Stdout,
)
if err != nil {
panic("running tmsp_app: " + err.Error())
panic("running abci_app: " + err.Error())
}
// TODO a better way to handle this?
@ -32,16 +33,16 @@ func StartApp(tmspApp string) *process.Process {
return proc
}
func StartClient(tmspType string) tmspcli.Client {
func StartClient(abciType string) abcicli.Client {
// Start client
client, err := tmspcli.NewClient("tcp://127.0.0.1:46658", tmspType, true)
client, err := abcicli.NewClient("tcp://127.0.0.1:46658", abciType, true)
if err != nil {
panic("connecting to tmsp_app: " + err.Error())
panic("connecting to abci_app: " + err.Error())
}
return client
}
func SetOption(client tmspcli.Client, key, value string) {
func SetOption(client abcicli.Client, key, value string) {
res := client.SetOptionSync(key, value)
_, _, log := res.Code, res.Data, res.Log
if res.IsErr() {
@ -49,7 +50,7 @@ func SetOption(client tmspcli.Client, key, value string) {
}
}
func Commit(client tmspcli.Client, hashExp []byte) {
func Commit(client abcicli.Client, hashExp []byte) {
res := client.CommitSync()
_, data, log := res.Code, res.Data, res.Log
if res.IsErr() {
@ -61,20 +62,20 @@ func Commit(client tmspcli.Client, hashExp []byte) {
}
}
func AppendTx(client tmspcli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) {
res := client.AppendTxSync(txBytes)
func DeliverTx(client abcicli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) {
res := client.DeliverTxSync(txBytes)
code, data, log := res.Code, res.Data, res.Log
if code != codeExp {
panic(Fmt("AppendTx response code was unexpected. Got %v expected %v. Log: %v",
panic(Fmt("DeliverTx response code was unexpected. Got %v expected %v. Log: %v",
code, codeExp, log))
}
if !bytes.Equal(data, dataExp) {
panic(Fmt("AppendTx response data was unexpected. Got %X expected %X",
panic(Fmt("DeliverTx response data was unexpected. Got %X expected %X",
data, dataExp))
}
}
func CheckTx(client tmspcli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) {
func CheckTx(client abcicli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) {
res := client.CheckTxSync(txBytes)
code, data, log := res.Code, res.Data, res.Log
if res.IsErr() {


+ 19
- 19
tests/test_app/main.go View File

@ -4,15 +4,15 @@ import (
"fmt"
"os"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
var tmspType string
var abciType string
func init() {
tmspType = os.Getenv("TMSP")
if tmspType == "" {
tmspType = "socket"
abciType = os.Getenv("ABCI")
if abciType == "" {
abciType = "socket"
}
}
@ -21,28 +21,28 @@ func main() {
}
func testCounter() {
tmspApp := os.Getenv("TMSP_APP")
if tmspApp == "" {
panic("No TMSP_APP specified")
abciApp := os.Getenv("ABCI_APP")
if abciApp == "" {
panic("No ABCI_APP specified")
}
fmt.Printf("Running %s test with tmsp=%s\n", tmspApp, tmspType)
appProc := StartApp(tmspApp)
fmt.Printf("Running %s test with abci=%s\n", abciApp, abciType)
appProc := StartApp(abciApp)
defer appProc.StopProcess(true)
client := StartClient(tmspType)
client := StartClient(abciType)
defer client.Stop()
SetOption(client, "serial", "on")
Commit(client, nil)
AppendTx(client, []byte("abc"), types.CodeType_BadNonce, nil)
DeliverTx(client, []byte("abc"), types.CodeType_BadNonce, nil)
Commit(client, nil)
AppendTx(client, []byte{0x00}, types.CodeType_OK, nil)
DeliverTx(client, []byte{0x00}, types.CodeType_OK, nil)
Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1})
AppendTx(client, []byte{0x00}, types.CodeType_BadNonce, nil)
AppendTx(client, []byte{0x01}, types.CodeType_OK, nil)
AppendTx(client, []byte{0x00, 0x02}, types.CodeType_OK, nil)
AppendTx(client, []byte{0x00, 0x03}, types.CodeType_OK, nil)
AppendTx(client, []byte{0x00, 0x00, 0x04}, types.CodeType_OK, nil)
AppendTx(client, []byte{0x00, 0x00, 0x06}, types.CodeType_BadNonce, nil)
DeliverTx(client, []byte{0x00}, types.CodeType_BadNonce, nil)
DeliverTx(client, []byte{0x01}, types.CodeType_OK, nil)
DeliverTx(client, []byte{0x00, 0x02}, types.CodeType_OK, nil)
DeliverTx(client, []byte{0x00, 0x03}, types.CodeType_OK, nil)
DeliverTx(client, []byte{0x00, 0x00, 0x04}, types.CodeType_OK, nil)
DeliverTx(client, []byte{0x00, 0x00, 0x06}, types.CodeType_BadNonce, nil)
Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5})
}

+ 5
- 5
tests/test_app/test.sh View File

@ -1,17 +1,17 @@
#! /bin/bash
set -e
# These tests spawn the counter app and server by execing the TMSP_APP command and run some simple client tests against it
# These tests spawn the counter app and server by execing the ABCI_APP command and run some simple client tests against it
ROOT=$GOPATH/src/github.com/tendermint/tmsp/tests/test_app
ROOT=$GOPATH/src/github.com/tendermint/abci/tests/test_app
cd $ROOT
# test golang counter
TMSP_APP="counter" go run *.go
ABCI_APP="counter" go run *.go
# test golang counter via grpc
TMSP_APP="counter -tmsp=grpc" TMSP="grpc" go run *.go
ABCI_APP="counter -abci=grpc" ABCI="grpc" go run *.go
# test nodejs counter
# TODO: fix node app
#TMSP_APP="node $GOPATH/src/github.com/tendermint/js-tmsp/example/app.js" go test -test.run TestCounter
#ABCI_APP="node $GOPATH/src/github.com/tendermint/js-abci/example/app.js" go test -test.run TestCounter

+ 10
- 0
tests/test_cli/ex1.abci View File

@ -0,0 +1,10 @@
echo hello
info
commit
deliver_tx "abc"
info
commit
query "abc"
deliver_tx "def=xyz"
commit
query "def"

+ 32
- 0
tests/test_cli/ex1.abci.out View File

@ -0,0 +1,32 @@
> echo hello
-> data: hello
> info
-> data: {"size":0}
> commit
-> data: 0x
> deliver_tx "abc"
-> code: OK
> info
-> data: {"size":1}
> commit
-> data: 0x750502FC7E84BBD788ED589624F06CFA871845D1
> query "abc"
-> code: OK
-> data: {"index":0,"value":"abc","valueHex":"616263","exists":true}
> deliver_tx "def=xyz"
-> code: OK
> commit
-> data: 0x76393B8A182E450286B0694C629ECB51B286EFD5
> query "def"
-> code: OK
-> data: {"index":1,"value":"xyz","valueHex":"78797a","exists":true}

+ 0
- 10
tests/test_cli/ex1.tmsp View File

@ -1,10 +0,0 @@
echo hello
info
commit
append_tx abc
info
commit
query abc
append_tx def=xyz
commit
query def

+ 0
- 31
tests/test_cli/ex1.tmsp.out View File

@ -1,31 +0,0 @@
> echo hello
-> data: {hello}
> info
-> data: {size:0}
> commit
> append_tx abc
-> code: OK
> info
-> data: {size:1}
> commit
-> data: {750502FC7E84BBD788ED589624F06CFA871845D1}
> query abc
-> code: OK
-> data: {Index=0 value=abc exists=true}
> append_tx def=xyz
-> code: OK
> commit
-> data: {76393B8A182E450286B0694C629ECB51B286EFD5}
> query def
-> code: OK
-> data: {Index=1 value=xyz exists=true}

tests/test_cli/ex2.tmsp → tests/test_cli/ex2.abci View File


tests/test_cli/ex2.tmsp.out → tests/test_cli/ex2.abci.out View File


+ 5
- 3
tests/test_cli/test.sh View File

@ -1,5 +1,7 @@
#! /bin/bash
cd $GOPATH/src/github.com/tendermint/abci
function testExample() {
N=$1
INPUT=$2
@ -8,7 +10,7 @@ function testExample() {
echo "Example $N"
$APP &> /dev/null &
sleep 2
tmsp-cli --verbose batch < $INPUT > "${INPUT}.out.new"
abci-cli --verbose batch < $INPUT > "${INPUT}.out.new"
killall "$APP"
pre=`shasum < "${INPUT}.out"`
@ -26,8 +28,8 @@ function testExample() {
rm "${INPUT}".out.new
}
testExample 1 tests/test_cli/ex1.tmsp dummy
testExample 2 tests/test_cli/ex2.tmsp counter
testExample 1 tests/test_cli/ex1.abci dummy
testExample 2 tests/test_cli/ex2.abci counter
echo ""
echo "PASS"

+ 1
- 1
testutil/messages.go View File

@ -2,7 +2,7 @@ package testutil
import (
"github.com/tendermint/go-crypto"
"github.com/tendermint/tmsp/types"
"github.com/tendermint/abci/types"
)
//----------------------------------------


+ 13
- 12
types/application.go View File

@ -8,13 +8,13 @@ import (
type Application interface {
// Return application info
Info() (info string)
Info() ResponseInfo
// Set application option (e.g. mode=mempool, mode=consensus)
SetOption(key string, value string) (log string)
// Append a tx
AppendTx(tx []byte) Result
// Deliver a tx
DeliverTx(tx []byte) Result
// Validate a tx for the mempool
CheckTx(tx []byte) Result
@ -34,11 +34,11 @@ type BlockchainAware interface {
InitChain(validators []*Validator)
// Signals the beginning of a block
BeginBlock(height uint64)
BeginBlock(hash []byte, header *Header)
// Signals the end of a block
// diffs: changed validators from app to TendermintCore
EndBlock(height uint64) (diffs []*Validator)
EndBlock(height uint64) ResponseEndBlock
}
//------------------------------------
@ -59,16 +59,17 @@ func (app *GRPCApplication) Flush(ctx context.Context, req *RequestFlush) (*Resp
}
func (app *GRPCApplication) Info(ctx context.Context, req *RequestInfo) (*ResponseInfo, error) {
return &ResponseInfo{app.app.Info()}, nil
resInfo := app.app.Info()
return &resInfo, nil
}
func (app *GRPCApplication) SetOption(ctx context.Context, req *RequestSetOption) (*ResponseSetOption, error) {
return &ResponseSetOption{app.app.SetOption(req.Key, req.Value)}, nil
}
func (app *GRPCApplication) AppendTx(ctx context.Context, req *RequestAppendTx) (*ResponseAppendTx, error) {
r := app.app.AppendTx(req.Tx)
return &ResponseAppendTx{r.Code, r.Data, r.Log}, nil
func (app *GRPCApplication) DeliverTx(ctx context.Context, req *RequestDeliverTx) (*ResponseDeliverTx, error) {
r := app.app.DeliverTx(req.Tx)
return &ResponseDeliverTx{r.Code, r.Data, r.Log}, nil
}
func (app *GRPCApplication) CheckTx(ctx context.Context, req *RequestCheckTx) (*ResponseCheckTx, error) {
@ -95,15 +96,15 @@ func (app *GRPCApplication) InitChain(ctx context.Context, req *RequestInitChain
func (app *GRPCApplication) BeginBlock(ctx context.Context, req *RequestBeginBlock) (*ResponseBeginBlock, error) {
if chainAware, ok := app.app.(BlockchainAware); ok {
chainAware.BeginBlock(req.Height)
chainAware.BeginBlock(req.Hash, req.Header)
}
return &ResponseBeginBlock{}, nil
}
func (app *GRPCApplication) EndBlock(ctx context.Context, req *RequestEndBlock) (*ResponseEndBlock, error) {
if chainAware, ok := app.app.(BlockchainAware); ok {
diffs := chainAware.EndBlock(req.Height)
return &ResponseEndBlock{diffs}, nil
resEndBlock := chainAware.EndBlock(req.Height)
return &resEndBlock, nil
}
return &ResponseEndBlock{}, nil
}

+ 10
- 10
types/messages.go View File

@ -31,9 +31,9 @@ func ToRequestSetOption(key string, value string) *Request {
}
}
func ToRequestAppendTx(txBytes []byte) *Request {
func ToRequestDeliverTx(txBytes []byte) *Request {
return &Request{
Value: &Request_AppendTx{&RequestAppendTx{txBytes}},
Value: &Request_DeliverTx{&RequestDeliverTx{txBytes}},
}
}
@ -61,9 +61,9 @@ func ToRequestInitChain(validators []*Validator) *Request {
}
}
func ToRequestBeginBlock(height uint64) *Request {
func ToRequestBeginBlock(hash []byte, header *Header) *Request {
return &Request{
Value: &Request_BeginBlock{&RequestBeginBlock{height}},
Value: &Request_BeginBlock{&RequestBeginBlock{hash, header}},
}
}
@ -93,9 +93,9 @@ func ToResponseFlush() *Response {
}
}
func ToResponseInfo(info string) *Response {
func ToResponseInfo(resInfo ResponseInfo) *Response {
return &Response{
Value: &Response_Info{&ResponseInfo{info}},
Value: &Response_Info{&resInfo},
}
}
@ -105,9 +105,9 @@ func ToResponseSetOption(log string) *Response {
}
}
func ToResponseAppendTx(code CodeType, data []byte, log string) *Response {
func ToResponseDeliverTx(code CodeType, data []byte, log string) *Response {
return &Response{
Value: &Response_AppendTx{&ResponseAppendTx{code, data, log}},
Value: &Response_DeliverTx{&ResponseDeliverTx{code, data, log}},
}
}
@ -141,9 +141,9 @@ func ToResponseBeginBlock() *Response {
}
}
func ToResponseEndBlock(validators []*Validator) *Response {
func ToResponseEndBlock(resEndBlock ResponseEndBlock) *Response {
return &Response{
Value: &Response_EndBlock{&ResponseEndBlock{validators}},
Value: &Response_EndBlock{&resEndBlock},
}
}


+ 1
- 1
types/result.go View File

@ -28,7 +28,7 @@ func (res Result) IsErr() bool {
}
func (res Result) Error() string {
return fmt.Sprintf("TMSP code:%v, data:%X, log:%v", res.Code, res.Data, res.Log)
return fmt.Sprintf("ABCI code:%v, data:%X, log:%v", res.Code, res.Data, res.Log)
}
func (res Result) PrependLog(log string) Result {


+ 412
- 230
types/types.pb.go
File diff suppressed because it is too large
View File


+ 37
- 11
types/types.proto View File

@ -1,7 +1,7 @@
syntax = "proto3";
package types;
// This file is copied from http://github.com/tendermint/tmsp
// This file is copied from http://github.com/tendermint/abci
//----------------------------------------
// Message types
@ -18,7 +18,7 @@ enum MessageType {
Info = 0x03;
SetOption = 0x04;
Exception = 0x05;
AppendTx = 0x11;
DeliverTx = 0x11;
CheckTx = 0x12;
Commit = 0x13;
Query = 0x14;
@ -79,7 +79,7 @@ message Request {
RequestFlush flush = 2;
RequestInfo info = 3;
RequestSetOption set_option = 4;
RequestAppendTx append_tx = 5;
RequestDeliverTx deliver_tx = 5;
RequestCheckTx check_tx = 6;
RequestCommit commit = 7;
RequestQuery query = 8;
@ -104,7 +104,7 @@ message RequestSetOption{
string value = 2;
}
message RequestAppendTx{
message RequestDeliverTx{
bytes tx = 1;
}
@ -124,7 +124,8 @@ message RequestInitChain{
}
message RequestBeginBlock{
uint64 height = 1;
bytes hash = 1;
Header header = 2;
}
message RequestEndBlock{
@ -142,7 +143,7 @@ message Response {
ResponseFlush flush = 3;
ResponseInfo info = 4;
ResponseSetOption set_option = 5;
ResponseAppendTx append_tx = 6;
ResponseDeliverTx deliver_tx = 6;
ResponseCheckTx check_tx = 7;
ResponseCommit commit = 8;
ResponseQuery query = 9;
@ -164,14 +165,17 @@ message ResponseFlush{
}
message ResponseInfo {
string info = 1;
string data = 1;
string version = 2;
uint64 last_block_height = 3;
bytes last_block_app_hash = 4;
}
message ResponseSetOption{
string log = 1;
}
message ResponseAppendTx{
message ResponseDeliverTx{
CodeType code = 1;
bytes data = 2;
string log = 3;
@ -207,7 +211,29 @@ message ResponseEndBlock{
}
//----------------------------------------
// Misc types
// Blockchain Types
message Header {
string chain_id = 1;
uint64 height = 2;
uint64 time = 3;
uint64 num_txs = 4;
BlockID last_block_id = 5;
bytes last_commit_hash = 6;
bytes data_hash = 7;
bytes validators_hash = 8;
bytes app_hash = 9;
}
message BlockID {
bytes hash = 1;
PartSetHeader parts = 2;
}
message PartSetHeader {
uint64 total = 1;
bytes hash = 2;
}
message Validator {
bytes pubKey = 1;
@ -217,12 +243,12 @@ message Validator {
//----------------------------------------
// Service Definition
service TMSPApplication {
service ABCIApplication {
rpc Echo(RequestEcho) returns (ResponseEcho) ;
rpc Flush(RequestFlush) returns (ResponseFlush);
rpc Info(RequestInfo) returns (ResponseInfo);
rpc SetOption(RequestSetOption) returns (ResponseSetOption);
rpc AppendTx(RequestAppendTx) returns (ResponseAppendTx);
rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx);
rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx);
rpc Query(RequestQuery) returns (ResponseQuery);
rpc Commit(RequestCommit) returns (ResponseCommit);


+ 41
- 0
types/validators.go View File

@ -0,0 +1,41 @@
package types
import (
"bytes"
"github.com/tendermint/go-wire"
)
// validators implements sort
type Validators []*Validator
func (v Validators) Len() int {
return len(v)
}
// XXX: doesn't distinguish same validator with different power
func (v Validators) Less(i, j int) bool {
return bytes.Compare(v[i].PubKey, v[j].PubKey) <= 0
}
func (v Validators) Swap(i, j int) {
v1 := v[i]
v[i] = v[j]
v[j] = v1
}
//-------------------------------------
type validatorPretty struct {
PubKey []byte `json:"pub_key"`
Power uint64 `json:"power"`
}
func ValidatorsString(vs Validators) string {
s := make([]validatorPretty, len(vs))
for i, v := range vs {
s[i] = validatorPretty{v.PubKey, v.Power}
}
return string(wire.JSONBytes(s))
}

+ 7
- 0
types/version.go View File

@ -0,0 +1,7 @@
package types
const Maj = "0"
const Min = "3" // ResponseInfo, ResponseEndBlock
const Fix = "0" //
const Version = Maj + "." + Min + "." + Fix

Loading…
Cancel
Save