寺院
安装及部署
利用如下指令获取项目源代码
go get github.com/ontio/ontology
进入项目目录,构建项目,该步骤会在项目中生成可执行文件
make
创建钱包及账号,输入密码
./ontology account add --default
可以部署单节点测试网络,亦可使用其他共识算法,具体配置方法可参见官方文档
./ontology --testmode
如果需要连接主网或测试网可以通过指定–networkid来确定该节点连接到何种网络,例如连接至主网可以使用
./ontology --networkid 1
由于Ontology中转账等操作均使用智能合约完成,其内置了完成这些功能的智能合约,因此接下来简要介绍智能合约的编写、部署及调用过程。
首先利用Ontology提供的在线编译工具SmartX完成智能合约的编写及编译(登陆SmartX时需使用代理),目前该网站支持Python及C#编写智能合约,并保存ABI文件及AVM文件。
部署该智能合约,该条命令中--needstore标志该智能合约需要使用存储,gaslimit在其文档中要求至少设定为该值,不确定数字是如何得出的
./ontology contract deploy --name=KV --code=./KV.avm --author=none --desc=nonoe --email=none --needstore --gaslimit=100000000
#该指令执行完成后该合约已经完成了部署,会返回一hash,可使用./ontology info status来确定该合约的状态,State字段为1表示合约已经成功部署,也可使用./ontology info tx 了解该合约的具体信息
执行该智能合约,执行智能合约时可能有一预执行阶段,该阶段是由于某些操作如查询等并不需要等待区块链的确认,可以直接通过查询本地数据得到一个可接受的结果
#调用智能合约时需要指定两个参数,一个时operation,一个是args,args需为一数组
./ontology contract invoke --address=7b37e88c3cdad2fec3e4af0caf0286994dbc1046 --params string:modify,[string:a,string:1]
#此时可以从ontology的Debug日志中发现对Neovm的调用,但不知为什么并没有任何有关智能合约的输出
总体流程分析
- ontology使用cli来作为命令行框架,参数可以通过main.go中setupAPP函数里的Commands来查看不同命令及其子命令,可根据其中的Action字段找到对应命令的处理函数。同时ontology还使用protoactor-go来进行消息的传递与处理。
- ontology中发送一笔转账交易的过程如下:
- 找到对应命令的处理函数位于cmd/asset_cmd.go中的transfer函数,该函数有唯一的参数cli.Context,该参数由cli框架自动传递给该函数。
- 该函数会分析命令行参数,并调用utils.Transfer
- utils.Transfer会调用TransferTx来构建一个交易。为构建该交易会使用BuildNativeInvokeCode将参数整合为一invokeCode,该invokeCode中包含了需要调用的智能合约的地址,ontology内置了部分智能合约,其地址声明在smartcontract/service/native/utils/params.go中
- 构建完成交易后会对该交易的hash值进行签名
- 签名完成后会利用SendRawTransaction将该交易发送至Ontology网络中,该函数会实际使用sendRpcRequest将该交易发送至本地对应端口,该端口应当有对应的进程监听
- setupApp函数对应的Action为startOntology,该函数会进行节点信息的初始化,包括初始化共识服务以及设置不同消息的actor。
- 从staratOntology中可以看到initRpc函数,该函数启动了一RPC服务器,并为“sendrawtransaction”添加了处理函数rpc.SendRawTransaction。查看该函数,如果交易类型为types.Invoke,会执行PreExecuteContract,之后调用VerifyAndSendTx,该函数会将向TxActor发送一条信息(TxActor在initTxPool中进行初始化),进而调用TxActor.handleTransaction。该函数会调用assignTxToWorker来将交易分配给未处理的交易列表最短的一个Worker。Worker为启动TxnPoolServer时创建的多个(默认为2)GoRoutine,worker收到交易后会将该交易发送给validator来进行验证,并将该交易放入pendingTxList中。validator在验证完成这笔交易后会生成CheckResponse返回给发送者,进而分发给在StartTxnPoolServer注册的VerifyRspActor,进而调用assignRspToWorker将交易的验证结果返回给对应的worker。worker会根据交易的验证结果决定将该交易放入交易池中、重新进行验证(validator分为两种,分别为stateful_validator、stateless_validator)或直接丢弃该交易,一个交易在验证后会生成一个TXEntry,TXEntry中不仅包含该交易还包含一些与该交易验证结果有关的消息,包括当这笔交易被验证时区块链的高度,如果之后生成区块时发现这笔交易的验证已经过旧则会要求重新进行该交易的验证。
- 接下来的分析基于使用testmode时使用的仅有单个节点的共识算法。该共识算法会有一goroutine每隔一段一段时间调用一次genBlock。genBlock会首先调用makeBlock,该函数会使用IncrementValidator,该对象保存了过去部分区块的交易Hash,可以用来检测在过去的部分区块中是否存在相同Hash的交易,之后会利用GetTxnPool获取交易池中的交易生成一个新的区块。由于此时仅有一个节点,因此直接将该区块加入默认账本中。
- 将该区块加入账本会调用AddBlock函数,该函数会进而调用LedgerStoreImp的AddBlock函数,该函数会根据区块的高度确定该区块的高度是否合适,如果该区块的高度不为下一个区块则会将该区块进行缓存。如果该区块为下一个区块则会将该区块进行存储,并调用saveBlockToStateStore,在该函数中会调用handleTransaction来执行交易,利用该交易的类型是Deploy还是Invoke来决定进一步的操作。
利用ontology客户端发送交易流程图