咨询热线:027-52344235 关注我们
分享到

以太坊源码分析(13)RPC分析 怎么制作区块链

来源: 网络 2018-09-30 加入收藏 870

以太坊源码分析(13)RPC分析 怎么制作区块链以太坊源码分析(13)RPC分析

作者:尹成

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符。在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以直接使用这些对象。这些对象主要包括:

eth:包含一些跟操作区块链相关的方法;

net:包含一些查看p2p网络状态的方法;

admin:包含一些与管理节点相关的方法;

miner:包含启动&停止挖矿的一些方法;

personal:主要包含一些管理账户的方法;

txpool:包含一些查看交易内存池的方法;

web3:包含了以上对象,还包含一些单位换算的方法。

('liyuechun')

 

account1 = web3.eth.coinbase

web3.eth.getBalance(account1)

发送交易:

({from:"0x1c0f18be339b56073e5d18b479bbc43b0ad5349c", to:"0x13d0dc1c592570f48360d7b779202d8df404563e", value: (, "ether")})

#增加节点

("..")

#查看当前链连接信息

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包主要的服务逻辑在和包中。接口的定义在中。

RPC包主要实现在启动节点的时候,将自己写的api包通过反射的形式将方法名和调用的api绑定。在启动命令行之后,通过输入命令的形式,通过RPC方法找到对应的方法调用,获取返回值。

## RPC方法追踪

首先,在geth启动时,geth中有startNode方法,通过层层跟踪我们进入到了()方法中。

在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[]Service) error {

// Gather all the possible APIs to surface

apis := ()

for _, service := range services {

apis = append(apis, ()...)

}

// Start the various API endpoints, terminating all in case of errors

if err := (apis); err != nil {

return err

}

if err := (apis); err != nil {

()

return err

}

if err := (n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors); err != nil {

()

()

return err

}

if err := (n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {

()

()

()

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() [] {

return []{

{

Namespace: "admin",

Version: "",

Service: NewPrivateAdminAPI(n),

}, {

Namespace: "admin",

Version: "",

Service: NewPublicAdminAPI(n),

Public: true,

}, {

Namespace: "debug",

Version: "",

Service: ,

}, {

Namespace: "debug",

Version: "",

Service: NewPublicDebugAPI(n),

Public: true,

}, {

Namespace: "web3",

Version: "",

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 []) 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 := ()

for _, api := range apis {

if err := (api.Namespace, api.Service); err != nil {

return err

}

(("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 == nil {

= make(serviceRegistry)

}

svc := new(service)

= Of(rcvr)

rcvrVal := (rcvr)

if name == "" {

return fmt.Errorf("no service name for type %s", ())

}

if !isExported((rcvrVal).Type().Name()) {

return fmt.Errorf("%s is not exported", (rcvrVal).Type().Name())

}

methods, subscriptions := suitableCallbacks(rcvrVal, )

// already a previous service register under given sname, merge methods/subscriptions

    if regsvc, present := [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 {

            [formatName()] = m

        }

        for _, s := range subscriptions {

            [formatName()] = s

        }

        return nil

    }

     = name

    , = methods, subscriptions

    if len() == 0 && len() == 0 {

        return fmt.Errorf("Service %T doesn't have any suitable methods/subscriptions to expose", rcvr)

    }

    [] = svc

    return nil

}

```

在RegisterName方法中,这个方法会将所提供包下所有符合RPC调用标准的方法注册到Server的callback调用集合中等待调用。

这里,筛选符合条件的RPC调用方法又suitableCallbacks方法实现。

这样就将对应包中的方法注册到Server中,在之后的命令行中即可调用。

文章发布只为分享区块链技术内容,版权归原作者所有,观点仅代表作者本人,绝不代表区块链百科赞同其观点或证实其描述。

【免责声明】本文仅代表作者本人观点,与本网站无关。本网站对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。请读者仅作参考,并请自行承担全部责任。
广告位
中亿财经网官方公众号
  • 咨询热线 400-022-9909
  • 投稿咨询QQ:2126755803
  • 问题咨询处理QQ:1821361971
  • 官方交流群:(群:157829371)
  • 增值电信业务经营许可证:鄂B2-20170157
  • 广播电视节目许可证:鄂字第00358号
  • 网文经营许可证:鄂网文(2017)10517-260号