以太坊dapp 的应用程式架构分析

作者:Peter Lai


开始学习开发以太坊dapp 的应用程式后,你了解了以太坊的智能合约的运作方式,并且阅读网路上很多篇的教学文章,开始会写智能合约以及自动测试,这时你会面临新的问题,要怎么规划以太坊dapp 的应用程式架构?会跟传统的app 应用程式架构一样吗?

因为使用区块链的关系,使得传统的主从架构增加了新的元素–区块链,让设计以太坊dapp的应用程式架构变得复杂。这篇文章会分享一些以太坊应用程式架构,也许你可以找到可以使用的方式(因为平常开发都使用web3.js,文章中的范例都是使用web3.js)。

web3.js目前还在测试版,要注意API的规格随时都可能调整!


客户端– 区块链,无伺服器应用


以太坊dapp的应用程式最基本的就是无伺服器架构,这种方式只有客户端跟区块链,客户端可以直接跟区块链沟通,如果要写网页程式,可以使用web3.js来让网页与区块链沟通,如果要写手机程式,则需要使用以太坊该语言的web3函式库,目前只有看到web3j android。


这时你可能好奇,我要怎么放档案在区块链上?如果要放档案在区块链的网路上,目前以太坊的Swarm和Protocol Labs ipfs都可以做到,档案会分散储存在不同的电脑,不过需要注意一点档案有可能会被删除!


查询交易


以太坊每一个区块可以塞很多笔交易,要怎么查询交易的内容呢?


首先要建立web3 连线物件:
const Web3 = require(‘web3’);
const provider = new Web3.providers.HttpProvider(‘ https://mainnet.infura.io/vuethexplore’);
const web3 = new Web3(provider);


取得区块的资料:


let txs = [];
web3.eth.getBlock(blockNumber).then((block) => {
txs = block.transactions;
}).catch((err) => {
console.warn(err.message);
});


最后取得交易的资料:


web3.eth.getTransactionReceipt(transactionHash).then((transaction) => {
console.log(transaction);
}).catch((err) => {
console.warn(err.message);
});


以主要网路的这笔交易为例,会取得这些资料:


blockHash:”0x2e70662ed2e44f92b054e06ad640ffb2a865a3c8923fa2b3956684d616a7736b”
blockNumber:”0x46d623″
contractAddress:null
cumulativeGasUsed:”0x5208″
from:”0x32be343b94f860124dc4fee278fdcbd38c102d88″
gasUsed:”0x5208″
logs:[]
logsBloom:”0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000″
status:”0x1″
to:”0x00fed6dd82611313e26818b82dfe6dff71aeb309″
transactionHash:”0xcf9ab5afac463944dda517c9592d9cd58d55432e869e72bb549c2fa632067986″
transactionIndex:”0x0″


想要写个以太坊区块链的explore吗?可以参考vuethexplore!


送出交易


每一笔交易都需要私要签章,目前有很多的钱包都可以送出一般的交易和复杂的合约交易,如果就是喜欢自己来,可以使用ethereumjs-tx来签章。


const ethereumTx = require(‘ethereumjs-tx’);
const privateKey = Buffer.from(‘your private key’, ‘hex’);
const txParams = {
nonce: ‘0x00’,
gasPrice: ‘0x04e3b29200’,
gasLimit: ‘0x5208 ‘,
to: ‘0xca35b7d915458ef540ade6068dfe2f44e8fa733c’,
value: ‘0x02d79883d20000’,
data: ”,
// EIP 155 specify chainId
chainId: 1
};


const tx = new ethereumTx(txParams);
// sign
tx.sign(privateKey);


送出交易:


web3.sendRawTransaction(‘0x’ + tx.serialize(), (err, txId) => {
if (err) {
console.warn(err.message);
}
console.log(txId);
});


确认交易:


web3.eth.getTransaction(txId, (err, tx) => {
if (err || !tx) {
// transaction was failed
return;
}
if (web3.eth.blockNumber >= (tx.blockNumber + 12)) {
// transaction was confirmed
}
});


跟区块链沟通有时需要另一台主机运行节点,测试的时候要运行节点是很麻烦的一件事,目前有一个专案infura,开放用API连接不同以太坊的网路,让开发者可以不用担心基础建设的问题,范例中的连结位置就是使用该专案产生。


想要写个以太坊区块链的钱包吗?可以参考vuethwallet!


伺服器端 — 区块链


接着我们来看看伺服器端与区块链的沟通方式,这里指的伺服器可能是单独的服务应用、批次的程式,例如:oraclize


建立当地节点


若想将资料放在公开的区块链,可以用geth或是parity建置当地的节点,透过该节点跟公共网路节点同步,并将签章的交易送到这个节点上,交易会透过这个节点广播到公共网路并验证。


线下签章交易


另一种方式可以线下签章交易,在透过web3送到其他公开的公共网路节点,例如:先前范例提到的infura,就是先在线下签章交易,之后再传送到该API服务,使用这种方式要注意对方(API服务)可能可以修改交易的内容。


结合客户端、伺服器端及区块链


上面分别介绍了客户端对区块链以及伺服器端对区块链,接着我们来看看如何结合三者。


结合客户端以及伺服器端


有些时候我们会同时需要客户端和伺服器端对智能合约的状态改变进行相对应的动作,例如确认客户端有没有进行代币交易或是客户端有没有购买某项产品。这种时候我们会需要客户端和伺服器端观察智能合约,也就是监听智能合约的事件。设计合约事件的时候要注意一般写入的资料都会写在data里,但如果在事件的变数加入indexed,到时候这个变数对应写入的值就会写在topics里,在topcis里的值可以用来当作监听器的筛选条件,详细可以参考这篇文章。


客户端可能会将交易id 传送到伺服器,而不是让伺服器监听事件作为交易的证明,这可能导致恶意的攻击者传送不同的交易id 到伺服器,假装这笔交易是他的。记得确保客户端及伺服器端的讯息只作为通知讯息使用。


记得要确认交易后才回复客户端,因为即使这笔交易被存放到区块且被矿工挖到了,还是可能会发生chain reorganisation,导致该笔交易无效,通常是确认12个区块(约3分钟)。
区块链dapp 的开发是比较新的领域,相信还有其他更好的架构在文章没有提到,欢迎大家一起提出讨论。


文章转载只为分享区块链技术内容,版权归原作者所有,如有侵权请及时与我们取得联系

该内容来自于互联网公开内容,非区块链原创内容,如若转载,请注明出处:https://htzkw.com/archives/4300

联系我们

aliyinhang@gmail.com