Python以太坊互動將區塊鏈資料存入sql資料庫
關於區塊鏈介紹性的研討會通常以易於理解的點對點網路和銀行分類賬這類故事開頭,然後直接跳到編寫智慧合約,這顯得非常突兀。因此,想象自己走進叢林,想象以太坊區塊鏈是一個你即將研究的奇怪生物。今天我們將觀察該生物,並與其進行互動然後將有關它的所有資料收集到一個集中儲存中供自己使用。
進行第一次設定
首先,你需要安裝web3py。Web3py是一個用於連線以太坊區塊鏈的Python庫。你需要事先知道的是,沒有可以從中下載資料的中央管理系統。彼此共享資源的內連節點(“對等體”)儲存經驗證的資料副本(或其一部分)。網路執行以太坊協議,該協議定義節點彼此之間的互動規則及網路上的智慧合約。
如果要訪問有關交易,餘額,區塊或其他任何被寫入區塊鏈的資訊,協議需要你連線到節點。節點不斷地相互共享新資料並驗證資料,因此這樣你就可以確定那些是未被篡改的資料,那些是最新的資料。
你可以在第一次接觸以太坊的方法中使用兩種基本型別的節點:本地或託管。本地節點可以在你的計算機上執行,這意味著你首先需要下載像geth這樣的客戶端,它會將區塊鏈同步到你的裝置,要佔用儲存空間並花費大量時間來完成。對於第一次學習,託管節點是更好的選擇——它由其他人控制,但你可以輕鬆連線到它並自己玩區塊鏈。
去Infura並建立自己的免費帳戶以訪問此類託管節點。當你完成後,你可以看到mainnet主網(即以太坊區塊鏈)和一堆testnets測試網,它們基本上可以測試你的智慧合約,這樣你就可以在將昂貴的程式碼部署到mainnet之前犯錯誤,並糾正它們。
這第一次我們先匯入Web3物件並建立HTTP連線。
from web3 import Web3
web3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/your-own-personal-number"))
現在你已經完成了!你可以使用web3 API瀏覽查詢資料結構了。
查詢特定區塊資訊
#current block number >>> web3.eth.blockNumber 5658173 #get the content of the most recently mined block >>> web3.eth.getBlock('latest')
此命令返回AttributeDict資料結構,該結構是key-value鍵值對的字典,如下所示:
AttributeDict({'difficulty': 3297284143124448,
'extraData': HexBytes('0x65746865726d696e652d6177732d61736961312d34'),
'gasLimit': 7999992,
'gasUsed': 7990111,
'hash': HexBytes('0x8c09ba67123601c08ef5d292acaffd36798ca178b7d6fecd5e1144ce8e3b9e50'),
'logsBloom': HexBytes('0x348000240b40620836308460180004415000c8ccb260021402420721c22801ca847c625c0a89030482044001523a4d100050100250d100858381260a186312088006c154010000491216446840888200c1812088c12b06000809a808530014160000812c2ac20008a201c83380314d02242338400c0500c2a028005010988c44b0608a020400201032e10e16142b931115469824248066100b082224200222140a41a20aa2006224d608210f1a22811d03969423e8c08058100388c0800402002a000802130c40d289201900c38142a1cc0380a4010f0201040d4022200022018c5801346c168502841906940485ea1d9864044060a00000a00616004d006090'),
'miner': '0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8',
'mixHash': HexBytes('0x84320fd71345778b48e437f3403e9021575520ba23aaac48dd7a352c9ce31f75'),
'nonce': HexBytes('0x98a0b1e00bfabac6'),
'number': 5658173,
'parentHash': HexBytes('0x01eda8a47a0151533d1afacf9b9108606d4d89a86e269dddaac9698b6fb12930'),
'receiptsRoot': HexBytes('0xc40f774ad10ad443457c3a5a0db96b539af3007f8d351b198ca7bf2ef196b7e0'),
'sha3Uncles': HexBytes('0x55725ec296c6c64257ed6a88d7d8c66160abe7b672f5d89bbad5487779b1d5fe'),
'size': 27161,
'stateRoot': HexBytes('0x5bfc7a9a87fb9991f2760807d56319154f1dab91d3cfc9530a597b6c5d064aba'),
'timestamp': 1527002893,
'totalDifficulty': 4339832462578780814928,
'transactions': [HexBytes('0x1ce6bca99701c4e8acae986b10e7649d628d70ec62b7a8314bbb13726a312225'),
HexBytes('0x6ba5e657243aea5f95afb40090313d10bb9443db41ed1216fbf7e7e60a16749a'),
loooooots_of_transactions_here],
'transactionsRoot': HexBytes('0x67e1e1f2f4b1d33791a0fba2d5ebf039bd6c331c665cb8020ff41d0e0eade46e'),
'uncles': [HexBytes('0x3df1bffa62d73b3847b434e9ea459c10cfdc3e212a2e78ebbf0db58adbef30b5'),
HexBytes('0x74bdcd4b88427854ae18f9c7ada28d46f26411bed09af6b040cbede66fdb1853')]})
並非所有這些變數都會立即對你有用,因為有些變數非常技術性,只有當你對區塊鏈的實際工作方式有了更深入的瞭解時,它們的含義才有意義。你可以在所謂的黃皮書中閱讀有關它們的更多資訊,或暫時跳過它們並使用易於理解的方法。
簡而言之,一個包含區塊頭部資訊的區塊,一個寫入它的已驗證交易列表和一個未確認列表(礦工的塊識別符號,他們的區塊太慢,無法進入主區塊鏈,但仍因其計算工作量而獲得以太獎勵)。下面你可以看到每個變數的含義,我把它分成子類別。
General常規資料
Block variable | Meaning | 翻譯 |
---|---|---|
number | scalar value equal to the number of ancestor blocks (genesis block=0) | 標量值相對創始塊的數量,genesis block=0 |
size | size of the block in bytes | 塊的大小,以位元組為單位 |
timestamp | Unix's time() at this block's inception | 這個塊開始時的Unix時間 |
miner | 160-bit address for fees collected from successful mining | 成功採礦收取以太的160位地址 |
gasLimit | maximum gas expenditure allowed in this block | 此區塊允許的最大氣體消耗量 |
gasUsed | total gas used by all transactions in this block | 此區塊中所有交易使用的總氣體 |
transactions | list of transaction hashes included in the block | 塊中包含的交易雜湊列表 |
parentHash | Keccak256 hash of the parent block's header | 父塊區塊頭的Keccak 256雜湊值 |
hash | current block's hash | 當前塊的雜湊值 |
extraData | extra data in byte array | 位元組陣列中的額外資料 |
挖礦相關
Block variable | Meaning | 翻譯 |
---|---|---|
difficulty | scalar value corresponding to the difficulty level of the block | 對應於塊的難度級別的標量值 |
totalDifficulty | integer of the total difficulty of the chain until this block | 直到此區塊的鏈的總難度值 |
nonce | hash of the generated proof-of-work; null when its a pending block | 生成工作量證明的雜湊值;當區塊掛起時為null |
mixHash | 256-bit hash which is combined with the nonce and used to prove that sufficient amount of computation has been carried out on this block | 256位雜湊與nonce結合使用來證明已對此塊執行了足夠的計算量 |
uncle相關
Block variable | Meaning | 翻譯 |
---|---|---|
uncles | list of uncle hashes | uncle雜湊值列表 |
sha3Uncles | SHA3 of the uncles data in the block | 塊中uncles資料的SHA3值 |
技術相關
Block variable | Meaning | 翻譯 |
---|---|---|
receiptsRoot | Keccak 256-bit hash of the root node of the tree structure populated with receipts of all transactions in this block | Keccak樹結構的根節點的256位雜湊填充了此塊中所有交易的收據 |
stateRoot | Keccak256 hash of the root node if the state trie after all transactions are executed and finalisations applied | 在執行所有交易並應用終止後,如狀態為trie根節點的keccak256雜湊值 |
transactionsRoot | Keccak256 hash of the root node of the trie structure populated with the receipts of each transaction in the transactions list | trie結構的根節點的keccak256雜湊填充了交易列表中每個交易的收據 |
logsBloom | the Bloom filter from indexable info (logger address and log topics) contained in each log entry from the receipt of each transaction in the transaction list | 交易列表中每個交易的接收日誌條目中包含的可索引資訊(記錄器地址和日誌主題)的Bloom過濾器 |
交易和收據
現在,我們還可以通過其唯一識別符號(即交易雜湊)查詢區塊中的單個交易。
>>> web3.eth.getTransaction('0x1ce6bca99701c4e8acae986b10e7649d628d70ec62b7a8314bbb13726a312225')
AttributeDict({'blockHash': HexBytes('0x8c09ba67123601c08ef5d292acaffd36798ca178b7d6fecd5e1144ce8e3b9e50'),
'blockNumber': 5658173,
'from': '0x390dE26d772D2e2005C6d1d24afC902bae37a4bB',
'gas': 45000,
'gasPrice': 123400000000,
'hash': HexBytes('0x1ce6bca99701c4e8acae986b10e7649d628d70ec62b7a8314bbb13726a312225'),
'input': '0x',
'nonce': 415710,
'r': HexBytes('0x1bb901ad0a3add517504cc459fdb1545d193020ec5c63a566e440ee39dbfe131'),
's': HexBytes('0x4b7ac95eb321b5947948ecb624e1d80b19d9cc876668c69cc2b32670f52b061a'),
'to': '0xBbA2D99C9B3aF394B0d6417b1D58815eE495029D',
'transactionIndex': 0,
'v': 37,
'value': 1000000000000000000})
和以前一樣,web3py返回一個屬性字典。下表總結了每個鍵的含義。
Transaction variable | Meaning | 翻譯 |
---|---|---|
blockHash | hash of the block the transaction belongs to | 交易所屬區塊的雜湊值 |
blockNumber | number of that block | 該塊的編號 |
hash | transaction hash (unique identifier) | 交易地址雜湊(唯一識別符號) |
from | 160-bit address of a sender of a transaction | 來自交易傳送方的160位地址雜湊 |
to | address of the recipient or null for a contract creation transaction | 收件人的地址或者建立合約交易時為null |
value | number of wei to be transfered to the recipient or newly created account (case of contract creation) | 要轉移給收件人或新建立帳戶的wei數量(建立合約的情況) |
gas | gas consumed by the transaction | 交易消耗的天然氣 |
gasPrice | number of Wei to be paid per unit of gas for all computatioon costs of this transaction | 此交易所有計算成本的每單位天然氣的支付數量 |
nonce | number of transactions/contract creations sent by the sender prior to this one | 傳送方在此之前傳送的交易和建立合約的數量 |
v/r/s | used to identify the sender; the signature values of the transaction | 用於識別發件人交易的簽名值 |
input | the data sent along with the transaction | 與交易一起傳送的資料 |
transactionIndex | index of the transaction in the block | 區塊中交易的索引 |
最後,我們還可以檢視交易收據:
>>> web3.eth.getTransactionReceipt('0x68c70c5ffe54a42ebf7118e7e931aeac018cee4656a816ffe6a01388da50c851')
AttributeDict({'blockHash': HexBytes('0x44338e1f80302037c7213e8f56dd35d8a473b000319bc200f76e910e62d12f98'),
'blockNumber': 5617795,
'contractAddress': None,
'cumulativeGasUsed': 21004,
'from': '0xea6e3e41ebaa09d550d3c3f0d72971b3c5ccc261',
'gasUsed': 21004,
'logs': [],
'logsBloom': HexBytes('0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),
'status': 1,
'to': '0xd96a6e75d099ce529bbd257cbcb403224cceaebf',
'transactionHash': HexBytes('0x68c70c5ffe54a42ebf7118e7e931aeac018cee4656a816ffe6a01388da50c851'),
'transactionIndex': 0})
交易收據包含一些重複和新條目,新的條目解釋如下。
Receipt variable | Meaning | 翻譯 |
---|---|---|
status | boolean whether the transaction was successfull; false if the EVM (Ethereum Virtual Machine) reverted the transaction | 交易是否成功,如果EVM(以太坊虛擬機器)還原了交易則返回false |
contractAddress | the contract address created if the transaction was a contract creation; otherwise null | 如果交易是合約建立,則建立的合同地址;否則為null |
gasUsed | the total amount of gas used when this transaction was executed in the block | 在區塊中執行此交易時使用的總氣體量 |
cumulativeGasUsed | the sum of gasUsed by this transaction and all preceding transactions in the same block | 此交易使用的gasUse和同一塊中所有先前交易的總和 |
logs | array of log objects which the transaction has generated | 交易生成的日誌物件陣列 |
作為參考,除了黃皮書之外,我還包括各種額外資源來編制這些表格2,3,4,5。
如你所見,只需幾個簡單的命令,就可以連線到網路並獲得有關原始格式的交易,區塊或狀態的基本資訊。這將為這些資料開啟一個新視窗!
資料庫管理系統
當計劃將資料寫入適當的資料庫時,你可能會意識到有許多針對Python愛好者的管理系統解決方案,例如無伺服器SQLite,或基於伺服器的MySQL,PostgreSQL或Hadoop。根據你的意圖,必須確定哪個選項最適合你的專案。總的來說,我發現這些要點很有幫助:
- 資料庫的預期大小是什麼(即可以在單個機器系統上處理)?
- 這些條目是經常編輯還是會保持不變?
- 資料庫是否應該由多方/應用程式同時訪問和編輯?
隨著時間的推移,以太坊區塊鏈正在穩步增長,截止到2018年6月接近1TB,這個很小,因此對於像Hadoop這樣的分散式處理系統來說並不是最佳選擇。區塊鏈資料庫將被寫入一次,然後僅使用新條目進行擴充套件,保留舊條目不變。此資料庫的預期用例由一個通道編寫,並由其他通道以只讀方式訪問,因此我們實際上不需要在伺服器上執行它。在你的機器上本地儲存資料庫將導致快速讀取,這對於像SQLite這樣的無伺服器管理系統是可取的和可實現的。Python有一個內建的庫sqlite3
,因此我們甚至不需要安裝新的包。
資料庫設計
下一步是設計資料庫。請記住哪些資料欄位與你的分析最相關,並且旨在優化搜尋和儲存。例如,如果你不打算使用stateRoot
,則可能需要完全跳過它或將其儲存在單獨的表中。可以更快地搜尋具有較少列的表,如果稍後意識到你實際上具有stateRoot
的用例,你仍然可以訪問它。你可能還希望將塊資訊與交易資訊分開;如果不這樣做,那麼區塊屬性如timestamp
將對區塊中的所有交易重複N次,浪費大量空間。稍後使用JOIN
操作可以輕鬆地將交易與其塊屬性進行匹配。
我設計的資料庫包含3個表:
- Quick:最相關的交易資訊,用於快速訪問和分析。
- TX:所有剩餘的交易資訊,
- Block:指定區塊的資訊。
變數的命名約定相對於原始的web3py略有改變,以消除歧義,例如將塊雜湊和交易雜湊都稱為“雜湊”,或使用“from”/“to”作為列名,這在SQL有不同的含義,會使程式崩潰。
交易值,餘額和其他大數字需要作為字串儲存在資料庫中。原因是SQLite只能處理最多8位元組儲存的有符號整數,最大值為2的63次方-1大約是9223372036854775807.這通常遠低於wei中的交易值(例如,1ETH = 10*18 wei)。
構建你的迷你資料庫
完整的程式碼可以在GitHub上找到。它將根據上層架構組織區塊鏈資訊,並輸出包含預先指定數量的塊資料的blockchain.db檔案。要測試它,請轉到database.py
檔案併為要寫入的塊數選擇合理的數字,例如:
Nblocks = 10000
預設情況下,你應該將web3物件指向Infura端點。 如果你有IPC提供商(即你的本地節點),也可以切換到IPC提供商,只需取消註釋該行:
# or connection via node on the VM
#web3 = Web3(Web3.IPCProvider('/path-to-geth.ipc/'))
修改路徑,然後只需在命令列python database.py
中執行。程式碼會將最後寫入的塊的編號轉儲到lastblock.txt
檔案中,以防你需要重新啟動。
如何使用資料庫
一旦將第一個條目寫入資料庫,就可以通過ipython shell開始與它進行通訊。例如,要打印表“Quick”的前5行,你可以執行下面的程式碼。
import sqlite3 as sq3
conn = sq3.connect("blockchain.db")
cur = conn.cursor()
# some SQL code, e.g. select first five entries of the table Quick
cur.execute("SELECT * FROM Quick LIMIT 5")
a = cur.fetchall() #list of tuples containing all elements of the row
print(a)
conn.close()
本地節點與Infura
如果要構建大型資料庫,則應下載geth並同步節點。同步可以在3種基本模式下完成:
如果你不需要過去的帳戶狀態,則可以在快速模式下同步節點6。
下面的圖表顯示了此程式碼寫入資料庫的速度,與本地完全同步的節點(IPC)與Infura(Infura)上的地址進行通訊。正如你所看到的,在本地節點上執行此程式碼是值得的,因為你可以將速度提升近2個數量級(即100x)!
總結
現在你已擁有自己的本地資料庫,瞭解區塊鏈上發生的事情,可以開始探索它。例如,你可以計算自其起源以來的交易數量,檢視作為時間函式生成的地址數量——天空是你可以瞭解的有關區塊鏈的限制。我們為你的資料科學遊樂場奠定了基礎。因此,請繼續探討,或檢視下一篇文章,瞭解潛在的應用。
python用web3.py庫開發以太坊來說非常的方便,有興趣的使用者可以關注我們的python以太坊教程,主要是針對python工程師使用web3.py進行區塊鏈以太坊開發的詳解。
另外其他語言可以學習的以太坊教程如下:
匯智網原創翻譯,轉載請標明出處。這裡是原文