目录导航页
【区块链开发入门】(一) 以太坊的搭建与运行
【区块链开发入门】(二) 以太坊的编程接口
【区块链开发入门】(三) Solidity合约编译、部署
【区块链开发入门】(四) Truffle详解篇1
【区块链开发入门】(四) Truffle详解篇2

目录

  • 一、编译智能合约
    • 1.安装solc编译工具
    • 2.开始编译合约
  • 二.部署合约
    • 1.启动以太坊geth节点
    • 2.部署智能合约

这里将讲解如何在控制台中编译、部署Solidity智能合约。智能合约部署流程如下:

  1. 使用solc编译智能合约。
  2. 启动一个以太坊节点(geth或testrpc)。
  3. 将编译好的合约发布到以太坊的网络上。
  4. 用web3.js api调用部署好的合约。

以下是即将编译、部署的智能合约:文件名为Storage.sol,路径为/home/geth/solc。

pragma solidity ^0.7.5;
contract Storage {uint256 public storedData;function set(uint256 data) public {storedData = data;}function get() public returns (uint256) {return storedData;}
}

一、编译智能合约

1.安装solc编译工具

在Ubuntu下安装solc:

$ sudo apt-get install -y software-properties-common
$ sudo add-apt-repository -y ppa:ethereum/ethereum
$ sudo apt-get update
$ sudo apt-get install -y solc

安装完成后,查看solc是否安装完毕:

$ solc --version
solc, the solidity compiler commandline interface
Version: 0.7.5+commit.eb77ed08.Linux.g++

2.开始编译合约

进入控制台执行:

$ echo "var storageOutput=`solc --optimize --combined-json abi,bin,interface Storage.sol`" > storage.js
$ cat storage.js
var storageOutput={"contracts":{"Storage.sol:Storage":{"abi":"[{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]","bin":"608060405234801561001057600080fd5b5060c28061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80632a1afcd914604157806360fe47b11460595780636d4ce63c146075575b600080fd5b6047607b565b60408051918252519081900360200190f35b607360048036036020811015606d57600080fd5b50356081565b005b60476086565b60005481565b600055565b6000549056fea2646970667358221220b8a43d477b990de26dbe99f3bce799d045ed22483cd83701c916a07f5119dded64736f6c63430007050033"}},"version":"0.7.5+commit.eb77ed08.Linux.g++"}


注意这里不是单引号而是反引号,使用solc命令编译Storage.sol合约,把输出的结果赋值给storageOutput变量,同时输出到storage.js文件中。输出的内容有两部分组成
1)ABI:Application Binary Interface的缩写,字面意思为“应用的二进制接口”,可以通俗理解为合约的借口说明,当合约被编译后,它的abi也就确定了。以下是Storage.sol的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"}
]

可以看到合约的ABI解析后是一个数组,这里包含两个对象,每个对象对应一个合约方法,所以这个合约实际包含两个方法。
有几个关键字:

  • type:方法类型,包括function,constructor,fallback,默认为function。
  • name:方法名。
  • inputs:方法参数,对应一个数组,数组里面的每个对象都是一个参数说明。
    name:参数名。
    type:参数类型。
  • outputs:outputs是一个数组,数组内的参数含义可以参考上面的inputs,这两个数组的格式是一样的。
  • constant:布尔值,如果为true指明方法,则不会修改合约的状态变量。
  • payable:布尔值,标明方法是否可以接收ether。

2)bin:合约被编译后的二进制内容。

二.部署合约

1.启动以太坊geth节点

启动之前搭建好的私有链:

$ geth --datadir "./db" --rpc --rpcaddr=0.0.0.0 --rpcport 8545 --rpccorsdomain "*" --rpcapi "eth,net,web3,personal,admin,shh,txtool,debug,miner" --nodiscover --maxpeers 30 --networkid 2020 --port 30303 --mine --minerthreads 1 --etherbase "0xeb680f30715f347d4eb5cd03ac5eced297ac5046" console --allow-insecure-unlock
WARN [11-28|12:56:08.493] Sanitizing cache to Go's GC limits       provided=1024 updated=656
INFO [11-28|12:56:08.520] Maximum peer count                       ETH=30 LES=0 total=30
WARN [11-28|12:56:08.527] The flag --rpc is deprecated and will be removed in the future, please use --http
WARN [11-28|12:56:08.530] The flag --rpcaddr is deprecated and will be removed in the future, please use --http.addr
WARN [11-28|12:56:08.569] The flag --rpcport is deprecated and will be removed in the future, please use --http.port
WARN [11-28|12:56:08.570] The flag --rpccorsdomain is deprecated and will be removed in the future, please use --http.corsdomain
WARN [11-28|12:56:08.570] The flag --rpcapi is deprecated and will be removed in the future, please use --http.api
INFO [11-28|12:56:08.570] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
WARN [11-28|12:56:08.642] The flag --etherbase is deprecated and will be removed in the future, please use --miner.etherbase
INFO [11-28|12:56:08.643] Set global gas cap                       cap=25000000
INFO [11-28|12:56:08.644] Allocated trie memory caches             clean=163.00MiB dirty=164.00MiB
INFO [11-28|12:56:08.644] Allocated cache and file handles         database=/home/yulin/geth/db/geth/chaindata cache=328.00MiB handles=2048
INFO [11-28|12:56:08.955] Opened ancient database                  database=/home/yulin/geth/db/geth/chaindata/ancient
INFO [11-28|12:56:08.997] Initialised chain configuration          config="{ChainID: 666 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: 0 EIP155: 0 EIP158: 0 Byzantium: <nil> Constantinople: <nil> Petersburg: <nil> Istanbul: <nil>, Muir Glacier: <nil>, YOLO v2: <nil>, Engine: unknown}"
INFO [11-28|12:56:09.006] Disk storage enabled for ethash caches   dir=/home/yulin/geth/db/geth/ethash count=3
INFO [11-28|12:56:09.026] Disk storage enabled for ethash DAGs     dir=/home/yulin/.ethash             count=2
INFO [11-28|12:56:09.027] Initialising Ethereum protocol           versions="[65 64 63]" network=2020 dbversion=<nil>
WARN [11-28|12:56:09.027] Upgrade blockchain database version      from=<nil> to=8
INFO [11-28|12:56:09.054] Loaded most recent local header          number=5 hash="92e8f5…2bdfb9" td=655361 age=1w2d19h
INFO [11-28|12:56:09.059] Loaded most recent local full block      number=5 hash="92e8f5…2bdfb9" td=655361 age=1w2d19h
INFO [11-28|12:56:09.059] Loaded most recent local fast block      number=5 hash="92e8f5…2bdfb9" td=655361 age=1w2d19h
INFO [11-28|12:56:09.059] Loaded local transaction journal         transactions=0 dropped=0
INFO [11-28|12:56:09.062] Regenerated local transaction journal    transactions=0 accounts=0
WARN [11-28|12:56:09.062] Switch sync mode from fast sync to full sync
INFO [11-28|12:56:09.085] Starting peer-to-peer node               instance=Geth/v1.9.24-stable-cc05b050/linux-amd64/go1.15.5
INFO [11-28|12:56:09.498] IPC endpoint opened                      url=/home/yulin/geth/db/geth.ipc
ERROR[11-28|12:56:09.498] Unavailable modules in HTTP API list     unavailable="[shh txtool]" available="[admin debug web3 eth txpool personal ethash miner net]"
INFO [11-28|12:56:09.500] HTTP server started                      endpoint=[::]:8545 cors=* vhosts=localhost
INFO [11-28|12:56:09.500] Transaction pool price threshold updated price=1000000000
WARN [11-28|12:56:09.501] The flag --minerthreads is deprecated and will be removed in the future, please use --miner.threads
INFO [11-28|12:56:09.501] Updated mining threads                   threads=1
INFO [11-28|12:56:09.512] Transaction pool price threshold updated price=1000000000
INFO [11-28|12:56:09.509] New local node record                    seq=11 id=a5ba809fab82885b ip=127.0.0.1 udp=0 tcp=30303
INFO [11-28|12:56:09.526] Started P2P networking                   self="enode://57ed0b7b9dfc0ac65e6e6ed8bbf8364484e64855c58c0ba74cb9c13dac5528df4eea51268d37dc4a74d532d2277e463055fa2e38f31356113ab5c2f9ec3e93d7@127.0.0.1:30303?discport=0"
INFO [11-28|12:56:09.527] Commit new mining work                   number=6 sealhash="14d58a…230691" uncles=0 txs=0 gas=0 fees=0 elapsed="183.601µs"
Welcome to the Geth JavaScript console!instance: Geth/v1.9.24-stable-cc05b050/linux-amd64/go1.15.5
coinbase: 0xeb680f30715f347d4eb5cd03ac5eced297ac5046
at block: 5 (Wed Nov 18 2020 17:32:44 GMT+0800 (CST))datadir: /home/yulin/geth/dbmodules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0To exit, press ctrl-d
>

加载之前生成的storage.js文件如下,接着就可以使用编译好的合约了。

