mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-13 05:11:21 +00:00
handshake
This commit is contained in:
@ -1,10 +1,20 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
. "github.com/tendermint/go-common"
|
||||
cfg "github.com/tendermint/go-config"
|
||||
"github.com/tendermint/tendermint/types" // ...
|
||||
tmspcli "github.com/tendermint/tmsp/client"
|
||||
"github.com/tendermint/tmsp/example/dummy"
|
||||
nilapp "github.com/tendermint/tmsp/example/nil"
|
||||
)
|
||||
|
||||
//-----------------------------
|
||||
|
||||
// Tendermint's interface to the application consists of multiple connections
|
||||
type AppConns interface {
|
||||
Service
|
||||
@ -19,7 +29,9 @@ func NewAppConns(config cfg.Config, clientCreator ClientCreator, state State, bl
|
||||
}
|
||||
|
||||
// a multiAppConn is made of a few appConns (mempool, consensus, query)
|
||||
// and manages their underlying tmsp clients, ensuring they reboot together
|
||||
// and manages their underlying tmsp clients, including the handshake
|
||||
// which ensures the app and tendermint are synced.
|
||||
// TODO: on app restart, clients must reboot together
|
||||
type multiAppConn struct {
|
||||
BaseService
|
||||
|
||||
@ -57,6 +69,7 @@ func (app *multiAppConn) Consensus() AppConnConsensus {
|
||||
return app.consensusConn
|
||||
}
|
||||
|
||||
// Returns the query Connection
|
||||
func (app *multiAppConn) Query() AppConnQuery {
|
||||
return app.queryConn
|
||||
}
|
||||
@ -85,11 +98,102 @@ func (app *multiAppConn) OnStart() error {
|
||||
}
|
||||
app.consensusConn = NewAppConnConsensus(concli)
|
||||
|
||||
// TODO: handshake
|
||||
// ensure app is synced to the latest state
|
||||
return app.Handshake()
|
||||
}
|
||||
|
||||
// TODO: replay blocks
|
||||
// TODO: retry the handshake once if it fails the first time
|
||||
func (app *multiAppConn) Handshake() error {
|
||||
// handshake is done on the query conn
|
||||
res, tmspInfo, blockInfo, configInfo := app.queryConn.InfoSync()
|
||||
if res.IsErr() {
|
||||
return fmt.Errorf("Error calling Info. Code: %v; Data: %X; Log: %s", res.Code, res.Data, res.Log)
|
||||
}
|
||||
|
||||
if blockInfo == nil {
|
||||
log.Warn("blockInfo is nil, aborting handshake")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Notice("TMSP Handshake", "height", blockInfo.BlockHeight, "block_hash", blockInfo.BlockHash, "app_hash", blockInfo.AppHash)
|
||||
|
||||
// TODO: check overflow or change pb to int32
|
||||
blockHeight := int(blockInfo.BlockHeight)
|
||||
blockHash := blockInfo.BlockHash
|
||||
appHash := blockInfo.AppHash
|
||||
|
||||
if tmspInfo != nil {
|
||||
// TODO: check tmsp version (or do this in the tmspcli?)
|
||||
_ = tmspInfo
|
||||
}
|
||||
|
||||
// of the last block (nil if we starting from 0)
|
||||
var header *types.Header
|
||||
var partsHeader types.PartSetHeader
|
||||
|
||||
// check block
|
||||
// if the blockHeight == 0, we will replay everything
|
||||
if blockHeight != 0 {
|
||||
blockMeta := app.blockStore.LoadBlockMeta(blockHeight)
|
||||
if blockMeta == nil {
|
||||
return fmt.Errorf("Handshake error. Could not find block #%d", blockHeight)
|
||||
}
|
||||
|
||||
// check block hash
|
||||
if !bytes.Equal(blockMeta.Hash, blockHash) {
|
||||
return fmt.Errorf("Handshake error. Block hash at height %d does not match. Got %X, expected %X", blockHeight, blockHash, blockMeta.Hash)
|
||||
}
|
||||
|
||||
// check app hash
|
||||
if !bytes.Equal(blockMeta.Header.AppHash, appHash) {
|
||||
return fmt.Errorf("Handshake error. App hash at height %d does not match. Got %X, expected %X", blockHeight, appHash, blockMeta.Header.AppHash)
|
||||
}
|
||||
|
||||
header = blockMeta.Header
|
||||
partsHeader = blockMeta.PartsHeader
|
||||
}
|
||||
|
||||
if configInfo != nil {
|
||||
// TODO: set config info
|
||||
_ = configInfo
|
||||
}
|
||||
|
||||
// replay blocks up to the latest in the blockstore
|
||||
err := app.state.ReplayBlocks(header, partsHeader, app.consensusConn, app.blockStore)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error on replay: %v", err)
|
||||
}
|
||||
|
||||
// TODO: (on restart) replay mempool
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
// Get a connected tmsp client
|
||||
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
|
||||
}
|
||||
|
Reference in New Issue
Block a user