Python智能合約開發(fā)指南(以太坊+web3py)

在以太坊上獲得一個(gè)基本的智能合約是一個(gè)很簡單的事冒晰,只需google查詢“ERC20代幣教程”同衣,你會(huì)發(fā)現(xiàn)有關(guān)如何做到這一點(diǎn)的大量信息。以編程方式與合約交互完全是另一回事壶运,如果你是一個(gè)Python程序員耐齐,那么教程就很少。所以寫這個(gè)Python中的以太坊智能合約開發(fā)指南蒋情。

按我的統(tǒng)計(jì)對我們來說幸運(yùn)的是埠况,2017年Web3.py的第4版發(fā)布,這意味著現(xiàn)在比以往更容易運(yùn)行python腳本并觀察區(qū)塊鏈上發(fā)生的神奇事情棵癣。像幽靈般的辕翰。

Piper Merriam,Jason Carver以及其他所有在Web3.py上努力工作以使我們其他人生活更輕松的人大聲呼喊狈谊,在Sempo金蜀,我們正在使用以太坊來使災(zāi)難般的響應(yīng)更加透明刷后,而且它是只有Web3.py才能真正實(shí)現(xiàn)。

設(shè)置

首先我們進(jìn)行設(shè)置渊抄,確保我們安裝了相關(guān)的python庫尝胆。

Python庫無處不在,但它們的用途是什么护桦?

有很多與以太坊相關(guān)的python庫含衔,但是當(dāng)人們談?wù)撘蕴粫r(shí),有兩個(gè)會(huì)出現(xiàn)很多:Web3.py和Pyethereum二庵。乍一看贪染,你應(yīng)該使用哪一個(gè)并不明顯喉刘。

Pyethereum

以太坊虛擬機(jī)(EVM)的Python實(shí)現(xiàn)打毛。反過來甘有,EVM是以太坊協(xié)議的一部分窖张,它實(shí)際運(yùn)行智能合約中的代碼并確定其輸出。因此钠导,如果你想在Python中運(yùn)行以太坊節(jié)點(diǎn)芜抒,那么Pyethereum是一個(gè)很好的起點(diǎn)锅纺。

即使你非常高興在不運(yùn)行自己的節(jié)點(diǎn)的情況下運(yùn)行智能合約攀涵,Pyethereum仍然是一個(gè)很好的庫铣耘,它包含許多功能,可以執(zhí)行有用的功能以故,例如從私鑰計(jì)算用戶的地址等等蜗细。

Web3.py

用于實(shí)際與以太坊區(qū)塊鏈交互的庫。我們談?wù)摰氖虑榘ㄔ谫~戶之間轉(zhuǎn)移以太網(wǎng)怒详,發(fā)布智能合約以及觸發(fā)附加現(xiàn)有智能合約的功能炉媒。它受到流行的JavaScript庫Web3.js的啟發(fā),它將成為我們在本教程中使用的主庫昆烁。

好的吊骤,少說多做!

起初我嘗試使用Python3.5版本善玫,但在運(yùn)行時(shí)我遇到了問題水援,顯然是由Python的類型提示造成的密强∶├桑基于Python3.6創(chuàng)建虛擬環(huán)境解決了這個(gè)問題,所以我建議你做同樣的事情或渤。

繼續(xù)并pip-install web3 (確保你獲得版本4)系冗。

除非你喜歡花錢,否則你需要在以太坊測試網(wǎng)上使用錢包薪鹦,例如Ropsten和其他大量以太玩法掌敬。一個(gè)簡單的方法是下載Chrome的Metamask擴(kuò)展惯豆,并從那里創(chuàng)建一個(gè)新帳戶。

image

確保你還選擇左側(cè)的'Ropsten Test Net'奔害。

即使你的現(xiàn)有錢包中包含真正的以太幣楷兽,我也強(qiáng)烈建議你為開發(fā)目的創(chuàng)建一個(gè)新的錢包。我們將使用私鑰做一些相對無法預(yù)測的事华临,所以如果它們不小心變成公共主網(wǎng)絡(luò)的話就不會(huì)有問題(公私鑰芯杀?)

為新創(chuàng)建的錢包獲取測試Ether非常簡單:只需訪問faucet.metamask.io并點(diǎn)擊“請求來自faucet的1個(gè) 以太”。對于我們將要做的事情雅潭,這應(yīng)該是充足的揭厚。

