Python开发以太坊智能合约指南(web3.py)
在以太坊上獲得一個基本的智能合約是一個很簡單的事,只需google查詢“ERC20代幣教程”,你會發現有關如何做到這一點的大量信息。以編程方式與合約交互完全是另一回事,如果你是一個Python程序員,那么教程就很少。所以寫這個Python中的以太坊智能合約開發指南。
按我的統計對我們來說幸運的是,2017年Web3.py的第4版發布,這意味著現在比以往更容易運行python腳本并觀察區塊鏈上發生的神奇事情。像幽靈般的。
Piper Merriam,Jason Carver以及其他所有在Web3.py上努力工作以使我們其他人生活更輕松的人大聲呼喊,在Sempo,我們正在使用以太坊來使災難般的響應更加透明,而且它是只有Web3.py才能真正實現。
設置
首先我們進行設置,確保我們安裝了相關的python庫。
Python庫無處不在,但它們的用途是什么?
有很多與以太坊相關的python庫,但是當人們談論以太坊時,有兩個會出現很多:Web3.py和Pyethereum。乍一看,你應該使用哪一個并不明顯。
Pyethereum
以太坊虛擬機(EVM)的Python實現。反過來,EVM是以太坊協議的一部分,它實際運行智能合約中的代碼并確定其輸出。因此,如果你想在Python中運行以太坊節點,那么Pyethereum是一個很好的起點。
即使你非常高興在不運行自己的節點的情況下運行智能合約,Pyethereum仍然是一個很好的庫,它包含許多功能,可以執行有用的功能,例如從私鑰計算用戶的地址等等。
Web3.py
用于實際與以太坊區塊鏈交互的庫。我們談論的事情包括在賬戶之間轉移以太網,發布智能合約以及觸發附加現有智能合約的功能。它受到流行的JavaScript庫Web3.js的啟發,它將成為我們在本教程中使用的主庫。
好的,少說多做!
起初我嘗試使用Python3.5版本,但在運行時我遇到了問題,顯然是由Python的類型提示造成的?;赑ython3.6創建虛擬環境解決了這個問題,所以我建議你做同樣的事情。
繼續并pip-install web3 (確保你獲得版本4)。
除非你喜歡花錢,否則你需要在以太坊測試網上使用錢包,例如Ropsten和其他大量以太玩法。一個簡單的方法是下載Chrome的Metamask擴展,并從那里創建一個新帳戶。
確保你還選擇左側的'Ropsten Test Net'。
即使你的現有錢包中包含真正的以太幣,我也強烈建議你為開發目的創建一個新的錢包。我們將使用私鑰做一些相對無法預測的事,所以如果它們不小心變成公共主網絡的話就不會有問題(公私鑰?)
為新創建的錢包獲取測試Ether非常簡單:只需訪問faucet.metamask.io并點擊“請求來自faucet的1個 以太”。對于我們將要做的事情,這應該是充足的。
最后,因為我們將在沒有托管我們自己的節點的情況下使用Ropsten TestNet,我們需要一個可以連接Blockchain的供應商。Infura.io適用于此,所以去那里創建一個免費帳戶。記下Ropsten TestNet的提供者URL(看起來像https://ropsten.infura.io/FE2...)。
部署智能合約
使用Python來部署智能合約而不運行自己的節點是非常困難的,所以我們將在這一步上做點兒手腳。對于許多智能合約用例,你只需要執行一次。
正如我之前提到的,有關如何部署ERC20合約的百萬條指南,因此我們將部署一些不同的(并且更方便地更短)。
問:誰喜歡在互聯網上分享他們的意見?
大家都喜歡?
好答案。以下我稱之為“Soap Box”肥皂盒的智能合約允許任何人向區塊鏈廣播他們想要的任何意見,在永恒的剩余時間(給予或接受)可以看到它。
但是有一個問題:只有支付了必要的0.02以太網費用的地址才能播出他們的意見。聽起來不太公平,但就這樣。
Remix,以太坊的在線代碼編輯器非常出色,因此在那里創建一個新文件并粘貼以下代碼。它是用Solidity(Smart Contracts的編程語言)編寫的。如果代碼沒有太多意義并不重要,我們將在稍后詳細介紹相關部分,但最終這是一個Python教程。
pragma solidity ^0.4.0; contract SoapBox { // Our 'dict' of addresses that are approved to share opinions //我們批準分享意見的地址的“字典” mapping (address => bool) approvedSoapboxer;string opinion;// Our event to announce an opinion on the blockchain //我們的事件發布對區塊鏈的意見 event OpinionBroadcast(address _soapboxer, string _opinion); // This is a constructor function, so its name has to match the contract //這是一個構造函數,所以它的名字必須與合約相匹配 function SoapBox() public {}// Because this function is 'payable' it will be called when ether is sent to the contract address.//因為這個函數是“支付”,所以當以太網被發送到合約地址時將被調用。 function() public payable{// msg is a special variable that contains information about the transaction// msg是一個特殊變量,包含有關交易的信息 if (msg.value > 20000000000000000) { //if the value sent greater than 0.02 ether (in Wei)//如果發送的值大于0.02 ether(在Wei中) // then add the sender's address to approvedSoapboxer //然后將發件人的地址添加到approvedSoapboxer approvedSoapboxer[msg.sender] = true;}}// Our read-only function that checks whether the specified address is approved to post opinions.//我們的只讀函數,用于檢查指定地址是否被批準發布意見。 function isApproved(address _soapboxer) public view returns (bool approved) {return approvedSoapboxer[_soapboxer];} // Read-only function that returns the current opinion//返回當前意見的只讀函數 function getCurrentOpinion() public view returns(string) {return opinion;} //Our function that modifies the state on the blockchain//我們的函數修改了區塊鏈上的狀態 function broadcastOpinion(string _opinion) public returns (bool success) {// Looking up the address of the sender will return false if the sender isn't approved//如果發件人未獲批準,查找發件人的地址將返回false if (approvedSoapboxer[msg.sender]) {opinion = _opinion;emit OpinionBroadcast(msg.sender, opinion);return true;} else {return false;}} }以下是Metamask變得非常有用的地方:如果你點擊重新混音窗口右上角的“run”運行標簽并在“Environment”環境下拉列表中選擇“Injected Web3”注入的Web3,則“Account”帳戶下拉列表中應填充你的帳戶地址早在MetaMask中創建。如果沒有,只需刷新瀏覽器即可。
然后單擊“create”創建。Metamask應該彈出一個彈出窗口,要求你確認交易。如果沒有,只需打開Metamask擴展并在那里執行:
你將在Remix控制臺底部收到一條消息,告知你合約的創建正在等待處理。單擊鏈接以在Etherscan上查看其狀態。如果刷新并且“To”收件人字段填充了合約地址,則合約已成功部署。
一旦你記下了合約地址,我們就該開始通過Web3.py與合約進行交互了。
在我看來,有四種(半)方式可以與以太坊智能合約進行互動。最后兩個(一半)經?;煸谝黄?#xff0c;但差異很重要。我們已經看到了第一個:在區塊鏈上部署智能合約?,F在我們將介紹其余的python:
- 向合約發送以太:真正自我解釋,將以太幣從錢包發送到智能合約的地址。希望換取有用的東西。
- 調用函數:執行智能合約的只讀功能以獲取某些信息(例如地址的余額)。
- 與功能進行交易:執行智能合約的功能,該功能可以更改區塊鏈的狀態。
- 查看事件:查看由于先前的功能交易而發布到區塊鏈的信息。
將以太幣發送給合約
一些(但不是全部)智能合約包括“payable”應付功能。如果你將Ether發送到合約的地址,則會觸發這些功能。一個典型的用例就是ICO:將以太送到合約中,然后返回給你的是代幣。
首先,我們將從導入開始,創建一個新的web3對象,通過Infura.io連接到Ropsten TestNet。
import time from web3 import Web3, HTTPProvidercontract_address = [YOUR CONTRACT ADDRESS] wallet_private_key = [YOUR TEST WALLET PRIVATE KEY] wallet_address = [YOUR WALLET ADDRESS]w3 = Web3(HTTPProvider([YOUR INFURA URL]))w3.eth.enable_unaudited_features()你可以在Metamask中的帳戶名稱旁邊的菜單中找到你的錢包私鑰。因為我們使用的Web3.py的某些功能尚未經過完全審核以確保安全性,所以我們需要調用w3.eth.enable_unaudited_features()來確認我們知道可能會發生問題的情況。我告訴過你我們用私鑰做了一些危險的事情!
現在我們將編寫一個函數,將以太幣從我們的錢包發送到合約:
def send_ether_to_contract(amount_in_ether):amount_in_wei = w3.toWei(amount_in_ether,'ether');nonce = w3.eth.getTransactionCount(wallet_address)txn_dict = {'to': contract_address,'value': amount_in_wei,'gas': 2000000,'gasPrice': w3.toWei('40', 'gwei'),'nonce': nonce,'chainId': 3}signed_txn = w3.eth.account.signTransaction(txn_dict, wallet_private_key)txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction)txn_receipt = Nonecount = 0while txn_receipt is None and (count < 30):txn_receipt = w3.eth.getTransactionReceipt(txn_hash)print(txn_receipt)time.sleep(10)if txn_receipt is None:return {'status': 'failed', 'error': 'timeout'}return {'status': 'added', 'txn_receipt': txn_receipt}首先讓我們回顧一下交易字典txn_dict:它包含了定義我們發送給智能合約的交易所需的大部分信息。
- to:我們將以太送到哪里(在這種情況下是智能合約)。
- Vaule:我們送多少錢單位wei。
- gas:gas是衡量在以太坊上執行交易的計算工作量度。在這種情況下,我們指定了我們愿意執行此交易的天然氣量的上限。
- gasPrice:我們愿意為每單位gas支付多少錢(以wei為單位)。
- Nonce:這是一個地址nonce而不是更常見的工作證明。它只是發送地址所做的先前交易次數的計數,用于防止雙重花費。
- Chain ID:每個以太坊網絡都有自己的鏈ID:主網的ID為1,而Ropsten為3。你可以在這里找到更長的列表。
關于gas限制的快速說明:有一些功能可以讓你估算交易將使用多少gas。但是,我發現選擇限制的最佳方法是計算出你愿意支付多少錢,然后再讓交易失敗,然后再去做。
一旦我們定義了交易的重要部分,我們就會使用我們錢包的私鑰對其進行簽名。然后它就可以發送到網絡了,我們將使用sendRawTransaction方法。
在礦工決定將其包含在一個區塊中之前,我們的交易實際上不會完成。一般而言,你為每個單位支付的費用Gas(記住我們的天然氣價格參數)決定了一個節點決定將你的交易包含在一個區塊中的速度(如果有的話)。
https://ethgasstation.info/是...,可以確定你將等待你的交易包含在一個區塊中的時間。
此時間延遲意味著交易是異步的。當我們調用sendRawTransaction時,我們會立即獲得交易的唯一哈希值。你可以隨時使用此哈希來查詢你的交易是否已包含在塊中。我們知道,當且僅當我們能夠獲得交易收據時才將交易添加到區塊鏈中(因為所有好的購買都帶有收據嗎?)。這就是為什么我們創建循環來定期檢查我們是否有收據:
txn_receipt = Nonecount = 0while txn_receipt is None and (count < 30):txn_receipt = w3.eth.getTransactionReceipt(txn_hash)print(txn_receipt)time.sleep(10)值得注意的是,交易可以添加到區塊鏈中,但仍然因各種原因而失敗,例如沒有足夠的gas。
這就是將以太符號發送給合約的Python代碼。讓我們快速回顧一下我們在Solidity中寫的應付函數:
function() public payable{if (msg.value >= 20000000000000000) { approvedSoapboxer[msg.sender] = true;}}Msg是智能合約中的一個特殊變量,其中包含有關發送到智能合約的交易的信息。在這種情況下,我們使用msg.value,它給出了交易中發送的Ether數量(在Wei而不是raw Ether中)。同樣,msg.sender給出了進行交易的錢包的地址:如果已經發送了足夠的以太幣,我們會將其添加到已批準帳戶的字典中。
繼續運行send_ether_to_contract函數。希望你能收到回執。你還可以通過在Etherscan的Ropsten Network部分查找你的錢包地址來檢查交易是否完成。我們將在下一節中獲得Python中的更多信息。
調用一個函數
我們剛剛向我們的智能合約發送了一些以太幣,因此我們想檢查我們的錢包地址是否已被批準分享意見是有意義的。為此,我們在智能合約中定義了以下功能:
function isApproved(address _soapboxer) public view returns (bool approved) {return approvedSoapboxer[_soapboxer];}與python相比,這個函數附帶了很多額外的東西,比如聲明類型(地址和bool)。盡管如此,這個函數只需要一個地址(_soapboxer參數),在有效(但不完全)的哈希表/python dict中查找相應的批準布爾值并返回該值。
你調用的時候一個智能合約函數,以太坊節點將計算結果,并將其返回給你。這里的事情變得有點復雜:調用是只讀的,這意味著它們不會對區塊鏈進行任何更改。如果上述函數包含一行代碼來記錄數字時間,則檢查地址是否已批準:
approvedCheckedCount[_soapboxer] = approvedCheckedCount[_soapboxer] + 1然后,當調用該函數時,該節點將計算approvedCheckedCount的新值,但一旦返回結果就丟棄它。
作為只讀的交換,函數調用不會花費你運行任何以太,因此你可以愉快地檢查帳戶是否已被批準而不必擔心成本。
讓我們跳回到我們的python文件的頂部并添加一些更多的設置代碼。
import contract_abi contract = w3.eth.contract(address = contract_address, abi = contract_abi.abi)你需要創建另一個名為contract_abi的python文件。這將包含一個大的JSON信息字符串,Python需要與我們在智能合約中定義的函數進行交互,稱為應用程序二進制接口(ABI)。你可以在Remix中找到智能合約的ABI的JSON字符串:
- 單擊編譯“Compile”選項卡。
- 單擊詳細信息“Details”——應顯示包含大量信息的模式。
- 向下滾動到ABI部分,然后單擊復制到剪貼板“Copy to clipboard”圖標。
將復制的字符串粘貼到contract_abi.py文件中,該文件應如下所示:
abi = """[{A BIG LIST OF ABI INFO SPREAD ACROSS MULTIPLE DICTS} ]""我們添加到主python文件的另一行現在使用此ABI JSON字符串并使用它來設置合約對象。如果你瀏覽合約,你會注意到它包含一個函數屬性,其中包含我們在智能合約中創建的三個函數。
現在我們將創建一個python函數,該函數調用Smart Contract智能合約的isApproved函數來檢查指定的地址是否被批準分享意見。
def check_whether_address_is_approved(address):return contract.functions.isApproved(address).call()那很短暫。
你現在可以使用它來檢查你的錢包地址是否已獲批準。如果你之前運行了send_ether_to_contract函數并發送了足夠數量的以太,那么希望你能回到true。
與函數交易
我們正在與智能合約進行最后的主要互動:廣播意見。再一次,我們來看看我們的Solidity Code:
function broadcastOpinion(string _opinion) public returns (bool success) {if (approvedSoapboxer[msg.sender]) { opinion = _opinion;emit OpinionBroadcast(msg.sender, opinion);return true;} else {return false;}}這里沒有什么新東西:我們采用傳入的_opinion參數并使用它來設置全局變量意見。(如果你愿意,可以通過getter函數查詢實習生)。有一條線有點不同:
emit OpinionBroadcast(msg.sender, opinion)我們很快就會介紹。
當你通過交易與智能合約的功能進行交互時,功能對智能合約狀態所做的任何更改都會在區塊鏈上發布。為了換取這種特權,你必須向礦工支付一些(希望很小)的以太量。Python時間:
def broadcast_an_opinion(covfefe):nonce = w3.eth.getTransactionCount(wallet_address)txn_dict = contract.functions.broadcastOpinion(covfefe).buildTransaction({'chainId': 3,'gas': 140000,'gasPrice': w3.toWei('40', 'gwei'),'nonce': nonce,})signed_txn = w3.eth.account.signTransaction(txn_dict, private_key=wallet_private_key)result = w3.eth.sendRawTransaction(signed_txn.rawTransaction)tx_receipt = w3.eth.getTransactionReceipt(result)count = 0while tx_receipt is None and (count < 30):time.sleep(10)tx_receipt = w3.eth.getTransactionReceipt(result)print(tx_receipt)if tx_receipt is None:return {'status': 'failed', 'error': 'timeout'}processed_receipt = contract.events.OpinionBroadcast().processReceipt(tx_receipt)print(processed_receipt)output = "Address {} broadcasted the opinion: {}"\.format(processed_receipt[0].args._soapboxer, processed_receipt[0].args._opinion)print(output)return {'status': 'added', 'processed_receipt': processed_receipt}這實際上與將Ether發送到智能合約時使用的過程相同。我們將創建并簽署一個交易,然后將其發送到網絡。再一次,交易是異步的,這意味著無論函數被告知在Solidity代碼中返回什么,你實際得到的東西總是交易的哈希。
鑒于交易本身并沒有返回任何有用的信息,我們需要其他東西。這導致我們采用最后(半)方式與智能合約進行互動。
事件events
我將事件稱為與智能合約交互的“一半”方式,因為從技術上講,它們是由交易發出的。 事件是智能合約以易于閱讀的形式在區塊鏈上記錄事物的方式,它們基本上只是一組可以使用特定交易的收據查找的值。我們在智能合約的最頂層定義了一個:
event OpinionBroadcast(address _soapboxer, string _opinion);然后,當我們使用broadcastOpinion函數時,我們使用它向區塊鏈發出信息。
將交易添加到塊后,你可以使用交易哈希查詢區塊鏈以查找OpinionBroadcast事件發出的特定值。這是我們在函數broadcast_an_opinion中的最后一點python代碼。你會注意到我們要求事件發出的信息存儲在'args'屬性中。
這個事件非常公開。實際上,任何人都可以輕松使用Etherscan或類似工具來查看智能合約發出的所有事件的日志。
Etherscan會自動檢測“Transfer”轉移事件并列出所有事件。Nifty
如果你已經做到這一點,你就有權發表意見。繼續用你選擇的意見運行broadcast_an_opinion。
如果一切順利進行,你應該很快就會收到已處理的收據,以及已放入區塊鏈的OpinionBroadcast事件的打印輸出。
Nice。
這是完整的python代碼:
import time from web3 import Web3, HTTPProvidercontract_address = [YOUR CONTRACT ADDRESS] wallet_private_key = [YOUR TEST WALLET PRIVATE KEY] wallet_address = [YOUR WALLET ADDRESS]w3 = Web3(HTTPProvider([YOUR INFURA URL]))w3.eth.enable_unaudited_features()contract = w3.eth.contract(address = contract_address, abi = contract_abi.abi)def send_ether_to_contract(amount_in_ether):amount_in_wei = w3.toWei(amount_in_ether,'ether');nonce = w3.eth.getTransactionCount(wallet_address)txn_dict = {'to': contract_address,'value': amount_in_wei,'gas': 2000000,'gasPrice': w3.toWei('40', 'gwei'),'nonce': nonce,'chainId': 3}signed_txn = w3.eth.account.signTransaction(txn_dict, wallet_private_key)txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction)txn_receipt = Nonecount = 0while txn_receipt is None and (count < 30):txn_receipt = w3.eth.getTransactionReceipt(txn_hash)print(txn_receipt)time.sleep(10)if txn_receipt is None:return {'status': 'failed', 'error': 'timeout'}return {'status': 'added', 'txn_receipt': txn_receipt}def check_whether_address_is_approved(address):return contract.functions.isApproved(address).call()def broadcast_an_opinion(covfefe):nonce = w3.eth.getTransactionCount(wallet_address)txn_dict = contract.functions.broadcastOpinion(covfefe).buildTransaction({'chainId': 3,'gas': 140000,'gasPrice': w3.toWei('40', 'gwei'),'nonce': nonce,})signed_txn = w3.eth.account.signTransaction(txn_dict, private_key=wallet_private_key)result = w3.eth.sendRawTransaction(signed_txn.rawTransaction)tx_receipt = w3.eth.getTransactionReceipt(result)count = 0while tx_receipt is None and (count < 30):time.sleep(10)tx_receipt = w3.eth.getTransactionReceipt(result)print(tx_receipt)if tx_receipt is None:return {'status': 'failed', 'error': 'timeout'}processed_receipt = contract.events.OpinionBroadcast().processReceipt(tx_receipt)print(processed_receipt)output = "Address {} broadcasted the opinion: {}"\.format(processed_receipt[0].args._soapboxer, processed_receipt[0].args._opinion)print(output)return {'status': 'added', 'processed_receipt': processed_receipt}if __name__ == "__main__":send_ether_to_contract(0.03)is_approved = check_whether_address_is_approved(wallet_address)print(is_approved)broadcast_an_opinion('Despite the Constant Negative Press')打包封裝
所以關于它。正如我所提到的,我們還沒有達到使用python實際部署智能合約很容易的地步,但其他一切都在那里。在Sempo,我們正在使用上面提到的所有技術來使問題響應更加透明。
感謝Sebastian Dirman指出w3.toWei(value, ‘ether’)是一種更好的方式在Ether和Wei之間進行轉換——只需將以太量乘以1000000000000000000即可導致類型錯誤!
======================================================================
分享一些以太坊、EOS、比特幣等區塊鏈相關的交互式在線編程實戰教程:
- java以太坊開發教程,主要是針對java和android程序員進行區塊鏈以太坊開發的web3j詳解。
- python以太坊,主要是針對python工程師使用web3.py進行區塊鏈以太坊開發的詳解。
- php以太坊,主要是介紹使用php進行智能合約開發交互,進行賬號創建、交易、轉賬、代幣開發以及過濾器和交易等內容。
- 以太坊入門教程,主要介紹智能合約與dapp應用開發,適合入門。
- 以太坊開發進階教程,主要是介紹使用node.js、mongodb、區塊鏈、ipfs實現去中心化電商DApp實戰,適合進階。
- C#以太坊,主要講解如何使用C#開發基于.Net的以太坊應用,包括賬戶管理、狀態與交易、智能合約開發與交互、過濾器和交易等。
- EOS教程,本課程幫助你快速入門EOS區塊鏈去中心化應用的開發,內容涵蓋EOS工具鏈、賬戶與錢包、發行代幣、智能合約開發與部署、使用代碼與智能合約交互等核心知識點,最后綜合運用各知識點完成一個便簽DApp的開發。
- java比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈存儲、去中心化共識機制、密鑰與腳本、交易與UTXO等,同時也詳細講解如何在Java代碼中集成比特幣支持功能,例如創建地址、管理錢包、構造裸交易等,是Java工程師不可多得的比特幣開發學習課程。
- php比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈存儲、去中心化共識機制、密鑰與腳本、交易與UTXO等,同時也詳細講解如何在Php代碼中集成比特幣支持功能,例如創建地址、管理錢包、構造裸交易等,是Php工程師不可多得的比特幣開發學習課程。
- tendermint區塊鏈開發詳解,本課程適合希望使用tendermint進行區塊鏈開發的工程師,課程內容即包括tendermint應用開發模型中的核心概念,例如ABCI接口、默克爾樹、多版本狀態庫等,也包括代幣發行等豐富的實操代碼,是go語言工程師快速入門區塊鏈開發的最佳選擇。
匯智網原創翻譯,轉載請標明出處。這里是原文Python以太坊智能合約開發指南
總結
以上是生活随笔為你收集整理的Python开发以太坊智能合约指南(web3.py)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python常见数据存储 csv txt
- 下一篇: Mac安装Open CC进行繁简转化