From d2724c973179baed5f485edfb0d9300521e5ac9c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 25 Mar 2015 18:06:57 -0700 Subject: [PATCH] rpc: give each call a dedicated Response struct, add basic test --- daemon/daemon.go | 4 +++ p2p/switch.go | 4 +++ rpc/accounts.go | 34 ++++++++++++++------- rpc/blocks.go | 26 +++++++++++----- rpc/mempool.go | 17 +++++++---- rpc/net.go | 54 ++++++++++++++++++++++++---------- rpc/test/rpc_test.go | 70 ++++++++++++++++++++++++++++++++++++++++++++ rpc/txs.go | 11 ++++++- rpc/validators.go | 16 ++++++---- 9 files changed, 191 insertions(+), 45 deletions(-) create mode 100644 rpc/test/rpc_test.go diff --git a/daemon/daemon.go b/daemon/daemon.go index ccb2932d..b5050618 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -144,6 +144,10 @@ func (n *Node) StartRpc() { rpc.StartHTTPServer() } +func (n *Node) Switch() *p2p.Switch { + return n.sw +} + func (n *Node) ConsensusState() *consensus.ConsensusState { return n.consensusState } diff --git a/p2p/switch.go b/p2p/switch.go index 635e0eca..42d2db9a 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -223,6 +223,10 @@ func (sw *Switch) StopPeerGracefully(peer *Peer) { sw.doRemovePeer(peer, nil) } +func (sw *Switch) GetChainId() string { + return sw.chainId +} + func (sw *Switch) SetChainId(hash []byte, network string) { sw.chainId = hex.EncodeToString(hash) + "-" + network } diff --git a/rpc/accounts.go b/rpc/accounts.go index aba49908..8a44d03b 100644 --- a/rpc/accounts.go +++ b/rpc/accounts.go @@ -8,16 +8,28 @@ import ( . "github.com/tendermint/tendermint/common" ) +//----------------------------------------------------------------------------- + +// Request: {} + +type ResponseGenPrivAccount struct { + PrivAccount *account.PrivAccount +} + func GenPrivAccountHandler(w http.ResponseWriter, r *http.Request) { privAccount := account.GenPrivAccount() - WriteAPIResponse(w, API_OK, struct { - PrivAccount *account.PrivAccount - }{privAccount}) + WriteAPIResponse(w, API_OK, ResponseGenPrivAccount{privAccount}) } //----------------------------------------------------------------------------- +// Request: {"address": string} + +type ResponseGetAccount struct { + Account *account.Account +} + func GetAccountHandler(w http.ResponseWriter, r *http.Request) { addressStr := GetParam(r, "address") @@ -37,13 +49,18 @@ func GetAccountHandler(w http.ResponseWriter, r *http.Request) { return } - WriteAPIResponse(w, API_OK, struct { - Account *account.Account - }{account_}) + WriteAPIResponse(w, API_OK, ResponseGetAccount{account_}) } //----------------------------------------------------------------------------- +// Request: {} + +type ResponseListAccounts struct { + BlockHeight uint + Accounts []*account.Account +} + func ListAccountsHandler(w http.ResponseWriter, r *http.Request) { var blockHeight uint var accounts []*account.Account @@ -54,8 +71,5 @@ func ListAccountsHandler(w http.ResponseWriter, r *http.Request) { return false }) - WriteAPIResponse(w, API_OK, struct { - BlockHeight uint - Accounts []*account.Account - }{blockHeight, accounts}) + WriteAPIResponse(w, API_OK, ResponseListAccounts{blockHeight, accounts}) } diff --git a/rpc/blocks.go b/rpc/blocks.go index 1415f1ff..5a9e37e5 100644 --- a/rpc/blocks.go +++ b/rpc/blocks.go @@ -7,6 +7,15 @@ import ( "github.com/tendermint/tendermint/types" ) +//----------------------------------------------------------------------------- + +// Request: {} + +type ResponseBlockchainInfo struct { + LastHeight uint + BlockMetas []*types.BlockMeta +} + func BlockchainInfoHandler(w http.ResponseWriter, r *http.Request) { minHeight, _ := GetParamUint(r, "min_height") maxHeight, _ := GetParamUint(r, "max_height") @@ -26,14 +35,18 @@ func BlockchainInfoHandler(w http.ResponseWriter, r *http.Request) { blockMetas = append(blockMetas, blockMeta) } - WriteAPIResponse(w, API_OK, struct { - LastHeight uint - BlockMetas []*types.BlockMeta - }{blockStore.Height(), blockMetas}) + WriteAPIResponse(w, API_OK, ResponseBlockchainInfo{blockStore.Height(), blockMetas}) } //----------------------------------------------------------------------------- +// Request: {"height": uint} + +type ResponseGetBlock struct { + BlockMeta *types.BlockMeta + Block *types.Block +} + func GetBlockHandler(w http.ResponseWriter, r *http.Request) { height, _ := GetParamUint(r, "height") if height == 0 { @@ -48,8 +61,5 @@ func GetBlockHandler(w http.ResponseWriter, r *http.Request) { blockMeta := blockStore.LoadBlockMeta(height) block := blockStore.LoadBlock(height) - WriteAPIResponse(w, API_OK, struct { - BlockMeta *types.BlockMeta - Block *types.Block - }{blockMeta, block}) + WriteAPIResponse(w, API_OK, ResponseGetBlock{blockMeta, block}) } diff --git a/rpc/mempool.go b/rpc/mempool.go index 81402ebb..5be8997b 100644 --- a/rpc/mempool.go +++ b/rpc/mempool.go @@ -10,6 +10,17 @@ import ( "github.com/tendermint/tendermint/types" ) +//----------------------------------------------------------------------------- + +// Request: {"tx": string} +// Note: "tx" should be json encoded signed transaction + +type ResponseBroadcastTx struct { + TxHash []byte + CreatesContract bool + ContractAddr []byte +} + func BroadcastTxHandler(w http.ResponseWriter, r *http.Request) { txJSON := GetParam(r, "tx") var err error @@ -37,11 +48,7 @@ func BroadcastTxHandler(w http.ResponseWriter, r *http.Request) { } } - WriteAPIResponse(w, API_OK, struct { - TxHash []byte - CreatesContract bool - ContractAddr []byte - }{txHash, createsContract, contractAddr}) + WriteAPIResponse(w, API_OK, ResponseBroadcastTx{txHash, createsContract, contractAddr}) return } diff --git a/rpc/net.go b/rpc/net.go index ae187e1a..6caeaec4 100644 --- a/rpc/net.go +++ b/rpc/net.go @@ -2,22 +2,47 @@ package rpc import ( "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/types" "net/http" ) +//----------------------------------------------------------------------------- + +// Request: {} + +type ResponseStatus struct { + ChainId string + LatestBlockHash []byte + LatestBlockHeight uint + LatestBlockTime int64 // nano + Network string +} + func StatusHandler(w http.ResponseWriter, r *http.Request) { - genesisHash := blockStore.LoadBlockMeta(0).Hash + genesisHash := p2pSwitch.GetChainId() latestHeight := blockStore.Height() - latestBlockMeta := blockStore.LoadBlockMeta(latestHeight) - latestBlockHash := latestBlockMeta.Hash - latestBlockTime := latestBlockMeta.Header.Time.UnixNano() - WriteAPIResponse(w, API_OK, struct { - GenesisHash []byte - LatestBlockHash []byte - LatestBlockHeight uint - LatestBlockTime int64 // nano - Network string - }{genesisHash, latestBlockHash, latestHeight, latestBlockTime, config.App().GetString("Network")}) + var ( + latestBlockMeta *types.BlockMeta + latestBlockHash []byte + latestBlockTime int64 + ) + if latestHeight != 0 { + latestBlockMeta = blockStore.LoadBlockMeta(latestHeight) + latestBlockHash = latestBlockMeta.Hash + latestBlockTime = latestBlockMeta.Header.Time.UnixNano() + } + + WriteAPIResponse(w, API_OK, ResponseStatus{genesisHash, latestBlockHash, latestHeight, latestBlockTime, config.App().GetString("Network")}) +} + +//----------------------------------------------------------------------------- + +// Request: {} + +type ResponseNetInfo struct { + NumPeers int + Listening bool + Network string } func NetInfoHandler(w http.ResponseWriter, r *http.Request) { @@ -25,9 +50,6 @@ func NetInfoHandler(w http.ResponseWriter, r *http.Request) { numPeers := o + i listening := p2pSwitch.IsListening() network := config.App().GetString("Network") - WriteAPIResponse(w, API_OK, struct { - NumPeers int - Listening bool - Network string - }{numPeers, listening, network}) + WriteAPIResponse(w, API_OK, + ResponseNetInfo{numPeers, listening, network}) } diff --git a/rpc/test/rpc_test.go b/rpc/test/rpc_test.go new file mode 100644 index 00000000..b480e310 --- /dev/null +++ b/rpc/test/rpc_test.go @@ -0,0 +1,70 @@ +package rpc + +import ( + "encoding/json" + "fmt" + "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/daemon" + "github.com/tendermint/tendermint/p2p" + "github.com/tendermint/tendermint/rpc" + "io/ioutil" + "net/http" + "testing" + "time" +) + +var ( + rpcAddr = "127.0.0.1:8089" + requestAddr = "http://" + rpcAddr + "/" + chainId string + node *daemon.Node +) + +func newNode() { + // Create & start node + node = daemon.NewNode() + l := p2p.NewDefaultListener("tcp", config.App().GetString("ListenAddr"), false) + node.AddListener(l) + node.Start() + + // Run the RPC server. + node.StartRpc() + + // Sleep forever + ch := make(chan struct{}) + <-ch +} + +func init() { + app := config.App() + app.Set("SeedNode", "") + app.Set("DB.Backend", "memdb") + app.Set("RPC.HTTP.ListenAddr", rpcAddr) + config.SetApp(app) + // start a node + go newNode() + time.Sleep(2 * time.Second) +} + +func TestSayHello(t *testing.T) { + resp, err := http.Get(requestAddr + "status") + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + var status struct { + Status string + Data rpc.ResponseStatus + } + err = json.Unmarshal(body, &status) + if err != nil { + t.Fatal(err) + } + if status.Data.ChainId != node.Switch().GetChainId() { + t.Fatal(fmt.Errorf("ChainId mismatch: got %s expected %s", status.Data.ChainId, node.Switch().GetChainId())) + } +} diff --git a/rpc/txs.go b/rpc/txs.go index 5c7588f7..6ef8c314 100644 --- a/rpc/txs.go +++ b/rpc/txs.go @@ -9,6 +9,15 @@ import ( "github.com/tendermint/tendermint/types" ) +//----------------------------------------------------------------------------- + +// Request: {"tx": string} +// Note: "tx" should be json encoded unsigned transaction + +type ResponseSignTx struct { + types.Tx +} + func SignTxHandler(w http.ResponseWriter, r *http.Request) { txStr := GetParam(r, "tx") privAccountsStr := GetParam(r, "privAccounts") @@ -53,5 +62,5 @@ func SignTxHandler(w http.ResponseWriter, r *http.Request) { rebondTx.Signature = privAccounts[0].Sign(rebondTx).(account.SignatureEd25519) } - WriteAPIResponse(w, API_OK, struct{ types.Tx }{tx}) + WriteAPIResponse(w, API_OK, ResponseSignTx{tx}) } diff --git a/rpc/validators.go b/rpc/validators.go index 9e277515..dfd4104a 100644 --- a/rpc/validators.go +++ b/rpc/validators.go @@ -6,6 +6,16 @@ import ( sm "github.com/tendermint/tendermint/state" ) +//----------------------------------------------------------------------------- + +// Request: {} + +type ResponseListValidators struct { + BlockHeight uint + BondedValidators []*sm.Validator + UnbondingValidators []*sm.Validator +} + func ListValidatorsHandler(w http.ResponseWriter, r *http.Request) { var blockHeight uint var bondedValidators []*sm.Validator @@ -22,9 +32,5 @@ func ListValidatorsHandler(w http.ResponseWriter, r *http.Request) { return false }) - WriteAPIResponse(w, API_OK, struct { - BlockHeight uint - BondedValidators []*sm.Validator - UnbondingValidators []*sm.Validator - }{blockHeight, bondedValidators, unbondingValidators}) + WriteAPIResponse(w, API_OK, ResponseListValidators{blockHeight, bondedValidators, unbondingValidators}) }