以太坊教程:搭建环境、编写编译一个智能合约
dancing520
发表于 2022-11-6 21:10:54
636
0
0
1 s: l& m; U5 g
以太坊是什么
8 i2 E- V8 M$ x
以太坊(Ethereum)是一个开源的有智能合约功能的公共区块链平台。通过其专用加密货币以太币(Ether)提供去中心化的虚拟机(“以太虚拟机”EthereumVirtualMachine)来处理点对点合约。0 W' }% V/ j4 |. O$ V% W, f
以太坊的概念首次在2013至2014年间由程序员VitalikButerin,受比特币启发后提出,大意为“下一代加密货币与去中心化应用平台”,在2014年通过ICO众筹得以开始发展。目前以太币是市值第二高的加密货币,仅次于比特币。
以太坊区块链是什么?
以太坊区块链有2个主要组件:7 W- P# d' \ D6 M1 Z
数据存储:网络中每笔交易都存储在区块链上。当你部署合约时,就是一笔交易。当你执行合约功能时,也是另一笔交易。所有的这些交易都是公开的,每个人都可以看到并进行验证。这个数据永远也无法篡改。为了确保网络中的所有节点都有着同一份数据拷贝,并且没有向区块链中写入任何的无效数据,以太坊使用一个叫做工作量证明的算法来保证网络安全。
l9 C9 [/ v) c# I! w4 O2 C9 b! k
代码:就数据的层面而言,区块链就是存储交易。在以太坊的世界里,你可以通过一个叫Solidity的语言编写逻辑/应用代码(也就是智能合约)。然后用solidity编译器将代码编译为以太坊字节码,并将字节码部署到区块链上(也有一些其他的语言可以写合约,不过solidity是到目前为止用得最多也是相对更容易的选择)。所以,以太坊不仅仅会存储交易数据,它还会存储和执行智能合约代码。, n/ N `, q C% V' _5 T M! S
! Z+ x2 `! o5 j+ ]( p
可以简单的理解以太坊区块链的作用就是存储数据和代码,并在EVM(EthereumVirtualMachine,以太坊虚拟机)中执行代码。) B, p! Z q% E1 f
2 J0 m6 y4 i3 `- b' A
要准备的基础知识* _; l2 S. C& v& [4 [
为了进行以太坊开发,你应该对以下语言/技术有基本了解:3 N$ n5 R& H9 g: r1 f3 x+ M
* l# j- Z3 ^+ ^3 X+ O- s; s9 a
熟悉某种面向对象语言(如Python,Java,go)1 O' q0 \/ T9 R
HTML/CSS/Javascript
基本的命令行交互如Linuxshell命令5 X! E! ?" f& O8 K
理解数据库的基本概念+ d+ G4 [* b; F& N/ F- S
1 f1 _ t/ N" U
为了构建以太坊去中心化应用即Dapp(Decentralizedapplication),以太坊有一个非常方便的JavaScript库即web3.js,你也可以在一些js框架中直接引入该库构建应用,比如react,angular,vue等。' Q y# S9 Q2 x9 U* ?( W& a
. H: m- A3 o3 g0 F4 `& y% N
示例:一个以太坊投票应用
# h7 M, i) P( {6 H
以太坊教程示例中,我们将会构建一个简单的去中心化投票应用。所谓去中心化应用,就是一个不只存在于某一中心化服务器上的应用。在网络中成百上千的电脑上,会运行着非常多的应用副本,这使得它几乎不可能出现宕机的情况。你将会构建一个投票应用,在这个应用中,你可以初始化参与选举的候选者,并对候选者投票,而这些投票将会被记录在区块链上。你将会经历编写投票合约,部署到区块链并与之交互的整个过程。你将会了解什么是一个合约,将合约部署到区块链上并与之交互意味着什么。
+ X n( [1 w: T B
本质上,区块链就像是一个分布式数据库,这个数据库维护了一个不断增长的记录链表。如果熟悉关系型数据库,你应该知道一张表里有很多行的数据。现在,对数据进行批(batch)量处理(比如每批100行),并将每个处理的批次相连。就可以形成一个区块链了!在区块链里,每个批次的数据就叫一个块(block),块里的每一行就叫一笔交易(transaction)。0 B: z4 ?$ Z6 H& L- R
) v& S- ]# F ]+ c
现在,你对以太坊已经有了基本了解,我们可以开始构建投票的dapp了。这将会加强你对以太坊的认识,并且初略了解以太坊的功能。
以太坊开发环境搭建
Linux
* I( @5 E7 l$ Q* h; w6 a
示例是Ubuntu16.04下的学习环境搭建,你只需要成功安装了nodejs和npm,就可以继续项目的下一步了。
# K6 _+ E3 q9 _$ C7 c4 _
我们通过npm安装ganache和web3包来为以太坊教程提供支撑。我们也需要安装solc来编译合约。8 |1 @$ O! G% Y3 r5 Q9 n
7 K6 |: D2 p8 j1 C5 m% m
下面是安装过程:9 Z# G0 v% H4 ?' \
$sudoapt-getupdate
( f/ v9 m1 G- X; ^3 |' `
$curl-sLhttps://deb.nodesource.com/setup_7.x-onodesource_setup.sh) M4 Q: \- n, r+ ~) d! U
$sudobashnodesource_setup.sh: L1 c0 P* L2 I0 U1 j1 g% i; v- g' t
$sudoapt-getinstallnodejs% g) C% U' ]" y) z9 C5 x, }
$node--version
6 h9 S3 k1 T2 e
v7.4.0
$npm--version
4.0.5
7 \% J9 w9 N' p4 ?6 Q$ z) {# q
$mkdir-pethereum_voting_dapp/chapter1
" n) m: G$ C, L( w7 \# `% s
$cdethereum_voting_dapp/chapter1
$npminstallganache-cliweb3@0.20.1solc
" y5 g$ y9 G$ L# l+ |' {/ _
$node_modules/.bin/ganache-cli( W& C1 ]& y$ }- v: R# ^
/ ^/ \! l" h$ G3 T% z8 I
如果安装成功,运行命令node_modules/.bin/ganache-cli,应该能够看到下面的输出。8 i2 X% [; V" {) L) X
GanacheCLIv6.0.3(ganache-core:2.0.2)- Y5 H$ O* U8 N" v& k/ Y6 I* K/ _
AvailableAccounts
% C1 x, v5 E% I
==================7 k0 Y/ i* U, p. U& O
, @* {. V+ S1 Z9 \) L& {
(0)0x5c252a0c0475f9711b56ab160a1999729eccce978 t: J" T7 ?' R) l7 I+ `9 s) }- v
* ^" P, X5 J' t: X, g8 O
(1)0x353d310bed379b2d1df3b727645e200997016ba3
(2)0xa3ddc09b5e49d654a43e161cae3f865261cabd235 s9 `8 t ?' K" A
(3)0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec5/ F8 c. Y7 |) C, W8 Y5 c
9 A2 P6 y0 }, Z: {( t$ b* h
(4)0xc0aa5f8b79db71335dacc7cd116f357d7ecd2798: U( V) G1 P. V" R/ O9 b
(5)0xda695959ff85f0581ca924e549567390a0034058
1 q5 @& u$ N! K8 q' D* b' @
(6)0xd4ee63452555a87048dcfe2a039208d113323790
(7)0xc60c8a7b752d38e35e0359e25a2e0f6692b10d14
/ p* r- s1 _% W N6 h) b6 H% p
(8)0xba7ec95286334e8634e89760fab8d2ec1226bf42
(9)0x208e02303fe29be3698732e92ca32b88d80a2d36/ p1 B( c/ x' J8 V7 Y! x0 D
PrivateKeys8 k2 b2 u/ a, s9 y! z$ N8 g
2 H: ~. M. e5 V" M/ M; G
==================8 x4 ?- z0 y0 h$ x, r) s' {
(0)a6de9563d3db157ed9926a993559dc177be74a23fd88ff5776ff0505d21fed2b
(1)17f71d31360fbafbc90cad906723430e9694daed3c24e1e9e186b4e3ccf4d603; q: c4 {+ V) K0 P# R( P1 U- D* m
8 b: V, h& ^* q3 K8 r" X
(2)ad2b90ce116945c11eaf081f60976d5d1d52f721e659887fcebce5c81ee6ce99& X4 \' F$ [6 `8 n& e; P/ k% M
(3)68e2288df55cbc3a13a2953508c8e0457e1e71cd8ae62f0c78c3a5c929f354304 l0 n8 D! `/ ?7 }9 x
(4)9753b05bd606e2ffc65a190420524f2efc8b16edb8489e734a607f589f0b67a8
& I0 H+ j L) n+ E, I
(5)6e8e8c468cf75fd4de0406a1a32819036b9fa64163e8be5bb6f7914ac71251cc3 a6 q) U, j* |6 f! d: G& Q: D
' _( P& k$ J+ @3 ^
(6)c287c82e2040d271b9a4e071190715d40c0b861eb248d5a671874f3ca6d978a9; Y L( x( l* A! a
* Z8 D C5 m A+ N
(7)cec41ef9ccf6cb3007c759bf3fce8ca485239af1092065aa52b703fd04803c9d7 |, Y8 r9 }! F# e0 w5 O" n
: u# \. }' o0 h0 ~
(8)c890580206f0bbea67542246d09ab4bef7eeaa22c3448dcb7253ac2414a5362a
(9)eb8841a5ae34ff3f4248586e73fcb274a7f5dd2dc07b352d2c4b71132b3c73f0( [9 s0 S6 p- ]2 `( u# N
HDWallet* `6 ^" g; p% a+ b' a4 p) B) V3 U
* c0 Q0 r3 \- {
==================3 t7 Y7 A3 p; {/ I/ K
Mnemonic:cancelbettershockladycapablemaincrunchalcoholderivealarmduckumbrella1 z8 l+ a1 a9 J! i: H
# n5 X5 m @. N7 l" m/ t1 Z
BaseHDPath:m/44'/60'/0'/0/{account_index}
Listeningonlocalhost:85451 }8 q/ Z" A- x; {, a4 p2 v' J7 c
为了便于测试,ganache默认会创建10个账户,每个账户有100个以太。如果你还不懂什么是账户,把它想象成存钱的银行账户就可以了(以太(Ether,ETH)就是以太坊生态系统中的钱/货币)。你需要用这个账户创建交易,发送/接收以太。- o& C8 [3 r3 P' M# {/ h! n
4 D1 o+ v$ _! ~
MacOS
如果你还没有安装homebrew,请按照https://brew.sh/的指示安装homebrew。homebrew是一个包管理器,它可以帮助我们安装开发所需的所有其他软件。按照下面的指示安装所有其他所需的包。
$brewupdate1 O% B8 P {; Y- a6 L
9 k4 o4 [+ M- ]+ W0 A
$brewinstallnodejs: r* f, Q. G# p4 I' L, t* o
$node--version
) o5 ~; n% v% ?7 }1 e
v7.10.0
( Q8 J+ d: _/ T1 ?8 r
$npm--version, w7 f: \% e# _& W
4.2.08 C: a# z; d7 [& M- E; K; k ?# Y$ c
$mkdir-pethereum_voting_dapp/chapter1
, j& n: }0 m( i$ F) I
$cdethereum_voting_dapp/chapter1
$npminstallganache-cliweb3@0.20.1solc
$node_modules/.bin/ganache-cli. @* c7 N$ w: H a' H
我们通过npm安装ganache和web3包。我们也需要安装solc来编译合约。! ?6 x+ o1 F" d; J& r
, T! E1 Q' R2 k# s
如果安装成功,运行命令node_modules/.bin/ganache-cli,应该能够看到右图所示的输出。 p( ^/ O t2 [, g
0 s: m0 T2 u: n/ B9 p
GanacheCLIv6.0.3(ganache-core:2.0.2)
1 A0 _* v. s) Q+ [$ F5 S0 D
AvailableAccounts8 `: Q8 V4 x7 @- G
' E9 C( f2 k& u0 \9 Q+ J \, |
==================, U/ ^& `; v4 k/ i9 I5 ]6 P) J
(0)0x5c252a0c0475f9711b56ab160a1999729eccce97, r' y8 v+ E( z5 n
R# G: ^% H0 j" k
(1)0x353d310bed379b2d1df3b727645e200997016ba3
(2)0xa3ddc09b5e49d654a43e161cae3f865261cabd23# a3 |5 A. w4 i" Q& S( w8 t1 b* h2 y
(3)0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec5
(4)0xc0aa5f8b79db71335dacc7cd116f357d7ecd27985 g+ b2 T u# k; y
(5)0xda695959ff85f0581ca924e549567390a0034058
4 n, Q% E) s+ E: U( C
(6)0xd4ee63452555a87048dcfe2a039208d113323790
" C' B* h; o8 S$ G$ w* G A) q
(7)0xc60c8a7b752d38e35e0359e25a2e0f6692b10d14
" X* W+ v3 D/ c/ l
(8)0xba7ec95286334e8634e89760fab8d2ec1226bf42
( d/ W3 `& D2 X4 w) J+ p" B3 c4 L
(9)0x208e02303fe29be3698732e92ca32b88d80a2d36
2 r, P- g; t; C' R2 {8 `
PrivateKeys
==================$ c4 `1 I0 `) Z
(0)a6de9563d3db157ed9926a993559dc177be74a23fd88ff5776ff0505d21fed2b+ T, L) q, e& L+ {# y( H
(1)17f71d31360fbafbc90cad906723430e9694daed3c24e1e9e186b4e3ccf4d603
(2)ad2b90ce116945c11eaf081f60976d5d1d52f721e659887fcebce5c81ee6ce99
; D( d" B0 Y8 K3 U- Z& k
(3)68e2288df55cbc3a13a2953508c8e0457e1e71cd8ae62f0c78c3a5c929f35430
(4)9753b05bd606e2ffc65a190420524f2efc8b16edb8489e734a607f589f0b67a85 f8 ]; w# b, `/ m L: k
(5)6e8e8c468cf75fd4de0406a1a32819036b9fa64163e8be5bb6f7914ac71251cc
6 y; v& |; s) J. u4 o2 R9 u! r* j' a
(6)c287c82e2040d271b9a4e071190715d40c0b861eb248d5a671874f3ca6d978a97 z8 [% I2 g: [ g1 |
1 Q) D4 G. i4 p4 G8 }
(7)cec41ef9ccf6cb3007c759bf3fce8ca485239af1092065aa52b703fd04803c9d2 j4 c% e! y) F8 E, i# @
. I; _( [7 O4 J
(8)c890580206f0bbea67542246d09ab4bef7eeaa22c3448dcb7253ac2414a5362a+ }. h& y5 t. u d: h
) @1 `/ f2 a! T& u; M3 n" O8 u8 Y
(9)eb8841a5ae34ff3f4248586e73fcb274a7f5dd2dc07b352d2c4b71132b3c73f0
HDWallet
==================
Mnemonic:cancelbettershockladycapablemaincrunchalcoholderivealarmduckumbrella: G9 o% D) _8 E+ x+ q* S1 e, p Q
7 t% A, a5 B$ I% [/ z
BaseHDPath:m/44'/60'/0'/0/{account_index}% v" _& _1 X& D9 {7 T0 O+ Q
Listeningonlocalhost:8545
为了便于测试,ganache默认会创建10个账户,每个账户有100个以太。如果你还不懂什么是以太坊账户,把它想象成存钱的银行账户就可以了(以太(Ether,ETH)就是以太坊生态系统中的钱/货币)。你需要用这个账户创建交易,发送/接收以太。" Q& \1 R8 N3 v6 g6 G, x3 ?
Windows: C+ {3 m: g9 A5 b: `
安装VisualStudioCommunityEdition。如果你选择定制安装,那么至少应该安装VisualC++(目前的版本是VS2017)' d4 Q$ ?9 m" i3 }; g+ \& y) t
/ {+ O. k" B7 O+ o( S) w* W* I; h7 p
安装WindowsSDKforWindows
2 J- d9 g3 V4 U
安装Python2.7如果你还没有安装的话,并且确保将它加入到环境变量PATH! [2 v1 P% r! J3 f- q+ [. ~0 e
1 B; L& Q6 i4 N* e6 l$ p! U
安装git如果你还没有安装并加入到PATH
: J3 n& ?: s0 }! _" b& m# N, W
安装OpenSSL。确保选择了正确的安装包,并且只安装完整版(而不是轻装版)。你必须将OpenSSL安装到推荐安装的位置–不要改变安装路径
下载和安装nodev8.1.2。不推荐使用版本v6.11.0搭配VS2017
! a8 D, G4 v0 Y0 S
执行命令npminstallganache-cliweb3@0.20.1solc9 X3 C( X; l/ H
SolidityContracts
现在已经安装好ganache并运行,我们将会开始编写第一个以太坊智能合约。
: X, ]& M; Q' `9 S
我们会使用solidity编程语言来编写合约。如果你熟悉面向对象编程,学习用solidity写合约应该非常简单。我们会写一个叫做Voting的合约(可以把合约看成是面对对象编程语言的一个类),这个合约有以下内容:9 Z. n: i* _( y0 q N& z
) k$ B$ L/ }3 `
一个构造函数,用来初始化一些候选者。+ X( C, l2 M8 o. F
一个用来投票的方法(对投票数加1)
; m6 q, i4 A' P, N$ p
一个返回候选者所获得的总票数的方法* w% q. M. d) j2 z1 I Q. k
当你把合约部署到区块链的时候,就会调用构造函数,并只调用一次。与web世界里每次部署代码都会覆盖旧代码不同,在区块链上部署的合约是不可改变的,也就是说,如果你更新合约并再次部署,旧的合约仍然会在区块链上存在,并且数据仍在。新的部署将会创建合约的一个新的实例。
; D6 G- M9 T" l
pragmasolidity^0.4.18;
contractVoting{' S- a; j. z! o
mapping(bytes32=>uint8)publicvotesReceived;: ~6 V: e+ t0 i) N- O
bytes32[]publiccandidateList;
0 N" K. C1 X; f) |2 |7 k
functionVoting(bytes32[]candidateNames)public{' i3 B4 s7 Y/ S. k$ E$ E
candidateList=candidateNames;
! l2 u, L' {; _: V( b2 y
}
functiontotalVotesFor(bytes32candidate)viewpublicreturns(uint8){
A( k" w, d8 v) c9 f
require(validCandidate(candidate));
returnvotesReceived[candidate];5 ]) C5 z) r& u4 q2 u& W3 y8 W& D
5 j* N% n2 Z4 q0 [$ F. E
}
functionvoteForCandidate(bytes32candidate)public{
require(validCandidate(candidate));
votesReceived[candidate]+=1;1 q1 X" a6 a6 ]; j; Y
}% n3 s( `" z0 h- g# X0 b9 }
. f& ]# J! ?9 L1 _2 r6 q( C( s; ?8 N
functionvalidCandidate(bytes32candidate)viewpublicreturns(bool){, }! [9 k: J3 `' m& F% Z: S
: C2 c# z4 L4 C/ C. N% g+ k
for(uinti=0;i
( ?% |3 H- L; a1 U+ ~ U7 e$ P
将右侧代码拷贝到一个叫做Voting.sol的文件中,并保存到chapter1目录下面。
代码和解释
Line1.我们必须指定代码将会哪个版本的编译器进行编译
Line3.mapping相当于一个关联数组或者是字典,是一个键值对。mappingvotesReceived的键是候选者的名字,类型为bytes32。mapping的值是一个未赋值的整型,存储的是投票数。
Line4.在很多编程语言中,仅仅通过votesReceived.keys就可以获取所有的候选者姓名。但是,但是在solidity中没有这样的方法,所以我们必须单独管理一个候选者数组candidateList。
4 r5 k. t0 [. N+ P
Line14.注意到votesReceived[key]有一个默认值0,所以你不需要将其初始化为0,直接加1即可。
* C2 d! S% {3 G, j& N8 g; J
你也会注意到每个函数有个可见性说明符(visibilityspecifier)(比如本例中的public)。这意味着,函数可以从合约外调用。如果你不想要其他任何人调用这个函数,你可以把它设置为私有(private)函数。如果你不指定可见性,编译器会抛出一个警告。最近solidity编译器进行了一些改进,如果用户忘记了对私有函数进行标记导致了外部可以调用私有函数,编译器会捕获这个问题。这里可以看到所有的可见性说明符。2 }' ]/ C2 R. i X+ C
) P2 m+ X. O0 Y. O3 Q! y6 S8 U
你也会在一些函数上看到一个修饰符view。它通常用来告诉编译器函数是只读的(也就是说,调用该函数,区块链状态并不会更新)。所有的修饰符都可以在这里看到。
编译智能合约$ x! c4 Y7 e) A
我们将会使用上一节安装的solc库来编译代码。如果你还记得的话,之前我们提到过web3js是一个库,它能够让你通过RPC与区块链进行交互。我们将会在node控制台里用这个库部署合约,并与区块链进行交互。
" O/ k c2 F+ @! j1 A
首先,在终端中运行node进入node控制台,初始化web3对象,并向区块链查询获取所有的账户。4 A1 u- N. R. I9 D
确保与此同时ganache已经在另一个窗口中运行" D6 T% }! y! B0 G
: j6 f7 w2 d, z" i5 E! q9 N
为了编译合约,先从Voting.sol中加载代码并绑定到一个string类型的变量,然后像下边这样对合约进行编译。
' e. {. N9 s/ U9 I( ?( t! j2 d) }! a
$node( b) o% {& a# ]7 M
, }8 w$ I' e* \7 a+ t; I) Y
Inthenodeconsole% ]) E$ Q1 W* l* c; q: j: g) ~
>Web3=require('web3'); U* k8 n- @/ d2 [4 E
9 f2 T, U3 C& J$ }) w
>web3=newWeb3(newWeb3.providers.HttpProvider("http://localhost:8545"));
# n; _5 w" ]7 M( Y% J! D& g
>web3.eth.accounts
2 e: x" M( `1 T$ v) o8 k* j& O! Z a
['0x5c252a0c0475f9711b56ab160a1999729eccce97'- p% z6 h/ K& m( n
5 V- J4 f1 \; d2 {1 H
'0x353d310bed379b2d1df3b727645e200997016ba3': x7 Z5 @# P1 H- x' ~# s0 b C- K
'0xa3ddc09b5e49d654a43e161cae3f865261cabd23'6 H( J( O* s; V/ j2 h
6 Z' v( x1 P( j- Z/ e' B
'0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec5'% n$ K9 X4 Y$ h% {
'0xc0aa5f8b79db71335dacc7cd116f357d7ecd2798'7 ?9 w" F: ?! o+ G/ I- O# O& f
, [/ d( U' e( M9 W% C, _2 p4 O
'0xda695959ff85f0581ca924e549567390a0034058'; ~" h& A* I* t4 X3 a
'0xd4ee63452555a87048dcfe2a039208d113323790'; k! e! E; H/ z1 @
( Q! [& S* ^6 m% M* U
'0xc60c8a7b752d38e35e0359e25a2e0f6692b10d14'" [6 a x/ p$ H2 ]
'0xba7ec95286334e8634e89760fab8d2ec1226bf42'
3 \- D! g" F6 s+ [1 ~# a) f
'0x208e02303fe29be3698732e92ca32b88d80a2d36']
' R ?$ g6 k5 J8 O c* U n
>code=fs.readFileSync('Voting.sol').toString()
4 D8 `- D L) p1 u r
>solc=require('solc')
>compiledCode=solc.compile(code) k- f7 y/ E2 b0 v' m$ x
当你成功地编译好合约,打印compiledCode对象(直接在node控制台输入compiledCode就可以看到内容),你会注意到有两个重要的字段,它们很重要,你必须要理解:
1.compiledCode.contracts[’:Voting’].bytecode:这就是Voting.sol编译好后的字节码。也是要部署到区块链上的代码。# u3 m4 h8 @" L1 @. D3 J
2.compiledCode.contracts[’:Voting’].interface:这是一个合约的接口或者说模板(叫做abi定义),它告诉了用户在这个合约里有哪些方法。在未来无论何时你想要跟任意一个合约进行交互,你都会需要这个abi定义。你可以在这里看到ABI的更多内容。$ m* b7 o U' [" J
教程参考汇智网的DAPP开发入门教程,如果大家等不及博客更新,也可以直接访问这个以太坊教程。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
成为第一个吐槽的人