最后,因?yàn)槲覀儗⒃跊]有托管我們自己的節(jié)點(diǎn)的情況下使用Ropsten TestNet扶供,我們需要一個(gè)可以連接Blockchain的供應(yīng)商筛圆。Infura.io適用于此,所以去那里創(chuàng)建一個(gè)免費(fèi)帳戶椿浓。記下Ropsten TestNet的提供者URL(看起來像https://ropsten.infura.io/FE2Gfedcm3tfed3)太援。

部署智能合約

使用Python來部署智能合約而不運(yùn)行自己的節(jié)點(diǎn)是非常困難的,所以我們將在這一步上做點(diǎn)兒手腳轰绵。對于許多智能合約用例粉寞,你只需要執(zhí)行一次。

正如我之前提到的左腔,有關(guān)如何部署ERC20合約的百萬條指南唧垦,因此我們將部署一些不同的(并且更方便地更短)。

問:誰喜歡在互聯(lián)網(wǎng)上分享他們的意見液样?

大家都喜歡振亮?

好答案。以下我稱之為“Soap Box”肥皂盒的智能合約允許任何人向區(qū)塊鏈廣播他們想要的任何意見鞭莽,在永恒的剩余時(shí)間(給予或接受)可以看到它坊秸。

但是有一個(gè)問題:只有支付了必要的0.02以太網(wǎng)費(fèi)用的地址才能播出他們的意見。聽起來不太公平澎怒,但就這樣褒搔。

Remix,以太坊的在線代碼編輯器非常出色喷面,因此在那里創(chuàng)建一個(gè)新文件并粘貼以下代碼星瘾。它是用Solidity(Smart Contracts的編程語言)編寫的。如果代碼沒有太多意義并不重要惧辈,我們將在稍后詳細(xì)介紹相關(guān)部分琳状,但最終這是一個(gè)Python教程。

pragma solidity ^0.4.0;
contract SoapBox {
// Our 'dict' of addresses that are approved to share opinions   
//我們批準(zhǔn)分享意見的地址的“字典” 
    mapping (address => bool) approvedSoapboxer;
    string opinion;
     
    // Our event to announce an opinion on the blockchain  
    //我們的事件發(fā)布對區(qū)塊鏈的意見 
 
    event OpinionBroadcast(address _soapboxer, string _opinion);
// This is a constructor function, so its name has to match the contract   
//這是一個(gè)構(gòu)造函數(shù)盒齿,所以它的名字必須與合約相匹配 

    function SoapBox() public {
    }
    
    // Because this function is 'payable' it will be called when ether is sent to the contract address.
    //因?yàn)檫@個(gè)函數(shù)是“支付”念逞,所以當(dāng)以太網(wǎng)被發(fā)送到合約地址時(shí)將被調(diào)用困食。 
    function() public payable{
        // msg is a special variable that contains information about the transaction
        // msg是一個(gè)特殊變量,包含有關(guān)交易的信息 
        if (msg.value > 20000000000000000) {  
            //if the value sent greater than 0.02 ether (in Wei)
            //如果發(fā)送的值大于0.02 ether(在Wei中) 
            // then add the sender's address to approvedSoapboxer 
            //然后將發(fā)件人的地址添加到approvedSoapboxer 
            approvedSoapboxer[msg.sender] =  true;
        }
    }
    
    
    // Our read-only function that checks whether the specified address is approved to post opinions.
    //我們的只讀函數(shù)翎承,用于檢查指定地址是否被批準(zhǔn)發(fā)布意見硕盹。 
    function isApproved(address _soapboxer) public view returns (bool approved) {
        return approvedSoapboxer[_soapboxer];
    } 
    
    // Read-only function that returns the current opinion
    //返回當(dāng)前意見的只讀函數(shù) 
    function getCurrentOpinion() public view returns(string) {
        return opinion;
    }
//Our function that modifies the state on the blockchain
  //我們的函數(shù)修改了區(qū)塊鏈上的狀態(tài) 
    function broadcastOpinion(string _opinion) public returns (bool success) {
        // Looking up the address of the sender will return false if the sender isn't approved
        //如果發(fā)件人未獲批準(zhǔn),查找發(fā)件人的地址將返回false 
        if (approvedSoapboxer[msg.sender]) {
            
            opinion = _opinion;
            emit OpinionBroadcast(msg.sender, opinion);
            return true;
            
        } else {
            return false;
        }
        
    }
}

以下是Metamask變得非常有用的地方:如果你點(diǎn)擊重新混音窗口右上角的“run”運(yùn)行標(biāo)簽并在“Environment”環(huán)境下拉列表中選擇“Injected Web3”注入的Web3叨咖,則“Account”帳戶下拉列表中應(yīng)填充你的帳戶地址早在MetaMask中創(chuàng)建莱睁。如果沒有,只需刷新瀏覽器即可芒澜。

image

然后單擊“create”創(chuàng)建仰剿。Metamask應(yīng)該彈出一個(gè)彈出窗口,要求你確認(rèn)交易痴晦。如果沒有南吮,只需打開Metamask擴(kuò)展并在那里執(zhí)行:

image

你將在Remix控制臺底部收到一條消息,告知你合約的創(chuàng)建正在等待處理誊酌。單擊鏈接以在Etherscan上查看其狀態(tài)部凑。如果刷新并且“To”收件人字段填充了合約地址,則合約已成功部署碧浊。

一旦你記下了合約地址涂邀,我們就該開始通過Web3.py與合約進(jìn)行交互了。

在我看來箱锐,有四種(半)方式可以與以太坊智能合約進(jìn)行互動(dòng)比勉。最后兩個(gè)(一半)經(jīng)常混在一起驹止,但差異很重要浩聋。我們已經(jīng)看到了第一個(gè):在區(qū)塊鏈上部署智能合約。現(xiàn)在我們將介紹其余的python:

  • 向合約發(fā)送以太:真正自我解釋臊恋,將以太幣從錢包發(fā)送到智能合約的地址衣洁。希望換取有用的東西。
  • 調(diào)用函數(shù):執(zhí)行智能合約的只讀功能以獲取某些信息(例如地址的余額)抖仅。
  • 與功能進(jìn)行交易:執(zhí)行智能合約的功能坊夫,該功能可以更改區(qū)塊鏈的狀態(tài)。
  • 查看事件:查看由于先前的功能交易而發(fā)布到區(qū)塊鏈的信息撤卢。

將以太幣發(fā)送給合約

一些(但不是全部)智能合約包括“payable”應(yīng)付功能环凿。如果你將Ether發(fā)送到合約的地址,則會(huì)觸發(fā)這些功能凸丸。一個(gè)典型的用例就是ICO:將以太送到合約中拷邢,然后返回給你的是代幣袱院。

首先屎慢,我們將從導(dǎo)入開始瞭稼,創(chuàng)建一個(gè)新的web3對象,通過Infura.io連接到Ropsten TestNet腻惠。

import time
from web3 import Web3, HTTPProvider

contract_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中的帳戶名稱旁邊的菜單中找到你的錢包私鑰环肘。因?yàn)槲覀兪褂玫腤eb3.py的某些功能尚未經(jīng)過完全審核以確保安全性,所以我們需要調(diào)用w3.eth.enable_unaudited_features()來確認(rèn)我們知道可能會(huì)發(fā)生問題的情況集灌。我告訴過你我們用私鑰做了一些危險(xiǎn)的事情悔雹!

