自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從Python角度了解以太坊

開發(fā) 后端
Web3.py是一個用于與以太坊網(wǎng)絡(luò)交互的Python庫,它封裝了很多操作,便于我們進(jìn)行交易、與智能合約交互、讀取區(qū)塊中的數(shù)據(jù)等等。

  [[431026]]

區(qū)塊鏈基礎(chǔ)

以太坊(Ethereum)的底層是區(qū)塊鏈技術(shù),而區(qū)塊鏈簡單而言就是由Hash值串聯(lián)起來的鏈表結(jié)構(gòu),鏈表中的節(jié)點會記錄交易信息,如果將節(jié)點中的信息以JSON格式描述,看起來是這個樣子:

  1.    "number": 1234567, 
  2.    "hash""0xabc123..."
  3.    "parentHash""0xdef456..."
  4.    "miner""0xa1b2c3..."
  5.    ..., 
  6.    "transactions": [...] 
  • hash:當(dāng)前節(jié)點的Hash值
  • parentHash:前一個節(jié)點的Hash值
  • miner:礦工地址
  • transactions:當(dāng)前節(jié)點包含的交易數(shù)據(jù)

礦工接收交易數(shù)據(jù)后,會將其封裝到一個區(qū)塊里,并將區(qū)塊信息廣播到以太坊網(wǎng)絡(luò)中,這里會有很多細(xì)節(jié),建議找本書看看,這里想強調(diào)的是,想讓礦工干活,需要花錢,在以太坊上,其貨幣稱為「ether」。

使用Web3.py

Web3.py是一個用于與以太坊網(wǎng)絡(luò)交互的Python庫,它封裝了很多操作,便于我們進(jìn)行交易、與智能合約交互、讀取區(qū)塊中的數(shù)據(jù)等等。

Web3.py官方文檔:https://web3py.readthedocs.io/en/stable/index.html

通過一張圖,可以很清晰的知道我們開發(fā)的應(yīng)用、Web3.py以及是以太坊網(wǎng)絡(luò)的關(guān)系。

從上圖可知,Web3.py其實就是中間層,它可以通過HTTP、IPC(進(jìn)程間通信)、WebSocket的方法連接到以太坊節(jié)點,從而實現(xiàn)與整個以太坊網(wǎng)絡(luò)的交互。

使用前,我們需要安裝Web3.py:

  1. pip install web3 
  2. pip install 'web3[tester]' 

安裝web3[tester]的目的時,使用Web3.py提供的模擬節(jié)點進(jìn)行測試,如果我們要同步真正的節(jié)點需要做:

  • 1.下載Geth構(gòu)建以太坊節(jié)點。
  • 2.啟動Geth并等待它同步以太坊網(wǎng)絡(luò)中的數(shù)據(jù),Geth默認(rèn)會啟動HTTP服務(wù),端口為8545.
  • 3.使用Web3.py通過HTTP連接到剛剛構(gòu)建好的節(jié)點。
  • 4.使用Web3.py提供的API與節(jié)點進(jìn)行交互

Geth是使用Go實現(xiàn)Ethereum協(xié)議的程序,與之類似的還是使用C++或Python實現(xiàn)的,只是Geth勢頭第一。

同步過程需要拉取數(shù)據(jù),可能需要幾個小時。

這里只是演示,所以直接使用模擬節(jié)點就好了,如下圖:

上圖中,Web3.py提供了4種接入以太坊節(jié)點的方式,其中第4種便是通過TesterProvider接入模擬的以太坊節(jié)點,要使用這個功能,你需要安裝web3[tester]。

安裝好web3后,先通過TesterProvider方法連接到模擬節(jié)點中。

  1. In [1]: from web3 import Web3 
  2.  
  3. # 使用EthereumTesterProvider,連接模擬節(jié)點 
  4. In [2]: w3 = Web3(Web3.EthereumTesterProvider()) 
  5.  
  6. # 判斷連接是否正常 
  7. In [3]: w3.isConnected() 
  8. Out[3]: True 

