博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python通过JSON-RPC请求对以太坊智能合约进行部署和交易
阅读量:7080 次
发布时间:2019-06-28

本文共 14240 字,大约阅读时间需要 47 分钟。

hot3.png

本文探讨了如何将JSON-RPC请求发送到Geth节点以创建原生的交易。目标是在使用高级库(如web3py或web3js)时了解并查看后台发生的情况。

另外,对处理错误和异常不是本文的重点。如果出现任何问题,它将只是显示失败。这篇文章主要是学习。对于生产环境,还是考虑使用web3.py。

我们将仅使用HTTP请求在私有链上使用智能合约部署和交互(调用函数和读取公共变量)。交易是离线签名的,然后才发送到geth节点进行处理。

对于本指南,我们使用的是私有的Proof-of-Authority网络。如果想创建这样一个网络,可以阅读我们以前的帖子。本文假设使用Ganache(以前称为TestRPC)或任何以太坊网络都完全没问题。因此,不会介绍有关在网络设置的任何内容,重点是使用python将HTTP请求发送到Geth节点。

条件

  • 1.通过IPC或RPC访问以太坊网络(可能是公有,私有或像Ganache这样的模拟器)。
  • 2.安装了python 3。 我个人喜欢。
  • 3.安装最新版本的。

1.向Geth发送一个简单的请求

让我们通过向Geth发送一个非常简单的请求来热个身。查询下网络ID。 第一步是。 我们需要的方法称为net_version,在进行描述。

我的Geth节点URL和端口是:http://localhost:8501。如果你使用的是具有默认值的Ganache,则URL可能是http://localhost:7545

我正在使用来发出我的HTTP请求。

import requests# create persistent HTTP connectionsession = requests.Session()# as defined in https://github.com/ethereum/wiki/wiki/JSON-RPC#net_versionmethod = 'net_version'params = []payload= {"jsonrpc":"2.0",           "method":method,           "params":params,           "id":1}headers = {'Content-type': 'application/json'}response = session.post('http://localhost:8501', json=payload, headers=headers)print('raw json response: {}'.format(response.json()))print('network id: {}'.format(response.json()['result']))

结果是:

raw json response: {'id': 1, 'jsonrpc': '2.0', 'result': '1515'}network id: 1515

不错,从那里我们准备好与合约一起部署和交易,这建立了一个良好的基础。1515是我的私有区块链的网络ID,如创世文件中所定义。目前看起来都很棒。 使用Ganache,应该获得5777的网络ID。

但在能够签署和发送交易之前,我们需要一个地址,一个私钥和一些以太币。

2.创建公钥私钥对并获取一些以太币

web3py(release 4)库将帮助我们创建密钥对。

import web3w3 = web3.Web3()myAccount = w3.eth.account.create('put some extra entropy here')myAddress = myAccount.addressmyPrivateKey = myAccount.privateKeyprint('my address is     : {}'.format(myAccount.address))print('my private key is : {}'.format(myAccount.privateKey.hex()))

在这个示例中,我得到:

my address is    : 0xF464A67CA59606f0fFE159092FF2F474d69FD675my private key is: 0x94cb9f766ef067eb229da85213439cf4cbbcd0dc97ede9479be5ee4b7a93b96f

请永远不要分享你的私钥!我这样做是因为它是一个本地私有链,我每天都要销毁并重启几次。我没有在任何公共网络上使用这个密钥对。

现在为了获得这个地址,有多种方法:

1.一种非常简单的方法是在genesis.json文件中添加此地址并启动新网络。下面是之前我的创世纪文件,其中包括我们刚刚创建的地址(删除0x)。

