【比原链起步】使用Python与节点rpc通信以及编译比原链智能合约

490 阅读4分钟

此文将投稿给“比原链|用技术书写未来”。

前言:作为一个2016年末开始投资区块链的Python程序员,我对比原链从诞生发布到主网上线的过程是很有记忆的,公司新的业务是比原链挖矿和钱包项目,我开始接触Bytom的代码,这一系列文章将是我学习比原链技术之路,希望能和你一起进步。

在之前我们已经编译运行了比原链节点了,在bytom/目录下,有cmd/目录,cmd/bytomd/是之前我们运行节点使用的,/cmd/bytomcli/ 目录是与节点通信的client工具,使用 netstat -ltn 命令,bytomd运行后开放了9888端口,可以直接通过ip:9888 访问Dashboard,在这之前查看 api wiki 可以使用bycomcli 命令行工具创建访问所需要的access-token。

但是在程序中远程调试和调用的需要,更多是使用比原链节点的rpc api来代替命令行交互,我使用Python,所以 会使用Python来封装接口。

class btm(object):

    def __init__(self):
        self.url = 'http://118.xx.xxx.xx:9888'
        self.access_token = base64.b64encode(b'mac:xxx00efe24566804138907b6e9')
        self.authHeader = {'Authorization': 'Basic ' + self.access_token.decode()}


    def create_key(self,alias,password):
        uri = self.url+'/create-key'
        playload = {'alias':alias,'password':str(password)}
        r = requests.post(uri,json=playload,timeout=10,headers=self.authHeader)
        return json.loads(r.text)

    def list_keys(self):
        uri = self.url+'/list-keys'
        r = requests.post(uri,timeout=10,headers=self.authHeader)
        return json.loads(r.text)

这是节点一些rpc功能举例,可以根据需要把所需要的接口封装,其中在远程访问是需要创建的access-token需要经过base64编码并放在Headers中。

比原链最近发布了比原链智能合约语言Equity,可以使用智能合约了,由于之前一章我们搭建节点时,比原链还没有发布智能合约,所以我们需要更新下节点来支持我们智能合约的编译。通过Git下Bytom代码库更新代码再次编译,所有区块文件和钱包文件都在。运行节点后,就已经支持compile接口啦。

学习比原链智能合约官方教程,感觉学习曲线是比较友好的,我将使用Python编译和部署一个简单的合约。

准备环境:Linux Ubuntu 16.04 Python3.6

1../bytomcli create-key super 111222 创建keystore文件

2../bytomcli create-account alias root_xpub 使用之前key的xpub来创建账户

3../bytomcli list-accounts 找到我们创建账户的id和xpubs,后续要用

4../bytomcli create-asset GOLD xpubs 使用我们之前账户的xpubs创建一种我们自定义的叫GOLD的资产

5../bytomcli list-assets 可以找到我们已经创建的GOLD资产,找到资产id,我们后续要用

6.编写一个基本的智能合约,这个合约表示锁定一些资产,并且只能使用对应pubkey才能解锁资产

contract = '''
    contract LockBySuper (pubkey: PublicKey) locks SuperValue {
        clause spend(sig: Signature) {
            verify checkTxSig(pubkey,sig)
            unlock SuperValue
        }
    }
  1. 构建向节点发送编译的body内容
body = {
    'contract':'contract LockWithPublicKey(publicKey: PublicKey) locks locked { clause unlockWithSig(sig: Signature) { verify checkTxSig(publicKey, sig) unlock locked }}',
    'args':[
        {
            'string':'66be3da3ea40f3d37075e32d1b3a4beca03703d27d9ed8c4a8edd047961e0d6d'
        }
    ]
}

这里的string类型放置的就是pubickey值,可以用./bytomcli list-key account_id获取到

8.编译合约

import requests
import base64

node = 'http://118.24.xxx.xx:9888/compile'
access_token = base64.b64encode(b'mac:xxxxxfff4bf00ea3d78f00bab81ab57f0c6746117c857d241')
authHeader = {'Authorization': 'Basic '+access_token.decode()}

def main():
    r = requests.post(url=node,headers=authHeader,json=body)
    print(r.text)

执行main()方法后,节点返回编译后的信息

表示编译成功。返回结构中的program值是我们要锁定的合约

9.锁定合约,编译完成后,需要将合约锁定,这里和发送资产一样使用build-transaction方法,编写交易body

{"base_transaction":null,"actions":[{"account_id":"0BF63M2UXXXX","amount":20000000,"asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","type":"spend_account"},{"account_id":"0BF63M2UXXXX","amount":999,"asset_id":"a937476fdb0585b466c312bb4e2b4a157d50dfc6270d53d8acd49d9ce43d3140","type":"spend_account"},{"amount":999,"asset_id":"a937476fdb0585b466c312bb4e2b4a157d50dfc6270d53d8acd49d9ce43d3140","control_program":"bm1q50u3z8empm5ke0g3ngl2t3sqtr6sd7cepd3z68","type":"control_program"}],"ttl":0,"time_range": 1521625823}

表示使用这个账户来锁定1000个GOLD资产

    def build_transaction(self,account_id,amount,address):
        uri = self.url+'/build-transaction'
        r = requests.post(uri,json=playload,headers=self.authHeader)
        return json.loads(r.text)
  1. build-transaction后使用钱包密码,对创建的交易进行签名
    def sign_transaction(self,password,builded_transaction):
        uri = self.url+'/sign-transaction'
        playload = {'password':password,'transaction':builded_transaction}
        r = requests.post(uri,json=playload,headers=self.authHeader)
        return json.loads(r.text)

被签名的就是之前返回的json数据

11.向节点提交已被签署的transaction

    def submit_transaction(self,raw_transaction):
        uri = self.url+'/submit-transaction'
        playload = {'raw_transaction':raw_transaction}
        r = requests.post(uri,json=playload,headers=self.authHeader)
        return json.loads(r.text)

成功后返回的是交易哈希值,至此,一个合约就锁定完成。