[TOC]
服务器端
RPC的启动是下面流程: /home/pct/go/src/github.com/Baptist-Publication/chorus/src/chain/cmd/run.go 中添加run命令:
func init() {
RootCmd.AddCommand(runCmd)
run命令会启动节点:
var runCmd = &cobra.Command{
Use: "run",
Short: "Run a blockchain full-capacity node",
Long: ``,
Args: cobra.NoArgs,
PreRun: func(cmd *cobra.Command, args []string) {
},
Run: func(cmd *cobra.Command, args []string) {
env := viper.GetString("environment")
logpath := viper.GetString("log_path")
if logpath == "" {
var err error
if logpath, err = os.Getwd(); err != nil {
cmd.Println(err)
os.Exit(1)
}
}
viper.Set("log_path", logpath)
logger := log.Initialize(env, path.Join(logpath, "node.output.log"), path.Join(logpath, "node.err.log"))
node.RunNode(logger, viper.GetViper())
},
}
RunNode函数绑定地址和路由表:
func RunNode(logger *zap.Logger, config *viper.Viper) {
node := NewNode(logger, config)
if err := node.Start(); err != nil {
cmn.Exit(cmn.Fmt("Failed to start node: %v", err))
}
if config.GetString("rpc_laddr") != "" {
if _, err := node.StartRPC(); err != nil {
cmn.PanicCrisis(err)
}
}
if config.GetBool("pprof") {
go func() {
http.ListenAndServe(":6060", nil)
}()
}
fmt.Printf("node (%s) is running on %s:%d ......\n", node.MainChainID, node.NodeInfo().ListenHost(), node.NodeInfo().ListenPort())
cmn.TrapSignal(func() {
node.Stop()
})
}
端口为6060,路由表如下:
func (n *Node) rpcRoutes() map[string]*rpc.RPCFunc {
h := newRPCHandler(n)
return map[string]*rpc.RPCFunc{
// subscribe/unsubscribe are reserved for websocket events.
// "subscribe": rpc.NewWSRPCFunc(SubscribeResult, argsWithChainID("event")),
// "unsubscribe": rpc.NewWSRPCFunc(UnsubscribeResult, argsWithChainID("event")),
// info API
"organizations": rpc.NewRPCFunc(h.Orgs, ""),
"status": rpc.NewRPCFunc(h.Status, argsWithChainID("")),
"net_info": rpc.NewRPCFunc(h.NetInfo, argsWithChainID("")),
"blockchain": rpc.NewRPCFunc(h.BlockchainInfo, argsWithChainID("minHeight,maxHeight")),
"genesis": rpc.NewRPCFunc(h.Genesis, argsWithChainID("")),
"block": rpc.NewRPCFunc(h.Block, argsWithChainID("height")),
"validators": rpc.NewRPCFunc(h.Validators, argsWithChainID("")),
"dump_consensus_state": rpc.NewRPCFunc(h.DumpConsensusState, argsWithChainID("")),
"unconfirmed_txs": rpc.NewRPCFunc(h.UnconfirmedTxs, argsWithChainID("")),
"num_unconfirmed_txs": rpc.NewRPCFunc(h.NumUnconfirmedTxs, argsWithChainID("")),
"num_archived_blocks": rpc.NewRPCFunc(h.NumArchivedBlocks, argsWithChainID("")),
"za_surveillance": rpc.NewRPCFunc(h.ZaSurveillance, argsWithChainID("")),
"core_version": rpc.NewRPCFunc(h.CoreVersion, argsWithChainID("")),
// broadcast API
"broadcast_tx_commit": rpc.NewRPCFunc(h.BroadcastTxCommit, argsWithChainID("tx")),
"broadcast_tx_sync": rpc.NewRPCFunc(h.BroadcastTx, argsWithChainID("tx")),
// query API
"query": rpc.NewRPCFunc(h.Query, argsWithChainID("query")),
"info": rpc.NewRPCFunc(h.Info, argsWithChainID("")),
"event_code": rpc.NewRPCFunc(h.EventCode, argsWithChainID("code_hash")), // TODO now id is base-chain's name
// control API
// "dial_seeds": rpc.NewRPCFunc(h.UnsafeDialSeeds, argsWithChainID("seeds")),
"unsafe_flush_mempool": rpc.NewRPCFunc(h.UnsafeFlushMempool, argsWithChainID("")),
// "unsafe_set_config": rpc.NewRPCFunc(h.UnsafeSetConfig, argsWithChainID("type,key,value")),
// profiler API
// "unsafe_start_cpu_profiler": rpc.NewRPCFunc(UnsafeStartCPUProfilerResult, argsWithChainID("filename")),
// "unsafe_stop_cpu_profiler": rpc.NewRPCFunc(UnsafeStopCPUProfilerResult, argsWithChainID("")),
// "unsafe_write_heap_profile": rpc.NewRPCFunc(UnsafeWriteHeapProfileResult, argsWithChainID("filename")),
// specialOP API
"request_special_op": rpc.NewRPCFunc(h.RequestSpecialOP, argsWithChainID("tx")),
// "vote_special_op": rpc.NewRPCFunc(h.VoteSpecialOP, argsWithChainID("tx")),
// "request_vote_channel": rpc.NewRPCFunc(RequestForVoteChannel, "tx"),
// refuse_list API
"blacklist": rpc.NewRPCFunc(h.Blacklist, argsWithChainID("")),
"non_empty_heights": rpc.NewRPCFunc(h.NonEmptyHeights, argsWithChainID("")),
}
}
客户端调用
客户端调用部分比较简单,直接创建RPC并调用即可:
func (act nodeActions) jsonRPC(chainID string, p []byte) (*types.RPCResult, error) {
clt := rpcclient.NewClientJSONRPC(logger, commons.QueryServer)
tmResult := new(types.RPCResult)
_, err := clt.Call("broadcast_tx_sync", []interface{}{chainID, p}, tmResult)
if err != nil {
return nil, err
}
return tmResult, nil
}