現(xiàn)在我們將編寫一個(gè)函數(shù),將以太幣從我們的錢包發(fā)送到合約:

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 = None
    count = 0
    while 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:它包含了定義我們發(fā)送給智能合約的交易所需的大部分信息欣喧。

  • to:我們將以太送到哪里(在這種情況下是智能合約)腌零。
  • Vaule:我們送多少錢單位wei。
  • gas:gas是衡量在以太坊上執(zhí)行交易的計(jì)算工作量度唆阿。在這種情況下益涧,我們指定了我們愿意執(zhí)行此交易的天然氣量的上限。
  • gasPrice:我們愿意為每單位gas支付多少錢(以wei為單位)驯鳖。
  • Nonce:這是一個(gè)地址nonce而不是更常見的工作證明闲询。它只是發(fā)送地址所做的先前交易次數(shù)的計(jì)數(shù),用于防止雙重花費(fèi)浅辙。
  • Chain ID:每個(gè)以太坊網(wǎng)絡(luò)都有自己的鏈ID:主網(wǎng)的ID為1扭弧,而Ropsten為3。你可以在這里找到更長的列表记舆。

關(guān)于gas限制的快速說明:有一些功能可以讓你估算交易將使用多少gas鸽捻。但是,我發(fā)現(xiàn)選擇限制的最佳方法是計(jì)算出你愿意支付多少錢泽腮,然后再讓交易失敗泊愧,然后再去做。

