solidity合约编译、部署

在学习了solidity的基本语法后,我们可以尝试来编译和部署一个solidity智能合约,部署流程如下
1)使用solc编译智能合约
2)启动一个以太坊节点(geth或testrpc)
3)将编译好的合约发布到以太坊的网络上
4)用web3.js api调用部署好的合约


1.编译合约

1.1solc

如果没有安装过solc,需要先安装,在ubuntu执行以下命令

sudo apt-get install -y software-properties-common
sudo add-apt-respository -y ppa:ethereum/ehtereum
sudo apt-get update
sudo ape-get install -y solc
solc --version//有版本则成功

1.2编写智能合约

新建/geth/solc目录,文件Storage.sol,使用的ide是atom,自动补全

pragma solidity ^0.4.25;

contract Storage {
  uint256 storedData;
  function set(uint256 data) {
    storedData = data;
  }
  function Get() constant returns (uint256) {
    return storedData;
  }
}

1.3编译合约

注意下这里不是单引号而是反引号,使用solc命令编译Storage.sol合约,把输出的结果赋值给storageOutput变量,同时输出到storage.js文件中

parallels@parallels-vm:~/geth/solc$ echo "var storageOutput=`solc --optimize --combined-json abi,bin,interface Storage.sol`" > storage.js
Storage.sol:5:3: Warning: No visibility specified. Defaulting to "public". 
  function set(uint256 data) {
  ^ (Relevant source part starts here and spans across multiple lines).
Storage.sol:8:3: Warning: No visibility specified. Defaulting to "public". 
  function Get() constant returns (uint256) {
  ^ (Relevant source part starts here and spans across multiple lines).
parallels@parallels-vm:~/geth/solc$ cat storage.js var storageOutput={"contracts":{"Storage.sol:Storage":{"abi":"[{\"constant\":false,\"inputs\":[{\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"Get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]","bin":"608060405234801561001057600080fd5b5060bf8061001f6000396000f30060806040526004361060485763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166360fe47b18114604d578063b1976a02146064575b600080fd5b348015605857600080fd5b5060626004356088565b005b348015606f57600080fd5b506076608d565b60408051918252519081900360200190f35b600055565b600054905600a165627a7a723058207329b6c82bb730452e864cf684fe48ef2f9e88498eb90bfcdb2c3cbe2d8811830029"}},"version":"0.4.25+commit.59dbf8f1.Linux.g++"}

输出的内容有两部分组成
1)ABI:Application Binary Interface的缩写,字面意思为“应用的二进制接口”,可以通俗理解为合约的借口说明,当合约被编译后,它的abi也就确定了

[
    {
        "constant":false,//是否会修改合约的状态变量
        "inputs":[//方法参数,对应一个数组
            {
                "name":"data",
                "type":"uint256"
                }
         ],
         "name":"set",
         "outputs":[],
         "payable":false,//标明方法是否可以接受ether
         "stateMutability":"nonpayable",
         "type":"function"//方法类型,包括function,constructor,fallback
     },
     {
        "constant":true,
        "inputs":[],
        "name":"Get",
        "outputs":[
            {
                "name":"",
                "type":"uint256"
             }
        ]

可以看到abi解析后是一个数组,这里包含两个对象,每个对象对应一个合约方法,所以这个合约实际包含两个方法
2)bin:合约被编译后的二进制内容

2.部署合约

2.1启动geth节点

启动我们之前搭建好的私有链

geth --datadir "./db" --rpc --rpcaddr=0.0.0.0 --rpcport 8545 --rpccorsdomain "*" --rpcapi "eth,net,web3,personl,admin,shh,txpool,debug,miner" --nodiscover --maxpeers 30 --networkid 1981 --port 30303  console

通过attach进入geth控制台

geth --datadir './db' attach ipc:./db/geth.ipc 

加载之前生成的storage.js文件

> loadScript('solc/storage.js')
true
> storageOutput
{
  contracts: {
    Storage.sol:Storage: {
      abi: "[{\"constant\":false,\"inputs\":[{\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"Get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]",
      bin: "608060405234801561001057600080fd5b5060bf8061001f6000396000f30060806040526004361060485763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166360fe47b18114604d578063b1976a02146064575b600080fd5b348015605857600080fd5b5060626004356088565b005b348015606f57600080fd5b506076608d565b60408051918252519081900360200190f35b600055565b600054905600a165627a7a723058207329b6c82bb730452e864cf684fe48ef2f9e88498eb90bfcdb2c3cbe2d8811830029"
    }
  },
  version: "0.4.25+commit.59dbf8f1.Linux.g++"
}

分别获取abi和bin

> var storageContractAbi = storageOutput.contracts['Storage.sol:Storage'].abi
undefined
> var storageContract = eth.contract(JSON.parse(storageContractAbi))
undefined
> var storageBinCode = "0x" + storageOutput.contracts['Storage.sol:Storage'].bin
undefined

2.2部署合约

先解锁账户

> personal.unlockAccount(eth.accounts[0],"123456",600)

true

然后发送

> var deployTransationObject = { from:eth.accounts[0],data:storageBinCode,gas:1000000 };
undefined
> var storageInstance = storageContract.new(deployTransationObject)
Error: insufficient funds for gas * price + value
    at web3.js:3143:20
    at web3.js:6347:15
    at web3.js:5081:36
    at web3.js:3021:24
    at <anonymous>:1:23

错误是因为这个账户里没有以太币,挖矿后重新运行

> var storageInstance = storageContract.new(deployTransationObject)
undefined

现在网络中待处理的交易

> txpool.status
{
  pending: 1,
  queued: 0
}
> txpool.inspect.pending
{
  0xAe5B8710f1a506bac5f6F4F6aC79D796B6Bf2C7d: {
    0: "contract creation: 0 wei + 1000000 gas × 1000000000 wei"
  }
}

开始挖矿,使这笔交易写入区块

> miner.start(1);admin.sleepBlocks(1);miner.stop();
null
INFO [10-12|13:31:10.896] Successfully sealed new block            number=16 sealhash=d59e90…dd3cea hash=8271b3…e14d75 elapsed=4.027s
INFO [10-12|13:31:10.896] ? block reached canonical chain          number=9  hash=e06dc1…ab82ee
INFO [10-12|13:31:10.896] ? mined potential block                  number=16 hash=8271b3…e14d75
INFO [10-12|13:31:10.896] Commit new mining work                   number=17 sealhash=e14361…feeca6 uncles=0 txs=0 gas=0      fees=0           elapsed=156.404µs

通过storageInstance对象可以看到部署成功后的合约地址

> storageInstance
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "set",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "Get",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }],
  address: "0x25c2bf1b06e9feedb2e3866a309bddd735f5eed0",
  transactionHash: "0x5127129f147d8ff5fe1f2ae11fea215ca132fea4d8d5cbd8ef0a6716604a254e",
  Get: function(),
  allEvents: function(),
  set: function()
}

