兄弟连区块链入门教程eth源码分析RPC分析

这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符。在这个环境里也内置了一些用来操作eth的 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

RPC包概述

RPC包主要的服务逻辑在server.go和subscription.go包中。接口的定义在types.go中。
RPC包主要实现在启动节点的时候,将自己写的api包通过反射的形式将方法名和调用的api绑定。在启动命令行之后,通过输入命令的形式,通过RPC方法找到对应的方法调用,获取返回值。

RPC方法追踪

首先,在geth启动时,geth中有startNode方法,通过层层跟踪我们进入到了Node.Start()方法中。
在start方法中,有一个startRPC方法,启动节点的RPC。

// 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()的定义如下:

// 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调用方法标准如下:

·对象必须导出
·方法必须导出
·方法返回0,1(响应或错误)或2(响应和错误)值
·方法参数必须导出或是内置类型
·方法返回值必须导出或是内置类型

在将各个API都写入到列表中之后,然后启动多个API endpoints。
这里我们以启动IPC为例,主要看startIPC方法。

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中。

// 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://blog.51cto.com/14027137/2303920

时间: 2024-07-31 13:07:50

兄弟连区块链入门教程eth源码分析RPC分析的相关文章

区块链入门教程eth的账户和基本单位

我们在命令行输入 eth.accounts 可以看到当前该区块链中共有几个账号,以及每个账号的公钥地址. 在eth系统中,状态是由被称为"账户"(每个账户由一个20字节的地址)的对象和在两个账户之间转移价值和信息的状态转换构成的. eth的账户包含四个部分: 随机数,用于确定每笔交易只能被处理一次的计数器 账户目前的以太币余额 账户的合约代码,如果有的话 账户的存储(默认为空) 简单地说,每一个eth账户都有一对公钥和私钥组成. 公钥我们可以理解为就是账户地址,任何其他账户都可以访问该

兄弟连区块链入门教程分享区块链POW证明代码实现demo

这里强调一下区块链的协议分层?应用层?合约层?激励机制?共识层?网络层?数据层上 一篇主要实现了区块链的 数据层,数据层主要使用的技术就是对数据的校验,求hash.这里介绍工作量证明POW, POW是属于共识机制的内容.PoW机制中根据矿工的工作量来执行货币的分配和记账权的确定.算力竞争的胜者将获得相应区块记账权和比特币奖励.因此,矿机芯片的算力越高,挖矿的时间更长,就可以获得更多的数字货币.优点:算法简单,容易实现:节点间无需交换额外的信息即可达成共识:破坏系统需要投入极大的成本.缺点:浪费能

兄弟连区块链入门教程之基础开发通过接口查询币种提币情况bch

代码如下 package main import ( "encoding/json" "fmt" "github.com/buger/jsonparser" "github.com/levigross/grequests" ) // HTTPGet . func HTTPGet(url string, requestOptions *grequests.RequestOptions) (response []byte, err

区块链入门教程以太坊源码分析fast sync算法一

区块链入门教程以太坊源码分析fast sync算法一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上.this PR aggregates a lot of small modifications to core, trie, eth and other packages to collectively implement the eth/63 fast synch

区块链入门教程

区块链(blockchain)是眼下的大热门,新闻媒体大量报道,宣称它将创造未来. 可是,简单易懂的入门文章却很少.区块链到底是什么,有何特别之处,很少有解释. 下面,我就来尝试,写一篇最好懂的区块链教程.毕竟它也不是很难的东西,核心概念非常简单,几句话就能说清楚.我希望读完本文,你不仅可以理解区块链,还会明白什么是挖矿.为什么挖矿越来越难等问题. 需要说明的是,我并非这方面的专家.虽然很早就关注,但是仔细地了解区块链,还是从今年初开始.文中的错误和不准确的地方,欢迎大家指正. 一.区块链的本质

区块链入门教程(转)

原作者:阮一峰 原文链接:http://www.ruanyifeng.com/blog/2017/12/blockchain-tutorial.html 区块链(blockchain)是眼下的大热门,新闻媒体大量报道,宣称它将创造未来. 可是,简单易懂的入门文章却很少.区块链到底是什么,有何特别之处,很少有解释. 下面,我就来尝试,写一篇最好懂的区块链教程.毕竟它也不是很难的东西,核心概念非常简单,几句话就能说清楚.我希望读完本文,你不仅可以理解区块链,还会明白什么是挖矿.为什么挖矿越来越难等问

区块链入门教程以太坊源码分析p2p-rlpx节点之间的加密链路二

// Sign known message: static-shared-secret ^ nonce // 这个地方应该是直接使用了静态的共享秘密. 使用自己的私钥和对方的公钥生成的一个共享秘密. token, err = h.staticSharedSecret(prv) if err != nil { return nil, err } //这里我理解用共享秘密来加密这个initNonce. signed := xor(token, h.initNonce) // 使用随机的私钥来加密这个

区块链入门教程以太坊源码分析p2p-dial.go源码分析

dial.go在p2p里面主要负责建立链接的部分工作. 比如发现建立链接的节点. 与节点建立链接. 通过discover来查找指定节点的地址.等功能.dial.go里面利用一个dailstate的数据结构来存储中间状态,是dial功能里面的核心数据结构.// dialstate schedules dials and discovery lookups.// it get's a chance to compute new tasks on every iteration// of the ma

兄弟连区块链入门到精通教程基础开发通过接口查询xrp提币情况

package main import ( "errors" "fmt" "math" "strconv" "strings" "github.com/buger/jsonparser" "github.com/levigross/grequests" ) const min = 0.000000000001 func isEqual(f1, f2 float64)