在以太坊上创建一个智能合约(十七)|入门系列

2017/5/13 posted in  Solidity入门系列

我们写好一个合约后,一个合约如何部署到以太坊网络,并实现合约函数的调用呢?合约部署到以太坊网络上,也是一个类似交易的过程。首先向全网发送一个合约创建的交易,待矿工打包交易,并获得全网的认可从而生效后,则得到合约的地址;既而向这个地址发送消息调用,实现调用合约的某个函数。

初始创建合约

以太坊提供了基于JSON格式的JSON RPC API1,可以通过套接字,HTTP等,用来与以太坊网络进行交互。

以太坊还提供了一套在上述基础上的,JavaScript语言封装的工具库web3.js2
如何使用web3.js创建合约建议参考此文,非常详尽:http://web3.tryblockchain.org/web3-js-in-action.html

不是所有的客户端都实现了对JSON RPC API的全部支持。go客户端JSON RPC的几乎全部支持,具体可以参见这里:https://github.com/ethereum/wiki/wiki/JSON-RPC。

合约中创建合约

在Solidity中创建一个合约非常简单,但创建者必须知道要创建的合约源码。通过下面的例子,我们来看下如何在合约中创建合约。

下面是一个要被创建的合约的源码:

pragma solidity ^0.4.0;


contract Test{
  function add(uint a, uint b) constant returns (uint){
    return a + b;
  }
}

在创建者合约中,使用new关键字创建合约,由于创建者合约必须要知道源码。我们可以把多个合约写到同一个文件,或使用import关键字来引入关联合约,下面是引入Test合约,并创建的一个实例的具体实现:

pragma solidity ^0.4.0;

import "./Test.sol";

contract NewContract{
  function createAndCallContract() returns(address addr, uint result){
    Test t = new Test();
    return (t, t.add(1, 2));
  }
}

上述实现中,我们首先引入了Test.sol源代码文件。需要注意的是,使用./说明两个文件是放在同级目录下,不以.开头默认是以绝对路径寻址3。在合约NewContract中,我们使用new关键字部署了一个Test.sol合约。成功调用后,我们不止可以得到合约部署的地址,也可以直接调用合约提供的函数。

构造器

每个合约都允许存在构造器,构造器是与合约同名的一个特殊函数,有且只能有一个,不允许重载。构造器将在合约创建时,执行一次,用于初始化一些配置。

pragma solidity ^0.4.0;

contract ContractConstructor{
  uint public counter;

  function ContractConstructor(){
    counter++;
  }
}

上述合约在创建成功后,counter的值将为1。说明合约在创建时,被调用了一次。

构造器内,由于合约尚未初始化完成,故不能使用this来以external的方式来调用当前合约中的函数,下面来看一个例子。

pragma solidity ^0.4.0;

contract A{
  function A(){
    innerCall();
    //Exception during execution. (out of gas).
    //this.externalCall();
  }

  function innerCall() internal {}
  function externalCall() external{}

}

contract ConstructorCall{
  function create(){
    A a = new A();
  }
}

上述的代码中,如果取消掉this.externalCall()的注释,将导致创建时报错Exception during execution. (out of gas)。因为合约尚未创建完成,不能通过外部方式调用。但我们可以使用internal的方式使用函数,正如innerCall();所示。

构造器还允许接收ether,只需要在构造器函数上增加payable关键字,下面是一个简单的例子:

pragma solidity ^0.4.0;

contract ConstructorEther{
    function ConstructorEther() payable {}

    function getBalance() constant returns (uint){
        return this.balance;
    }
}

在上面的例子中,ConstructorEther可以在创建时接收指定数量的ether。

关于作者

专注基于以太坊(Ethereum)的相关区块链(Blockchain)技术,了解以太坊,Solidity,Truffle,web3.js。

个人博客: http://tryblockchain.org
版权所有,转载注明出处

参考资料

基于JavaScript的封装。https://github.com/ethereum/wiki/wiki/JavaScript-API

处于某些特定的环境下,可以看到评论框,欢迎留言交流^_^。

友情链接: 区块链技术中文社区    深入浅出区块链