前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在以太坊私有链上部署智能合约

在以太坊私有链上部署智能合约

作者头像
字节流动
发布2020-06-02 11:27:18
1.3K0
发布2020-06-02 11:27:18
举报
文章被收录于专栏:字节流动字节流动

上节简单介绍了基于以太坊搭建私有链以及挖矿和交易,在部署智能合约之前请确保私有链上的账户有余额,因为部署智能合约需要消耗 Gas ,而 Gas 需要 ether 币来兑换。

1. 智能合约

什么是智能合约?智能合约是存储在以太坊网络特定地址的一组代码和数据集。在以太坊网络中智能合约以以太坊虚拟机(EVM)字节码的形式存在,由以太坊虚拟机解释执行。用于编写智能合约常用的语言有 Solidity 、Serpent 以及 LLL ,其中最著名的就是 Solidity 。智能合约的部署和执行都需要燃料(Gas),一旦部署便不能修改。

2. 部署智能合约

部署智能合约可以使用以太坊命令行客户端(Geth Console)和 Mist 。 选用 Solidity 官网的例子 Coin 。

代码语言:javascript
复制
pragma solidity ^0.4.0;
contract Coin {
    // The keyword "public" makes those variables
    // easily readable from outside.
    address public minter;
    mapping (address => uint) public balances;

    // Events allow light clients to react to
    // changes efficiently.
    event Sent(address from, address to, uint amount);

    // This is the constructor whose code is
    // run only when the contract is created.
    constructor() public {
        minter = msg.sender;
    }

    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        require(amount < 1e60);
        balances[receiver] += amount;
    }

    function send(address receiver, uint amount) public {
        require(amount <= balances[msg.sender], "Insufficient balance.");
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

以太坊命令行客户端部署

打开网站

https://remix.ethereum.org,

将上面的智能合约代码替换为 Coin 的例子。

然后选择 Compile ,点击 Start to compile 生成 EVM 的字节码,复制生成的 ABI 和 ByteCode 。

ABI:

代码语言:javascript
复制
[
    {
        "constant": false,
        "inputs": [
            {
                "name": "receiver",
                "type": "address"
            },
            {
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "mint",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "name": "receiver",
                "type": "address"
            },
            {
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "send",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "name": "from",
                "type": "address"
            },
            {
                "indexed": false,
                "name": "to",
                "type": "address"
            },
            {
                "indexed": false,
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "Sent",
        "type": "event"
    },
    {
        "inputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "constant": true,
        "inputs": [
            {
                "name": "",
                "type": "address"
            }
        ],
        "name": "balances",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "minter",
        "outputs": [
            {
                "name": "",
                "type": "address"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    }
]

ByteCode, 其中 object 字段对应的就是就是我们需要的 EVM 字节码(下面只贴出来部分代码):

代码语言:javascript
复制
{
    "linkReferences": {},
    "object": "608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506104df806100606000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806307546172146...",
    "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLER PUSH1 0x0 DUP1 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF MUL NOT AND SWAP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND MUL OR SWAP1 SSTORE POP PUSH2 0x4DF DUP1 PUSH2 0x60 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x62 JUMPI
    ...",
    "sourceMap": "24:902:0:-;;;427:57;8:9:-1;5:2;;;30:1;27;20:12;5:2;427:57:0;467:10;458:6;;:19;;;;;;;;;;;;;;;;;;24:902;;;;;;"
}

另外 ABI 需要转义成字符串,使用网站

http://www.bejson.com,选择【删除空格并转义】。

代码语言:javascript
复制
[{\"constant\":false,\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Sent\",\"type\":\"event\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"balances\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"minter\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]

通过 Geth Console 创建合约对象。

代码语言:javascript
复制
// 声明合约 coin
> var abi = JSON.parse('[{\"constant\":false,\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Sent\",\"type\":\"event\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"balances\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"minter\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]')
> coin = web3.eth.contract(abi)

// 需要为字节码添加,'0x' 前缀。
> byteCode = "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506104df80610060600039
6000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063075461721461006757806327e235e3146100be57806340c10f1914610115578063d0679d34146101
..."

"0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506104df806100606000396000f30060806
0405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063075461721461006757806327e235e3146100be57806340c10f19146101..."
// 就是部署智能合约需要的燃料(Gas)值。
> eth.estimateGas({data: byteCode})
406661
// 我们输入的燃料值需要大于 406661 
>
// 解锁 coinbase 账户
> personal.unlockAccount(eth.coinbase)
Unlock account 0x33213084015dab454fee16eb369fa2a8e6e65eee
Passphrase:
true

// 创建 coin 合约对象,部署合约
> coinContractIns = coin.new({data: byteCode gas: 410000, from: eth.coinbase}, function(e, contract){
  if(!e){
    if(!contract.address){
      console.log("Contract transaction send: Transaction Hash: "+contract.transactionHash+" waiting to be mined...");
    }else{
      console.log("Contract mined! Address: " + contract.address);
      console.log(contract);
    }
  }else{
    console.log(e)
  }
})
INFO [10-07|12:19:00.077] Submitted contract creation              fullhash=0x114e241d2a62064b0d41ec143c595768f648306595a931563a3add4cee3c2d77 contract=0x7227255a42b167061B4260A0b1827e3E6F737905
Contract transaction send: Transaction Hash: 0x114e241d2a62064b0d41ec143c595768f648306595a931563a3add4cee3c2d77 waiting to be mined...
{
  abi: [{
      constant: false,
      inputs: [{...}, {...}],
      name: "mint",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: false,
      inputs: [{...}, {...}],
      name: "send",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      anonymous: false,
      inputs: [{...}, {...}, {...}],
      name: "Sent",
      type: "event"
  }, {
      inputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "constructor"
  }, {
      constant: true,
      inputs: [{...}],
      name: "balances",

// coin 合约并没有部署成功,需要启动挖矿
> miner.start();
> // 等待约 12 以上区块生成,停止挖矿
> miner.stop();

// 查看合约是否部署成功
> eth.getCode(coinContractIns.address)
"0x608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063075461721461006757806327e235e31461
b600080fd5b34801561007357600080fd5b5061007c6101af565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff
00080fd5b506100ff600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506101d4565b6040518082815260200191505060405180
..."
// 合约部署成功


//解锁账户
> eth.defaultAccount=eth.coinbase
"0x33213084015dab454fee16eb369fa2a8e6e65eee" // coinbase 账户
> personal.unlockAccount(eth.coinbase)
Unlock account 0x33213084015dab454fee16eb369fa2a8e6e65eee
Passphrase:
true

// 查看账户在合约中的余额
> coinContractIns.balances("0x33213084015DAB454fEe16eb369FA2a8E6E65eEE") //替换成自己的 coinbase 账户
0
// 由于合约没有被执行,合约中的余额为 0

// 通过合约中的 mint 接口设置 coinbase 账户在合约中的 coin 数目为 30000 。
> coinContractIns.mint("0x33213084015DAB454fEe16eb369FA2a8E6E65eEE", 30000);
INFO [10-07|12:37:31.191] Submitted transaction                    fullhash=0x788857480e7c33d59f5893e7287c697d33e5ad29a52817e19930ec26178e62b3 recipient=0x7227255a42b1
"0x788857480e7c33d59f5893e7287c697d33e5ad29a52817e19930ec26178e62b3"

// 上述操作并未执行,需要启动挖矿
> miner.start();
> // 等待约 12 以上区块生成,停止挖矿
> miner.stop();

// 挖矿结束,查看 coinbase 账户 coin 数量
> coinContractIns.balances("0x33213084015DAB454fEe16eb369FA2a8E6E65eEE")
30000

//解锁 coinbase 账户,进行交易
> personal.unlockAccount(eth.coinbase)
Unlock account 0x33213084015dab454fee16eb369fa2a8e6e65eee
Passphrase:
true
// 发送给账户 0x55213084015DAB454fEe16eb369FA2a8E6E65ebb(这个账户可以随意填写,保证 20 Byte)10000 个 coin
> coinContractIns.send("0x55213084015DAB454fEe16eb369FA2a8E6E65ebb", 10000);
INFO [10-07|12:47:17.161] Submitted transaction                    fullhash=0xf0ec8dc4daf6d85cf55be8289a37fbd271437658b2a02fc330272403192d863e recipient=0x7227255a42
"0xf0ec8dc4daf6d85cf55be8289a37fbd271437658b2a02fc330272403192d863e"
// 交易还未执行,这个账户余额还是 0 
> coinContractIns.balances("0x55213084015DAB454fEe16eb369FA2a8E6E65ebb")
0
// 上述操作并未执行,需要启动挖矿
> miner.start();
> // 等待约 12 以上区块生成,停止挖矿
> miner.stop();

// 挖矿结束,查看账户的 coin 余额,合约执行成功。
> coinContractIns.balances("0x55213084015DAB454fEe16eb369FA2a8E6E65ebb")
10000
> coinContractIns.balances("0x33213084015DAB454fEe16eb369FA2a8E6E65eEE")
20000
>

Mist 部署

通过 Mist 部署智能合约非常简单方便。打开 Mist ,选择【CONTRACT】=>【DEPLOY NEW CONTRACT】,

在 【SOLIDITY CONTRACT SOURCE CODE】 中,将 coin 例子代码粘贴进来,将合约改为 LTCCoin 。

点击【DEPLOY】输入账户密码创建合约(这里创建账户选择 Account1)。

点击【WALLETS】在下面的【Latest Transaction】可以看到合约正在创建中,这里需要在 Geth Console 启动挖矿,合约才能创建成功,当然进行任何交易操作都需要挖矿来完成。

挖矿后,选择【CONTRACT】查看合约部署成功。

然后在右侧【Select function】选择相应操作,注意执行 mint 函数执行账户需要选择为创建账户 Account1 ,交易成功需要挖矿。

3. 参考

https://github.com/EthFans/wiki/wiki/%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6 https://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 字节流动 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
区块链
云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档