mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-30 19:51:58 +00:00
proxy: typed app conns
This commit is contained in:
@@ -2,8 +2,135 @@ package proxy
|
||||
|
||||
import (
|
||||
tmspcli "github.com/tendermint/tmsp/client"
|
||||
"github.com/tendermint/tmsp/types"
|
||||
)
|
||||
|
||||
type AppConn interface {
|
||||
tmspcli.Client
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Enforce which tmsp msgs can be sent on a connection at the type level
|
||||
|
||||
type AppConnConsensus interface {
|
||||
SetResponseCallback(tmspcli.Callback)
|
||||
Error() error
|
||||
|
||||
InitChainSync(validators []*types.Validator) (err error)
|
||||
|
||||
BeginBlockSync(height uint64) (err error)
|
||||
AppendTxAsync(tx []byte) *tmspcli.ReqRes
|
||||
EndBlockSync(height uint64) (changedValidators []*types.Validator, err error)
|
||||
CommitSync() (res types.Result)
|
||||
}
|
||||
|
||||
type AppConnMempool interface {
|
||||
SetResponseCallback(tmspcli.Callback)
|
||||
Error() error
|
||||
|
||||
CheckTxAsync(tx []byte) *tmspcli.ReqRes
|
||||
|
||||
FlushAsync() *tmspcli.ReqRes
|
||||
FlushSync() error
|
||||
}
|
||||
|
||||
type AppConnQuery interface {
|
||||
Error() error
|
||||
|
||||
EchoSync(string) (res types.Result)
|
||||
InfoSync() (res types.Result)
|
||||
QuerySync(tx []byte) (res types.Result)
|
||||
|
||||
// SetOptionSync(key string, value string) (res types.Result)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Implements AppConnConsensus (subset of tmspcli.Client)
|
||||
|
||||
type appConnConsensus struct {
|
||||
appConn tmspcli.Client
|
||||
}
|
||||
|
||||
func NewAppConnConsensus(appConn tmspcli.Client) *appConnConsensus {
|
||||
return &appConnConsensus{
|
||||
appConn: appConn,
|
||||
}
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) SetResponseCallback(cb tmspcli.Callback) {
|
||||
app.appConn.SetResponseCallback(cb)
|
||||
}
|
||||
func (app *appConnConsensus) Error() error {
|
||||
return app.appConn.Error()
|
||||
}
|
||||
func (app *appConnConsensus) InitChainSync(validators []*types.Validator) (err error) {
|
||||
return app.appConn.InitChainSync(validators)
|
||||
}
|
||||
func (app *appConnConsensus) BeginBlockSync(height uint64) (err error) {
|
||||
return app.appConn.BeginBlockSync(height)
|
||||
}
|
||||
func (app *appConnConsensus) AppendTxAsync(tx []byte) *tmspcli.ReqRes {
|
||||
return app.appConn.AppendTxAsync(tx)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) EndBlockSync(height uint64) (changedValidators []*types.Validator, err error) {
|
||||
return app.appConn.EndBlockSync(height)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) CommitSync() (res types.Result) {
|
||||
return app.appConn.CommitSync()
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Implements AppConnMempool (subset of tmspcli.Client)
|
||||
|
||||
type appConnMempool struct {
|
||||
appConn tmspcli.Client
|
||||
}
|
||||
|
||||
func NewAppConnMempool(appConn tmspcli.Client) *appConnMempool {
|
||||
return &appConnMempool{
|
||||
appConn: appConn,
|
||||
}
|
||||
}
|
||||
|
||||
func (app *appConnMempool) SetResponseCallback(cb tmspcli.Callback) {
|
||||
app.appConn.SetResponseCallback(cb)
|
||||
}
|
||||
|
||||
func (app *appConnMempool) Error() error {
|
||||
return app.appConn.Error()
|
||||
}
|
||||
|
||||
func (app *appConnMempool) FlushAsync() *tmspcli.ReqRes {
|
||||
return app.appConn.FlushAsync()
|
||||
}
|
||||
|
||||
func (app *appConnMempool) FlushSync() error {
|
||||
return app.appConn.FlushSync()
|
||||
}
|
||||
|
||||
func (app *appConnMempool) CheckTxAsync(tx []byte) *tmspcli.ReqRes {
|
||||
return app.appConn.CheckTxAsync(tx)
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Implements AppConnQuery (subset of tmspcli.Client)
|
||||
|
||||
type appConnQuery struct {
|
||||
appConn tmspcli.Client
|
||||
}
|
||||
|
||||
func NewAppConnQuery(appConn tmspcli.Client) *appConnQuery {
|
||||
return &appConnQuery{
|
||||
appConn: appConn,
|
||||
}
|
||||
}
|
||||
|
||||
func (app *appConnQuery) Error() error {
|
||||
return app.appConn.Error()
|
||||
}
|
||||
|
||||
func (app *appConnQuery) InfoSync() (res types.Result) {
|
||||
return app.appConn.InfoSync()
|
||||
}
|
||||
|
||||
func (app *appConnQuery) QuerySync(tx []byte) (res types.Result) {
|
||||
return app.appConn.QuerySync(tx)
|
||||
}
|
||||
|
@@ -5,10 +5,42 @@ import (
|
||||
"testing"
|
||||
|
||||
. "github.com/tendermint/go-common"
|
||||
tmspcli "github.com/tendermint/tmsp/client"
|
||||
"github.com/tendermint/tmsp/example/dummy"
|
||||
"github.com/tendermint/tmsp/server"
|
||||
"github.com/tendermint/tmsp/types"
|
||||
)
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
type AppConnTest interface {
|
||||
EchoAsync(string) *tmspcli.ReqRes
|
||||
FlushSync() error
|
||||
InfoSync() (res types.Result)
|
||||
}
|
||||
|
||||
type appConnTest struct {
|
||||
appConn tmspcli.Client
|
||||
}
|
||||
|
||||
func NewAppConnTest(appConn tmspcli.Client) AppConnTest {
|
||||
return &appConnTest{appConn}
|
||||
}
|
||||
|
||||
func (app *appConnTest) EchoAsync(msg string) *tmspcli.ReqRes {
|
||||
return app.appConn.EchoAsync(msg)
|
||||
}
|
||||
|
||||
func (app *appConnTest) FlushSync() error {
|
||||
return app.appConn.FlushSync()
|
||||
}
|
||||
|
||||
func (app *appConnTest) InfoSync() types.Result {
|
||||
return app.appConn.InfoSync()
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
var SOCKET = "socket"
|
||||
|
||||
func TestEcho(t *testing.T) {
|
||||
@@ -21,12 +53,12 @@ func TestEcho(t *testing.T) {
|
||||
}
|
||||
defer s.Stop()
|
||||
// Start client
|
||||
proxy, err := NewRemoteAppConn(sockPath, SOCKET)
|
||||
cli, err := NewTMSPClient(sockPath, SOCKET)
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
} else {
|
||||
t.Log("Connected")
|
||||
}
|
||||
proxy := NewAppConnTest(cli)
|
||||
t.Log("Connected")
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
proxy.EchoAsync(Fmt("echo-%v", i))
|
||||
@@ -44,12 +76,12 @@ func BenchmarkEcho(b *testing.B) {
|
||||
}
|
||||
defer s.Stop()
|
||||
// Start client
|
||||
proxy, err := NewRemoteAppConn(sockPath, SOCKET)
|
||||
cli, err := NewTMSPClient(sockPath, SOCKET)
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
} else {
|
||||
b.Log("Connected")
|
||||
}
|
||||
proxy := NewAppConnTest(cli)
|
||||
b.Log("Connected")
|
||||
echoString := strings.Repeat(" ", 200)
|
||||
b.StartTimer() // Start benchmarking tests
|
||||
|
||||
@@ -72,12 +104,13 @@ func TestInfo(t *testing.T) {
|
||||
}
|
||||
defer s.Stop()
|
||||
// Start client
|
||||
proxy, err := NewRemoteAppConn(sockPath, SOCKET)
|
||||
cli, err := NewTMSPClient(sockPath, SOCKET)
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
} else {
|
||||
t.Log("Connected")
|
||||
}
|
||||
proxy := NewAppConnTest(cli)
|
||||
t.Log("Connected")
|
||||
|
||||
res := proxy.InfoSync()
|
||||
if res.IsErr() {
|
||||
t.Errorf("Unexpected error: %v", err)
|
116
proxy/multi_app_conn.go
Normal file
116
proxy/multi_app_conn.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
. "github.com/tendermint/go-common"
|
||||
cfg "github.com/tendermint/go-config"
|
||||
tmspcli "github.com/tendermint/tmsp/client"
|
||||
"github.com/tendermint/tmsp/example/dummy"
|
||||
nilapp "github.com/tendermint/tmsp/example/nil"
|
||||
)
|
||||
|
||||
// Get a connected tmsp client and perform handshake
|
||||
func NewTMSPClient(addr, transport string) (tmspcli.Client, error) {
|
||||
var client tmspcli.Client
|
||||
|
||||
// use local app (for testing)
|
||||
// TODO: local proxy app conn
|
||||
switch addr {
|
||||
case "nilapp":
|
||||
app := nilapp.NewNilApplication()
|
||||
mtx := new(sync.Mutex) // TODO
|
||||
client = tmspcli.NewLocalClient(mtx, app)
|
||||
case "dummy":
|
||||
app := dummy.NewDummyApplication()
|
||||
mtx := new(sync.Mutex) // TODO
|
||||
client = tmspcli.NewLocalClient(mtx, app)
|
||||
default:
|
||||
// Run forever in a loop
|
||||
mustConnect := false
|
||||
remoteApp, err := tmspcli.NewClient(addr, transport, mustConnect)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to connect to proxy for mempool: %v", err)
|
||||
}
|
||||
client = remoteApp
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// TODO
|
||||
func Handshake(config cfg.Config, state State, blockStore BlockStore) {
|
||||
// XXX: Handshake
|
||||
/*res := client.CommitSync()
|
||||
if res.IsErr() {
|
||||
PanicCrisis(Fmt("Error in getting multiAppConnConn hash: %v", res))
|
||||
}
|
||||
if !bytes.Equal(hash, res.Data) {
|
||||
log.Warn(Fmt("ProxyApp hash does not match. Expected %X, got %X", hash, res.Data))
|
||||
}*/
|
||||
}
|
||||
|
||||
//---------
|
||||
|
||||
// a multiAppConn is made of a few appConns (mempool, consensus)
|
||||
// and manages their underlying tmsp clients, ensuring they reboot together
|
||||
type multiAppConn struct {
|
||||
QuitService
|
||||
|
||||
config cfg.Config
|
||||
|
||||
state State
|
||||
blockStore BlockStore
|
||||
|
||||
mempoolConn *appConnMempool
|
||||
consensusConn *appConnConsensus
|
||||
}
|
||||
|
||||
// Make all necessary tmsp connections to the application
|
||||
func NewMultiAppConn(config cfg.Config, state State, blockStore BlockStore) *multiAppConn {
|
||||
multiAppConn := &multiAppConn{
|
||||
config: config,
|
||||
state: state,
|
||||
blockStore: blockStore,
|
||||
}
|
||||
multiAppConn.QuitService = *NewQuitService(log, "multiAppConn", multiAppConn)
|
||||
multiAppConn.Start()
|
||||
return multiAppConn
|
||||
}
|
||||
|
||||
// Returns the mempool connection
|
||||
func (app *multiAppConn) Mempool() AppConnMempool {
|
||||
return app.mempoolConn
|
||||
}
|
||||
|
||||
// Returns the consensus Connection
|
||||
func (app *multiAppConn) Consensus() AppConnConsensus {
|
||||
return app.consensusConn
|
||||
}
|
||||
|
||||
func (app *multiAppConn) OnStart() error {
|
||||
app.QuitService.OnStart()
|
||||
|
||||
addr := app.config.GetString("proxy_app")
|
||||
transport := app.config.GetString("tmsp")
|
||||
|
||||
memcli, err := NewTMSPClient(addr, transport)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app.mempoolConn = NewAppConnMempool(memcli)
|
||||
|
||||
concli, err := NewTMSPClient(addr, transport)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app.consensusConn = NewAppConnConsensus(concli)
|
||||
|
||||
// TODO: handshake
|
||||
|
||||
// TODO: replay blocks
|
||||
|
||||
// TODO: (on restart) replay mempool
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
tmspcli "github.com/tendermint/tmsp/client"
|
||||
)
|
||||
|
||||
// This is goroutine-safe, but users should beware that
|
||||
// the application in general is not meant to be interfaced
|
||||
// with concurrent callers.
|
||||
type remoteAppConn struct {
|
||||
tmspcli.Client
|
||||
}
|
||||
|
||||
func NewRemoteAppConn(addr, transport string) (*remoteAppConn, error) {
|
||||
client, err := tmspcli.NewClient(addr, transport, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appConn := &remoteAppConn{
|
||||
Client: client,
|
||||
}
|
||||
return appConn, nil
|
||||
}
|
9
proxy/state.go
Normal file
9
proxy/state.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package proxy
|
||||
|
||||
type State interface {
|
||||
// TODO
|
||||
}
|
||||
|
||||
type BlockStore interface {
|
||||
// TODO
|
||||
}
|
Reference in New Issue
Block a user