為了方便我們測試(如測試編寫好的智能合約),Web3.py提供的模擬節(jié)點中已經(jīng)為我們提供了一些賬戶,每個賬戶中有1000000個ether。

  1. # 獲得可以使用的測試賬戶 
  2. In [4]: w3.eth.accounts 
  3. Out[4]: 
  4. ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf'
  5.  '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF'
  6.  '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69'
  7.  '0x1efF47bc3a10a45D4B230B5d10E37751FE6AA718'
  8.  '0xe1AB8145F7E55DC933d51a18c793F901A3A0b276'
  9.  '0xE57bFE9F44b819898F47BF37E5AF72a0783e1141'
  10.  '0xd41c057fd1c78805AAC12B0A94a405c0461A6FBb'
  11.  '0xF1F6619B38A98d6De0800F1DefC0a6399eB6d30C'
  12.  '0xF7Edc8FA1eCc32967F827C9043FcAe6ba73afA5c'
  13.  '0x4CCeBa2d7D2B4fdcE4304d3e09a1fea9fbEb1528'
  14.  
  15. # 獲得第一個賬戶下的金額  
  16.  In [5]: w3.eth.get_balance(w3.eth.accounts[0]) 
  17. Out[5]: 1000000000000000000000000 

使用w3.eth.get_balance方法獲得的金額為1000000000000000000000000,是因為其單位是wei。

因為計算機不太擅長處理浮點數(shù),所以為了解決這個問題,很多程序員會將1.23元以123存到數(shù)據(jù)庫中,即以分為基本單位。以太坊這邊也一樣,ether類似于元的單位,而wei類似于分,只是分只是增大了100倍,而wei與ether的比例是(18個0):

  1. 1 ether = 100000000000000000 wei  
  2. 1 wei = 0.0000000000000000001 ether 