{    "config": {        "chainId": 1515,        "homesteadBlock": 1,        "eip150Block": 2,        "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",        "eip155Block": 3,        "eip158Block": 3,        "byzantiumBlock": 4,        "clique": {            "period": 5,            "epoch": 30000        }    },    "nonce": "0x0",    "timestamp": "0x5a722c92",    "extraData": "0x000000000000000000000000000000000000000000000000000000000000000008a58f09194e403d02a1928a7bf78646cfc260b087366ef81db496edd0ea2055ca605e8686eec1e60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",    "gasLimit": "0x8000000",    "difficulty": "0x1",    "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",    "coinbase": "0x0000000000000000000000000000000000000000",    "alloc": {        "08a58f09194e403d02a1928a7bf78646cfc260b0": {            "balance": "0x200000000000000000000000000000000000000000000000000000000000000"        },        "87366ef81db496edd0ea2055ca605e8686eec1e6": {            "balance": "0x200000000000000000000000000000000000000000000000000000000000000"        },        "F464A67CA59606f0fFE159092FF2F474d69FD675": {            "balance": "0x200000000000000000000000000000000000000000000000000000000000000"        }    },    "number": "0x0",    "gasUsed": "0x0",    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"}

2.如果你有可以挖矿的节点或ganache,请打开并手动创建交易:

$ geth attach ipc:'http://localhost:8501' // 7545 for ganacheWelcome to the Geth JavaScript console!instance: Geth/v1.7.3-stable-4bb3c89d/linux-amd64/go1.9coinbase: 0x87366ef81db496edd0ea2055ca605e8686eec1e6at block: 1585 (Wed, 14 Feb 2018 11:46:04 CET) modules: eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0> eth.sendTransaction({'from':eth.coinbase, 'to':'0xF464A67CA59606f0fFE159092FF2F474d69FD675', 'value':1000000000000000000000})"0xdbc86acbe3644ac2cdb68132bbeecda40733c10f07ca16d87a2e5001e50eec4c"> exit

这里我从0x87366...发送1000以太币到我的地址0xF464A...,1个以太坊是10的18次方wei(1个后跟18个零)。值的单位是wei。

3.在公共测试链上,使用faucet。

3.使用智能合约部署和交易

太好了,既然我们有一个带有一些以太网的地址(为了支付gas费用),我们可以离线创建我们的交易,签名并将其发送到具有原生JSON-RPC的HTTP请求节点。

我们将使用send_rawTransaction方法,该方法将交易的签名作为输入参数。

python代码正在查询truffle在编译智能合约时创建的包含合约abi和字节码的json文件。在测试python代码之前,创建一个truffle工作区并编译虚拟合约AdditionContract.sol

$ truffle init// add the smart contract in contracts/$ truffle compile

然后更新python代码,用geth节点的URL以及truffle工作空间和genesis文件的路径(不要忘记在路径中用你的userName替换我的userName)。

其他一切都在代码中,应该是不言自明的。

pragma solidity ^0.4.18;contract AdditionContract {  uint public state = 0;  function add(uint value1, uint value2) public {    state = value1 + value2;  }  function getState() public constant returns (uint) {      return state;  }}

文末附完整代码。

我们让一切都变得简单易于修改和测试。 玩的开心 :)

python用web3.py库开发以太坊来说非常的方便,有兴趣的用户可以关注我们的,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。

另外其他语言可以学习的以太坊教程如下:

  • ,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • ,主要介绍智能合约与dapp应用开发,适合入门。
  • ,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • ,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和事件等内容。
  • ,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和事件等。

汇智网原创翻译,转载请标明出处。这里是

raw_JSON_RPC_requests_to_smart_contract.py

