主页 > 怎么注册imtoken钱包 > 浅谈以太坊智能合约

浅谈以太坊智能合约

怎么注册imtoken钱包 2023-05-31 07:48:33

本文节选自《区块链开发指南》一书

投稿区块链方向的文章,更正文章,寻求报道,请发邮件至jiawd@csdn.net

什么是合同?

合约是存在于以太坊区块链上特定地址的代码(其功能)和数据(其状态)的集合。 合约账户可以相互传递信息,进行图灵完备的计算。 合约在称为以太坊虚拟机 (EVM) 的字节码(以太坊特定二进制格式)上针对区块链运行。

合约通常用高级语言(如 Solidity)编写,然后编译成字节码并上传到区块链。

还有Serpent、LLL等其他语言也可以用来编写智能合约,下一节将进一步阐述。 分散的应用程序开发资源列出了全面的开发环境、帮助您使用这些语言进行开发的开发人员工具、测试和部署支持等。

以太坊高级语言

合约在称为以太坊虚拟机 (EVM) 的字节码(以太坊特定二进制格式)上针对区块链运行。 然而,合约通常是用诸如 Solidity 之类的高级语言编写的,它将被编译成字节码并使用以太坊虚拟机编译器上传到区块链。

以下是开发人员可以用来为以太坊编写智能合约的高级语言。

坚固性

Solidity 是一种类似于 JavaScript 的语言,您可以使用它来开发编译为以太坊虚拟机字节码的合约。 它是目前以太坊最流行的语言。 蛇

Serpent 是一种类似于 Python 的语言,可用于开发编译成以太坊虚拟机字节码的合约。 它力求简单,结合了低级语言在效率方面的优势和编程风格的易操作性,同时契约编程增加了独特的领域特定特性。 Serpent 是用 LLL 编译的。 生命周期

类 Lisp 语言 (LLL) 是一种类似于汇编的低级语言。 它追求极简主义; 它本质上只是直接在以太坊虚拟机上的一个小包装器。 Mutan(已弃用)

Mutan 是一种静态类型的类 C 语言,由 Jeffrey Wilcke 开发和设计。 不再维护,写合约

没有 Hello World 程序,任何语言都是不完整的。 Solidity 在以太坊环境中运行,没有明显的“输出”字符串的方式。 我们最接近的做法是使用日志记录事件将字符串放入区块链,例如:

contract HelloWorld {
event Print(string out);
function() { Print("Hello, World!"); }
}

每次执行时,该合约都会在区块链中创建一个日志条目,打印“Hello, World!” 范围。

另请参阅:Solidity 文档,了解有关编写 Solidity 代码的更多示例和指南。

编译合约

solidity 合约的编译可以通过多种机制来完成。

注意:可以在此处找到有关 solc 和编译 Solidity 合约代码的更多信息。

1.在geth中设置solidity编译器

如果你启动一个 geth 节点,你可以看到哪些编译器可用。 举例如下:

\> web3.eth.getCompilers();
["lll", "solidity", "serpent"]

此命令返回一个字符串,显示当前可用的编译器。

注意:solc编译器是和cpp-ethereum一起安装的。 或者,您可以创建自己的。

如果您的 solc 可执行文件不在标准位置,您可以使用 --solc 标志为 solc 可执行文件指定自定义路由。 举例如下:

智能合约 以太坊_以太坊智能合约安全性_以太坊智能合约理解

$ 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

2. 编写一个简单的合约

我们来编译一个简单的合约源码,示例如下:

source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"

该合约提供了一个 multiply 方法,该方法使用正整数 a 调用并返回 a*7。

接下来,准备在 geth JS 控制台中使用 eth.compile.solidity() 编译 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.js 访问浏览器中通过 RPC/IPC 连接到 geth 的任何 Dapp。

