如何通过solc编译solidity编写的以太坊智能合约
曲水流觞113
发表于 2022-11-6 23:42:53
117
0
0
solidity编写的以太坊智能合约可通过命令行编译工具solc来进行编译,成为以太坊虚拟机中的代码。solc编译后最终部署到链上形成我们所见到的各种智能合约。( U4 ]$ d9 a0 P6 L8 @
$ {/ [" \3 S, W5 t
作为一个solidity命令行编译工具,我们来看看官网都怎么说solc。
/ R4 E- Z/ J2 B
solc的安装很简单:
npminstall-gsolc
//或者
npminstall-gsolc-cli: v* }! `+ t7 o& s0 i
//或者
sudoapt-getinstallsolc E; z6 p, \# u3 n1 O" F
. k S% l' D& p: \- c; I `
安装完成后我们来看,solc--help,solc--help命令显示所有的solc命令选项。编译器可以生成各种输出,比如最终的二进制合约文件、语法树的汇编或者需要预计的要花费的gas等。solc--binsourceFile.sol,可以编译后输出一个名为sourceFile.sol的智能合约文件。如果你想从solc获得更丰富的一些输出变量,你可以使用solc-ooutputDirectory--bin--ast--asmsourceFile.sol。
, s8 ?3 w- w7 B& X; D
你在部署以太坊智能合约之前可以用solc--optimize--binsourceFile.sol优化一下。默认情况下solc编译器会帮你优化200次。你也可以设置--runs=1,这样就按照最小化的方式进行编译,如果你希望多次交易不太在乎成本,那你可以设置成你想要的次数:)。6 o- j( d' q+ I2 S: v) u
$ {3 x5 h- P9 |: q/ k
命令行编译器会自动读取需要导入的文件,也可以通过使用prefix=path来指定路径,例如:' V, K- ?" i; C2 r& Z$ G! D5 n
% U# }3 A7 c$ ?0 a; }) `
solcgithub.com/ethereum/dapp-bin/=/usr/local/lib/dapp-bin/=/usr/local/lib/fallbackfile.sol
8 X- P1 d( E Y( N# N, _5 [
这样编译器就会从指定目录github.com/ethereum/dapp-bin/下的/usr/local/lib/dapp-bin/目录开始搜索,如果没有找到文件,它将查看/usr/local/lib/fallback。solc将只读取你指定的这两个路径的,因此像import"/etc/passwd";必须要通过/=重新映射才起作用。如果有多个匹配,则选择具有最长公共前缀的进行匹配。( _. C$ G7 O2 U8 v, B( R8 z
( [( Q/ f# Y2 `
出于安全上的考虑,编译器限制了它可以访问的一些目录。在命令行中指定的源文件的路径(及其子目录)和命令行指定的路径外其他所有内容都会被拒绝。--allow-paths/sample/path,/another/sample/path来切换。$ V6 p) l. q1 ~$ {0 }
如果智能合约使用了libraries,你会注意到字节码包含了__LibraryName______的子字符串。您可以使用solc作为链接器,这意味着它将在这些点为您插入库地址。. m9 Y" B$ x7 k \$ O+ G4 X* V" C& \
可以通过添加库--libraries"Math:0x12345678901234567890Heap:0xabcdef0123456"到您的命令,以提供每个库的地址,或者使用文件中的说明字符串(每行一个库),并使用--librariesfileName运行solc。 ^* p: G! @) \; P
" X8 E+ P5 f. _2 U8 o K
如果用选项--link调用Solc,则所有输入文件都被解释为未链接的二进制文件(HEX编码),在上面给出的__LibraryName____格式中,将其链接到适当地址(如果从stdin读取输入,则将其写入stdout)。在这种情况下,除了库外,所有选项都被忽略(包括-o)。) r, h* m. c1 T" d3 G0 |
如果用--standard-json调用SOLC,它就将标准的JSON输入(如下所述),并返回JSON输出。: [5 w- G8 ?3 \0 W0 [+ N2 ?
#solc编译器输入输出JSON描述1 `( f7 B U$ ~- z0 R! T
2 l3 t/ O9 P# s
这些JSON格式通过编译器API使用,可以通过SOLC获得。内容都是可以修改的,一些对象是可选的(如前所述),其目的是向后兼容。
编译器的API需要一个JSON格式的输入,然后以JSON格式输出编译结果。% w+ ] U$ x2 L* Y
+ U1 _# g, Z$ ~. x$ `
注意不允许注释。下面示例中的注释,是官网为了学习者更好的理解标注的。" K8 H) Q4 l3 L+ ^
, Y* e( S) \8 D8 {# L$ R
输入格式说明:. u8 l3 |4 G" N7 s$ D
{- e, x3 K; n) |) f
& `# X; v0 h' c0 K: D
//Required:Sourcecodelanguage,suchas"Solidity","serpent","lll","assembly",etc.
4 l# o$ u# Z2 B( J9 _$ S
language:"Solidity",9 R) |8 X0 C8 Z ~( `3 T
( O8 q7 x- o; w0 L, @# x3 U
//Required2 o- z2 H. o3 y5 i2 x% Z9 J
. B% f; B0 Z/ k6 k
sources:) g: ]3 k% H+ _ `
{' k7 p6 M4 v+ G2 q: g) G# O* w. H
//Thekeysherearethe"global"namesofthesourcefiles,7 @- Z. Y$ P/ X8 [0 K( S. C4 [
//importscanuseotherfilesviaremappings(seebelow).
"myFile.sol":
{5 b0 o' n5 |, s3 D1 A) k
7 i2 S: h; |6 B+ f" [3 \5 t! x
//Optional:keccak256hashofthesourcefile( ^' W. r# h6 j1 U
5 v/ Y d& e9 K$ z
//ItisusedtoverifytheretrievedcontentifimportedviaURLs.+ Q+ I# m% Z" A% \6 s
"keccak256":"0x123...",, m, s' A; E3 @- p. ~
//Required(unless"content"isused,seebelow):URL(s)tothesourcefile.
2 N7 ^ x. m& F1 g) R& Q! {6 c
//URL(s)shouldbeimportedinthisorderandtheresultcheckedagainstthe! n0 g/ ^4 m& ]5 l/ B2 E# i" n
//keccak256hash(ifavailable).Ifthehashdoesn'tmatchornoneofthe
//URL(s)resultinsuccess,anerrorshouldberaised. X0 x, {! _- w" b5 _
( v& q8 c! M2 ?6 \5 _
"urls":
3 k, }, x; d- m7 T% J
[
N9 O. J- M- {/ y/ T' a
"bzzr://56ab...",* O7 r: a1 d8 Y/ ^2 C
! x; M' L, |% I; H9 t9 L
"ipfs://Qma...",
"file:///tmp/path/to/file.sol"+ l2 X! L5 S" _ `: K6 T" I5 {0 i
& y) r4 `( R# I6 a* P' r
]6 _7 h9 x7 t! w8 T
},
8 @+ [( o2 y8 J& I% k
"mortal":" V7 d* Q8 L; R1 ~6 o9 K$ A) L7 [, S
{
7 K" ~5 e; K& X: v, f3 I
//Optional:keccak256hashofthesourcefile( R& R l) ]( p2 W, y; n2 k
4 j3 b$ G* N2 b! h
"keccak256":"0x234...",8 s- z: q: {2 n" x
, R; j9 x2 Y$ ]% L l
//Required(unless"urls"isused):literalcontentsofthesourcefile
"content":"contractmortalisowned{functionkill(){if(msg.sender==owner)selfdestruct(owner);}}"
- p& b: M) G- a$ k8 h
}% D# q' T; l8 n( ?& \
},
; X: D5 j5 l8 B2 Q
//Optional
$ L7 d* l1 |* y( l
settings:
, d/ z" q5 e8 U" z Y
{
+ T% H; l) E) ^- d: ^$ V. g2 X r
//Optional:Sortedlistofremappings
remappings:[":g/dir"],( \; E% Y/ V( p1 Z, f
6 C- O( G/ O. P; r m* z
//Optional:Optimizersettings" P+ y* s$ P- c
optimizer:{
; C: _7 w3 ^; Z3 g! |, C
//disabledbydefault' L4 o) r6 @: z6 }) L
9 s2 c t2 O% i
enabled:true,
//Optimizeforhowmanytimesyouintendtorunthecode.
//Lowervalueswilloptimizemoreforinitialdeploymentcost,highervalueswilloptimizemoreforhigh-frequencyusage.
4 e4 i- Q8 m& w0 _' b7 ]; A
runs:200
* x+ r' t+ z+ N- r$ ?$ z
},: E+ o% A2 I j" Q" Y* v$ w& l
evmVersion:"byzantium",//VersionoftheEVMtocompilefor.Affectstypecheckingandcodegeneration.Canbehomestead,tangerineWhistle,spuriousDragon,byzantiumorconstantinople9 m" C! P& u$ E V9 c0 F
//Metadatasettings(optional)& _2 D7 b( s4 f* u
metadata:{
% D& [- L P2 S) X% }
//UseonlyliteralcontentandnotURLs(falsebydefault)$ T. y+ n( f& D u' Y( |& y" d
useLiteralContent:true
},
//Addressesofthelibraries.Ifnotalllibrariesaregivenhere,itcanresultinunlinkedobjectswhoseoutputdataisdifferent.
0 c* x- M4 |+ |( J& k3 Z O( |
libraries:{$ m5 W# w, T1 z: l. _! H! s
//Thetoplevelkeyisthethenameofthesourcefilewherethelibraryisused. g$ O f3 E/ v+ K
//Ifremappingsareused,thissourcefileshouldmatchtheglobalpathafterremappingswereapplied.
/ Z6 l" t2 R& R$ a
//Ifthiskeyisanemptystring,thatreferstoagloballevel.
% b5 b* }( q! b4 P- N. \9 z
"myFile.sol":{, {, j0 M7 F% y/ ~3 b
0 I4 r9 o6 H/ S9 e1 z
"MyLib":"0x123123..."% G$ J- E- \% Y- Z4 j3 q+ ^/ o
5 H: X( Q0 S5 y
}5 E. m5 T3 d" v
}; R1 Z7 a; s+ ?9 D6 k' }# H, T
//Thefollowingcanbeusedtoselectdesiredoutputs.
2 V& d# s: |* ^4 I
//Ifthisfieldisomitted,thenthecompilerloadsanddoestypechecking,butwillnotgenerateanyoutputsapartfromerrors.7 y0 V e' x. g, i& A# `0 q
//Thefirstlevelkeyisthefilenameandthesecondisthecontractname,whereemptycontractnamereferstothefileitself,* |9 }! t' G! Q1 M, B! r( s3 v
//whilethestarreferstoallofthecontracts./ ?* }6 j' E7 z9 K1 C
6 V& y9 I7 H* p [
//
! s" [, ]" i1 U# C* z
//Theavailableoutputtypesareasfollows:/ ~0 b: B P! d ~
//abi-ABI
//ast-ASTofallsourcefiles
- M( A2 v% F8 s- ]1 s& ^" L
//legacyAST-legacyASTofallsourcefiles/ W. t' p7 C5 ^1 j- T1 \; F
7 J4 r8 @, z/ |$ d7 A6 J) u4 E
//devdoc-Developerdocumentation(natspec)1 b+ r; c9 |0 Q- D
//userdoc-Userdocumentation(natspec)
//metadata-Metadata
" a% ] q7 I; w
//ir-Newassemblyformatbeforedesugaring' K. k' i0 F- ~7 V9 w
; C& D" R0 m: d& }% E7 \
//evm.assembly-Newassemblyformatafterdesugaring% f* ^% Q, D3 \/ i# R* W" w0 ]
//evm.legacyAssembly-Old-styleassemblyformatinJSON
//evm.bytecode.object-Bytecodeobject( H+ d" V% R3 d& C D
0 Y& D6 L1 X" H4 q; y( {* G( t
//evm.bytecode.opcodes-Opcodeslist
: y. |5 ?: ?' S8 w" J
//evm.bytecode.sourceMap-Sourcemapping(usefulfordebugging)7 i" {* a- c$ y2 I4 B3 m
//evm.bytecode.linkReferences-Linkreferences(ifunlinkedobject)
//evm.deployedBytecode*-Deployedbytecode(hasthesameoptionsasevm.bytecode)
//evm.methodIdentifiers-Thelistoffunctionhashes2 k: T! o6 r# s* W& ~3 }
//evm.gasEstimates-Functiongasestimates
( M& k6 F4 o9 {4 J8 q3 W, Y2 v
//ewasm.wast-eWASMS-expressionsformat(notsupportedatm)
3 {4 p; P" e3 V( x1 e
//ewasm.wasm-eWASMbinaryformat(notsupportedatm)7 x# @; [4 G1 }/ J1 @) {$ L) R
* q( f. V5 d/ [$ a" s( c$ m! a
//
# u& ~7 r7 [5 S3 B2 j3 M0 A k6 @
//Notethatusingausing`evm`,`evm.bytecode`,`ewasm`,etc.willselectevery
6 c) A3 G' o& S) [. j7 N8 j" [3 N
//targetpartofthatoutput.Additionally,`*`canbeusedasawildcardtorequesteverything./ ]5 u. \7 L% \
, W [' o! R9 S, s: F3 H& {% ?
//
outputSelection:{# C) B- R: y6 h- K: w" `& a* |
6 c! r; Q# y. L4 h
//Enablethemetadataandbytecodeoutputsofeverysinglecontract.7 b7 W" V: U3 f5 z
"*":{: x; W) [$ B3 s7 X
"*":["metadata","evm.bytecode"]
},
4 V1 D7 ~% i/ a* Y
//EnabletheabiandopcodesoutputofMyContractdefinedinfiledef.; p! W5 K3 `! z; Q$ K6 m
+ x$ p/ |7 V8 R1 c+ x1 ^" \
"def":{# x# G4 y1 L# Z
"MyContract":["abi","evm.bytecode.opcodes"]3 a5 [ h3 l( u3 {8 x; v* v- l
. Y9 j* [2 ~* I3 t V0 v; ~' w' g* } P
},9 f! u/ G# y9 |1 k- y
//Enablethesourcemapoutputofeverysinglecontract.
"*":{
' S( @$ K+ j0 U u
"*":["evm.bytecode.sourceMap"]
' M7 |/ K; K* x+ I! V- H
},
//EnablethelegacyASToutputofeverysinglefile.9 B. t! v1 r8 F) Y5 D- ]
' M2 k! s2 k3 h- M( x' G8 w
"*":{ a; f) U" V# \& s. o9 [
% f& }( f1 }# M. K
"":["legacyAST"]
! j9 e ^ H, U3 F6 S' _
}
x6 C( E+ G/ P( U
}
}; y) f2 k$ k/ `6 j8 L4 \# H
}
输出格式说明
{2 A X- u# C! w* j6 X- \( f
//Optional:notpresentifnoerrors/warningswereencountered( k5 M" Q3 v' d7 } o
& [, @- F" C1 s8 P2 K
errors:[
. r$ _5 ?$ W# D2 T
{
; n4 D0 U; {8 J! t
//Optional:Locationwithinthesourcefile.
6 L% M) G: a8 ]) x: Z) \* f
sourceLocation:{- p: K. C3 t# N8 U5 @6 n7 j
file:"sourceFile.sol",
! ^ F m9 ], g3 C r4 K
start:0,
7 y+ l& @! ~" p; B3 x7 r4 O) `
end:100
" G& I c, I+ R+ z$ w
],
- F* v" T" w8 r- e
//Mandatory:Errortype,suchas"TypeError","InternalCompilerError","Exception",etc.( { J3 x0 |, M
//Seebelowforcompletelistoftypes.! G: b5 w+ d( U) a" _* R5 @6 K
type:"TypeError",
//Mandatory:Componentwheretheerrororiginated,suchas"general","ewasm",etc.* G4 Z7 p5 y% U8 E$ z' ]! r4 Y
6 l, l0 T7 P7 @, z+ I( d
component:"general",
+ O' Y! _7 b! i
//Mandatory("error"or"warning")
severity:"error",
0 n; I; \6 ?- E6 M- f
//Mandatory* j5 n/ E: v$ V4 T7 @1 F* e
- i9 r- B7 q8 g
message:"Invalidkeyword"
8 m# [& g) i2 T; J( K* M
//Optional:themessageformattedwithsourcelocation
formattedMessage:"sourceFile.sol:100:Invalidkeyword"
}$ V) C2 }7 K, s( v9 m
0 d% w: \, V" ^
],3 E. P1 k8 U: p& t9 [$ C
//Thiscontainsthefile-leveloutputs.Incanbelimited/filteredbytheoutputSelectionsettings.6 Y$ ~6 v2 E; t* w$ J) S8 D8 k
sources:{
"sourceFile.sol":{2 i) C8 C% h! t2 O
//Identifier(usedinsourcemaps); _4 x% F; t6 \8 K d, i
id:1,, d2 a4 i; I2 C" b3 u, g; r
8 I w5 ]3 ]9 \/ H' G1 @) a
//TheASTobject: D/ `2 G Z) E& I2 N. F9 B
@6 Y2 P! x0 E& e: o1 Q
ast:{},1 ^. i! L. }* m9 ^/ c9 b( S
; r4 r, }9 @% x, j: W, U4 I/ a; G
//ThelegacyASTobject* Q3 a9 ]* b) ^
legacyAST:{}
}
% ^$ O! |( ?: H" a* x
},
//Thiscontainsthecontract-leveloutputs.Itcanbelimited/filteredbytheoutputSelectionsettings.9 e( O' F3 p4 R2 A/ h1 F/ V
contracts:{6 W$ L" B( v6 J* ?& m ]
"sourceFile.sol":{; j' \8 I1 g. k* Z
( e" y6 l( ` [( o- ]3 e2 [ g. G
//Ifthelanguageusedhasnocontractnames,thisfieldshouldequaltoanemptystring.5 |, w, S3 V+ r! h4 ~) l' H$ a2 C
"ContractName":{
//TheEthereumContractABI.Ifempty,itisrepresentedasanemptyarray.) p- ]- [/ X' m7 c
//Seehttps://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI5 n+ _2 T/ d# J
abi:[],6 W$ R2 w2 J( V! x6 m# @
//SeetheMetadataOutputdocumentation(serialisedJSONstring)
metadata:"{...}",
//Userdocumentation(natspec)$ m( n7 y T% g! F9 T5 M
userdoc:{},+ {/ d3 ~: g9 Y8 k
$ L% [: U* n: b3 L: ]
//Developerdocumentation(natspec)# I! v X: h& x. ~/ U
9 D7 N5 v% @0 d+ T' b' Q
devdoc:{},: F! N& z `& A$ l2 `. T# l
1 u5 r9 ?& L( E9 A- X
//Intermediaterepresentation(string)
ir:"",1 R- D( {+ o* b* b3 g+ c
% K# s. }, C) S, \
//EVM-relatedoutputs
evm:{
' K2 i) D6 s+ t9 r+ l* r
//Assembly(string)
, f7 l7 }' d7 E
assembly:"",, `4 j8 L7 m' t
//Old-styleassembly(object)) f+ N$ _: D9 c. R3 D* R# O
1 S! A' x" ~+ k. j7 r6 G2 t
legacyAssembly:{},$ Q, e6 n2 y/ F" Z
5 ~1 M4 V0 R9 g3 [" N
//Bytecodeandrelateddetails.4 M0 C$ U( `* j5 h$ ~! ~
) U% @2 p- Q, A W% f! N, M
bytecode:{+ y# U$ q0 C5 q6 Z! a( o9 N6 i
7 o) I3 {4 H. i! |, j w
//Thebytecodeasahexstring.9 k2 W* A9 T: C' ^+ U
3 P3 ~& n) f! K( F# ~2 n( l' e. i
object:"00fe",, F) ~5 \+ `' ^/ j \2 J5 b
//Opcodeslist(string)
( H: @* E& K8 v. Z) `3 I
opcodes:"",/ h& D" I. p. e4 h( N4 r
//Thesourcemappingasastring.Seethesourcemappingdefinition.% x% h5 m& ^1 g _/ r0 e7 K
3 ~9 {$ A) J* h8 ^, f- J
sourceMap:"",
" O4 e3 Q* K& V* i m
//Ifgiven,thisisanunlinkedobject.
: v- u' x0 R& v! j
linkReferences:{
"libraryFile.sol":{5 n( F4 C: o r" ]. N
( Y# g# D* @8 h$ D4 X
//Byteoffsetsintothebytecode.Linkingreplacesthe20byteslocatedthere.
"Library1":[( |' X( m7 L- P; }5 C9 v
{start:0,length:20},/ w8 ~# O% p/ G7 m0 g; E7 j. q C/ j
0 L3 I9 m& C8 ?2 k/ n0 p* S
{start:200,length:20}8 t! _& ] `" }6 E' n1 F
| w; O4 E2 y$ Q/ m
]/ }4 F# ]- B! P. g: a/ P K3 U8 E
# J$ W" ]4 }; }4 E2 ]
}6 k0 n- R6 N4 J- m$ d% l
7 I' L7 `9 m0 \' Z- x' B8 w
}) n# V7 K6 ~3 S! ]# j
4 C) l0 w! A( ?1 o3 r. b
},
% t) \$ T- c) R5 }6 v `/ c
//Thesamelayoutasabove.
' S }$ G& l1 o; F
deployedBytecode:{},
//Thelistoffunctionhashes$ X* [: x6 j9 H& l' k' ^$ P
: [2 {6 {% y9 d
methodIdentifiers:{
"delegate(address)":"5c19a95c"
}," K* o( G6 @1 M- d
) y' c6 l. x, A4 P2 b& w
//Functiongasestimates3 Q: _/ a, M3 e# ^% h: |
7 d9 j7 U; q, V; e% I8 y6 |
gasEstimates:{. L3 q5 U) a; u" K$ P. Z
creation:{$ W* S9 _ G! w* r) E6 g3 e6 I
8 _. I) h! k& U7 W( ?! p, S7 f: ^
codeDepositCost:"420000",/ z$ x& |1 @' j- @- b; h5 Z
executionCost:"infinite",( f0 @6 e( V& s# ?3 O& g, {+ X, H
totalCost:"infinite"; E( ~: C- ?# [+ O2 F! H0 H
) J% z, R& G# |2 {' l' d
},+ ?; |4 S& E7 e5 n2 M8 J& w
external:{" `/ d2 Y% u6 J
"delegate(address)":"25000"
& N& C( T/ d: J: q2 H5 f
},
internal:{' _/ [; }( l' I8 s$ U
"heavyLifting()":"infinite"
}
}
},
//eWASMrelatedoutputs
ewasm:{
//S-expressionsformat
; n. b6 y4 K$ `, q1 {- R4 `
wast:"",
. ~" s" @8 f6 v8 q, X* f
//Binaryformat(hexstring)4 o* l- U+ v7 q. w: Q$ X& j
wasm:""7 a6 T3 \9 G* V
7 S& i8 ~4 h! B& q, _- `
}
}% b: @+ J) _9 z( O3 R, v& p
0 G2 M2 ?1 Q5 @
}1 d" z5 g/ d4 a4 @2 V- g; i0 j" T
}
}
错误类型说明:
3 G8 c# Y$ y7 L' z6 g
JSONError:JSON错误,JSON输入不符合要求的格式,例如输入不是JSON对象,不支持语言,等等。7 Q4 }/ u5 @/ J; P7 t& i: c6 {
- y1 L1 I& j' ~# }8 F
IOError:IO错误,IO和导入处理错误,如提供的源中的不可解析URL或hash不匹配。* f9 ]6 Q+ N% H% b- _
ParserError:语法f分析错误,源代码不符合语言规则。4 ^: d2 @1 V+ L8 }) D
DocstringParsingError:文档解析错误,无法解析注释块中的NATSPEC标记。
) ~+ m/ E7 ^; a; z% S0 l
SytRealError:语法错误,如continue在for循环之外使用。
DeclarationError:声明错误,无效、不可解析或冲突的标识符名称。例如未找到标识符
TypeError:类型错误,如无效类型转换、无效赋值等。
+ c; o) \/ O% ? C }+ V
UnimplementedFeatureError:编译器不支持该特性,但希望在将来的版本中得到支持。7 R# L+ v$ \3 |' S& }* G
& j0 C5 S0 c/ _( |. e, y
InternalCompilerError:编译器中触发内部错误,这应该作为一个问题来反馈。
/ k2 C- G: s& N; V" c$ F
Exception:例外,编译过程中未知的故障,这应该作为一个问题反馈。8 z y2 V' n% r+ C: j6 n
" \" Q0 y. D; \# c9 B
CompilerError:编译错误,编译器堆栈的使用无效,这应该作为一个问题来反馈。( G7 p: i3 k9 c+ n, h ?
) m0 m# \+ }6 u% O
FatalError:致命错误,这应该作为一个问题来反馈。
' |; U5 x0 \) M+ Q- l
Warning:警告并没有停止编译,但如果可能的话,应该加以处理。
" J% o- G6 i0 t8 Y! Q" D5 f
- {" r# Q0 _# H1 ^) ]
3 C, u% z; D" V. t- w( h4 i
原文请访问:solc
如果你希望马上开始学习以太坊DApp开发,推荐访问一个在线教程:8 `( w1 U2 v) m r7 z8 G- ?" @
/ k* V1 D3 N9 B2 t
以太坊智能合约,主要介绍智能合约与dapp应用开发,适合入门。
以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
成为第一个吐槽的人