# associated medium post: https://medium.com/@ethervolution/ethereum-create-raw-json-rpc-requests-with-python-for-deploying-and-transacting-with-a-smart-7ceafd6790d9import requestsimport jsonimport web3 # Release 4.0.0-beta.8import pprintimport time# create persistent HTTP connectionsession = requests.Session()w3 = web3.Web3()pp = pprint.PrettyPrinter(indent=2)requestId = 0 # is automatically incremented at each requestURL = 'http://localhost:8501' # url of my geth nodePATH_GENESIS = '/home/salanfe/privateNetworks/geth_PoA/genesis.json'PATH_SC_TRUFFLE = '/home/salanfe/Projects/AdditionContract/' # smart contract path# extracting data from the genesis filegenesisFile = json.load(open(PATH_GENESIS))CHAINID = genesisFile['config']['chainId']PERIOD  = genesisFile['config']['clique']['period']GASLIMIT = int(genesisFile['gasLimit'],0)# compile your smart contract with truffle firsttruffleFile = json.load(open(PATH_SC_TRUFFLE + '/build/contracts/AdditionContract.json'))abi = truffleFile['abi']bytecode = truffleFile['bytecode']# Don't share your private key !myAddress = '0xF464A67CA59606f0fFE159092FF2F474d69FD675' # address funded in genesis filemyPrivateKey = '0x94cb9f766ef067eb229da85213439cf4cbbcd0dc97ede9479be5ee4b7a93b96f'''' =========================== SOME FUNCTIONS ============================ '''# see http://www.jsonrpc.org/specification# and https://github.com/ethereum/wiki/wiki/JSON-RPCdef createJSONRPCRequestObject(_method, _params, _requestId):    return {"jsonrpc":"2.0",            "method":_method,            "params":_params, # must be an array [value1, value2, ..., valueN]            "id":_requestId}, _requestId+1    def postJSONRPCRequestObject(_HTTPEnpoint, _jsonRPCRequestObject):    response = session.post(_HTTPEnpoint,                            json=_jsonRPCRequestObject,                            headers={'Content-type': 'application/json'})    return response.json()  ''' ======================= DEPLOY A SMART CONTRACT ======================= '''### get your noncerequestObject, requestId = createJSONRPCRequestObject('eth_getTransactionCount', [myAddress, 'latest'], requestId)responseObject = postJSONRPCRequestObject(URL, requestObject)myNonce = w3.toInt(hexstr=responseObject['result'])print('nonce of address {} is {}'.format(myAddress, myNonce))### create your transactiontransaction_dict = {'from':myAddress,                    'to':'', # empty address for deploying a new contract                    'chainId':CHAINID,                    'gasPrice':1, # careful with gas price, gas price below the --gasprice option of Geth CLI will cause problems. I am running my node with --gasprice '1'                    'gas':2000000, # rule of thumb / guess work                    'nonce':myNonce,                    'data':bytecode} # no constrctor in my smart contract so bytecode is enough### sign the transactionsigned_transaction_dict = w3.eth.account.signTransaction(transaction_dict, myPrivateKey)params = [signed_transaction_dict.rawTransaction.hex()]### send the transacton to your noderequestObject, requestId = createJSONRPCRequestObject('eth_sendRawTransaction', params, requestId)responseObject = postJSONRPCRequestObject(URL, requestObject)transactionHash = responseObject['result']print('contract submission hash {}'.format(transactionHash))### wait for the transaction to be mined and get the address of the new contractwhile(True):    requestObject, requestId = createJSONRPCRequestObject('eth_getTransactionReceipt', [transactionHash], requestId)    responseObject = postJSONRPCRequestObject(URL, requestObject)    receipt = responseObject['result']    if(receipt is not None):        if(receipt['status'] == '0x1'):            contractAddress = receipt['contractAddress']            print('newly deployed contract at address {}'.format(contractAddress))        else:            pp.pprint(responseObject)            raise ValueError('transacation status is "0x0", failed to deploy contract. Check gas, gasPrice first')        break    time.sleep(PERIOD/10)''' ================= SEND A TRANSACTION TO SMART CONTRACT  ================'''### get your noncerequestObject, requestId = createJSONRPCRequestObject('eth_getTransactionCount', [myAddress, 'latest'], requestId)responseObject = postJSONRPCRequestObject(URL, requestObject)myNonce = w3.toInt(hexstr=responseObject['result'])print('nonce of address {} is {}'.format(myAddress, myNonce))### prepare the data field of the transaction# function selector and argument encoding# https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encodingvalue1, value2 = 10, 32 # random numbers herefunction = 'add(uint256,uint256)' # from smart contractmethodId = w3.sha3(text=function)[0:4].hex()param1 = (value1).to_bytes(32, byteorder='big').hex()param2 = (value2).to_bytes(32, byteorder='big').hex()data = '0x' + methodId + param1 + param2transaction_dict = {'from':myAddress,                    'to':contractAddress,                    'chainId':CHAINID,                    'gasPrice':1, # careful with gas price, gas price below the threshold defined in the node config will cause all sorts of issues (tx not bieng broadcasted for example)                    'gas':2000000, # rule of thumb / guess work                    'nonce':myNonce,                    'data':data}### sign the transactionsigned_transaction_dict = w3.eth.account.signTransaction(transaction_dict, myPrivateKey)params = [signed_transaction_dict.rawTransaction.hex()]### send the transacton to your nodeprint('executing {} with value {},{}'.format(function, value1, value2))requestObject, requestId = createJSONRPCRequestObject('eth_sendRawTransaction', params, requestId)responseObject = postJSONRPCRequestObject(URL, requestObject)transactionHash = responseObject['result']print('transaction hash {}'.format(transactionHash))### wait for the transaction to be minedwhile(True):    requestObject, requestId = createJSONRPCRequestObject('eth_getTransactionReceipt', [transactionHash], requestId)    responseObject = postJSONRPCRequestObject(URL, requestObject)    receipt = responseObject['result']    if(receipt is not None):        if(receipt['status'] == '0x1'):            print('transaction successfully mined')        else:            pp.pprint(responseObject)            raise ValueError('transacation status is "0x0", failed to deploy contract. Check gas, gasPrice first')        break    time.sleep(PERIOD/10)''' ============= READ YOUR SMART CONTRACT STATE USING GETTER  =============='''# we don't need a nonce since this does not create a transaction but only ask# our node to read it's local database### prepare the data field of the transaction# function selector and argument encoding# https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding# state is declared as public in the smart contract. This creates a getter functionmethodId = w3.sha3(text='state()')[0:4].hex()data = '0x' + methodIdtransaction_dict = {'from':myAddress,                    'to':contractAddress,                    'chainId':CHAINID,                    'data':data}params = [transaction_dict, 'latest']requestObject, requestId = createJSONRPCRequestObject('eth_call', params, requestId)responseObject = postJSONRPCRequestObject(URL, requestObject)state = w3.toInt(hexstr=responseObject['result'])print('using getter for public variables: result is {}'.format(state))''' ============= READ YOUR SMART CONTRACT STATE GET FUNCTIONS  =============='''# we don't need a nonce since this does not create a transaction but only ask# our node to read it's local database### prepare the data field of the transaction# function selector and argument encoding# https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding# state is declared as public in the smart contract. This creates a getter functionmethodId = w3.sha3(text='getState()')[0:4].hex()data = '0x' + methodIdtransaction_dict = {'from':myAddress,                    'to':contractAddress,                    'chainId':CHAINID,                    'data':data}params = [transaction_dict, 'latest']requestObject, requestId = createJSONRPCRequestObject('eth_call', params, requestId)responseObject = postJSONRPCRequestObject(URL, requestObject)state = w3.toInt(hexstr=responseObject['result'])print('using getState() function: result is {}'.format(state))''' printsnonce of address 0xF464A67CA59606f0fFE159092FF2F474d69FD675 is 4contract submission hash 0x64fc8ce5cbb5cf822674b88b52563e89f9e98132691a4d838ebe091604215b25newly deployed contract at address 0x7e99eaa36bedba49a7f0ea4096ab2717b40d3787nonce of address 0xF464A67CA59606f0fFE159092FF2F474d69FD675 is 5executing add(uint256,uint256) with value 10,32transaction hash 0xcbe3883db957cf3b643567c078081343c0cbd1fdd669320d9de9d05125168926transaction successfully minedusing getter for public variables: result is 42using getState() function: result is 42'''

转载于:https://my.oschina.net/u/2275217/blog/1931957

你可能感兴趣的文章
16TB以后磁盘挂载方法
查看>>
洛谷—— P2895 [USACO08FEB]流星雨Meteor Shower
查看>>
expect 交互式脚本写法
查看>>
cacti程序安装过程
查看>>
学习Linux之路2
查看>>
解决在一行里文字和图片对齐
查看>>
golang hello
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
搭建高可用mongodb集群—— 副本集1
查看>>
分布式助手Zookeeper(一)
查看>>
redis源码分析1------dict的实现
查看>>
Spring HttpIvoker实现Java的远程调用
查看>>
list usage of python
查看>>
某互联网企业技术发展史(一)技术选型与服务器采购
查看>>
Core Dump
查看>>
【C】函数间传递多维数组的方法
查看>>
口碑营销让SNS绽放生命力
查看>>
如何做成功的市场调研(下)
查看>>
从资源池和管理的角度理解物理内存
查看>>