python智能合约编程_如何使用Python测试你的以太坊智能合约?

背景

最近开始做以太坊区块链开发工作。大多数开发工具,包括solidity语言都倾向JavaScript。

当我开始使用Tunffle进行测试时,我发现JavaScript测试(IMO)太长,不必要。

但这是语言的本质问题。我一直比较喜欢Python,而不是js。我喜欢并在以前的项目中使用了py.test。所以如果我能选择使用py.test去测试我的智能合约话,我肯定会尝试一下。

这时候我碰到了Populus,不过目前看它还不够强大(我目前这么认为,官方可不这么看)。

最初,这是一个个人项目,它正式通过以太坊官方组织(github)的推荐,确实已经为已经完成的出色工作增加极高的可信度。

你可以在这里阅读官方英文版的文件。

测试

正如我前面提到的,我来选择尝试用py.test测试智能合约。

编写测试(连同web3.py)相当简单。

在populus test中进行试验(和truffle test类似)。它是通过py.test,执行命令是这样的py.test /。

这里我遇到了一个“小故障”,挺有意思,这个是问题和解决办法

我喜欢使用py.test的一点原因是我不需要明确地启动testrpc。

对于truffle test,testrpc或geth需要明确运行。否则你会得到以下错误:

1

2

3

4

5

6$ truffle test

Could not connect to your Ethereum client. Please check that your Ethereum client:

- is running

- is accepting RPC connections (i.e., "--rpc" option is used in geth)

- is accessible over the network

- is properly configured in your Truffle configuration file (truffle.js)

我并不是说这有什么不对,只是可以省略一步,对于懒人来说很好。

创建本地链

另外一个很好的特点是populus有truffle创建本地geth实例的功能。

这可以很容易地实现:

1populus chain new

这个功能包括了以下几个方面:

创建一个genesis.json(通常需要手工创建,或者从某个地方复制现成的并进行修改)

创建一个帐户,并且有足够的余额。

建两个脚本。一个创建创世纪块(init_chain.sh)

另一个启动“节点”(run_chain.sh)

好处是,新手不需要理解genesis.json和geth命令行中很长的列表选项和各种选项的复杂性。

这样一句话就行了。

这对有一定经验的开发人员也是有用的。可以根据需要修改genesis.json和脚本。

由于没有“修改密码”的概念,我们不能创建一个我们认为“更好”的密码,却不用删除现有的帐户,就能完成修改一个密码。这意味着需要修改run_chain.sh脚本,因为它提到了一个解锁参数的帐户。还需要修改genesis.json,因为“预置”帐户是在alloc下的。

但也是可以的接受的,因为populus这样做都是为了更方便开发。

阅读关于使用populus创建本地链的详细教程

还有一个命令:populus chain reset ,但有时不起作用。我在这里提出了一个问题。

部署智能合约

对于简单的一次性合约,有一个命令行版本:

1populus deploy

对于稍微复杂的合约部署,尤其是当需要将参数传递给合约的构造函数时,需要编写自己的Python代码。

这与在truffle中编写迁移脚本没有什么不同,不过在truffle ini上可以获得默认脚本,我们这里没有。

用命令行部署一个合约

部署是通过部署命令$ populus deploy来处理的,下面这些都是自动处理的。

选择应该被部署到哪个区块链。

运行给定区块链。

项目合约的编制。

导出库依赖关系。

库链接。

个人合同部署。

让我们部署一个简单的钱包合约。首先,我们需要一个合约在我们的./contracts目录中。

1

2

3

4

5

6

7

8

9

10

11

12

13

14// ./contracts/Wallet.sol

contract Wallet {

mapping (address => uint) public balanceOf;

function deposit() {

balanceOf[msg.sender] += 1;

}

function withdraw(uint value) {

if (balanceOf[msg.sender] < value) throw;

balanceOf[msg.sender] -= value;

if (!msg.sender.call.value(value)()) throw;

}

}

