最近幾年區塊鏈技術的使用外延持續擴展,去中心化的節點認證機制可以大幅度改進傳統的支付結算模式的經營效率,降低交易者的成本并提高收益,但不能否認的是,區塊鏈技術也存在著極大的風險,所謂身懷利器,殺心自起,業內應當謹慎使用與推廣區塊鏈技術,
本次,就讓我們來為支付系統添上區塊鏈支付功能,通過Vue3.0+Tornado6的前后端分離系統,一睹區塊鏈加持下去中心化支付邏輯的風采,
前期準備
首先,我們當然需要一個加密貨幣錢包,關于系統集成MetaMask錢包的邏輯,請參見之前的一篇:青山不遮,畢竟東流,集成Web3.0身份錢包MetaMask以太坊一鍵登錄(Tornado6+Vue.js3),
其后,我們需要為接下來的支付行為領取一些“測驗加密貨幣”,領取測驗幣的網站被稱為水龍頭(faucet),測驗幣被稱為水,所以領取測驗幣的程序也被叫做領水,
我們以 Rinkeby 的測驗幣領取為例講解程序,其他測驗網的測驗幣領取方式類似,如果愿意,大家可以把幾個測驗網的水都領一些,
第一步,打開錢包插件,選擇一個錢包,點擊設定:

隨后,選擇高級,然后啟用測驗網路:

接著,將網路切換到Rinkeby測驗網路,網路中還可以看到 Ropsten、Kovan和 Goerli等其他三個測驗網路,四個測驗網路各有特點, Ropsten 采用 POW 機制,可以自己搭建節點挖測驗幣,但是穩定性較差,偶爾還會遇到區塊回滾的情況,很多實驗性測驗,比如 “區塊阻塞攻擊” 實驗會放到這個測驗網來測驗; Kovan 、Rinkeby 和 Goerli 是采用 POA 機制,這幾個測驗網路不能通過挖礦的方式獲取測驗幣,只能通過水龍頭領取,我們以 Rinkeby 為例講解領取程序, Kovan 和 Goerli 類似,但領取條件更為嚴格,大家可以根據需要領取,
切換好Rinkeby測驗網路后,訪問水龍頭網站:https://faucets.chain.link/rinkeby 通過錢包進行鏈接登錄,然后將錢包地址填入領取表單,即可領取0.1的eth貨幣:

領取交易確認之后,查看錢包余額:

至此,前期準備作業就完成了,
錢包支付加簽
前端在Vue3.0專案中安裝區塊鏈模塊和異步請求模塊:
npm install --save ethers
npm install --save axios
隨后在組件中匯入區塊鏈模塊:
import {ethers} from 'ethers';
并且對axios進行簡單封裝:
const myaxios = function(url,type,data=https://www.cnblogs.com/v3ucn/p/{}){
return new
Promise((resolve) => {
//判斷
if(type==="get" || type === "delete"){
axios({
method:type,
url:url,
params:data
}).then((result) => {
resolve(result.data);
});
}else{
axios({
method:type,
url:url,
data:qs.stringify(data)
}).then((result) => {
resolve(result.data);
});
}
});
}
const app = createApp(App)
app.config.globalProperties.myaxios = myaxios;
接著,當頁面首次加載時,我們希望檢查用戶是否已經將錢包連接到站點,為此,我們需要使用eth_accounts方法獲取用戶的帳戶,如果沒有回傳帳戶,這意味著用戶沒有連接:
checkIfWalletConnected:function() {
window.ethereum.request({ method: 'eth_accounts' }).then(function (accounts) {
if (accounts.length > 0) {
console.log(accounts[0]);
} else {
alert("應用未鏈接錢包");
}
});
}
隨后,在初始化方法內對當前用戶進行檢測:
created(){
this.checkIfWalletConnected();
}
如果用戶錢包鏈接沒問題,那么構建支付表單:
<input type="text" v-model="amount" />
<a-button type="primary" @click="create_sign">點擊支付</a-button>
這里用戶點擊支付按鈕后,進入加簽邏輯:
create_sign:function(){
var provider = new ethers.providers.Web3Provider(web3.currentProvider);
//獲取簽名物件
var signer = provider.getSigner();
//時間戳
var rightnow = (Date.now()/1000).toFixed(0);
var sortanow = rightnow - (rightnow % 600);
//生成簽名
signer.signMessage("Trade with "+document.domain+" at "+sortanow+" for "+this.amount,this.accountaddress,"test").then((signature) => {
this.check_sign(signature);
});
}
這里通過Web3Provider獲取到簽名實體,隨后根據時間戳+域名+支付金額生成簽名,簽名生成后,立刻呼叫check_sign方法向后臺發起異步請求進行驗簽操作:
check_sign:function(signature){
this.myaxios(this.weburl+"/sign/","post",{"signature":signature,"accountaddress":this.accountaddress,"amount":this.amount}).then(data =https://www.cnblogs.com/v3ucn/p/>{
if(data.errcode == 0){
this.makePaymentRequest(data.data.selleraddress,data.data.amount);
}
});
}
這里將簽名和錢包地址發送給后端,在客戶端與錢包請求互動的程序中,請求的資料很容易被攔截并篡改,所以加簽環節必不可少:

后端驗簽并創建交易
后端需要web3模塊的加持:
pip3 install web3
隨后創建驗簽方法:
from web3.auto import w3
# 反編譯方法
from eth_account.messages import defunct_hash_message
import time
class CheckSign(BaseHandler):
async def post(self):
signature = self.get_argument("signature",None)
accountaddress = self.get_argument("accountaddress",None)
amount = self.get_argument("amount",None)
selleraddress = "0x95f57Bf3837325FE99a611EFacff6b1d70C7731A"
# 獲取當前域名
domain = self.request.host
if ":" in domain:
domain = domain[0:domain.index(":")]
# 時間戳
now = int(time.time())
sortanow = now - now % 600
# 生成簽名
message = "Trade with {} at {} for {}".format(domain,sortanow,amount)
print(message)
# 反編譯
message_hash = defunct_hash_message(text=message)
# 獲取簽名物件
signer = w3.eth.account.recoverHash(message_hash,signature=signature)
print(accountaddress,signer)
if accountaddress == signer.lower():
res = {"errcode":0,"msg":"ok","data":{"selleraddress":selleraddress,"amount":str(w3.toWei(amount,'ether'))}}
else:
res = {"errcode":1,"msg":"failed"}
self.finish(res)
這里后端通過同樣的演算法對簽名進行驗證,如果驗簽通過,后端將會回傳商戶的錢包地址,也就是用戶轉賬的錢包地址,同時會將付款金額通過w3.toWei方法進行轉換,以太幣的最小單位為wei,1個以太幣相當于10的8次方wei,通常,大家也使用Gwei作為展示單位,比較常用的就是eth,Gwei和wei,
但為了統一標準,支付表單匯總顯示的是eth最大單位,所以通過toWei方法,將最大單位轉換為最小單位,即0.001eth=100000000000000wei,注意轉換后需要以字串的形式回傳到前端,
隨后后端將商戶錢包地址和轉換后的支付金額回傳給前端,
創建交易
回到前端,驗簽通過后,前端獲取支付錢包地址和金額,旋即通過錢包創建支付:
makePaymentRequest:function(sellerAddress,amount) {
window.ethereum.request({ method:'eth_sendTransaction', params: [{ from:this.accountaddress, to:sellerAddress,value:amount}] })
.then(response => {
console.log("交易號:"+response);
var orderid = response;
})
.catch(error => {
console.log(error);
});
}
通過eth_sendTransaction方法發起交易,當用戶同意支付請求時,將會回傳此筆交易的TransactionHash,也就是交易哈希號:

確認支付交易后,獲取TransactionHash:
交易號:0xe937c66e337322cf3b83788b495af2da35ff9635aaaa20f156c74c7f7fddad26
事實上,每一筆支付交易都會產生另一筆“燃料費”,交易燃料費將歸屬于挖出區跨鏈中本次交易區塊的礦工,當礦工挖礦時,他需要決定哪些交易放入到區塊中,可以隨機選擇交易, 也可以不包含任何交易,為了鼓勵讓礦工將你的交易放入區塊,相應地,你必須付出一部分“小費”,
支付查詢
支付確認之后,我們可以利用Rinkeby網路站點通過輸入交易哈希號來查詢這一筆交易:https://rinkeby.etherscan.io/tx/0xe937c66e337322cf3b83788b495af2da35ff9635aaaa20f156c74c7f7fddad26:

當然了,讓用戶自己在“水龍頭”上查詢支付結果顯然不怎么講究,后端肯定需要記錄交易哈希號并且查詢交易明細,這里我們需要一個“上鏈”服務,讓我們的后端也接上區塊鏈網路,訪問 https://infura.io/
Infura是一種IaaS產品,目的是為了降低訪問以太坊資料的門檻, 對于開發者來說,Infura是一個可以讓你的dApp快速接入以太坊的平臺,不需要本地運行以太坊節點, Infura背后是負載均衡的API節點集群, 有針對以太坊Infura有一系列的開發套件,
注冊后,創建鏈接專案:

隨后,復制Rinkeby節點鏈接:

接著,創建訂單查詢腳本 checkorder.py:
from web3 import Web3
w3 = Web3(Web3.HTTPProvider("https://rinkeby.infura.io/v3/32ff12c27a9c485db9a7b61b0a7f3f61"))
print(w3.isConnected())
print(w3.eth.getTransactionReceipt("0xe937c66e337322cf3b83788b495af2da35ff9635aaaa20f156c74c7f7fddad26"))
這里一旦“上鏈”成功,就可以根據交易哈希號來查詢交易的明細,系統回傳:
True
AttributeDict({'blockHash': HexBytes('0x4ede42c4bd15c7ce1736523ae1f84284c7bbdc17388cfbae0df2897bf19f287c'), 'blockNumber': 11098045, 'contractAddress': None, 'cumulativeGasUsed': 13409523, 'effectiveGasPrice': 1500000017, 'from': '0x3B14DdBa7FFF887ED3CCF01fCa0b84501Fd7a711', 'gasUsed': 21000, 'logs': [], 'logsBloom': HexBytes('0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'), 'status': 1, 'to': '0x95f57Bf3837325FE99a611EFacff6b1d70C7731A', 'transactionHash': HexBytes('0xe937c66e337322cf3b83788b495af2da35ff9635aaaa20f156c74c7f7fddad26'), 'transactionIndex': 16, 'type': '0x2'})
至此,完成的加密貨幣支付邏輯就完成了,大體流程如下:
1. 應用會載入并自動檢查 Metamask 錢包是否已連接,如果沒有,將會提示用戶安裝錢包插件并且鏈接,
2. 交易加簽操作,
3. 后端驗簽,并且回傳商戶錢包地址以及轉換金額,
4. 錢包創建交易,
5. 用戶審核并確認付款,
6. 用戶確認交易,生成交易號,用戶和應用都會收到付款確認,
退款
很遺憾,用戶在向錢包地址發送加密貨幣時必須非常小心,如果有人將加密貨幣發送到任何錯誤的地址,用戶將無法取消交易或提出任何投訴以獲得退款,是的,deal is deal,當交易行為已經被寫入區塊,那么是無法被撤銷的,
但這并不意味的用戶就會因此和平臺商戶產生糾紛,如果溝通之后,達成了退款協議,加密貨幣也可以直接從后臺進行轉賬操作:
from web3 import Web3
import os
w3 = Web3(Web3.HTTPProvider("https://rinkeby.infura.io/v3/32ff12c27a9c485db9a7b61b0a7f3f61"))
print(w3.isConnected())
address1 = w3.toChecksumAddress('selleraddress')
address2 = w3.toChecksumAddress ('accountaddress')
private_key = os.getenv('PRIVATE_KEY')
# in this case, the nonce is the amount of transactions on accounti
nonce = w3.eth.getTransactionCount(address1)
# setup the transaction
tx ={
'nonce':nonce,
"to":address2,
'value':w3.toWei("0.0001","ether"),
"gas": 21000,
"gasPrice":w3.toWei(40,'gwei'),
}
signed_tx = w3.eth.account.signTransaction(tx, private_key)
tx_hash = w3.sendRawTransaction(signed_tx.rawTransaction)
這里商戶只需要將錢包私鑰匯入環境變數,隨后創建交易并通過私鑰加簽,最后確認交易,并且獲取到交易哈希號,
結語
區塊鏈技術是二十一世紀的一記響雷,就像洪荒時代孑余的一頭恐龍、大戈壁中枝葉扶疏的一株胡楊、兵馬俑陣中一個脈搏跳動體溫猶存的肉身、死寂的山谷中憑空乍響的一聲洪鐘,所謂衣不如新,人不如故,不入春園,怎知春色幾許?所謂技術的本質就是最大額度地識訓創新,你同意嗎?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/503257.html
標籤:區塊鏈