Web3.py提供了toWei與fromWei方法進(jìn)行單位的換算,ether與wei單位之間還有多個單位,可以查閱Web3.py文檔Converting currency denominations。簡單使用toWei與fromWei兩個方法:

  1. In [7]: Web3.toWei(1, 'ether'
  2. Out[7]: 1000000000000000000 
  3.  
  4. In [8]: Web3.fromWei(1000000000000000000000000, 'ether'
  5. Out[8]: Decimal('1000000'

模擬交易

有了賬戶以及錢后,就可以模擬交易行為了,即將你賬戶中的幣轉(zhuǎn)到其他賬戶中。

先來看看,沒有任何轉(zhuǎn)賬狀態(tài)下的區(qū)塊鏈:

  1. # 獲取區(qū)塊鏈中最新一個區(qū)塊的信息 
  2. In [9]: w3.eth.get_block('latest'
  3. Out[9]: 
  4. AttributeDict({'number': 0, 
  5.  'hash': HexBytes('0x78b6514d115669937c0933824a0c74ff2eab14a25f1b1e799609872bcb18113b'), 
  6.  # 前一個區(qū)塊Hash為0 
  7.  'parentHash': HexBytes('0x0000000000000000000000000000000000000000000000000000000000000000'), 
  8. ... 
  9.  'gasLimit': 3141592, 
  10.  'gasUsed': 0, 
  11.  'timestamp': 1635092566, 
  12.  # 沒有交易 
  13.  'transactions': [], 
  14.  'uncles': []}) 

因為是模擬節(jié)點,所以與真實節(jié)點不同,它不會在大約15秒內(nèi)增加一個新區(qū)塊,而是會一直模擬等待,直到你進(jìn)行交易。

到目前為止,因為我們沒有進(jìn)行任何交易,所以parentHash(前置區(qū)塊Hash)為0,transactions(交易數(shù)據(jù))為空,這個區(qū)塊,其實就是創(chuàng)世區(qū)塊。

現(xiàn)在我們進(jìn)行一筆交易,如下:

  1. # 發(fā)起一筆交易 
  2. In [10]: tx_hash = w3.eth.send_transaction({ 
  3.     ...:     'from': w3.eth.accounts[0], 
  4.     ...:     'to': w3.eth.accounts[1], 
  5.     ...:     'value': w3.toWei(3, 'ether'
  6.     ...: }) 
  • from:發(fā)送者賬戶的地址
  • to:接受者賬戶的地址
  • value:此次轉(zhuǎn)賬金額

我們可以通過get_transaction獲得這次交易更詳細(xì)的信息,如下:

  1. # 獲取那筆交易的信息   
  2. In [14]: w3.eth.get_transaction(tx_hash) 
  3. Out[14]: 
  4. AttributeDict({'hash': HexBytes('0x15e9fb95dc39da2d70f4cc41556bd092c68a97a04892426a064e321bfe78662a'), 
  5.  'nonce': 0, 
  6.  'blockHash': HexBytes('0x9f92558e214519a5e4ba7b8b4769a59bdc8c6c13e6fe5b0ec062b806e18f049f'), 
  7. # 交易數(shù)據(jù)在第一個區(qū)塊中 
  8.  'blockNumber': 1, 
  9.  # 全網(wǎng)絡(luò)第一個交易 
  10.  'transactionIndex': 0, 
  11.  'from''0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf'
  12.  'to''0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF'
  13.  'value': 3000000000000000000, 
  14.  'gas': 21000, 
  15.  'gasPrice': 1, 
  16.  'data''0x'
  17.  'v': 28, 
  18.  'r': HexBytes('0x11bebd35f91582f55dc180dcfc1c5ccad48dadc207802727f7ac997df6490b22'), 
  19.  's': HexBytes('0x697db707f5b7cc4d3a3196b434b0d5616300b8afbe8a21ab47ed9335252e4ebd')}) 

完成交易后,我們可以查詢對應(yīng)賬戶的余額來判斷是否轉(zhuǎn)賬成功。

  1. In [15]: w3.eth.get_balance(w3.eth.accounts[0]) 
  2. Out[15]: 999996999999999999979000 
  3.  
  4. In [16]: w3.eth.get_balance(w3.eth.accounts[1]) 
  5. Out[16]: 1000003000000000000000000 

可以看到,第二個賬戶,余額從1,000,000到1,000,003 ether,但第一個賬戶減少的金額卻超過3 ether,這是因為交易需要扣除一筆小額手續(xù)費所導(dǎo)致的。

在真實的以太坊網(wǎng)絡(luò)中,交易手續(xù)費用是可以調(diào)整的,這取決于你發(fā)起交易時的網(wǎng)絡(luò)需求以及你希望處理交易的速度,就目前而言,交易手續(xù)費是比較大的成本。

創(chuàng)建賬戶

在Web 2.0中,大多數(shù)應(yīng)用在使用前需要創(chuàng)建賬戶,這個賬戶會保存到公司服務(wù)器中,即你雖然使用賬戶,但卻沒有賬戶的所有權(quán),以微信為例,如果哪天騰訊公司要封掉你的賬戶是非常輕松的,這個賬戶下對你非常重要的數(shù)據(jù)將與你不辭而別。

在Web 3.0中,你同樣可以創(chuàng)建賬戶,創(chuàng)建完后,你會擁有該賬戶的私鑰與公鑰,這個賬戶不會受到應(yīng)用創(chuàng)建者或公司的影響,只要你不泄露私鑰,那么賬戶的所有權(quán)就在你手中,當(dāng)然也要一些隱患,如果你丟失了私鑰,那么就丟失了賬戶,沒有找回密碼一說,所以在幣圈,非常強調(diào)對自己私鑰的保護。

通過Web3.py,我們可以輕松的創(chuàng)建一個賬戶,這個過程是無需連接到區(qū)塊鏈網(wǎng)絡(luò)或任何服務(wù)的,也沒有注冊過程,如下:

  1. # 創(chuàng)建賬戶 
  2. In [17]: acct = w3.eth.account.create() 
  3.  
  4. # 賬戶地址 
  5. In [19]: acct.address 
  6. Out[19]: '0x004D8ae69CD02Be5c491F7D095b5585cECE01407' 
  7.  
  8. # 賬戶私鑰(不可泄露給他人) 
  9. In [20]: acct.key 
  10. Out[20]: HexBytes('0x39a579d1302e36fbf8b283eca5e1d52b4c56811921dfcdc2996f59eff7be6258'

再次強調(diào),你不需要聯(lián)網(wǎng),不需要提供任何其他信息,便可以創(chuàng)建一個有效的以太坊賬戶,后續(xù)我會寫一下賬戶生成的過程。

賬戶是一個重要的概念,因為我們影響區(qū)塊鏈產(chǎn)生變化的唯一方式便是產(chǎn)生一個交易(調(diào)用智能合約也看為產(chǎn)生一個交易),而每個交易必須由一個賬戶進(jìn)行簽名,避免別人偽冒。

一個賬戶可以進(jìn)行交易、進(jìn)行交易間信息的傳輸、可以部署智能合約、可以與智能合約進(jìn)行交互等。

首先,我們實踐一下,如何通過賬戶進(jìn)行轉(zhuǎn)賬。

回顧前面的代碼,我們通過EthereumTesterProvider連接的模擬節(jié)點并有一些賬戶,這些賬戶的轉(zhuǎn)賬過程通過send_transaction方法完成,這里隱藏了比較多細(xì)節(jié),因為Web3.py知道你在使用EthereumTesterProvider管理的測試賬戶,而這些賬戶都處在unlocked狀態(tài),即默認(rèn)情況下,這些賬戶的交易都會自動完成簽名。

這次,我們從自己創(chuàng)建的賬戶轉(zhuǎn)賬看看,因為我們自己的賬戶沒有ether,所以需要先從測試賬戶轉(zhuǎn)點錢過去。

  1. In [25]: w3.eth.get_balance(acct.address) 
  2. Out[25]: 0 
  3.  
  4. In [26]: w3.eth.get_balance(test_acct) 
  5. Out[26]: 1000000000000000000000000 
  6.  
  7. # 測試賬戶轉(zhuǎn)10000000000到創(chuàng)建的賬戶中 
  8. In [27]: tx_hash = w3.eth.send_transaction({ 
  9.     ...:     'from': test_acct, 
  10.     ...:     'to': acct.address, 
  11.     ...:     'value': 10000000000 
  12.     ...: }) 
  13.  
  14. In [28]: tx_hash 
  15. Out[28]: HexBytes('0xa1b8be56bee0421035cbb9afb157218770f692c71b553a82cb52529c5dd12c3d'

創(chuàng)建的賬戶中有錢了,現(xiàn)在使用創(chuàng)建的賬戶來完成一筆交易,這個過程,我們需要手動對交易數(shù)據(jù)進(jìn)行簽名。

  1. # 交易數(shù)據(jù) 
  2. In [29]: tx_data = { 
  3.     ...:     'to': test_acct, 
  4.     ...:     'value': 500000000, 
  5.     ...:     'gas': 21000, 
  6.     ...:     'gasPrice': 1,  # 這個gas價格只存在于測試網(wǎng)絡(luò)中 
  7.     ...:     'nonce': 0 
  8.     ...:  } 
  9.  
  10. # 使用acct的私鑰對交易數(shù)據(jù)進(jìn)行簽名 
  11. In [30]: signed = w3.eth.account.sign_transaction(tx_data, acct.key
  12.  
  13. In [31]: signed 
  14. Out[31]: SignedTransaction(rawTransaction=HexBytes('0xf8638001825208946813eb9362372eef6200f3b1dbc3f819671cba69841dcd6500801ca029f2b216949529fbd19841c52e0cc78f218f45dd3531b918224f345f2e381aa9a0266619842d80050ab00bf8e0ea383056d7691a955113764e86927ddf36a478bb'), hash=HexBytes('0x402a89616ea2c37af4a17d8ff527e83141ac39968f3a61ddf92d4a1f5830cd29'), r=18973632901206428005591964593075310485747666570252293259781563419879236180649, s=17368282753934865160480197991111055873845272890414273881219608275127669913787, v=28) 
  15.  
  16. # 進(jìn)行交易 
  17. In [32]: tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction) 
  18.  
  19. In [33]: tx_hash 
  20. Out[33]: HexBytes('0x402a89616ea2c37af4a17d8ff527e83141ac39968f3a61ddf92d4a1f5830c 

先關(guān)注到交易數(shù)據(jù),其中g(shù)as、gasPrice、nonce是比較細(xì)的東西。

gas:表示這次交易需要花費多少gas(燃?xì)?

gasPrice:表示gas的價格,在真實的以太坊網(wǎng)絡(luò)中,gasPrice是很高的,也是目前以太坊網(wǎng)絡(luò)的一個問題與痛點

none:在以太坊網(wǎng)絡(luò)中,none表示當(dāng)前賬戶的交易數(shù),Ethereum protocol(以太坊協(xié)議)會追蹤這個值,避免發(fā)生雙重支付(也稱雙花攻擊),這里為0表示acct賬戶第一次產(chǎn)生交易。

需要注意,無論是send_transaction方法還是send_raw_transaction方法,都不代表交易完成了,這些方法只是將交易數(shù)據(jù)廣播到以太坊網(wǎng)絡(luò)中,只有當(dāng)以太坊網(wǎng)絡(luò)中的礦工節(jié)點將交易上鏈了,才能說交易完成了,如果你的gas與gasPrice很小,在真實以太坊網(wǎng)絡(luò)中,你將很難上鏈,即難以完成真正的交易。

從開發(fā)者角度看,以太坊上的這種賬戶模式可以讓我們在創(chuàng)建應(yīng)用時,不太需要考慮賬戶管理等功能,以太坊已經(jīng)天然解決了這部分問題,你可以將精力集中在具體的業(yè)務(wù)中。

與智能合約交互

以太坊被提出的一個重要原因是,比特幣網(wǎng)絡(luò)不支持圖靈完備的編程語言,導(dǎo)致很多應(yīng)用無法被開發(fā),以太坊則支持圖靈完畢的編程語言,如Solidity語言,它的語法與JS相近,是圖靈完備的語言,基于Solidity語言,可以快速開發(fā)智能合約。

簡單而言,智能合約就是存儲在以太坊區(qū)塊鏈上的程序,任何人都可以使用它,如果你需要部署一個智能合約,其過程與發(fā)起一筆交易類似,只是交易數(shù)據(jù)里,包含著Solidity編譯后的字節(jié)碼,偽代碼如下:

  1. # 代碼編譯成字節(jié)碼 
  2. bytecode = "6080604052348015610...36f6c63430006010033" 
  3.  
  4. tx = { 
  5.     # 將字節(jié)碼作為數(shù)據(jù)包含在交易數(shù)據(jù)體中 
  6.    'data': bytecode, 
  7.    'value': 0, 
  8.    'gas': 1500000, 
  9.    'gasPrice': 1, 
  10.    'nonce': 0 

部署智能合約相比于普通交易通常需要更多的gas,且部署智能合約的交易體中沒有to字段。

Web3.py將部署以及與智能合約交互的過程進(jìn)行了簡化,偽代碼如下:

  1. # 部署一個新的智能合約 
  2. Example = w3.eth.contract(abi=abi, bytecode=bytecode) 
  3. tx_hash = Example.constructor().transact() 
  4.  
  5. # 通過智能合約的地址連接一個智能合約 
  6. myContract = web3.eth.contract(address=address, abi=abi) 
  7. # 傳參、使用智能合約 
  8. twentyone = myContract.functions.multiply7(3).call() 

生成簽名信息

賬戶除了可以進(jìn)行交易等鏈上(on-chain)操作,還可以進(jìn)行消息簽名等鏈下(off-chain)操作。

與交易不同,被簽名消息不需要上鏈,也不會被廣播到區(qū)塊鏈網(wǎng)絡(luò)中,即不需要花費任何成本,簡單而言,簽名消息只是用你的私鑰對數(shù)據(jù)進(jìn)行了一個數(shù)學(xué)操作,當(dāng)你將這段數(shù)據(jù)發(fā)送給他人時,他人可以通過數(shù)據(jù)方法還原出簽名私鑰對應(yīng)的公鑰,從而確定這個數(shù)據(jù)是由你簽名的。

這有什么用?可以使用到NFT上。

你可以對你的作品(一段數(shù)據(jù))進(jìn)行簽名,然后到OpenSea(目前最大的NFT交易市場)進(jìn)行售賣,當(dāng)有賣家購買時,才會將購買時產(chǎn)生的交易數(shù)據(jù)上鏈,上鏈的過程需要花費ether,而你簽名的過程是不需要任何成本的,上鏈的操作其實只是表明你簽名的這個作品被某個賬戶購買了,這個購買的交易操作產(chǎn)生的數(shù)據(jù)會記錄到區(qū)塊鏈中,是不可更改的。

通過一段偽代碼,可以更直觀的理解簽名消息的整個流程:

  1. # 1. 待簽名數(shù)據(jù) 
  2. msg = "我是二兩,給我打錢" 
  3.  
  4. # 2. 使用你賬戶的私鑰進(jìn)行前面 
  5. pk = b"..." 
  6. signed_message = sign_message(message=msg, private_key=pk) 
  7.  
  8. # 3. 通過網(wǎng)絡(luò)發(fā)送簽名后的數(shù)據(jù) 
  9.  
  10. # 4. 消息接收者解碼發(fā)送的數(shù)據(jù),獲得數(shù)據(jù)的公鑰,從而可以確定發(fā)送消息者的身份 
  11. sender = decode_message_sender(msg, signed_message.signature) 
  12. print(sender) 

參考

A Developer's Guide to Ethereum, Pt. 1

A Developer's Guide to Ethereum, Pt. 2

責(zé)任編輯:武曉燕 來源: 懶編程
相關(guān)推薦

2021-07-27 05:21:34

邊緣計算數(shù)據(jù)網(wǎng)絡(luò)

2022-10-18 08:00:00

2022-03-01 08:10:24

區(qū)塊鏈以太坊數(shù)據(jù)庫

2020-12-02 13:24:07

強化學(xué)習(xí)算法

2022-09-14 10:23:46

以太坊技術(shù)

2025-01-16 16:36:00

2021-05-02 22:19:46

以太坊比特幣加密貨幣

2022-04-15 08:33:51

PythonGraph以太坊數(shù)據(jù)

2009-11-05 15:43:02

Visual Stud

2021-12-08 13:57:29

以太坊加密貨幣比特幣

2021-05-22 22:57:24

以太坊加密貨幣比特幣

2021-05-03 23:32:55

以太坊區(qū)塊鏈比特幣

2021-05-13 16:13:21

區(qū)塊鏈以太坊NFT

2021-04-29 16:11:14

以太坊共識鏈驗證者

2018-06-01 09:17:52

區(qū)塊鏈以太坊

2021-05-07 09:06:55

GraphQLAPI 以太坊

2010-01-12 17:33:06

C++

2021-06-04 11:45:36

病毒軟件挖礦惡意軟件

2022-09-06 14:35:34

區(qū)塊鏈以太坊NFT

2021-03-04 11:05:24

比特幣以太坊加密貨幣
點贊
收藏

51CTO技術(shù)棧公眾號