以太坊教程:搭建环境、编写编译一个智能合约
dancing520
发表于 2022-11-6 21:10:54
686
0
0
) C# S+ _% T% Z; s" O
以太坊是什么6 u w' k% F$ e$ L4 L6 [# J
以太坊(Ethereum)是一个开源的有智能合约功能的公共区块链平台。通过其专用加密货币以太币(Ether)提供去中心化的虚拟机(“以太虚拟机”EthereumVirtualMachine)来处理点对点合约。) R$ _" B! ?# w* F
以太坊的概念首次在2013至2014年间由程序员VitalikButerin,受比特币启发后提出,大意为“下一代加密货币与去中心化应用平台”,在2014年通过ICO众筹得以开始发展。目前以太币是市值第二高的加密货币,仅次于比特币。
以太坊区块链是什么?9 y! L5 x0 |/ V1 d* \5 I
) M$ l5 J% X$ L/ v
以太坊区块链有2个主要组件:
' Q* |. V( F" A$ k" d; T* \
数据存储:网络中每笔交易都存储在区块链上。当你部署合约时,就是一笔交易。当你执行合约功能时,也是另一笔交易。所有的这些交易都是公开的,每个人都可以看到并进行验证。这个数据永远也无法篡改。为了确保网络中的所有节点都有着同一份数据拷贝,并且没有向区块链中写入任何的无效数据,以太坊使用一个叫做工作量证明的算法来保证网络安全。
/ J( H" i7 G3 v5 R
代码:就数据的层面而言,区块链就是存储交易。在以太坊的世界里,你可以通过一个叫Solidity的语言编写逻辑/应用代码(也就是智能合约)。然后用solidity编译器将代码编译为以太坊字节码,并将字节码部署到区块链上(也有一些其他的语言可以写合约,不过solidity是到目前为止用得最多也是相对更容易的选择)。所以,以太坊不仅仅会存储交易数据,它还会存储和执行智能合约代码。' T9 Q& g7 P6 u) ?% U0 J
9 {7 n1 w ?: P) ?* ~2 P( G
可以简单的理解以太坊区块链的作用就是存储数据和代码,并在EVM(EthereumVirtualMachine,以太坊虚拟机)中执行代码。1 w0 ]- ^: D) p9 ]4 y
要准备的基础知识
为了进行以太坊开发,你应该对以下语言/技术有基本了解:
9 ]" E: [8 D6 a6 g# K
熟悉某种面向对象语言(如Python,Java,go)% u6 X9 X$ r0 X
HTML/CSS/Javascript
基本的命令行交互如Linuxshell命令& M7 d6 s) ]3 M' M
" o$ S% R5 f/ R$ F7 d* K/ ~- u+ e
理解数据库的基本概念
为了构建以太坊去中心化应用即Dapp(Decentralizedapplication),以太坊有一个非常方便的JavaScript库即web3.js,你也可以在一些js框架中直接引入该库构建应用,比如react,angular,vue等。8 H! T* |1 O Z. t
示例:一个以太坊投票应用
以太坊教程示例中,我们将会构建一个简单的去中心化投票应用。所谓去中心化应用,就是一个不只存在于某一中心化服务器上的应用。在网络中成百上千的电脑上,会运行着非常多的应用副本,这使得它几乎不可能出现宕机的情况。你将会构建一个投票应用,在这个应用中,你可以初始化参与选举的候选者,并对候选者投票,而这些投票将会被记录在区块链上。你将会经历编写投票合约,部署到区块链并与之交互的整个过程。你将会了解什么是一个合约,将合约部署到区块链上并与之交互意味着什么。& y0 z2 g, \: b) w
8 ?& m, [$ [) r [/ s$ E' N- z
本质上,区块链就像是一个分布式数据库,这个数据库维护了一个不断增长的记录链表。如果熟悉关系型数据库,你应该知道一张表里有很多行的数据。现在,对数据进行批(batch)量处理(比如每批100行),并将每个处理的批次相连。就可以形成一个区块链了!在区块链里,每个批次的数据就叫一个块(block),块里的每一行就叫一笔交易(transaction)。" J6 v+ r3 I+ L, p4 d
! L" h& k0 A& ^ ]: y3 ~1 T# D
现在,你对以太坊已经有了基本了解,我们可以开始构建投票的dapp了。这将会加强你对以太坊的认识,并且初略了解以太坊的功能。. }4 g- K: ^' u0 {+ I" T" }/ e
以太坊开发环境搭建2 h- j' Z: T- t- k
1 m) v1 J; q- k W4 D6 A A! p
Linux# c2 U, X% p/ A4 x8 R1 a* J
3 P9 ? ~: B, U8 G& v5 U. ?- F Z
示例是Ubuntu16.04下的学习环境搭建,你只需要成功安装了nodejs和npm,就可以继续项目的下一步了。
我们通过npm安装ganache和web3包来为以太坊教程提供支撑。我们也需要安装solc来编译合约。5 x$ S5 K z( ^/ a6 s8 C
* ]: G5 f( _# S8 B: o) b
下面是安装过程:3 _, X2 y5 l' X9 \0 e
$sudoapt-getupdate- x8 P2 U! d& E5 L8 u
$curl-sLhttps://deb.nodesource.com/setup_7.x-onodesource_setup.sh
$sudobashnodesource_setup.sh: w5 g9 K" Z; d, _/ C
% ]" j' g! d& p/ f0 }
$sudoapt-getinstallnodejs y( H6 d8 z2 z B7 s9 |- V9 M8 W
$node--version
) W R8 [+ ~7 j8 {1 ~1 v
v7.4.0 w6 T/ J- \ x" X$ U" [) a
' `& ]7 f; J) `$ P6 A$ r a
$npm--version
4.0.5$ p t& |: ~. E3 \, F
- X9 Q& ?! [( Z1 X
$mkdir-pethereum_voting_dapp/chapter15 h, u4 ?+ |8 `8 I5 U5 P8 G
$cdethereum_voting_dapp/chapter11 R% z1 {- a. D( R$ f! _. n, D7 P
$npminstallganache-cliweb3@0.20.1solc
7 ~8 {& V% n" ] b6 a( k. j
$node_modules/.bin/ganache-cli7 S- e6 H. T0 A+ ], N; l
5 [* i* r7 K5 I2 q
如果安装成功,运行命令node_modules/.bin/ganache-cli,应该能够看到下面的输出。: r5 ^( Q7 ^% v+ D4 A9 A
, o+ u8 e& W y; g$ y/ u) ^5 q
GanacheCLIv6.0.3(ganache-core:2.0.2)
AvailableAccounts
==================
2 x* A! a s& ~7 R; U% f- I7 u
(0)0x5c252a0c0475f9711b56ab160a1999729eccce97% m Z9 F7 x6 }3 A. H6 j% n
(1)0x353d310bed379b2d1df3b727645e200997016ba3, [: S2 S/ z. G0 @/ Y% F! N
4 E$ R5 c2 o# F
(2)0xa3ddc09b5e49d654a43e161cae3f865261cabd23
(3)0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec50 Z+ s) e A8 b4 ] g4 U I
(4)0xc0aa5f8b79db71335dacc7cd116f357d7ecd2798! q, k4 ^1 P' e8 S; O/ a# }
# e) m# t" R- ]% L X) Y. W
(5)0xda695959ff85f0581ca924e549567390a0034058
; r; S z9 J9 N# f6 b# Z n
(6)0xd4ee63452555a87048dcfe2a039208d113323790) |2 D2 {, @" h, u
(7)0xc60c8a7b752d38e35e0359e25a2e0f6692b10d14
5 j' K2 E+ }+ ]0 R2 X
(8)0xba7ec95286334e8634e89760fab8d2ec1226bf42, i# b. {6 Y2 c/ T' D
0 g/ j, q1 f3 H) B
(9)0x208e02303fe29be3698732e92ca32b88d80a2d365 G3 P" {5 _ w' Z
; y% t9 {+ r; @9 a, `0 Z
PrivateKeys
==================* l" l7 l. `9 l7 z) N$ @
(0)a6de9563d3db157ed9926a993559dc177be74a23fd88ff5776ff0505d21fed2b2 S; v+ W \: q- D6 t
(1)17f71d31360fbafbc90cad906723430e9694daed3c24e1e9e186b4e3ccf4d603
. U9 d1 ~9 K+ y6 u% U
(2)ad2b90ce116945c11eaf081f60976d5d1d52f721e659887fcebce5c81ee6ce99
(3)68e2288df55cbc3a13a2953508c8e0457e1e71cd8ae62f0c78c3a5c929f35430
(4)9753b05bd606e2ffc65a190420524f2efc8b16edb8489e734a607f589f0b67a8
(5)6e8e8c468cf75fd4de0406a1a32819036b9fa64163e8be5bb6f7914ac71251cc$ I& d( V- @* V7 M
( g3 f1 A2 }. M1 Z p& T
(6)c287c82e2040d271b9a4e071190715d40c0b861eb248d5a671874f3ca6d978a95 K/ ?/ X; t/ G2 F2 S& k
6 k, s% Q* q1 K6 Z# T
(7)cec41ef9ccf6cb3007c759bf3fce8ca485239af1092065aa52b703fd04803c9d' D) H( ]6 {9 B: R+ I" H, E+ U
* x) T6 Z$ k6 v7 k( p- o% t
(8)c890580206f0bbea67542246d09ab4bef7eeaa22c3448dcb7253ac2414a5362a
9 K4 ?) Q2 e0 I' E! m
(9)eb8841a5ae34ff3f4248586e73fcb274a7f5dd2dc07b352d2c4b71132b3c73f0
HDWallet t( ]) _! `; G. _) j( }8 @5 s# I D
==================
Mnemonic:cancelbettershockladycapablemaincrunchalcoholderivealarmduckumbrella5 t# t; _' h4 \8 E3 e3 |/ {0 W
BaseHDPath:m/44'/60'/0'/0/{account_index}
Listeningonlocalhost:85456 y+ i' M! v; Q
为了便于测试,ganache默认会创建10个账户,每个账户有100个以太。如果你还不懂什么是账户,把它想象成存钱的银行账户就可以了(以太(Ether,ETH)就是以太坊生态系统中的钱/货币)。你需要用这个账户创建交易,发送/接收以太。
MacOS0 p% ^. `6 e# S3 d' I# ?2 T) j
) p2 x* |' D" {: l7 J, J4 K
如果你还没有安装homebrew,请按照https://brew.sh/的指示安装homebrew。homebrew是一个包管理器,它可以帮助我们安装开发所需的所有其他软件。按照下面的指示安装所有其他所需的包。+ x* L) N$ V# H. b, O9 {1 Q4 g
# c$ u- o! A1 e" B# B5 w
$brewupdate
8 q, M9 U( {- @* x% b% y( a
$brewinstallnodejs
c# W4 Y3 m! }; }$ X
$node--version/ h4 Z; S& l* a7 ?7 L# D
6 `6 s( K$ Y: y
v7.10.0) T" |/ E% Z) n X. l
1 I5 ?( V; w6 ?
$npm--version
4.2.0* C* u4 s" a# i/ y5 [/ S
8 A: ~" j! |3 G- x) o- ~
$mkdir-pethereum_voting_dapp/chapter1% D& K- X. t" H) U0 G3 t
& [3 N% O* X9 Z3 a
$cdethereum_voting_dapp/chapter1
; h {$ J" w; k5 i. E5 |
$npminstallganache-cliweb3@0.20.1solc8 p7 F; C3 m3 f1 S5 y( A4 k
$node_modules/.bin/ganache-cli
% U7 W {0 @5 [
我们通过npm安装ganache和web3包。我们也需要安装solc来编译合约。
8 R, j+ o7 F, A. I0 r0 c" l1 h
如果安装成功,运行命令node_modules/.bin/ganache-cli,应该能够看到右图所示的输出。& ~( Y) @# o, d5 c/ l" ?4 v. O
2 v1 ^ b T& s9 h7 O
GanacheCLIv6.0.3(ganache-core:2.0.2)
AvailableAccounts
==================
(0)0x5c252a0c0475f9711b56ab160a1999729eccce97/ d+ U% w+ S0 M
(1)0x353d310bed379b2d1df3b727645e200997016ba3
(2)0xa3ddc09b5e49d654a43e161cae3f865261cabd23% ^% G h+ h3 O4 x3 m: d) D
0 S. v5 m, ^- Y9 r. s. R
(3)0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec5$ D5 c9 p0 h8 F3 V* I8 W i
(4)0xc0aa5f8b79db71335dacc7cd116f357d7ecd27984 m7 i1 x0 ^' d; b' O1 I' @# [8 X6 c/ f
) P/ K7 K( V; X# w. c3 L5 G& ~$ s9 T0 a
(5)0xda695959ff85f0581ca924e549567390a00340586 q2 [0 I' g, k+ {
(6)0xd4ee63452555a87048dcfe2a039208d113323790
7 [* V% @; q; t& G5 ?& y }# T
(7)0xc60c8a7b752d38e35e0359e25a2e0f6692b10d142 T& r0 S' l/ H" L, k1 P- ~
+ L# G$ `" S, ~, H' C
(8)0xba7ec95286334e8634e89760fab8d2ec1226bf42
" f; _, y: K" Y& F8 W
(9)0x208e02303fe29be3698732e92ca32b88d80a2d36* v0 x' `; I( B j: Z
PrivateKeys) a+ S- X" f0 j! s. b& n: N9 Z( i
( \# P4 F1 x: {& d( G6 I
==================
(0)a6de9563d3db157ed9926a993559dc177be74a23fd88ff5776ff0505d21fed2b) ]; h; c( q! g' O5 j5 i
(1)17f71d31360fbafbc90cad906723430e9694daed3c24e1e9e186b4e3ccf4d603
5 W% v( ^9 J# A8 `/ E0 ^! ~
(2)ad2b90ce116945c11eaf081f60976d5d1d52f721e659887fcebce5c81ee6ce99& M9 j: _& |* q, Y5 ~" N5 @
) |* D6 F7 n( P6 J5 c- ?- y& z+ }; v
(3)68e2288df55cbc3a13a2953508c8e0457e1e71cd8ae62f0c78c3a5c929f35430
4 m3 r( x. p/ I! T* o1 M# t
(4)9753b05bd606e2ffc65a190420524f2efc8b16edb8489e734a607f589f0b67a8: r- \& o' ^/ M: v# I7 f
) {5 k8 m# H5 J/ c
(5)6e8e8c468cf75fd4de0406a1a32819036b9fa64163e8be5bb6f7914ac71251cc( y: h2 |/ m: W# L% d8 p
o' B: |% H: V
(6)c287c82e2040d271b9a4e071190715d40c0b861eb248d5a671874f3ca6d978a9
(7)cec41ef9ccf6cb3007c759bf3fce8ca485239af1092065aa52b703fd04803c9d
^- I/ @' H4 {, v+ v
(8)c890580206f0bbea67542246d09ab4bef7eeaa22c3448dcb7253ac2414a5362a
(9)eb8841a5ae34ff3f4248586e73fcb274a7f5dd2dc07b352d2c4b71132b3c73f05 f) _: O$ ]+ X% F* \; q
HDWallet
0 k5 x+ @4 Q3 |& P8 U
==================# T l6 m) h) D' G
9 Y% U, `: a, A/ _
Mnemonic:cancelbettershockladycapablemaincrunchalcoholderivealarmduckumbrella
BaseHDPath:m/44'/60'/0'/0/{account_index}
' h( O* Y: [2 i1 l% |* Y+ Y& _9 H
Listeningonlocalhost:8545/ l; @4 c* g7 n! E* B
0 C( r# `8 t5 o* u& }. |; Z0 r
为了便于测试,ganache默认会创建10个账户,每个账户有100个以太。如果你还不懂什么是以太坊账户,把它想象成存钱的银行账户就可以了(以太(Ether,ETH)就是以太坊生态系统中的钱/货币)。你需要用这个账户创建交易,发送/接收以太。5 u8 @5 F: S4 C& J- n( m4 X1 b3 m1 [
& l7 ?; S0 y2 `% z5 J! X5 E
Windows: D4 d5 m0 v9 P- }) N# p
安装VisualStudioCommunityEdition。如果你选择定制安装,那么至少应该安装VisualC++(目前的版本是VS2017)3 _. f. E: S( y$ f9 i) }
& B* B6 s8 D% P+ K G( |. s
安装WindowsSDKforWindows
安装Python2.7如果你还没有安装的话,并且确保将它加入到环境变量PATH
% {9 f5 K2 r# O5 p
安装git如果你还没有安装并加入到PATH" ~8 N7 Z% j- a4 S* S
: A8 R6 \! P. u' b0 {8 S
安装OpenSSL。确保选择了正确的安装包,并且只安装完整版(而不是轻装版)。你必须将OpenSSL安装到推荐安装的位置–不要改变安装路径$ T7 a! r- H# T5 w0 ~8 M) g: o
下载和安装nodev8.1.2。不推荐使用版本v6.11.0搭配VS20171 o! P, H$ ^ h! d7 \
, b+ T) F0 f" j) L! q
执行命令npminstallganache-cliweb3@0.20.1solc
SolidityContracts& X" W" c6 G' L5 }# O/ B
5 R; w: L) I( F4 V& O8 R
现在已经安装好ganache并运行,我们将会开始编写第一个以太坊智能合约。
我们会使用solidity编程语言来编写合约。如果你熟悉面向对象编程,学习用solidity写合约应该非常简单。我们会写一个叫做Voting的合约(可以把合约看成是面对对象编程语言的一个类),这个合约有以下内容:
# ^& Q D L) a* J
一个构造函数,用来初始化一些候选者。
" r% m, q0 a2 N9 x8 b) [, f, o
一个用来投票的方法(对投票数加1)
一个返回候选者所获得的总票数的方法0 h& A* m6 U X. Q" q' X1 G+ K
当你把合约部署到区块链的时候,就会调用构造函数,并只调用一次。与web世界里每次部署代码都会覆盖旧代码不同,在区块链上部署的合约是不可改变的,也就是说,如果你更新合约并再次部署,旧的合约仍然会在区块链上存在,并且数据仍在。新的部署将会创建合约的一个新的实例。* H6 O0 r: X1 o5 ~9 c
1 A2 d- B9 P N# o% f* A
pragmasolidity^0.4.18;" C' a Y- i# r& G, v
]& }0 J1 I+ m7 p
contractVoting{' [2 N3 @1 x+ p) \6 r" g
+ Z- _. m4 ^& T, P
mapping(bytes32=>uint8)publicvotesReceived;
bytes32[]publiccandidateList;. P B% f4 {/ d+ T
functionVoting(bytes32[]candidateNames)public{
candidateList=candidateNames;
# k) S6 e, d: q3 ~4 b! h$ E8 O& U
}
functiontotalVotesFor(bytes32candidate)viewpublicreturns(uint8){
require(validCandidate(candidate));, T0 J7 N! N3 R1 A. @1 u
2 B4 F1 G5 _: y8 m$ g
returnvotesReceived[candidate];& j+ S4 s: k& L3 r
}
0 D Y! g% {5 F# C! m
functionvoteForCandidate(bytes32candidate)public{- p; m! X7 G X9 f
require(validCandidate(candidate));
votesReceived[candidate]+=1;5 ^. h7 F [4 h7 N+ e9 L
}% a( X, S4 Z5 ~$ w
functionvalidCandidate(bytes32candidate)viewpublicreturns(bool){/ {0 R1 T I- a5 |
for(uinti=0;i2 @9 m+ Y u; M' k1 k
将右侧代码拷贝到一个叫做Voting.sol的文件中,并保存到chapter1目录下面。# [# p. Z5 s* @
代码和解释
+ p' ~5 {* T" r4 A( Y; E
Line1.我们必须指定代码将会哪个版本的编译器进行编译
Line3.mapping相当于一个关联数组或者是字典,是一个键值对。mappingvotesReceived的键是候选者的名字,类型为bytes32。mapping的值是一个未赋值的整型,存储的是投票数。( t! W9 q& j W& c( A
Line4.在很多编程语言中,仅仅通过votesReceived.keys就可以获取所有的候选者姓名。但是,但是在solidity中没有这样的方法,所以我们必须单独管理一个候选者数组candidateList。
' d; O- L) n& a
Line14.注意到votesReceived[key]有一个默认值0,所以你不需要将其初始化为0,直接加1即可。
你也会注意到每个函数有个可见性说明符(visibilityspecifier)(比如本例中的public)。这意味着,函数可以从合约外调用。如果你不想要其他任何人调用这个函数,你可以把它设置为私有(private)函数。如果你不指定可见性,编译器会抛出一个警告。最近solidity编译器进行了一些改进,如果用户忘记了对私有函数进行标记导致了外部可以调用私有函数,编译器会捕获这个问题。这里可以看到所有的可见性说明符。
你也会在一些函数上看到一个修饰符view。它通常用来告诉编译器函数是只读的(也就是说,调用该函数,区块链状态并不会更新)。所有的修饰符都可以在这里看到。
5 j! [& D5 T- k' W( i" J/ O
编译智能合约2 M5 t( G6 o3 h" ]6 c
- p$ w$ p& \; J: ~. ~5 t: i
我们将会使用上一节安装的solc库来编译代码。如果你还记得的话,之前我们提到过web3js是一个库,它能够让你通过RPC与区块链进行交互。我们将会在node控制台里用这个库部署合约,并与区块链进行交互。$ r+ c, i' [8 L$ O& g
首先,在终端中运行node进入node控制台,初始化web3对象,并向区块链查询获取所有的账户。; U+ N0 n/ E% M. U o0 J( n8 E& l
确保与此同时ganache已经在另一个窗口中运行
为了编译合约,先从Voting.sol中加载代码并绑定到一个string类型的变量,然后像下边这样对合约进行编译。
: w* y% c# T! ]! E3 t3 V& Y8 y
$node
Inthenodeconsole
>Web3=require('web3')
- J! C4 c! l$ @" Y8 q" O6 f% z
>web3=newWeb3(newWeb3.providers.HttpProvider("http://localhost:8545"));
: U3 ~8 [; _; w- b/ x
>web3.eth.accounts
* _" S' e8 d- X" K" X5 R' p
['0x5c252a0c0475f9711b56ab160a1999729eccce97'% g ?6 y! K' J: W9 C
'0x353d310bed379b2d1df3b727645e200997016ba3'1 Y+ q- Y' ~8 U
'0xa3ddc09b5e49d654a43e161cae3f865261cabd23'- O5 R& u+ m4 o/ J
; d. L, q4 a* I" U: @0 V! F; j. [. e
'0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec5'
'0xc0aa5f8b79db71335dacc7cd116f357d7ecd2798'
'0xda695959ff85f0581ca924e549567390a0034058'
8 {( A! l9 x: d/ h
'0xd4ee63452555a87048dcfe2a039208d113323790'
'0xc60c8a7b752d38e35e0359e25a2e0f6692b10d14'
+ d/ n5 [6 G1 K5 o3 v
'0xba7ec95286334e8634e89760fab8d2ec1226bf42'" o- L+ z) a$ O+ q6 L$ v
% Z; U4 ^9 U) P J
'0x208e02303fe29be3698732e92ca32b88d80a2d36']
* m$ ^% S; F- B- M5 k M. n
>code=fs.readFileSync('Voting.sol').toString()
3 \1 q( T1 x$ g5 p! h D
>solc=require('solc')
+ _/ R' Y; ~% W5 N: i# X2 g7 S
>compiledCode=solc.compile(code)& a5 ?+ i" {; k
5 V8 h6 Y' Y1 r$ v6 w2 r
当你成功地编译好合约,打印compiledCode对象(直接在node控制台输入compiledCode就可以看到内容),你会注意到有两个重要的字段,它们很重要,你必须要理解:6 V. m6 g/ Y) w4 a4 Q
( R8 u9 a; P' R7 s8 @: ^
1.compiledCode.contracts[’:Voting’].bytecode:这就是Voting.sol编译好后的字节码。也是要部署到区块链上的代码。( c4 S+ C! c k, @4 V
2.compiledCode.contracts[’:Voting’].interface:这是一个合约的接口或者说模板(叫做abi定义),它告诉了用户在这个合约里有哪些方法。在未来无论何时你想要跟任意一个合约进行交互,你都会需要这个abi定义。你可以在这里看到ABI的更多内容。) }. R( D, y" l- s% h& @
教程参考汇智网的DAPP开发入门教程,如果大家等不及博客更新,也可以直接访问这个以太坊教程。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
成为第一个吐槽的人