一旦我們定義了交易的重要部分盛正,我們就會(huì)使用我們錢包的私鑰對其進(jìn)行簽名删咱。然后它就可以發(fā)送到網(wǎng)絡(luò)了,我們將使用sendRawTransaction方法豪筝。

在礦工決定將其包含在一個(gè)區(qū)塊中之前痰滋,我們的交易實(shí)際上不會(huì)完成。一般而言续崖,你為每個(gè)單位支付的費(fèi)用Gas(記住我們的天然氣價(jià)格參數(shù))決定了一個(gè)節(jié)點(diǎn)決定將你的交易包含在一個(gè)區(qū)塊中的速度(如果有的話)敲街。

https://ethgasstation.info/是一個(gè)很好的地方,可以確定你將等待你的交易包含在一個(gè)區(qū)塊中的時(shí)間严望。

image

此時(shí)間延遲意味著交易是異步的多艇。當(dāng)我們調(diào)用sendRawTransaction時(shí),我們會(huì)立即獲得交易的唯一哈希值像吻。你可以隨時(shí)使用此哈希來查詢你的交易是否已包含在塊中峻黍。我們知道复隆,當(dāng)且僅當(dāng)我們能夠獲得交易收據(jù)時(shí)才將交易添加到區(qū)塊鏈中(因?yàn)樗泻玫馁徺I都帶有收據(jù)嗎?)姆涩。這就是為什么我們創(chuàng)建循環(huán)來定期檢查我們是否有收據(jù):

 txn_receipt = None
    count = 0
    while txn_receipt is None and (count < 30):

        txn_receipt = w3.eth.getTransactionReceipt(txn_hash)

        print(txn_receipt)

        time.sleep(10)

值得注意的是挽拂,交易可以添加到區(qū)塊鏈中,但仍然因各種原因而失敗骨饿,例如沒有足夠的gas亏栈。

這就是將以太符號發(fā)送給合約的Python代碼。讓我們快速回顧一下我們在Solidity中寫的應(yīng)付函數(shù):

function() public payable{
        if (msg.value >= 20000000000000000) {  
            approvedSoapboxer[msg.sender] =  true;
        }
    }

Msg是智能合約中的一個(gè)特殊變量宏赘,其中包含有關(guān)發(fā)送到智能合約的交易的信息绒北。在這種情況下,我們使用msg.value察署,它給出了交易中發(fā)送的Ether數(shù)量(在Wei而不是raw Ether中)镇饮。同樣,msg.sender給出了進(jìn)行交易的錢包的地址:如果已經(jīng)發(fā)送了足夠的以太幣箕母,我們會(huì)將其添加到已批準(zhǔn)帳戶的字典中储藐。

繼續(xù)運(yùn)行send_ether_to_contract函數(shù)。希望你能收到回執(zhí)嘶是。你還可以通過在Etherscan的Ropsten Network部分查找你的錢包地址來檢查交易是否完成钙勃。我們將在下一節(jié)中獲得Python中的更多信息。

調(diào)用一個(gè)函數(shù)

我們剛剛向我們的智能合約發(fā)送了一些以太幣聂喇,因此我們想檢查我們的錢包地址是否已被批準(zhǔn)分享意見是有意義的辖源。為此,我們在智能合約中定義了以下功能:

function isApproved(address _soapboxer) public view returns (bool approved) {
        return approvedSoapboxer[_soapboxer];
    }

與python相比希太,這個(gè)函數(shù)附帶了很多額外的東西克饶,比如聲明類型(地址和bool)。盡管如此誊辉,這個(gè)函數(shù)只需要一個(gè)地址(_soapboxer參數(shù))矾湃,在有效(但不完全)的哈希表/python dict中查找相應(yīng)的批準(zhǔn)布爾值并返回該值。

