From 733dfcf4add7ff517369f1d7511905455a45e361 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Mon, 20 Apr 2015 20:39:42 -0700 Subject: [PATCH] Add dump_consensus_state rpc command. Made it a little more secure by moving the PrivValidator out of RoundState. --- consensus/state.go | 34 ++++++++------ rpc/core/{validators.go => consensus.go} | 8 +++- rpc/core/mempool.go | 1 - rpc/core/routes.go | 1 + rpc/core/types/responses.go | 4 ++ rpc/core_client/client_methods.go | 58 ++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 18 deletions(-) rename rpc/core/{validators.go => consensus.go} (75%) diff --git a/consensus/state.go b/consensus/state.go index 9fd94f3ce..16bb04560 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -187,7 +187,6 @@ type RoundState struct { Precommits *VoteSet Commits *VoteSet LastCommits *VoteSet - PrivValidator *sm.PrivValidator } func (rs *RoundState) String() string { @@ -241,6 +240,7 @@ type ConsensusState struct { blockStore *bc.BlockStore mempoolReactor *mempl.MempoolReactor + privValidator *sm.PrivValidator runActionCh chan RoundAction newStepCh chan *RoundState @@ -492,8 +492,12 @@ func (cs *ConsensusState) updateToState(state *sm.State, contiguous bool) { cs.Round = 0 cs.Step = RoundStepNewHeight if cs.CommitTime.IsZero() { - //cs.StartTime = state.LastBlockTime.Add(newHeightDelta) - cs.StartTime = time.Now() // Makes it easier to sync up dev nodes. + // "Now" makes it easier to sync up dev nodes. + // We add newHeightDelta to allow transactions + // to be gathered for the first block. + // And alternative solution that relies on clocks: + // cs.StartTime = state.LastBlockTime.Add(newHeightDelta) + cs.StartTime = time.Now().Add(newHeightDelta) } else { cs.StartTime = cs.CommitTime.Add(newHeightDelta) } @@ -523,12 +527,12 @@ func (cs *ConsensusState) updateToState(state *sm.State, contiguous bool) { } // If we've timed out, then send rebond tx. - if cs.PrivValidator != nil && cs.state.UnbondingValidators.HasAddress(cs.PrivValidator.Address) { + if cs.privValidator != nil && cs.state.UnbondingValidators.HasAddress(cs.privValidator.Address) { rebondTx := &types.RebondTx{ - Address: cs.PrivValidator.Address, + Address: cs.privValidator.Address, Height: cs.Height + 1, } - err := cs.PrivValidator.SignRebondTx(rebondTx) + err := cs.privValidator.SignRebondTx(rebondTx) if err == nil { log.Info("Signed and broadcast RebondTx", "height", cs.Height, "round", cs.Round, "tx", rebondTx) cs.mempoolReactor.BroadcastTx(rebondTx) @@ -567,7 +571,7 @@ func (cs *ConsensusState) setupNewRound(round uint) { func (cs *ConsensusState) SetPrivValidator(priv *sm.PrivValidator) { cs.mtx.Lock() defer cs.mtx.Unlock() - cs.PrivValidator = priv + cs.privValidator = priv } //----------------------------------------------------------------------------- @@ -600,14 +604,14 @@ func (cs *ConsensusState) RunActionPropose(height uint, round uint) { }() // Nothing to do if it's not our turn. - if cs.PrivValidator == nil { + if cs.privValidator == nil { return } - if !bytes.Equal(cs.Validators.Proposer().Address, cs.PrivValidator.Address) { - log.Debug("Not our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.PrivValidator) + if !bytes.Equal(cs.Validators.Proposer().Address, cs.privValidator.Address) { + log.Debug("Not our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator) return } else { - log.Debug("Our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.PrivValidator) + log.Debug("Our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator) } var block *types.Block @@ -675,7 +679,7 @@ func (cs *ConsensusState) RunActionPropose(height uint, round uint) { // Make proposal proposal := NewProposal(cs.Height, cs.Round, blockParts.Header(), polParts.Header()) - err := cs.PrivValidator.SignProposal(proposal) + err := cs.privValidator.SignProposal(proposal) if err == nil { log.Info("Signed and set proposal", "height", cs.Height, "round", cs.Round, "proposal", proposal) log.Debug(Fmt("Signed and set proposal block: %v", block)) @@ -1061,7 +1065,7 @@ func (cs *ConsensusState) stageBlock(block *types.Block, blockParts *types.PartS } func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.PartSetHeader) *types.Vote { - if cs.PrivValidator == nil || !cs.Validators.HasAddress(cs.PrivValidator.Address) { + if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.Address) { return nil } vote := &types.Vote{ @@ -1071,10 +1075,10 @@ func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.Part BlockHash: hash, BlockParts: header, } - err := cs.PrivValidator.SignVote(vote) + err := cs.privValidator.SignVote(vote) if err == nil { log.Info("Signed and added vote", "height", cs.Height, "round", cs.Round, "vote", vote) - cs.addVote(cs.PrivValidator.Address, vote) + cs.addVote(cs.privValidator.Address, vote) return vote } else { log.Warn("Error signing vote", "height", cs.Height, "round", cs.Round, "vote", vote, "error", err) diff --git a/rpc/core/validators.go b/rpc/core/consensus.go similarity index 75% rename from rpc/core/validators.go rename to rpc/core/consensus.go index fd8f2d736..c74cf8cc4 100644 --- a/rpc/core/validators.go +++ b/rpc/core/consensus.go @@ -1,12 +1,11 @@ package core import ( + "github.com/tendermint/tendermint/binary" ctypes "github.com/tendermint/tendermint/rpc/core/types" sm "github.com/tendermint/tendermint/state" ) -//----------------------------------------------------------------------------- - func ListValidators() (*ctypes.ResponseListValidators, error) { var blockHeight uint var bondedValidators []*sm.Validator @@ -25,3 +24,8 @@ func ListValidators() (*ctypes.ResponseListValidators, error) { return &ctypes.ResponseListValidators{blockHeight, bondedValidators, unbondingValidators}, nil } + +func DumpConsensusState() (*ctypes.ResponseDumpConsensusState, error) { + jsonBytes := binary.JSONBytes(consensusState.GetRoundState()) + return &ctypes.ResponseDumpConsensusState{string(jsonBytes)}, nil +} diff --git a/rpc/core/mempool.go b/rpc/core/mempool.go index 6f071e035..6d5d98926 100644 --- a/rpc/core/mempool.go +++ b/rpc/core/mempool.go @@ -2,7 +2,6 @@ package core import ( "fmt" - . "github.com/tendermint/tendermint/common" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" diff --git a/rpc/core/routes.go b/rpc/core/routes.go index 395ad82a4..17f196ab0 100644 --- a/rpc/core/routes.go +++ b/rpc/core/routes.go @@ -14,6 +14,7 @@ var Routes = map[string]*rpc.RPCFunc{ "call": rpc.NewRPCFunc(Call, []string{"address", "data"}), "call_code": rpc.NewRPCFunc(CallCode, []string{"code", "data"}), "list_validators": rpc.NewRPCFunc(ListValidators, []string{}), + "dump_consensus_state": rpc.NewRPCFunc(DumpConsensusState, []string{}), "dump_storage": rpc.NewRPCFunc(DumpStorage, []string{"address"}), "broadcast_tx": rpc.NewRPCFunc(BroadcastTx, []string{"tx"}), "list_accounts": rpc.NewRPCFunc(ListAccounts, []string{}), diff --git a/rpc/core/types/responses.go b/rpc/core/types/responses.go index fa031e040..b3b13c030 100644 --- a/rpc/core/types/responses.go +++ b/rpc/core/types/responses.go @@ -91,3 +91,7 @@ type ResponseListValidators struct { BondedValidators []*sm.Validator UnbondingValidators []*sm.Validator } + +type ResponseDumpConsensusState struct { + ConsensusState string +} diff --git a/rpc/core_client/client_methods.go b/rpc/core_client/client_methods.go index 391358615..8b2334974 100644 --- a/rpc/core_client/client_methods.go +++ b/rpc/core_client/client_methods.go @@ -18,6 +18,7 @@ type Client interface { BroadcastTx(tx types.Tx) (*ctypes.ResponseBroadcastTx, error) Call(address []byte, data []byte) (*ctypes.ResponseCall, error) CallCode(code []byte, data []byte) (*ctypes.ResponseCall, error) + DumpConsensusState() (*ctypes.ResponseDumpConsensusState, error) DumpStorage(address []byte) (*ctypes.ResponseDumpStorage, error) GenPrivAccount() (*ctypes.ResponseGenPrivAccount, error) GetAccount(address []byte) (*ctypes.ResponseGetAccount, error) @@ -150,6 +151,36 @@ func (c *ClientHTTP) CallCode(code []byte, data []byte) (*ctypes.ResponseCall, e return response.Result, nil } +func (c *ClientHTTP) DumpConsensusState() (*ctypes.ResponseDumpConsensusState, error) { + values, err := argsToURLValues(nil) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+reverseFuncMap["DumpConsensusState"], values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseDumpConsensusState `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + func (c *ClientHTTP) DumpStorage(address []byte) (*ctypes.ResponseDumpStorage, error) { values, err := argsToURLValues([]string{"address"}, address) if err != nil { @@ -558,6 +589,33 @@ func (c *ClientJSON) CallCode(code []byte, data []byte) (*ctypes.ResponseCall, e return response.Result, nil } +func (c *ClientJSON) DumpConsensusState() (*ctypes.ResponseDumpConsensusState, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: reverseFuncMap["DumpConsensusState"], + Params: []interface{}{}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseDumpConsensusState `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + func (c *ClientJSON) DumpStorage(address []byte) (*ctypes.ResponseDumpStorage, error) { request := rpc.RPCRequest{ JSONRPC: "2.0",