<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          通過 web3.py 用 Python 存取 Ethereum

          共 4662字,需瀏覽 10分鐘

           ·

          2022-04-19 11:41


          想要通過 Python 存取 Ethereum,從 Ethereum 官方的 Github 中可以看到有兩種模塊可以達(dá)成:web3.py 和 pyethereum 。就我目前的理解來說,兩者的差別在于 web3.py 主要是作為外部存取 Ethereum 的客戶端,也就是說 web3.py 函數(shù)庫本身不會(huì)成為區(qū)塊鏈節(jié)點(diǎn),也不會(huì)進(jìn)行區(qū)塊鏈同步,而是連接一個(gè)區(qū)塊鏈上的節(jié)點(diǎn),把區(qū)塊鏈當(dāng)成是外部資料庫一樣取用而已;而 pyethereum 則比較像是 geth 那樣,是用來把自己做成一個(gè)區(qū)塊鏈節(jié)點(diǎn),會(huì)正常進(jìn)行區(qū)塊同步,也可以作為礦工開始挖礦。

          在本篇當(dāng)中,因?yàn)槭窍胍粋€(gè)輕量級(jí)的客戶端來與區(qū)塊鏈互動(dòng),并不想要準(zhǔn)備龐大的儲(chǔ)存空間來存放區(qū)塊鏈的資料,因此會(huì)以 web3.py 為主。

          • 配置 web3.py 執(zhí)行環(huán)境

          • 通過 web3.py 連結(jié) Ethereum 節(jié)點(diǎn)

          • 存取區(qū)塊鏈上的 ERC20 合約

          • 簽署并送出交易

          配置 web3.py 執(zhí)行環(huán)境

          web3.py 可以直接通過 pip 安裝。

          1. pip install web3

          需注意的是,在 Windows 上想安裝時(shí),會(huì)需要事先安裝 Visual C++ Builder,否則在安裝的最后階段會(huì)因?yàn)闊o法編譯而失敗。

          通過 web3.py 連結(jié) Ethereum 節(jié)點(diǎn)

          web3.py 因?yàn)樽陨聿粫?huì)作為一個(gè)區(qū)塊鏈的節(jié)點(diǎn)存在,因此它需要有一個(gè)節(jié)點(diǎn)用來存取區(qū)塊鏈上的資料。一般來說最安全的方式應(yīng)該是自己使用 geth 或者 parity 來自建節(jié)點(diǎn),不過如果在不想要自建節(jié)點(diǎn)的狀況時(shí),可以考慮看看 infura 提供的 HTTP 節(jié)點(diǎn)服務(wù)。

          以 infura 現(xiàn)在的 API 來說,如果要連結(jié) Ropsten 測試鏈,連結(jié)的網(wǎng)址是 https://ropsten.infura.io/v3/api_key,其中 api_key 要去注冊帳號(hào)才取得。以下的程序仿照了 web3.py 內(nèi)建的 auto.infura 的作法,會(huì)從環(huán)境變數(shù)讀取 INFURA_API_KEY 這個(gè)參數(shù)來組出 infura.io 的 HTTP 位址,用來建立跟 Ropsten 測試鏈的連線。

          1. import os


          2. from web3 import (

          3. HTTPProvider,

          4. Web3,

          5. )


          6. INFURA_ROPSTEN_BASE_URL = 'https://ropsten.infura.io/v3'


          7. def load_infura_url():

          8. key = os.environ.get('INFURA_API_KEY', '')

          9. return "%s/%s" % (INFURA_ROPSTEN_BASE_URL, key)


          10. w3 = Web3(HTTPProvider(load_infura_url()))

          存取區(qū)塊鏈上的 ERC20 合約

          在開始存取合約之前,需要先談?wù)勈裁词?ABI 。在 Ethereum 中,因?yàn)楹霞s都是以編譯過的 binary code 形式存在,因此其實(shí)函數(shù)庫沒辦法直接知道合約傳輸?shù)膬?nèi)容到底是什么,因?yàn)楹霞s的回傳值全都是 binary。因此在操作合約之前,需要提供一份 ABI 文件,告訴函數(shù)庫如何使用合約。

          1. # Assume the contract we're going to invoke is a standard ERC20 contract.

          2. with open("erc20.abi.json") as f:

          3. erc20_abi = json.load(f)


          4. # Web3 accept only checksum address. So we should ensure the given address is a

          5. # checksum address before accessing the corresponding contract.

          6. contract_addr = w3.toChecksumAddress('0x4e470dc7321e84ca96fcaedd0c8abcebbaeb68c6');


          7. erc20_contract = w3.eth.contract(address=contract_addr, abi=erc20_abi)


          8. for func in erc20_contract.all_functions():

          9. logger.debug('contract functions: %s', func)


          10. logger.debug("Name of the token: %s", erc20_contract.functions.name().call())

          這里假設(shè)我們想存取 Ropsten 測試鏈上位址是 0x4e470dc7321e84ca96fcaedd0c8abcebbaeb68c6 的智能合約。這個(gè)合約是透過 etherscan 隨便找的某個(gè) ERC20 的合約,因此可以用標(biāo)準(zhǔn)的 ERC20 的 ABI 來存取它。我們在建立這個(gè)合約的 instance 時(shí),先跑一個(gè)回圈印出合約內(nèi)所有的 function(這個(gè)步驟其實(shí)是在列出 ABI 上的信息),接著試著呼叫合約中的 name() 來取得這個(gè)合約宣告的代幣名稱。最后輸出的內(nèi)容如下:

          1. 2018-09-07 15:02:53,815 | __main__ | DEBUG | contract functions: <Function name()>

          2. 2018-09-07 15:02:53,816 | __main__ | DEBUG | contract functions: <Function approve(address,uint256)>

          3. 2018-09-07 15:02:53,824 | __main__ | DEBUG | contract functions: <Function totalSupply()>

          4. 2018-09-07 15:02:53,824 | __main__ | DEBUG | contract functions: <Function transferFrom(address,address,uint256)>

          5. 2018-09-07 15:02:53,824 | __main__ | DEBUG | contract functions: <Function decimals()>

          6. 2018-09-07 15:02:53,824 | __main__ | DEBUG | contract functions: <Function balanceOf(address)>

          7. 2018-09-07 15:02:53,824 | __main__ | DEBUG | contract functions: <Function symbol()>

          8. 2018-09-07 15:02:53,825 | __main__ | DEBUG | contract functions: <Function transfer(address,uint256)>

          9. 2018-09-07 15:02:53,825 | __main__ | DEBUG | contract functions: <Function allowance(address,address)>

          10. 2018-09-07 15:02:54,359 | __main__ | DEBUG | Name of the token: KyberNetwork

          簽署并送出交易

          在上面的例子中,呼叫智能合約時(shí)是直接呼叫合約里的 function,但這一般只能用在讀取區(qū)塊鏈上的資料的狀況。如果是想要通過呼叫智能合約來寫入資料到區(qū)塊鏈,就必須要用另一種方式來呼叫合約,也就是必須先簽署交易,然后付 gas 去執(zhí)行這個(gè)交易。

          假設(shè)我們一樣是要呼叫一個(gè) ERC20 的合約,要執(zhí)行合約上的 transferFrom() 這個(gè)函數(shù)。transferFrom() 需要三個(gè)參數(shù) _from_to_value,表示要從 _from 帳號(hào)轉(zhuǎn)帳給 _to 帳號(hào),轉(zhuǎn)帳金額是 _value

          1. # Set the account which makes the transaction.

          2. account = w3.toChecksumAddress(os.environ.get('ETHEREUM_ACCOUNT', ''))

          3. w3.eth.defaultAccount = account


          4. # Web3 accept only checksum address. So we should ensure the given address is a

          5. # checksum address before accessing the corresponding contract.

          6. contract_address = w3.toChecksumAddress('0x4e470dc7321e84ca96fcaedd0c8abcebbaeb68c6')

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


          8. # Prepare the necessary parameters for making a transaction on the blockchain.

          9. estimate_gas = contract.functions.transferFrom(account, account, w3.toWei('1', 'eth')).estimateGas()

          10. nonce = w3.eth.getTransactionCount(account)


          11. # Build the transaction.

          12. txn = contract.functions.transferFrom(account, account, w3.toWei('1', 'eth')).buildTransaction({

          13. 'chainId': 3,

          14. 'gas': estimate_gas,

          15. 'gasPrice': w3.toWei('1', 'gwei'),

          16. 'nonce': nonce

          17. })


          18. logger.debug('Transaction: %s', txn)


          19. # Sign the transaction.

          20. private_key = bytes.fromhex(os.environ.get('ETHEREUM_ACCOUNT_PKEY', ''))

          21. signed_txn = w3.eth.account.signTransaction(txn, private_key=private_key)


          22. tx_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction)

          23. logger.debug('Txhash: 0x%s', bytes.hex(tx_hash))

          在上面的程序中,首先第 2 ~ 3 行先從環(huán)境變量中讀取我們要使用的帳號(hào),這個(gè)帳號(hào)將會(huì)用來發(fā)送交易,當(dāng)然要付 gas 時(shí)也會(huì)從這個(gè)帳號(hào)扣。第 10 ~ 20 行建立一個(gè)原始交易(raw transaction),這個(gè)交易中因?yàn)槲覀冃枰孕兄付ò?gas、nonce 等參數(shù),因此需要在前面 11 ~ 12 行確認(rèn)參數(shù)要設(shè)定多少。然后最重要的第 25 ~ 26 行讀取私鑰,并且用私鑰去簽署交易。這里假設(shè)私鑰的組成會(huì)是用 Hex 編碼的文字,所以使用 bytes.fromhex 把 Hex 編碼轉(zhuǎn)回成 byte 格式。簽好以后就送出交易,送出交易時(shí) API 會(huì)回傳 byte 格式的交易的 transaction hash,可以把它編碼后印出來,之后就可以去 etherscan 上查找這筆交易了。

          瀏覽 72
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲骚货| 黄色电影免费网站麻豆 | 国产又粗又猛视频 | 日本内射精品特黄 | 欧美性爱内射 |