写点什么

浅入浅出智能合约 - 部署(二)

  • 2019-12-05
  • 本文字数:3642 字

    阅读完需:约 12 分钟

浅入浅出智能合约 - 部署(二)


上一篇文章 浅入浅出智能合约 - 概述(一) 介绍了智能合约中的一些基本概念以及面向合约的编程语言 Solidity,在这篇文章中我们将要介绍智能合约在编写之后是如何部署到 Ethereum 网络的。



部署一个新的智能合约或者说 DApp 其实总共只需要两个步骤,首先要将已经编写好的合约代码编译成二进制代码,然后将二进制数据和构造参数打包成交易发送到网络中,等待当前交易被矿工追加到区块链就可以了。

编译

合约代码的编译过程非常简单,我们使用如下的合约代码为例,简单介绍合约的编译过程:


JavaScript


pragma solidity ^0.4.22;
contract Contract { constructor() public { }}
复制代码


编译 Solidity 代码需要 solidity 编译器参与工作,编译器的使用也非常简单,我们可以直接使用如下的命令将上述合约编译成二进制:


Bash


$ solc --bin contract.sol
======= contract.sol:Contract =======Binary:6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820d9b24bc33db482b29de2352889cc2dfeb66029c28b0daf251aad5a5c4788774a0029
复制代码


如果我们使用了 Ethereum Wallet 等客户端,就可以将上述二进制数据添加到如下图所示的 DATA 中:



用于创建合约的交易不需要填写目标地址需要在 DATA 中填写合约的二进制数据和编码后的构造器二进制参数,由于这个合约的构造器并不包含任何参数,所以我们只需要添加合约的二进制数据,点击发送后会生成如下的交易 e74c796a041bad60469f2ee023c87e08


JavaScript


{    "jsonrpc": "2.0",    "id": 1,    "result": {        "blockHash": "0xfb508342b89066fe2efa45d7dbb9a3ae241486eee66103c03049e2228a159ee8",        "blockNumber": "0x208c0a",        "from": "0xe118559d65f87aaa8caa4383b112ff679a21223a",        "gas": "0x2935a",        "gasPrice": "0x9502f9000",        "hash": "0xe74c796a041bad60469f2ee023c87e087847a6603b27972839d0c0de2e852315",        "input": "0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820d9b24bc33db482b29de2352889cc2dfeb66029c28b0daf251aad5a5c4788774a0029",        "nonce": "0x2",        "to": null,        "transactionIndex": "0x5",        "value": "0x0",        "v": "0x2c",        "r": "0xa5516d78a7d486d111f818b6b16eef19989ccf46f44981ed119f12d5578022db",        "s": "0x7125e271468e256c1577b1d7a40d26e2841ff6f0ebcc4da073610ab8d76c19d5"    }}
复制代码


在这个用于创建合约的特殊交易中,我们可以看到目标地址 to 的值为空,input 的值就是我们在 Ethereum Wallet 中发送交易时填写的 DATA,即合约的二进制代码。这笔交易被纳入区块链之后,我们就能在 Etherscan 上看到这笔交易成功的创建了一个合约 0xa6a158a131476d4e071f4a3a0d9af2d88769b25a

发送

从上面的测试已经可以看到合约都是由交易(Transaction)创建的,每一个创建合约的交易的 to 字段都是 null,而 input 是合约代码编译之后的二进制;经历了编译这一过程,剩下的就是交易的打包、签名和发送了。


在这里,我们可以通过阅读一个经典的 Ethereum 实现 parity 的源代码来研究交易是如何打包、签名和发送的;从源代码中,我们可以找到签名交易的入口 sign_transaction 函数:


Rust


// parity/rpc/src/v1/traits/eth_signing.rs#[rpc(meta, name = "eth_signTransaction")]fn sign_transaction(&self, Self::Metadata, TransactionRequest) -> BoxFuture<RichRawTransaction>;
// parity/rpc/src/v1/impls/signing.rsfn sign_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcRichRawTransaction> { let res = self.dispatch( RpcConfirmationPayload::SignTransaction(request), meta.dapp_id().into(), meta.origin, );
Box::new(res.flatten().and_then(move |response| { match response { RpcConfirmationResponse::SignTransaction(tx) => Ok(tx), e => Err(errors::internal("Unexpected result.", e)), } }))}
复制代码


