主页 > 苹果如何下载imtoken钱包 > Solidity 合约编译和部署

Solidity 合约编译和部署

苹果如何下载imtoken钱包 2023-02-10 07:38:55

在学习了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

报错是因为这个账户没有ether以太坊可以运行智能合约,挖完重新运行

> 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()
}