根据部署合约的交易hash查看详情

> eth.getTransactionReceipt(storageInstance.transactionHash);
{
  blockHash: "0x8271b3671a0bb1b614489c2d3977c04fa080b9ad3e5d6387df9f3058a7e14d75",
  blockNumber: 16,
  contractAddress: "0x25c2bf1b06e9feedb2e3866a309bddd735f5eed0",
  cumulativeGasUsed: 103631,
  from: "0xae5b8710f1a506bac5f6f4f6ac79d796b6bf2c7d",
  gasUsed: 103631,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0xf24b23c59413cdf30f5b52b191b90e0b85c4ca3efa55443f1165199ffd3ee7fb",
  to: null,
  transactionHash: "0x5127129f147d8ff5fe1f2ae11fea215ca132fea4d8d5cbd8ef0a6716604a254e",
  transactionIndex: 0
}

获取合约地址

> var storageAddress =eth.getTransactionReceipt(storageInstance.transactionHash).contractAddress
undefined
> storageAddress
"0x25c2bf1b06e9feedb2e3866a309bddd735f5eed0"

2.3调用合约

通过获取合约地址和合约进行交互

> var storage = storageContract.at(storageAddress);
undefined
> storage
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "set",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "Get",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }],
  address: "0x25c2bf1b06e9feedb2e3866a309bddd735f5eed0",
  transactionHash: null,
  Get: function(),
  allEvents: function(),
  set: function()
}

call表示直接在本地evm虚拟机中调用合约方法get()

> storage.Get.call()//在以太坊虚拟机本地执行功能,不会记录在区块链上,不需要花费以太币
0

调用合约set方法,先解锁

> storage.set.sendTransaction(42,{from:eth.accounts[0],gas:1000000})//通过发送交易来执行功能调用,永久记录在区块链上
"0x3c6b089a991066a8dae0c2fa938b70f016279d330107d30ba1246abe8d7c94ac"
> txpool.inspect.pending
{
  0xAe5B8710f1a506bac5f6F4F6aC79D796B6Bf2C7d: {
    1: "0x25C2Bf1b06e9FeedB2E3866A309bDDd735F5eED0: 0 wei + 1000000 gas × 1000000000 wei"
  }
}

开启挖矿

miner.start(1);admin.sleepBlocks(1);miner.stop();

再调用合约的get方法

> storage.Get.call()
42

到这里就是成功通过控制台部署和调用了智能合约,可以看出手动实现是一件比较麻烦的事,之后会学习使用truffle完成编译和部署

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值