你調(diào)用的時(shí)候一個(gè)智能合約函數(shù)堕澄,以太坊節(jié)點(diǎn)將計(jì)算結(jié)果邀跃,并將其返回給你。這里的事情變得有點(diǎn)復(fù)雜:調(diào)用是只讀的蛙紫,這意味著它們不會(huì)對區(qū)塊鏈進(jìn)行任何更改拍屑。如果上述函數(shù)包含一行代碼來記錄數(shù)字時(shí)間,則檢查地址是否已批準(zhǔn):

approvedCheckedCount[_soapboxer] = approvedCheckedCount[_soapboxer] + 1

然后坑傅,當(dāng)調(diào)用該函數(shù)時(shí)僵驰,該節(jié)點(diǎn)將計(jì)算approvedCheckedCount的新值,但一旦返回結(jié)果就丟棄它。

作為只讀的交換蒜茴,函數(shù)調(diào)用不會(huì)花費(fèi)你運(yùn)行任何以太星爪,因此你可以愉快地檢查帳戶是否已被批準(zhǔn)而不必?fù)?dān)心成本。

讓我們跳回到我們的python文件的頂部并添加一些更多的設(shè)置代碼矮男。

import contract_abi
contract = w3.eth.contract(address = contract_address, abi = contract_abi.abi)

你需要?jiǎng)?chuàng)建另一個(gè)名為contract_abi的python文件。這將包含一個(gè)大的JSON信息字符串室谚,Python需要與我們在智能合約中定義的函數(shù)進(jìn)行交互毡鉴,稱為應(yīng)用程序二進(jìn)制接口(ABI)。你可以在Remix中找到智能合約的ABI的JSON字符串:

  • 單擊編譯“Compile”選項(xiàng)卡秒赤。
  • 單擊詳細(xì)信息“Details”——應(yīng)顯示包含大量信息的模式猪瞬。
  • 向下滾動(dòng)到ABI部分,然后單擊復(fù)制到剪貼板“Copy to clipboard”圖標(biāo)入篮。

將復(fù)制的字符串粘貼到contract_abi.py文件中陈瘦,該文件應(yīng)如下所示:

abi = """[
 {
   A BIG LIST OF ABI INFO SPREAD ACROSS MULTIPLE DICTS
 }
]""

我們添加到主python文件的另一行現(xiàn)在使用此ABI JSON字符串并使用它來設(shè)置合約對象。如果你瀏覽合約潮售,你會(huì)注意到它包含一個(gè)函數(shù)屬性痊项,其中包含我們在智能合約中創(chuàng)建的三個(gè)函數(shù)。

現(xiàn)在我們將創(chuàng)建一個(gè)python函數(shù)酥诽,該函數(shù)調(diào)用Smart Contract智能合約的isApproved函數(shù)來檢查指定的地址是否被批準(zhǔn)分享意見鞍泉。

def check_whether_address_is_approved(address):
    return contract.functions.isApproved(address).call()

那很短暫。

你現(xiàn)在可以使用它來檢查你的錢包地址是否已獲批準(zhǔn)肮帐。如果你之前運(yùn)行了send_ether_to_contract函數(shù)并發(fā)送了足夠數(shù)量的以太咖驮,那么希望你能回到true

與函數(shù)交易

我們正在與智能合約進(jìn)行最后的主要互動(dòng):廣播意見训枢。再一次托修,我們來看看我們的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參數(shù)并使用它來設(shè)置全局變量意見。(如果你愿意恒界,可以通過getter函數(shù)查詢實(shí)習(xí)生)睦刃。有一條線有點(diǎn)不同:

emit OpinionBroadcast(msg.sender, opinion)

我們很快就會(huì)介紹。

當(dāng)你通過交易與智能合約的功能進(jìn)行交互時(shí)十酣,功能對智能合約狀態(tài)所做的任何更改都會(huì)在區(qū)塊鏈上發(fā)布眯勾。為了換取這種特權(quán),你必須向礦工支付一些(希望很衅攀摹)的以太量吃环。Python時(shí)間:

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 = 0
    while 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}

這實(shí)際上與將Ether發(fā)送到智能合約時(shí)使用的過程相同。我們將創(chuàng)建并簽署一個(gè)交易洋幻,然后將其發(fā)送到網(wǎng)絡(luò)郁轻。再一次,交易是異步的,這意味著無論函數(shù)被告知在Solidity代碼中返回什么好唯,你實(shí)際得到的東西總是交易的哈希竭沫。

鑒于交易本身并沒有返回任何有用的信息,我們需要其他東西骑篙。這導(dǎo)致我們采用最后(半)方式與智能合約進(jìn)行互動(dòng)蜕提。

事件events

我將事件稱為與智能合約交互的“一半”方式,因?yàn)閺募夹g(shù)上講靶端,它們是由交易發(fā)出的谎势。 事件是智能合約以易于閱讀的形式在區(qū)塊鏈上記錄事物的方式,它們基本上只是一組可以使用特定交易的收據(jù)查找的值杨名。我們在智能合約的最頂層定義了一個(gè):

event OpinionBroadcast(address _soapboxer, string _opinion);

然后脏榆,當(dāng)我們使用broadcastOpinion函數(shù)時(shí),我們使用它向區(qū)塊鏈發(fā)出信息台谍。

將交易添加到塊后须喂,你可以使用交易哈希查詢區(qū)塊鏈以查找OpinionBroadcast事件發(fā)出的特定值。這是我們在函數(shù)broadcast_an_opinion中的最后一點(diǎn)python代碼趁蕊。你會(huì)注意到我們要求事件發(fā)出的信息存儲(chǔ)在'args'屬性中坞生。

這個(gè)事件非常公開。實(shí)際上掷伙,任何人都可以輕松使用Etherscan或類似工具來查看智能合約發(fā)出的所有事件的日志恨胚。

image

Etherscan會(huì)自動(dòng)檢測“Transfer”轉(zhuǎn)移事件并列出所有事件。Nifty

如果你已經(jīng)做到這一點(diǎn)炎咖,你就有權(quán)發(fā)表意見赃泡。繼續(xù)用你選擇的意見運(yùn)行broadcast_an_opinion

如果一切順利進(jìn)行乘盼,你應(yīng)該很快就會(huì)收到已處理的收據(jù)升熊,以及已放入?yún)^(qū)塊鏈的OpinionBroadcast事件的打印輸出。

Nice绸栅。

這是完整的python代碼:

import time
from web3 import Web3, HTTPProvider

contract_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 = None

    count = 0
    while 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 = 0
    while 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')

打包封裝

所以關(guān)于它级野。正如我所提到的,我們還沒有達(dá)到使用python實(shí)際部署智能合約很容易的地步粹胯,但其他一切都在那里蓖柔。在Sempo,我們正在使用上面提到的所有技術(shù)來使問題響應(yīng)更加透明风纠。

感謝Sebastian Dirman指出w3.toWei(value, ‘ether’)是一種更好的方式在Ether和Wei之間進(jìn)行轉(zhuǎn)換——只需將以太量乘以1000000000000000000即可導(dǎo)致類型錯(cuò)誤况鸣!

======================================================================

分享一些以太坊、EOS竹观、比特幣等區(qū)塊鏈相關(guān)的交互式在線編程實(shí)戰(zhàn)教程:

  • java以太坊開發(fā)教程镐捧,主要是針對java和android程序員進(jìn)行區(qū)塊鏈以太坊開發(fā)的web3j詳解潜索。
  • python以太坊,主要是針對python工程師使用web3.py進(jìn)行區(qū)塊鏈以太坊開發(fā)的詳解懂酱。
  • php以太坊竹习,主要是介紹使用php進(jìn)行智能合約開發(fā)交互,進(jìn)行賬號創(chuàng)建列牺、交易整陌、轉(zhuǎn)賬、代幣開發(fā)以及過濾器和交易等內(nèi)容瞎领。
  • 以太坊入門教程泌辫,主要介紹智能合約與dapp應(yīng)用開發(fā),適合入門默刚。
  • 以太坊開發(fā)進(jìn)階教程甥郑,主要是介紹使用node.js逃魄、mongodb荤西、區(qū)塊鏈、ipfs實(shí)現(xiàn)去中心化電商DApp實(shí)戰(zhàn)伍俘,適合進(jìn)階邪锌。
  • C#以太坊,主要講解如何使用C#開發(fā)基于.Net的以太坊應(yīng)用癌瘾,包括賬戶管理觅丰、狀態(tài)與交易、智能合約開發(fā)與交互妨退、過濾器和交易等妇萄。
  • EOS教程,本課程幫助你快速入門EOS區(qū)塊鏈去中心化應(yīng)用的開發(fā)咬荷,內(nèi)容涵蓋EOS工具鏈冠句、賬戶與錢包、發(fā)行代幣幸乒、智能合約開發(fā)與部署懦底、使用代碼與智能合約交互等核心知識點(diǎn),最后綜合運(yùn)用各知識點(diǎn)完成一個(gè)便簽DApp的開發(fā)罕扎。
  • java比特幣開發(fā)教程聚唐,本課程面向初學(xué)者,內(nèi)容即涵蓋比特幣的核心概念腔召,例如區(qū)塊鏈存儲(chǔ)杆查、去中心化共識機(jī)制、密鑰與腳本臀蛛、交易與UTXO等根灯,同時(shí)也詳細(xì)講解如何在Java代碼中集成比特幣支持功能,例如創(chuàng)建地址、管理錢包烙肺、構(gòu)造裸交易等纳猪,是Java工程師不可多得的比特幣開發(fā)學(xué)習(xí)課程。
  • php比特幣開發(fā)教程桃笙,本課程面向初學(xué)者氏堤,內(nèi)容即涵蓋比特幣的核心概念,例如區(qū)塊鏈存儲(chǔ)搏明、去中心化共識機(jī)制鼠锈、密鑰與腳本、交易與UTXO等星著,同時(shí)也詳細(xì)講解如何在Php代碼中集成比特幣支持功能购笆,例如創(chuàng)建地址、管理錢包虚循、構(gòu)造裸交易等同欠,是Php工程師不可多得的比特幣開發(fā)學(xué)習(xí)課程。
  • tendermint區(qū)塊鏈開發(fā)詳解横缔,本課程適合希望使用tendermint進(jìn)行區(qū)塊鏈開發(fā)的工程師铺遂,課程內(nèi)容即包括tendermint應(yīng)用開發(fā)模型中的核心概念,例如ABCI接口茎刚、默克爾樹襟锐、多版本狀態(tài)庫等,也包括代幣發(fā)行等豐富的實(shí)操代碼膛锭,是go語言工程師快速入門區(qū)塊鏈開發(fā)的最佳選擇粮坞。

匯智網(wǎng)原創(chuàng)翻譯,轉(zhuǎn)載請標(biāo)明出處初狰。這里是原文Python以太坊智能合約開發(fā)指南

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末莫杈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子跷究,更是在濱河造成了極大的恐慌姓迅,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俊马,死亡現(xiàn)場離奇詭異丁存,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)柴我,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門解寝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人艘儒,你說我怎么就攤上這事聋伦》蚺迹” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵觉增,是天一觀的道長兵拢。 經(jīng)常有香客問我,道長逾礁,這世上最難降的妖魔是什么说铃? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮嘹履,結(jié)果婚禮上腻扇,老公的妹妹穿的比我還像新娘。我一直安慰自己砾嫉,他們只是感情好幼苛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著焕刮,像睡著了一般舶沿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上济锄,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天暑椰,我揣著相機(jī)與錄音霍转,去河邊找鬼荐绝。 笑死,一個(gè)胖子當(dāng)著我的面吹牛避消,可吹牛的內(nèi)容都是我干的低滩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼岩喷,長吁一口氣:“原來是場噩夢啊……” “哼恕沫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起纱意,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤婶溯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后偷霉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迄委,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年类少,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叙身。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡硫狞,死狀恐怖信轿,靈堂內(nèi)的尸體忽然破棺而出晃痴,到底是詐尸還是另有隱情,我是刑警寧澤财忽,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布倘核,位于F島的核電站,受9級特大地震影響即彪,放射性物質(zhì)發(fā)生泄漏笤虫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一祖凫、第九天 我趴在偏房一處隱蔽的房頂上張望琼蚯。 院中可真熱鬧,春花似錦惠况、人聲如沸遭庶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽峦睡。三九已至,卻和暖如春权埠,著一層夾襖步出監(jiān)牢的瞬間榨了,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工攘蔽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留龙屉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓满俗,卻偏偏與公主長得像转捕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子唆垃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容