> loadScript('/home/yulin/geth/solc/storage.js' )
undefined
> storageOutput
{contracts: {Storage.sol:Storage: {abi: "[{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",bin: "608060405234801561001057600080fd5b5060c28061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80632a1afcd914604157806360fe47b11460595780636d4ce63c146075575b600080fd5b6047607b565b60408051918252519081900360200190f35b607360048036036020811015606d57600080fd5b50356081565b005b60476086565b60005481565b600055565b6000549056fea2646970667358221220b8a43d477b990de26dbe99f3bce799d045ed22483cd83701c916a07f5119dded64736f6c63430007050033"}},version: "0.7.5+commit.eb77ed08.Linux.g++"
}

在storageOutput对象中存储了一个map对象;在storageOutput.contracts[‘Storage.sol:Storage’]中有两个key。分别定义了合约的ABI和编译后的二进制代码。接下来分别获取这两个对象并分别赋值给两个变量。将使用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.部署智能合约

在部署合约之前,需要先解锁账户

> personal.unlockAccount(eth.accounts[0],"6666")
true

使用web3.eth.contract的new方法向网络中发送部署合约的交易,返回一个web3js合约实例地址storageInstance。

> var deployTransationObject = { from:eth.accounts[0],data:storageBinCode,gas:1000000 };
undefined
> var storageInstance = storageContract.new(deployTransationObject)
undefined

此时网络中有一个待处理的交易:

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

开始挖矿,使这笔交易成功写入区块中。

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

交易被确认后,通过storageInstance对象可以看到部署成功后的合约地址
为"0x0642c9ec44a5d6ecfeb19a370e87ee2e90eaf04e"。

> storageInstance
{abi: [{inputs: [],name: "get",outputs: [{...}],stateMutability: "nonpayable",type: "function"}, {inputs: [{...}],name: "set",outputs: [],stateMutability: "nonpayable",type: "function"}, {inputs: [],name: "storedData",outputs: [{...}],stateMutability: "view",type: "function"}],address: "0x0642c9ec44a5d6ecfeb19a370e87ee2e90eaf04e",transactionHash: "0x82e8e6ac2ecc10359302834236bc806d176cfc52519f43907461038abd1ca0ca"
}

合约地址是独一无二的,它是根据发送者的地址和交易的nonce的Hash计算得出的。在后续操作中通过这个合约地址与合约进行交互,部署合约的交易地址也可以看到为:0x82e8e6ac2ecc10359302834236bc806d176cfc52519f43907461038abd1ca0ca

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

eth.getTransactionReceipt(storageInstance.transactionHash);
{blockHash: "0xc541afc9f0b8f8239b736d177d57ff15c0877607a1d5d5c19cd018b85d9375af",blockNumber: 6,contractAddress: "0x0642c9ec44a5d6ecfeb19a370e87ee2e90eaf04e",cumulativeGasUsed: 106233,from: "0x69e3683b008505fac66149ee69b01f6eaccd88fe",gasUsed: 106233,logs: [],logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",root: "0x5a0d54f66bc60c167f5e190878438dfa585d0ae1bd4387791593056f74d5c30a",to: null,transactionHash: "0x82e8e6ac2ecc10359302834236bc806d176cfc52519f43907461038abd1ca0ca",transactionIndex: 0
}

通过eth.getTransactionReceipt方法获取合约地址:

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

通过获取的合约地址与合约交互:

> var storage = storageContract.at(storageAddress);
undefined> storage
{abi: [{inputs: [],name: "get",outputs: [{...}],stateMutability: "nonpayable",type: "function"}, {inputs: [{...}],name: "set",outputs: [],stateMutability: "nonpayable",type: "function"}, {inputs: [],name: "storedData",outputs: [{...}],stateMutability: "view",type: "function"}],address: "0x0642c9ec44a5d6ecfeb19a370e87ee2e90eaf04e",transactionHash: null,allEvents: function(),get: function(),set: function(),storedData: function()
}

call表示直接在本地EVM虚拟机调用合约的get()方法,并且call方式调用合约不会修改区块链中的数据。

> storage.get.call()
0

调用合约set()方法,向以太坊中发送一条调用交易:

> storage.set.sendTransaction(42,{from: eth.accounts[0], gas: 1000000})
"0x13f21fc911ebcb9dbef71549e61b8aba7a97660a287872cac182c2f5223101db"

网络中有一个待处理的交易:

> txpool.status
{pending: 1,queued: 0
}
> txpool.inspect.pending
{0x69E3683b008505FaC66149EE69B01F6EACcD88FE: {2: "0x0642C9eC44A5d6ECFeb19a370e87eE2e90eAf04e: 0 wei + 1000000 gas × 1000000000 wei"}
}

开始挖矿

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

交易成功打包后,再调用合约的get()方法,发现合约的storedData变量值已经变成了刚刚设的值42.

> storage.get.call()
42