在上面代码中,可以看到基本部署的输出。

如果在项目目录之外,请使用:

1$ populus -p /path/to/my/project deploy Wallet -c local_a

以编程方式部署合约

还可以使用Python脚本部署合约。如果你的智能合约采用构造函数参数或需要更复杂的初始化调用,这是一种合适的方法。

示例(deploy_testnet.py):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79"""Deploy Edgeless token and smart contract in testnet.

A simple Python script to deploy contracts and then do a smoke test for them.

"""

from populus import Project

from populus.utils.wait import wait_for_transaction_receipt

from web3 import Web3

def check_succesful_tx(web3: Web3, txid: str, timeout=180) -> dict:

"""See if transaction went through (Solidity code did not throw).

:return: Transaction receipt

"""

# http://ethereum.stackexchange.com/q/6007/620

receipt = wait_for_transaction_receipt(web3, txid, timeout=timeout)

txinfo = web3.eth.getTransaction(txid)

# EVM has only one error mode and it's consume all gas

assert txinfo["gas"] != receipt["gasUsed"]

return receipt

def main():

project = Project()

# This is configured in populus.json

# We are working on a testnet

chain_name = "ropsten"

print("Make sure {} chain is running, you can connect to it, or you'll get timeout".format(chain_name))

with project.get_chain(chain_name) as chain:

# Load Populus contract proxy classes

Crowdsale = chain.get_contract_factory('Crowdsale')

Token = chain.get_contract_factory('EdgelessToken')

web3 = chain.web3

print("Web3 provider is", web3.currentProvider)

# The address who will be the owner of the contracts

beneficiary = web3.eth.coinbase

assert beneficiary, "Make sure your node has coinbase account created"

# Random address on Ropsten testnet

multisig_address = "0x83917f644df1319a6ae792bb244333332e65fff8"

# Deploy crowdsale, open since 1970

txhash = Crowdsale.deploy(transaction={"from": beneficiary}, args=[beneficiary, multisig_address, 1])

print("Deploying crowdsale, tx hash is", txhash)

receipt = check_succesful_tx(web3, txhash)

crowdsale_address = receipt["contractAddress"]

print("Crowdsale contract address is", crowdsale_address)

# Deploy token

txhash = Token.deploy(transaction={"from": beneficiary}, args=[beneficiary])

print("Deploying token, tx hash is", txhash)

receipt = check_succesful_tx(web3, txhash)

token_address = receipt["contractAddress"]

print("Token contract address is", token_address)

# Make contracts aware of each other

print("Initializing contracts")

crowdsale = Crowdsale(address=crowdsale_address)

token = Token(address=token_address)

txhash = crowdsale.transact({"from": beneficiary}).setToken(token_address)

check_succesful_tx(web3, txhash)

# Do some contract reads to see everything looks ok

print("Token total supply is", token.call().totalSupply())

print("Crowdsale max goal is", crowdsale.call().maxGoal())

print("All done! Enjoy your decentralized future.")

if __name__ == "__main__":

main()

完整的示例代码在这里

迁徙

populus在旧版本中有这个特性,但是它被移除了。gitter中问的时候,被告知有一个计划会把他们带回来。

最后的想法

虽然我想用populus作为唯一的选择,但我认为这与truffle相比还是不太成熟。

现在,我用truffle作为我与他人分享的项目(因为truffle似乎更为受大家欢迎),但对于我的个人项目,我继续使用populus(并报告问题,讨论并发送PR如果我知道问题在哪儿的话)

注意:您可以在这里查看我的(正在进行中的)代码。它既有truffle,也有populus配置文件。测试只在Python中进行。我在Python中有一个部署脚本。

python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。

web3j教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。

以太坊教程,主要介绍智能合约与dapp应用开发,适合入门。

以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。

php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和事件等内容。

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

你可能感兴趣的:(python智能合约编程)