以下示例将向您展示如何通过 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 {

单源编译器输出将为您提供合约对象智能合约 以太坊,每个对象代表一个合约。 eth.compile.solidity 的实际返回值是一个从合约名称到合约对象的映射。 由于合约名称是 test,eth.compile.solidity(source).test 将给出一个包含以下字段的测试合约对:

编译器输出(代码和信息)的直接结构反映了两种截然不同的部署路径。 编译后的 EVM 代码和合约创建交易被发送到区块,其余(信息)理想情况下位于去中心化云中,可公开验证的元数据在区块链上执行代码。

如果您的源包含多个合同,则输出将包括每个合同的条目,并且可以使用合同名称作为属性名称来检索相应的合同信息对象。 您可以通过检查当前的 GlobalRegistrar 代码来尝试一下:

contracts = eth.compile.solidity(globalRegistrarSrc)

创建和部署合约

在开始本节之前,请确保您有一个未锁定的帐户和一些资金。

现在使用上一章的 EVM 代码作为数据在区块链上创建一个合约,将交易发送到一个空地址。 举例如下:

注意:使用在线 Solidity Live 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: evmByteCodeFromPrevio

智能合约 以太坊_以太坊智能合约安全性_以太坊智能合约理解

所有二进制数据都以十六进制格式序列化。 十六进制字符串将始终具有 0x 的十六进制前缀。

注意:注意 arg1, arg2, ... 是合约构造函数参数,以防它接受参数。 如果合约不需要构造函数参数,这些参数可以省略。

值得指出的是,此步骤需要您付费才能执行。 一旦交易成功进入区块,您的账户余额(您作为发送者被放置在 from 字段中)将根据以太坊虚拟机的 gas 规则被扣除。 一段时间后智能合约 以太坊,你的交易会出现在一个区块中,确认它带来的状态是共识。 您的合同现在存在于区块链上。

异步地做同样的事情看起来像这样:

MyContract.new([arg1, arg2, ...,]{from: primaryAccount, data: evmCode}, function(err, contract) {
if (!err && contract.address)
console.log(contract.address);
});

与合约交互

与合约的交互通常是通过一个抽象层完成的,例如 eth.contract() 函数,它返回 javascript 对象,以及所有可用的合约函数,作为可调用的 javascript 函数。

描述合约可用功能的标准方法是 ABI 定义。 该对象是一个字符串,描述了每个可用合约函数的调用签名和返回值。 举例如下:

var Multiply7 = eth.contract(contract.info.abiDefinition);
var myMultiply7 = Multiply7.at(address);

ABI 中指定的所有函数调用现在都可以在合约实例中使用。 您可以通过以下两种方式之一调用这些合同实例的方法。

\> myMultiply7.multiply.sendTransaction(3, {from: address})
"0x12345"
> myMultiply7.multiply.call(3)
21

当使用 sendTransaction 调用时,函数调用是通过发送交易来执行的。 发送需要以太币,并且通话会永久记录在区块链上。 这样调用的返回值就是交易哈希表。

使用call调用时,函数在以太坊虚拟机本地执行,函数的返回值与函数一起返回。 以这种方式进行的调用不会记录在区块链上,因此不会更改合约的内部状态。 这种调用方式称为常量函数调用。 以这种方式进行的调用不需要以太币。

如果您只对返回值感兴趣,那么您应该使用调用。 如果你只关心合约状态的副作用,你应该使用 sendTransaction。

在上面的例子中,不会产生副作用,所以sendTransaction只会燃烧gas,增加宇宙的熵。

合同元数据

在前面的章节中,揭示了如何在区块链上创建合约。 现在来处理其余的编译器输出、合约元数据或合约信息。

与您未创建的合约进行交互时,您可能需要文档或查看源代码。 鼓励合同作者提供这种可见性,他们可以在区块链上注册或使用第三方服务,如 EtherChain。 管理 API 为所有选择注册以获取此捆绑包的合约提供便捷方法。 举例如下:

// get the contract info for contract address to do manual verification
var info = admin.getContractInfo(address) // lookup, fetch, decode
var source = info.source;
var abiDef = info.abiDefinition

这项工作的基本机制是:

智能合约 以太坊_以太坊智能合约理解_以太坊智能合约安全性

这些要求仅需两步即可通过区块链注册实现。 第一步是在名为 HashReg 的合约中用内容哈希表注册合约代码(哈希表)。 第二步是在 UrlHint 合约的内容哈希表中注册一个 url。 这些注册合约是 Frontier 版本的一部分,它已经包含在 Homestead 中。

利用这种机制,知道合约地址就可以查询url,获取实际的合约元数据信息包。

如果您是认真的合约创建者,请按照以下步骤操作:

将合约本身部署到区块链上,获取合约信息json文件 将合约信息json文件部署到你选择的任意url 注册码哈希表 -> 内容哈希表 -> url

JS API 通过提供助手使这个过程变得非常容易。 调用admin.register提取合约信息,写出指定文件中的json序列,计算文件的内容哈希表,最后将内容哈希表注册到合约代码哈希表中。 将该文件部署到任何 url 后,您可以使用 admin.registerUrl 将 url 注册到区块链上的内容哈希表(请注意,一旦固定内容寻址方案用于文件存储,url-hint 不再必要的)。

source = "contract test { function multiply(uint a) returns(uint d) { return a
*
7; } }"
// compile with solc
contract = eth.compile.solidity(source).test
// create contract object
var MyContract = eth.contract(contract.info.abiDefinition)
// extracts info from contract, save the json serialisation in the given file,
contenthash = admin.saveInfo(contract.info, "~/dapps/shared/contracts/test/info.json")// send off the contract to the blockchain
MyContract.new({from: primaryAccount, data: contract.code}, function(error, contract){
if(!error && contract.address) {
// calculates the content hash and registers it with the code hash in `HashReg`
// it uses address to send the transaction.
// returns the content hash that we use to register a url
admin.register(primaryAccount, contract.address, contenthash)
// here you deploy ~/dapps/shared/contracts/test/info.json to a url
admin.registerUrl(primaryAccount, hash, url)
}
});