上述函数初始化了一个 RpcConfirmationPayload::SignTransaction 结构体并在最后调用 fill_optional_fields 将请求中的参数 fromtononcegas_pricegasvaluedata 以及 condition 等数据填入到最终被签名的交易中:


Rust


// rpc/src/v1/helpers/dispatch.rsfn fill_optional_fields(&self, request: TransactionRequest, default_sender: Address, force_nonce: bool)                        -> BoxFuture<FilledTransactionRequest>{  let request = request;  let from = request.from.unwrap_or(default_sender);  let nonce = if force_nonce {    request.nonce.or_else(|| Some(self.state_nonce(&from)))  } else {    request.nonce  };
Box::new(future::ok(FilledTransactionRequest { from, used_default_from: request.from.is_none(), to: request.to, nonce, gas_price: request.gas_price.unwrap_or_else(|| { default_gas_price(&*self.client, &*self.miner, self.gas_price_percentile) }), gas: request.gas.unwrap_or_else(|| self.miner.sensible_gas_limit()), value: request.value.unwrap_or_else(|| 0.into()), data: request.data.unwrap_or_else(Vec::new), condition: request.condition, }))}
复制代码


经过内部的两次 RPC 请求 SignTransactionSignMessage 最后会由 signature.rs 文件中的 sign 函数使用 secp256k1 完成对传入数据的签名:


Rust


// ethkey/src/signature.rspub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {  let context = &SECP256K1;  let sec = SecretKey::from_slice(context, &secret)?;  let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, &sec)?;  let (rec_id, data) = s.serialize_compact(context);  let mut data_arr = [0; 65];
// no need to check if s is low, it always is data_arr[0..64].copy_from_slice(&data[0..64]); data_arr[64] = rec_id.to_i32() as u8; Ok(Signature(data_arr))}
复制代码


eth_signTransaction 的作用其实只有两部分,一部分是将传入的参数组合成一个交易,另一部分是通过 secp256k1 对交易进行签名:



签名好的二进制交易可以通过 eth_sendRawTransaction 广播到整个 Ethereum 网络,而 JSON 格式的交易可以通过 eth_sendTransaction 发送:


Rust


// parity/rpc/src/v1/traits/eth.rs#[rpc(name = "eth_sendRawTransaction")]fn send_raw_transaction(&self, Bytes) -> Result<H256>;
// parity/rpc/src/v1/impls/eth.rsfn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256> { Rlp::new(&raw.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction)) .and_then(|signed_transaction| { FullDispatcher::dispatch_transaction( &*self.client, &*self.miner, signed_transaction.into(), ) }) .map(Into::into)}
复制代码


send_raw_transaction 最终会将签名好的交易加入到当前节点的交易队列等待处理,交易队列中的交易随后会广播到整个网络中并被整个网络确认并纳入新的区块中。


Rust


fn import_own_transaction<C: miner::BlockChainClient>(  &self,  chain: &C,  pending: PendingTransaction,) -> Result<(), transaction::Error> {  let client = self.pool_client(chain);  let imported = self.transaction_queue.import(    client,    vec![pool::verifier::Transaction::Local(pending)]  ).pop().expect("one result returned per added transaction; one added => one result; qed");
if imported.is_ok() && self.options.reseal_on_own_tx && self.sealing.lock().reseal_allowed() { if self.engine.seals_internally().unwrap_or(false) || !self.prepare_pending_block(chain) { self.update_sealing(chain); } }
imported}
复制代码


当交易成为新区块的一部分之后,我们就能通过 Etherscan 或者其他方式查看被创建合约 0xa6a158a131476d4e071f4a3a0d9af2d88769b25a 的信息了。

总结

在 Ethereum 上部署合约的过程其实与交易发送的过程基本完全相似,唯一的区别就是用于创建合约的交易目前地址为空,并且 data 字段中的内容就是合约的二进制代码,也就是合约的部署由两部分组成:编译合约和发送消息。对于合约的部署这里差不多介绍完了,在下一篇文章中,我们将分析如何调用智能合约中声明的函数。


本文转载自 Draveness 技术博客。


