智能合约开发手记

最近用EVM做了不少智能合约的项目,有lotto,vote,dao等等,说说感受吧。

2018-09-12

28 次浏览

最近用EVM做了不少智能合约的项目,有lotto,vote,dao等等,说说感受吧。

  1. 千万不要用合约写复杂的逻辑,GAS的消耗是你的限制,库的功能是你的限制,VM的性能是你的限制,VM的稳定性也是你的限制。
  2. 可以把现在的合约当成数据库的存储过程,区块链当成数据库来理解,也就是看起来什么都能干,但是如果真的什么都放在里面干,你会死得很难看。
  3. 并行什么的,还是算了吧,不要试图向合约发起并行修改请求,最好的方式是在合约增加批量处理方法或者调用批量处理请求。因为账户的nonce是需要按次增加的,而每次增加1,都需要等到交易打包到区块中。
  4. 千万别用Java来开发与合约的交互,首先Web3j没有完全实现能力(例如批量提交就没有),第二用了Java你还得写前端逻辑,不如直接使用Web3.js,前端直接搞定,所以正确的架构应该是。  client -> ETH-Node ,Server -> ETH-Node这样的模式,如果确实需要一点中心化的东西,那么最好也是使用NodeJS,Web3.js是官方出品,而且功能全面。
  5. 做合约的产品,千万别搞复杂的逻辑,害人害己害用户,大家的手续费都老高,而且还不稳定。简单粗暴的产品最好。
  6. GAS的设计说实话,在外面看还以为牛逼哄哄,一旦自己成为了开发者,就觉得完全限制了你的发挥,合约的发展任重而道远。
  7. 可能区块链合约的发展都进入了一个误区,就是ETH的GAS或者EOS的资源使用计算,不过好在BM是看到了问题的,他在想办法脱离GAS,但是不够彻底,还是有资源消耗给费用的问题,这些都是限制合约发展的东西,应该统统去掉,要什么费用,这样大家都可以自由发挥了。当然,你说不激励节点怎么运作,那就是区块链项目的事情了,你不能激励节点就干掉用户体验,限制你自己的发展空间,所以链外的计算环境现在应该是个不错的方向,沙盒空间,你爱怎么玩就怎么玩。

后面想到什么再持续更新吧。

一点感悟:当然,我们帮助NULS做的NVM也有一部分是借鉴了EVM的架构和理念,所以EVM有的问题,NVM同样也有,当然NVM不同的地方在于VM的能力更强,这并不是本质的改变,我们会积极思考NVM2.0,从架构上全面的超越现有的合约体系。

更新1

  1. GAS还是GAS,这次是GAS Limit。如果你帮助用户管理账户,那么一定要注意计算每次与区块链交互的GAS是不同的,GAS Limit的设置也不同,你不能统一设置了事,这样会很大,我们把转账也设置成和业务交互一样的GAS Limit,最后结果就是提现小于GAS * GAS Limit就直接报告失败,而业务Limit在600万,提现应该只要30万左右就可以了。
  2. 由于区块链的去中心化,打包区块时间限制,所以dapp尽量不要设计有定时任务的那种,否则你就只有使用外部定时来解决了。
  3. 如果是非dapp的标准模式,即client->chain, server->chain的模式,而是client->server ->chain的模式,那么就要注意了,geth尽量使用light模式,否则fast你得准备200G+,full你得准备800G+,而且还必须是SSD。最好是对接infura.io,这样你就不需要节点,不过也得注意的是,web3j不支持infura的filters,web3.js的1.0版本全部支持,之前的版本也不支持。
  4. 一切都是异步,与区块链交互最好都是异步,所以你的dapp一定要基于异步去设计和考虑,不是每一次调用都能够立刻得到结果,而是需要等待一段时间,可能很短,也可能很长,也可能很长时间后告诉你有错误。
  5. 在合约中设计的struct时注意一点,不能超过16个属性,超过就会报告stack too deep的错误,这是EVM的设计限制的。
  6. 避免在合约中使用多层for循环,如果必须要,保证迭代的数据不要太多,否则GAS费用承受不起
  7. 数据结构的使用十分十分非常非常受限,mapping和array。mapping是无法被删除的,也无法通过for遍历,而array可以通过for遍历,也可以通过delete array的方式进行删除。如果你一定要删除mapping,我们只能迂回的去清空mapping的数据,把它设置成不要的情况,例如{a->1,b->2},清空后面的数字为一个代表无意义的数字,例如{a->-1,b->-1},但是你没法遍历mapping不是,所以怎么清空?这时候一种办法就是利用array再把mapping的key复制一次放在array中,接上面的例子,这个时候你就有个数组存储{a,b}, array[0] = a,  array[1] = b,然后通过遍历这个key数组去清空mapping。
  8. 虽然从链上查询是不消耗GAS的,但是也要考虑机器的性能,总之尽可能的保持产品简单,不要太复杂。
  9. remix是一个非常好的开发工具,所以尽量用remix去做测试,truffle也不是不行的,但是truffle有时候编译出来的二进制数据和remix编译出来的有些许不同,而remix编译出来的就和你发布到以太坊网络中的二进制是一致的。还有就是,当你发布了合约之后,一定要做code的验证,因为验证前后的bin可能是不同的。我现在的猜想就是合约的编译版本造成的不同,truffle我还不知道怎么确定编译时选择版本,只能配置优化和次数(默认都是200次),remix是可以选择的。这个BIN主要是影响Web3j生成Java合约代理,容易出现一个叫empty(0x)的问题,这种问题一出现,就是因为二进制不对引起的(所以这也是为什么别用web3j的原因,用web3.js是不需要bin就能生成代理的)。