rpc: give each call a dedicated Response struct, add basic test

This commit is contained in:
Ethan Buchman 2015-03-25 18:06:57 -07:00
parent 87e1f76324
commit d2724c9731
9 changed files with 191 additions and 45 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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})
}

View File

@ -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})
}

View File

@ -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
}

View File

@ -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})
}

70
rpc/test/rpc_test.go Normal file
View File

@ -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()))
}
}

View File

@ -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})
}

View File

@ -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})
}