原文链接:https://draveness.me/smart-contract-deploy


2019-12-05 18:171017

评论

发布
暂无评论
发现更多内容

时光有节,岁月有气,用 CodeBuddy + 地图 MCP 构建二十四节气

不惑

CodeBuddy首席试玩官

鸿蒙 HarmonyOS NEXT 系统 Preference 首选项使用全解析

威哥爱编程

HarmonyOS HarmonyOS NEXT Harmony5

AI 多 Agent 开发未来:iVX IDE 的 AST 架构与主流产品的模型优化路径

代码制造者

AI 编程

一站式等保服务

黑龙江陆陆信息测评部

实战:Dify智能体+Java=自动化运营工具!

王磊

Nessus Professional 10.8 | 10.6 Auto Installer for Ubuntu 24.04 (updated May 2025)

sysin

Nessus

鸿蒙仓颉开发语言实战教程:实现商城应用首页

幽蓝计划

RECCV检测人脸伪造项目尝试与扩展

溪抱鱼

人工智能 大数据 人脸识别

HarmonyOS NEXT 使用 relationalStore 实现数据库操作

威哥爱编程

#放码来战.端云一体化开发#HarmonyOS 5 【农民叔叔】03.什么是端云一体化开发,有什么优势?

与辉鸿蒙

HarmonyOS HarmonyOS NEXT

蚂蚁集团数字蚂力与珀莱雅战略合作:打造AI智能化应用矩阵 提升消费者体验和企业竞争力

Lily

重拾童年,用 CodeBuddy 做自己的快乐创作者

不惑

CodeBuddy首席试玩官

【CodeBuddy】三分钟开发一个实用小功能之:动态文字路径动画

jimaks

CSS

#放码来战.端云一体化开发#HarmonyOS 5 【农民叔叔】02.核心功能操作路径及ModelArts AI图像识别技术

与辉鸿蒙

HarmonyOS HarmonyOS NEXT

提升开发运维效率:原力棱镜游戏公司的 Amazon Q Developer CLI 实践

亚马逊云科技 (Amazon Web Services)

《算法导论(第4版)》阅读笔记:p101-p114

codists

算法

Artgee Q2 完成战略拼图:技术 + 理财 + 跨境支付全布局

股市老人

NAS远程访问选哪个?内网穿透工具对比:贝锐花生壳完胜节点小宝

科技热闻

Nessus Professional 10.8 | 10.6 Auto Installer for RHEL 9, AlmaLinux 9, Rocky Linux 9 (updated May 2025)

sysin

Nessus

腾讯推出端到端语音通话模型「混元 Voice」,1.6 秒响应;实时转录工具集体爆发丨日报

声网

再看2025大模型风云变幻,深根者立于终局

脑极体

AI

#放码来战.端云一体化开发#HarmonyOS 5 【农民叔叔】01.人工智能AI诊断分析农作物病虫害APP介绍

与辉鸿蒙

HarmonyOS NEXT 端云一体化 HarmonyOS5.0

#放码来战.端云一体化开发#HarmonyOS 5 【农民叔叔】05.端云一体化开发工程目录结构

与辉鸿蒙

HarmonyOS HarmonyOS NEXT 端云一体化

Nessus Professional 10.8 | 10.6 Auto Installer for macOS Sequoia (updated May 2025)

sysin

AI存储需求的演进与ScaleFlux的应对

ScaleFlux

数据中心 企业级NVMeSSD 存储优化

企业为什么要实施信息化体系建设

优秀

企业信息化 信息化 信息化系统

轻帆云ITSM:以AI赋能制造业,构建高效运维新范式

云智慧AIOps社区

ITSM ITSM软件 工单管理系统

Arthas thread(查看当前JVM的线程堆栈信息)

刘大猫

JVM 监控 Thread Arthas 监控工具

Arthas dashboard(当前系统的实时数据面板)

刘大猫

人工智能 监控 Arthas 监控工具 dashboard

【HarmonyOS 5】金融应用开发鸿蒙组件实践

GeorgeGcs

Nessus Professional 10.8 | 10.6 Auto Installer for Windows (updated May 2025)

sysin

浅入浅出智能合约 - 部署(二)_语言 & 开发_Draveness_InfoQ精选文章