【区块链开发入门】(三) Solidity合约编译、部署相关推荐

  1. 区块链开发入门:基于以太坊智能合约构建 ICO DApp

    写给前端开发者的第一本区块链开发入门指南,通过从 0 到 1 实战开发一个 ICO DApp 项目(基于 V 神的 DAICO 设计思想),深入掌握区块链及以太坊技术. 为什么要选择区块链开发? 未来 ...

  2. 【区块链开发入门】(四) Truffle详解篇2

    由于本篇篇幅较长,因此转为两篇文章.Truffle详解篇篇1请见:link 目录导航页 [区块链开发入门](一) 以太坊的搭建与运行 [区块链开发入门](二) 以太坊的编程接口 [区块链开发入门](三 ...

  3. 区块链开发(三)编写调试第一个以太坊智能合约

    李赫 2016年9月10日 一.       智能合约IDE简介 目前以太坊上支持三种语言编写智能合约,     Solidity:类似JavaScript,这是以太坊官方推荐语言,也是最流行的智能合 ...

  4. 区块链开发的权威指南

    原文:https://medium.freecodecamp.org/the-authoritative-guide-to-blockchain-development-855ab65b58bc 新的 ...

  5. 区块链开发初学者编程入门指南

    我有很多问题需要了解区块链Blockchain的工作原理.重要的是"我如何在其上构建应用程序dapp?".花了几个星期的时间挖掘,阅读和试验才最终了解.我找不到简短而全面的指南.现 ...

  6. 蚂蚁区块链投票案例(二)---投票合约设计开发

    文章目录 摘要 背景 案例场景 用例分析 系统管理员注册 添加小区.添加房屋 编辑房屋 发起投票 统计投票 业主注册 业主实名认证 客房关系认证 投票 合约设计 设计原则 合约设计 合约开发 命名规则 ...

  7. 区块链开发语言python_Python:不同区块链智能合约开发语言的选择

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 在本文中,将介绍比特币.超级账本Fabric和以太坊这三种区块链中,分别使用什么开发语言来进行智能合约的编程,并提供你进 ...

  8. aelf区块链开发指南(一) | 如何将以太坊合约转为aelf合约?

    2021年12月12日,aelf元宇宙黑客马拉松正式开启,为帮助更多的开发者快速加入aelf生态,开发更多创新项目,aelf特别开放黑客马拉松开发指南系列课程. 在本期aelf区块链开发指南中,ael ...

  9. 区块链技术入门 | 区块链开发技术栈

    如果你想要从事区块链行业,那么当前区块链技术开发划分必然值得一看. 大概我所了解的在区块链开发的分为区块链底层开发.区块链Dapp开发.区块链生态开发这三类. 如果想要从事与区块链底层开发,需要做以下 ...

最新文章

  1. 【学习笔记】Android 图像处理
  2. golang map 判断key是否存在
  3. 浅析三层架构与MVC模式的区别
  4. django1.4 关于处理静态文件的问题
  5. 无障碍开发(四)之ARIA aria-***状态值
  6. 让机器学会看图说话:Image Caption任务最新综述
  7. C语言文件操作 给M个数随机分组
  8. python学习笔记四——数据类型
  9. c语言按shift用户随时退出,2014年云南省“三校生”高考计算机第三次模拟试卷...
  10. Go语言反射之反射调用
  11. electron 多语言_Electron实用技巧electronbuilder中用户协议(license)的使用及多语言支持...
  12. php opencv答题卡,opencv实现答题卡识别
  13. java中怎么判断字符串的长度_java怎么判断字符串的字符串的长度
  14. 家用计算机音效部件图示,唱吧新版自定义音效设置方法(附上最佳音效设置参数图)...
  15. 电脑上的歌曲怎么传到苹果手机上面,怎么把电脑上的歌导入苹果手机
  16. poodle attack
  17. 香蕉派BPI-M64-〇〇五之:烧录Ubuntu16.04到emmc中(基于win10系统下操作)
  18. 淘宝产品3d展示-家具沙发三维模型应用
  19. php实例-微信第三方登录
  20. 账户经常被盗号怎么办?防盗“黑科技”了解一下

热门文章

  1. 如何解决office2007里出现盗版与需要验证的小星星图标
  2. Bootstrap4使用图标失效的解决方案
  3. 铃铛子简笔画训练营第二期+第一次作业
  4. 痞子衡嵌入式:大话双核i.MXRT1170之在线联合调试双核工程的三种方法(IAR篇)
  5. retrofit+rxjava京东订单
  6. 如何从门外汉到大概理解嵌入式(c语言)基础知识
  7. 解决textBox实时显示问题
  8. 中国汽车用品行业消费调研与需求前景分析报告2022-2028年版
  9. spark业务开发-union合并(union)
  10. 用JAVA写一个最简单的飞翔的小鸟