HPB EVM 合约介绍
合约是是什么?
契约是代码(其功能)和数据(其状态)的集合,它位于以太坊区块链的特定地址。 合同帐户能够在它们之间传递消息以及实际上进行图灵完整计算。 合同以区块链为特色,是以太坊特定的二进制格式生成,称为以太坊虚拟机(EVM)字节码,现在HPB芯链在上层也用ETH同样的架构,这篇文章技术介绍基本的合约理念!
合约通常用一些高级语言(如Solidity)编写,然后编译成字节码以上传到区块链中。
还存在其他语言,特别是Serpent和LLL,这篇文档的以太坊高级语言部分对此进行了进一步描述。
Dapp开发资源列出了集成开发环境,开发者工具可帮助您使用这些语言,并提供测试和部署等功能。
EVM 高阶语言
最早的合约以区块链的形式存在于以太坊特定的二进制格式(EVM字节码)中,由以太坊虚拟机(EVM)执行。 但是,合同通常使用更高级别的语言编写,然后使用EVM编译器编译为字节代码以部署到区块链。
以下是开发人员可以用来为以太坊编写智能合约的不同高级语言。
Solidity
Solidity是一种类似于JavaScript的语言,它允许您开发合同并编译为EVM字节码。 它目前是EVM开发的旗舰语言,也是最受欢迎的语言。
- Solidity Documentation - Solidity是用于编写合同的旗舰以太坊高级语言。
- Solidity online realtime compiler
- Standardized Contract APIs
- Useful Ðapp Patterns - 代码片段对Ðapp开发很有用。
Serpent
Serpent是一种类似于Python的语言,可用于开发合约并编译为EVM字节码。 它旨在最大限度地简洁,将低级语言的许多效率优势与编程风格的易用性结合起来,同时为合约编程添加特殊的域功能。 Serpent使用LLL编译。
LLL
Lisp Like Language (LLL) 是一种类似于汇编的低级语言。 它意味着非常简单和简约; 基本上只是在EVM中直接编码的一个小包装器。
Mutan (deprecated)
Mutan 是由Jeffrey Wilcke设计和开发的静态类型C语言, 它不再维护。
开发一个合约吧
没有Hello World计划,任何语言都不会完整。 在以太坊环境中运行,Solidity没有明显的“输出”字符串的方法。 我们最接近的是使用日志事件将字符串放入区块链中:
contract HelloWorld {
event Print(string out);
function() { Print("Hello, World!"); }
}
此合约将在每次执行时使用参数“Hello,World!”在Print类型的区块链上创建一个日志条目。
还可以看这些文档
Solidity docs 里面有过多的关于如何写合约的代码例子。
编译一个合约
可靠性合同的汇编可以通过许多机制来完成。
- Using the
solc
compiler via the command line. - Using
web3.eth.compile.solidity
in the javascript console provided bygeth
oreth
(This still requires thesolc
compiler to be installed). - The online Solidity realtime compiler.
- The Meteor dapp Cosmo for building solidity contracts.
- The Mix IDE.
- The Ethereum Wallet.
注意:
更多的关于编译的合约code可以在这里 这里发现.
在geth中设置solidity编译器
如果启动geth节点,则可以检查哪些编译器可用。
> web3.eth.getCompilers();
["lll", "solidity", "serpent"]
此命令返回一个字符串数组,指示当前可用的编译器。
注意:
这个 solc
编译器用这个去编译 cpp-ethereum
. 或者这样, 看这段例子 build it yourself.
如果您的solc
可执行文件位于非标准位置,则可以使用--solc
标志指定solcexecutable
的自定义路径。
$ geth --solc /usr/local/bin/solc
或者,您可以通过控制台在运行时设置此选项:
> admin.setSolc("/usr/local/bin/solc")
solc, the solidity compiler commandline interface
Version: 0.2.2-02bb315d/.-Darwin/appleclang/JIT linked to libethereum-1.2.0-8007cef0/.-Darwin/appleclang/JIT
path: /usr/local/bin/solc
编译一个简单的合约
让我们编译一段简单的合约代码:
> source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"
此契约提供单个方法->乘法,使用正整数a
调用并返回a* 7
,您已准备好使用eth.compile.solidity()在geth
JS控制台中编译solidity代码:
> contract = eth.compile.solidity(source).test
{
code: '605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056',
info: {
language: 'Solidity',
languageVersion: '0',
compilerVersion: '0.9.13',
abiDefinition: [{
constant: false,
inputs: [{
name: 'a',
type: 'uint256'
} ],
name: 'multiply',
outputs: [{
name: 'd',
type: 'uint256'
} ],
type: 'function'
} ],
userDoc: {
methods: {
}
},
developerDoc: {
methods: {
}
},
source: 'contract test { function multiply(uint a) returns(uint d) { return a * 7; } }'
}
}
注意:
编译器也可以通过RPC获得,也可以通过web3.javasdk连接到任何通过RPC / IPC连接到geth的浏览器Ðapp。
以下示例显示如何通过JSON-RPC连接geth以使用编译器。
$ geth --datadir ~/eth/ --loglevel 6 --logtostderr=true --rpc --rpcport 8100 --rpccorsdomain '*' --mine console 2>> ~/eth/eth.log
$ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"],"id":1}' http://127.0.0.1:8100
一个源的编译器输出将为您提供合约对象,每个合约对象代表一个合约。 eth.compile.solidity
的实际返回值是合约名称到合约对象对的映射。 由于我们的合约名称是test
,eth.compile.solidity(source).test
将为您提供包含以下字段的测试合同的合同对象:
code
编译好的 EVM 字节码
info
编译器的其他元数据输出
source
源代码
language
编写合约的语言 (Solidity, Serpent, LLL)
languageVersion
合约语言版本
compilerVersion
编译合约时的solidity编译器版本
abiDefinition
userDoc
用户手册 NatSpec Doc
developerDoc
开发者手册NatSpec Doc .
编译器输出的结构(代码和信息)反映了两种截然不同的部署路径。 已编译的EVM代码通过合约创建事务发送到区块链,而其余(信息)将理想地作为可公开验证的元数据部署在分散的云上,以补充区块链上的代码。
如果您的源码包含多个合同,则输出将包含每个合同的条目,可以使用合同名称作为属性名称检索相应的合同信息对象。 您可以通过检查最新的GlobalRegistrar代码来尝试此操作:
contracts = eth.compile.solidity(globalRegistrarSrc)
创建和部署一个合约
在开始此部分之前,请确保您拥有未锁定的帐户以及一些资金。
现在,您将区块链上的合约创建为空地址,并将上一节中的EVM代码作为数据。
如果你用这两个工具会更快些: online Solidity realtime compiler 或者 Mix IDE。
var primaryAddress = eth.accounts[0]
var abi = [{ constant: false, inputs: { name: 'a', type: 'uint256' } }]
var MyContract = eth.contract(abi)
var contract = MyContract.new(arg1, arg2, ..., {from: primaryAddress, data: evmByteCodeFromPreviousSection})
所有二进制数据都以十六进制形式序列化。 十六进制字符串的前缀始终为 0x
。
请注意,arg1,arg2,...
是合同构造函数的参数,以防它接受任何参数。 如果契约不需要任何构造函数参数,则可以省略这些参数。
值得指出的是,此步骤需要您支付执行费用, 一旦您的交易成为一个区块,您在帐户上的余额(您在from的字段中作为发件人)将根据HPB EVM的GAS规则减少, 一段时间后,您的交易应该出现在一个块中,确认它所带来的状态是一致的,你的合同现在住在区块链上。
执行相同操作的异步方式如下所示:
MyContract.new([arg1, arg2, ...,]{from: primaryAccount, data: evmCode}, function(err, contract) {
if (!err && contract.address)
console.log(contract.address);
});