测试合约和交易

在对交易和合约进行故障排除时,您通常会需要一些低级测试策略。 本章将介绍一些您可以使用的故障排除任务和实践。 为了在不产生实际后果的情况下测试合约和交易,最好在私有区块链上进行测试。 这可以通过配置备用网络 ID(选择唯一编号)和/或不可用的端点来完成。 推荐的做法是测试您使用备用数据目录和端口,这样您就不会意外地与实时运行的节点发生冲突(假设默认情况下正在运行。在 VM 调试模式下启动 geth,推荐用于分析和最高日志记录冗余其他水平):

geth --datadir ~/dapps/testing/00/ --port 30310 --rpcport 8110 --networkid 4567890 --nodiscover -

提交交易前,需要先创建私有测试链(参考测试网相关章节),示例如下:

// create account. will prompt for password
personal.newAccount();

智能合约 以太坊_以太坊智能合约理解_以太坊智能合约安全性

// name your primary account, will often use it primary = eth.accounts[0]; // check your balance (denominated in ether) balance = web3.fromWei(eth.getBalance(primary), "ether");

 // assume an existing unlocked primary account
primary = eth.accounts[0];
// mine 10 blocks to generate ether
// starting miner
miner.start(4);
// sleep for 10 blocks (this can take quite some time).
admin.sleepBlocks(10);
// then stop mining (just not to burn heat in vain)
miner.stop();
balance = web3.fromWei(eth.getBalance(primary), "ether");

创建事务后,您可以使用以下命令强制它运行:

矿工开始(1);

行政。 睡眠块(1);

矿工。 停止();

您还可以使用以下命令查看即将进行的交易:

// 显示交易池

txpool.status

// 待处理交易的数量

eth.getBlockTransactionCount("pending");

// 打印所有待处理的交易

eth.getBlock(“pending”, true).transactions

如果您提交合约创建交易,您可以检查所需代码是否实际嵌入到当前区块链中:

txhash = eth.sendTansaction({from:primary, data: code})
//... mining
contractaddress = eth.getTransactionReceipt(txhash);
eth.getCode(contractaddress)

《区块链发展指南》由申屠青春主编,宋博、张鹏、王晓明、季周东、左传敏联合主编,国内三大区块链联盟大家共同推荐。

这里写图片描述