开始学习开发以太坊dapp 的应用程式后,你了解了以太坊的智能合约的运作方式,并且阅读网络上很多篇的教学文章,开始会写智能合约以及自动测试,这时你会面临新的问题,要怎么规划以太坊dapp 的应用程式架构?会跟传统的app 应用程式架构一样吗?
因为使用区块链的关系,使得传统的主从架构增加了新的元素–区块链,让设计以太坊dapp的应用程式架构变得复杂。这篇文章会分享一些以太坊应用程式架构,也许你可以找到可以使用的方式(因为平常开发都使用web3.js,文章中的范例都是使用web3.js)。
web3.js目前还在测试版,要注意API的规格随时都可能调整!
客户端– 区块链,无伺服器应用
以太坊dapp的应用程式最基本的就是无伺服器架构,这种方式只有客户端跟区块链,客户端可以直接跟区块链沟通,如果要写网页程式,可以使用web3.js来让网页与区块链沟通,如果要写手机程式,则需要使用以太坊该语言的web3函式库,目前只有看到web3j android。
查询交易
以太坊每一个区块可以塞很多笔交易,要怎么查询交易的内容呢?
首先要建立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"
想要写个以太坊区块链的explorer吗?可以参考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);
送出交易:
区块链:以太币和以太坊是什么?
什么是以太币?以太币(Ether)是一种在以太坊(Ethereum)平台所流通的代币(Token),当使用以太坊的台平时,所需要花费得费用,将会使用以太币来支出。
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 的开发是比较新的领域,相信还有其他更好的架构在文章没有提到,欢迎大家一起提出讨论。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。
以太坊创始人Vitalik Buterin希望改用比特币和莱特币
全球第二大加密货币以太坊(ETH)的创始人Vitalik Buterin表示:就网络安全而言,权益证明(PoS)优于PoW(工作量证明)共识算法。他说,太好了。我们希望改用比特币(BTC)和莱特币(