ETH 中继接口
1. 接受其他服务端脸上的相关服务请求,中继处理请求业务,将处理后的响应返回给用户。如查询余额等
2. 发起交易的功能,包括ETH转账和ERC20转账
3. 用户的钱包创建
4. 对链上区块相关事件的监听,目前可以实现的监听事件包括但不限于如下:
a. ERC20 Token的授权Approve事件
b. Token转账Transfer的结果事件
c. WETH Token置换ETH事件
d. 新区块生成事件
e. 遍历一个区块事件
f. 区块分查事件
在中继开发中,事件的监听是开发难度最高的。 事件监听的技术原理主要是通过获取一个区块内部的交易信息并解析交易信息内的“EventLog”(日志事件)来达到目的。 目前ETH提供web.js库,该库中有区块事件监听函数,但并不完美,有以下不足:
为什么要监听? 中心化Exchange就要做这样的事情,比如充值或者提现,都需要对链上的数据进行监控,要链上转账成功后,再修改中心化服务端的数据库,如果不监控,就提现而言,如果链上交易失败,但是用户在中心化的数值减少了,就会有问题。
在ETH机制中,链上的授权,交易,合约发布等事件都是一条条的交易信息,可以把每一笔交易信息提取出来,进行划分处理,就可以实现不同的功能和业务。
RPC接口在基于通讯协议方面有多种实现方法,但是主要是如下两种:
两种方式的区别在于请求和响应的位置,一个是在应用层,一个是在传输层。 RPC接口和“RESTful API”接口,在HTTP/HTTPS协议实现,在速度方面几乎没有差别, 但是基于传输层的TCP协议实现的RPC接口,除了数据传输流的层级上比"RESTful"接口少而整体比它快外,传输时的整体数据报层面还少了HTTP/HTTPS的头部数据量及组装的时间损耗。也即是说,当RPC接口基于传输层的TCP协议实现时,RPC接口不仅请求和响应的速度比“RESTful”接口快,而且数据量也相对要少。
常见的RPC框架有以下几种:
简言之:RPC协议,就是规范了一种客户端和实现了RPC接口的服务端交互的数据格式。
RPC接口实现的大致流程:
在了解ETH RPC接口之前,先了解3个参数,因为这3个参数会出现在每一个接口中。
该接口可以根据传参(genesis,pending,latest)获取 3 种类型的区块高度
该接口根据区块高度获取区块的部分信息,是在遍历区块时主要用来获取区块数据信息的一个接口。该接口可以提供如下数据:
也就是说,返回的数据的结构体是Block,即这个结构体所含有的信息,都可以拿得到。
// Block表示以太坊区块链中的一个完整的区块。
type Block struct {
// block的header指向的是一个的结构体,其中带有该block的所有属性信息
header *Header
// 叔块block的数组
uncles []*Header
// 当前该区块所有打包的交易记录
transactions Transactions
// 缓存,应该是该区块的的hash及区块大小
hash atomic.Value
size atomic.Value
// total difficulty,当前区块总共的难度值=前一个区块的td+当前区块header中的difficulty。
td *big.Int
// 区块被接受的时间
ReceivedAt time.Time
// 记录区块是从哪个P2P网络传过来的
ReceivedFrom interface{}
}
该接口可以根据一笔交易记录的哈希值,可以获取这笔交易的详细信息。 该接口提供了交易查询功能,在获取交易区块信息后,从区块信息中获取被打包的交易的哈希值,进行全部交易信息的提取。处于pending(等待或者挂起)状态的交易,返回的将会是空,也可以根据接口的这一特点来判断一笔交易是否成功。 获取数据的结构体是Transaction。
// Transaction is an Ethereum transaction.
type Transaction struct {
inner TxData // Consensus contents of a transaction
time time.Time // Time first seen locally (spam avoidance)
// caches
hash atomic.Value
size atomic.Value
from atomic.Value
}
// TxData is the underlying data of a transaction.
//
// This is implemented by DynamicFeeTx, LegacyTx and AccessListTx.
type TxData interface {
txType() byte // returns the type ID
copy() TxData // creates a deep copy and initializes all fields
chainID() *big.Int
accessList() AccessList
data() []byte
gas() uint64
gasPrice() *big.Int
gasTipCap() *big.Int
gasFeeCap() *big.Int
value() *big.Int
nonce() uint64
to() *common.Address
rawSignatureValues() (v, r, s *big.Int)
setSignatureValues(chainID, v, r, s *big.Int)
}
该接口可以根据一个交易的哈希值来获取这笔交易收据信息。 该接口返回的数据在一定程度上和eth_TransactionByHash是相同的,但该接口返回的数据更加详细,例如交易的日志Logs,这也是进行事件监听最主要的数据源。和eth_getTransactionByHash一样,处于pending状态的交易,返回的将会是空。返回的结构体是Receipt
// Receipt represents the results of a transaction.
type Receipt struct {
// Consensus fields: These fields are defined by the Yellow Paper
Type uint8 `json:"type,omitempty"`
PostState []byte `json:"root"`
// 当这笔交易是成功的,该值为true,即 1 ,否则为 false
Status uint64 `json:"status"`
// 该字段和GasUsed不一样,它所代表的是当前的交易 所在区块的列表中,
// 当前TransactionIndex之上的包含的其他所有交易的Gas之和。
// 例如,TransactionIndex = 4,
// 那么它的CumulativeGasUsed数值就是下标为 01234的交易的GasUsed数值之和
CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"`
// 由当前交易生成的事件(Event)日志
Logs []*Log `json:"logs" gencodec:"required"`
// Implementation fields: These fields are added by geth when processing a transaction.
// They are stored in the chain database.
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
// 合约地址,只有在当前交易是合约创建的情况才会有值
// 对应的是新创建合约的ETH地址,其他情况为空
ContractAddress common.Address `json:"contractAddress"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
// Inclusion information: These fields provide information about the inclusion of the
// transaction corresponding to this receipt.
BlockHash common.Hash `json:"blockHash,omitempty"`
BlockNumber *big.Int `json:"blockNumber,omitempty"`
TransactionIndex uint `json:"transactionIndex"`
}
该接口获取的是某个ETH地址的ETH数值,即ETH余额。它不是获取ERC20 Token或者其他Token的余额。
是所有交易的触发接口。其中eth_sendRawTransaction 可以完成的交易类型包含eth_sendTransaction.
该接口可以根据一个ETH钱包地址获取当前钱包地址的交易序列号Nonce,该接口的第二参数是genesis、pending、latest,各个参数的分别对应的是下面的作用:
该接口根据ETH地址判断当前地址时合约地址还是非合约地址。如果不是,返回值是"0x",否则,返回的是智能合约当初创建时的十六进制码。
该接口用来估算一笔交易要消耗多少GasLimit,该所估算出来的值没有涉及GasPrice。 入参中的data是被估算的数据量,估算的结果数值和数据量成正比。 这个接口在钱包发起交易的时让用户选择燃料费为多少的功能上会用到,提现在燃料费进度条中的最大值上。最大值一般就是这个接口返回的数值。
这是ETH用来访问智能合约的万能RPC接口,也就是说,任何智能合约上的公有函数都能使用这个接口访问。
eth_getBalance是用来查询ETH余额的,但是ERC20 Token 余额,就需要通过eth_call来进行查询。这个接口的入参和 eth_sendRawTransaction/eth_sendTransaction入参是一样的。 eth_call接口是一个只读接口,不会改变区块链上的数据,可以访问ETH智能合约中的所有函数。
eth_call只读特性从源码上层面的理解 EVM在执行合约代码时, 先,使用区块号blockNumber找出对应的区块信息, 再,系统地根据这个区块的数据实例化一个名为status的变量,由status来实例化对应的EVM实例, 然后,根据区块提供的信息来实例化合约代码的变量值,即智能合约的函数在被执行前它的变量值是由当前区块高度决定的。 也就是说,eth_call在调用transfer函数时会直接在代码的内存层面进行值的修改,并没有广播出去和修改到数据层面。
目前获取节点链接的的方案有两种
对于第一种方法,操作流程是先下载对应的ETH节点版本源码,然后根据文档的编译方法进行自编译,生成可执行程序,再部署到服务器。需要注意的是,ETH节点的源码不仅仅有版本号不同的版本,还有不同计算机语言的版本,官方的Geth是Golang语言开发的版本。
第一种方整体实施起来的优缺点: (1) 可自定义性高
(2) 技术要求难度相对来说比较高
(3) 自运维成本高
(4) 需要自付费服务器等产品的花销
第二种方案
第二种方案和第一种方案对比,优缺点相反。 第二种方案也是最方便和便宜的,因为只需要一个链接即可。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!