以太坊原始碼分析(13)RPC分析
這是一個互動式的 JavaScript 執行環境,在這裡面可以執行 JavaScript 程式碼,其中 > 是命令提示符。在這個環境裡也內建了一些用來操作以太坊的 JavaScript 物件,可以直接使用這些物件。這些物件主要包括:
eth:包含一些跟操作區塊鏈相關的方法;
net:包含一些檢視p2p網路狀態的方法;
admin:包含一些與管理節點相關的方法;
miner:包含啟動&停止挖礦的一些方法;
personal:主要包含一些管理賬戶的方法;
txpool:包含一些檢視交易記憶體池的方法;
web3:包含了以上物件,還包含一些單位換算的方法。
personal.newAccount('liyuechun')
personal.listAccounts
account1 = web3.eth.coinbase
web3.eth.getBalance(account1)
傳送交易:
eth.sendTransaction({from:"0x1c0f18be339b56073e5d18b479bbc43b0ad5349c", to:"0x13d0dc1c592570f48360d7b779202d8df404563e", value: web3.toWei(0.05, "ether")})
#增加節點
admin.addPeers("..")
#檢視當前鏈連線資訊
admin.nodeInfo.enode
#檢視連線了幾個節點
web3.net.peerCount
net.listening
#檢視連線了幾個節點
net.peerCount
#連線對應workid鏈的控制檯
--networkid=1114 console
初始化創世塊
init /home/yujian/eth-go/genesis.json --datadir /home/yujian/eth-go
根據創世塊啟動,並且開啟控制檯
--datadir /home/yujian/eth-go --networkid 1114 --port 30304 console 2>>/home/yujian/eth-go/myEth2.log
eth:包含一些跟操作區塊鏈相關的方法;
net:包含一些檢視p2p網路狀態的方法;
admin:包含一些與管理節點相關的方法;
miner:包含啟動&停止挖礦的一些方法;
personal:主要包含一些管理賬戶的方法;
txpool:包含一些檢視交易記憶體池的方法;
web3:包含了以上物件,還包含一些單位換算的方法。
personal.newAccount('liyuechun')
personal.listAccounts
account1 = web3.eth.coinbase
web3.eth.getBalance(account1)
傳送交易:
eth.sendTransaction({from:"0x1c0f18be339b56073e5d18b479bbc43b0ad5349c", to:"0x13d0dc1c592570f48360d7b779202d8df404563e", value: web3.toWei(0.05, "ether")})
#增加節點
admin.addPeers("..")
#檢視當前鏈連線資訊
admin.nodeInfo.enode
#檢視連線了幾個節點
web3.net.peerCount
net.listening
#檢視連線了幾個節點
net.peerCount
#連線對應workid鏈的控制檯
--networkid=1114 console
初始化創世塊
init /home/yujian/eth-go/genesis.json --datadir /home/yujian/eth-go
根據創世塊啟動,並且開啟控制檯
--datadir /home/yujian/eth-go --networkid 1114 --port 30304 console 2>>/home/yujian/eth-go/myEth2.log
## RPC包概述
RPC包主要的服務邏輯在server.go和subscription.go包中。介面的定義在types.go中。
RPC包主要實現在啟動節點的時候,將自己寫的api包通過反射的形式將方法名和呼叫的api繫結。在啟動命令列之後,通過輸入命令的形式,通過RPC方法找到對應的方法呼叫,獲取返回值。
## RPC方法追蹤
首先,在geth啟動時,geth中有startNode方法,通過層層跟蹤我們進入到了Node.Start()方法中。
在start方法中,有一個startRPC方法,啟動節點的RPC。
```go
// startRPC is a helper method to start all the various RPC endpoint during node
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
func (n *Node) startRPC(services map[reflect.Type]Service) error {
// Gather all the possible APIs to surface
apis := n.apis()
for _, service := range services {
apis = append(apis, service.APIs()...)
}
// Start the various API endpoints, terminating all in case of errors
if err := n.startInProc(apis); err != nil {
return err
}
if err := n.startIPC(apis); err != nil {
n.stopInProc()
return err
}
if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors); err != nil {
n.stopIPC()
n.stopInProc()
return err
}
if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
n.stopHTTP()
n.stopIPC()
n.stopInProc()
return err
}
// All API endpoints started successfully
n.rpcAPIs = apis
return nil
}
```
這裡,startRPC方法在執行時就會去讀取api,然後暴露各個api。
apis()的定義如下:
```go
// apis returns the collection of RPC descriptors this node offers.
func (n *Node) apis() []rpc.API {
return []rpc.API{
{
Namespace: "admin",
Version: "1.0",
Service: NewPrivateAdminAPI(n),
}, {
Namespace: "admin",
Version: "1.0",
Service: NewPublicAdminAPI(n),
Public: true,
}, {
Namespace: "debug",
Version: "1.0",
Service: debug.Handler,
}, {
Namespace: "debug",
Version: "1.0",
Service: NewPublicDebugAPI(n),
Public: true,
}, {
Namespace: "web3",
Version: "1.0",
Service: NewPublicWeb3API(n),
Public: true,
},
}
}
```
其中,Namespace是我們定義的包名,即在命令列中可以呼叫的方法。
Version是這個包的版本號。
Service是所對映的API管理的結構體,這裡API的方法需要滿足RPC的標準才能通過校驗。
成為RPC呼叫方法標準如下:
```markdown
·物件必須匯出
·方法必須匯出
·方法返回0,1(響應或錯誤)或2(響應和錯誤)值
·方法引數必須匯出或是內建型別
·方法返回值必須匯出或是內建型別
```
在將各個API都寫入到列表中之後,然後啟動多個API endpoints。
這裡我們以啟動IPC為例,主要看startIPC方法。
```go
func (n *Node) startIPC(apis []rpc.API) error {
// Short circuit if the IPC endpoint isn't being exposed
if n.ipcEndpoint == "" {
return nil
}
// Register all the APIs exposed by the services
handler := rpc.NewServer()
for _, api := range apis {
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
n.log.Debug(fmt.Sprintf("IPC registered %T under '%s'", api.Service, api.Namespace))
}
...
```
這裡會首先啟建立一個rpc server。在啟動的過程中,rpc server會將自己註冊到handler中,即rpc包。
在建立rpc server之後,handler會通過RegisterName方法將暴露的方法註冊到rpc server中。
```go
// RegisterName will create a service for the given rcvr type under the given name. When no methods on the given rcvr
// match the criteria to be either a RPC method or a subscription an error is returned. Otherwise a new service is
// created and added to the service collection this server instance serves.
func (s *Server) RegisterName(name string, rcvr interface{}) error {
if s.services == nil {
s.services = make(serviceRegistry)
}
svc := new(service)
svc.typ = reflect.TypeOf(rcvr)
rcvrVal := reflect.ValueOf(rcvr)
if name == "" {
return fmt.Errorf("no service name for type %s", svc.typ.String())
}
if !isExported(reflect.Indirect(rcvrVal).Type().Name()) {
return fmt.Errorf("%s is not exported", reflect.Indirect(rcvrVal).Type().Name())
}
methods, subscriptions := suitableCallbacks(rcvrVal, svc.typ)
// already a previous service register under given sname, merge methods/subscriptions
if regsvc, present := s.services[name]; present {
if len(methods) == 0 && len(subscriptions) == 0 {
return fmt.Errorf("Service %T doesn't have any suitable methods/subscriptions to expose", rcvr)
}
for _, m := range methods {
regsvc.callbacks[formatName(m.method.Name)] = m
}
for _, s := range subscriptions {
regsvc.subscriptions[formatName(s.method.Name)] = s
}
return nil
}
svc.name = name
svc.callbacks, svc.subscriptions = methods, subscriptions
if len(svc.callbacks) == 0 && len(svc.subscriptions) == 0 {
return fmt.Errorf("Service %T doesn't have any suitable methods/subscriptions to expose", rcvr)
}
s.services[svc.name] = svc
return nil
}
```
在RegisterName方法中,這個方法會將所提供包下所有符合RPC呼叫標準的方法註冊到Server的callback呼叫集合中等待呼叫。
這裡,篩選符合條件的RPC呼叫方法又suitableCallbacks方法實現。
這樣就將對應包中的方法註冊到Server中,在之後的命令列中即可呼叫。
網址:http://www.qukuailianxueyuan.io/
欲領取造幣技術與全套虛擬機器資料
區塊鏈技術交流QQ群:756146052 備註:CSDN
尹成學院微信:備註:CSDN
相關文章
- 以太坊原始碼分析(51)rpc原始碼分析原始碼RPC
- 以太坊原始碼分析(37)eth以太坊協議分析原始碼協議
- 以太坊原始碼分析(18)以太坊交易執行分析原始碼
- 以太坊原始碼分析(36)ethdb原始碼分析原始碼
- 以太坊原始碼分析(38)event原始碼分析原始碼
- 以太坊原始碼分析(41)hashimoto原始碼分析原始碼
- 以太坊原始碼分析(43)node原始碼分析原始碼
- 以太坊原始碼分析(52)trie原始碼分析原始碼
- 以太坊原始碼分析(5)accounts程式碼分析原始碼
- 以太坊原始碼分析(8)區塊分析原始碼
- 以太坊原始碼分析(9)cmd包分析原始碼
- 以太坊原始碼分析(16)挖礦分析原始碼
- 以太坊交易池原始碼分析原始碼
- 以太坊原始碼分析(35)eth-fetcher原始碼分析原始碼
- 以太坊原始碼分析(20)core-bloombits原始碼分析原始碼OOM
- 以太坊原始碼分析(24)core-state原始碼分析原始碼
- 以太坊原始碼分析(29)core-vm原始碼分析原始碼
- 以太坊原始碼分析(34)eth-downloader原始碼分析原始碼
- 以太坊原始碼分析(10)CMD深入分析原始碼
- 以太坊原始碼分析(12)交易資料分析原始碼
- 以太坊原始碼分析(19)core-blockchain分析原始碼Blockchain
- 以太坊原始碼分析(23)core-state-process原始碼分析原始碼
- 以太坊原始碼分析(31)eth-downloader-peer原始碼分析原始碼
- 以太坊原始碼分析(32)eth-downloader-peer原始碼分析原始碼
- 以太坊原始碼分析(33)eth-downloader-statesync原始碼分析原始碼
- 以太坊原始碼分析(52)以太坊fast sync演算法原始碼AST演算法
- 以太坊原始碼分析(39)geth啟動流程分析原始碼
- 以太坊原始碼分析(6)accounts賬戶管理分析原始碼
- 以太坊原始碼分析(14)P2P分析原始碼
- 以太坊原始碼分析(9)CMD實際操作分析原始碼
- 以太坊原始碼分析(26)core-txpool交易池原始碼分析原始碼
- 以太坊原始碼分析(27)core-vm-jumptable-instruction原始碼分析原始碼Struct
- 以太坊原始碼分析(28)core-vm-stack-memory原始碼分析原始碼
- 以太坊原始碼分析(30)eth-bloombits和filter原始碼分析原始碼OOMFilter
- 以太坊原始碼分析(54)以太坊隨機數生成方式原始碼隨機
- 以太坊原始碼分析(3)以太坊交易手續費明細原始碼
- 死磕以太坊原始碼分析之state原始碼
- 死磕以太坊原始碼分析之txpool原始碼