Python以太坊交互後將區塊鏈信息寫入SQLite數據庫

關於區塊鏈介紹性的研討會一般以易於理解的點對點網絡和銀行分類帳這類故事開頭,而後直接跳到編寫智能合約,這顯得很是突兀。所以,想象本身走進叢林,想象以太坊區塊鏈是一個你即將研究的奇怪生物。今天咱們將觀察該生物,並與其進行交互而後將有關它的全部數據收集到一個集中存儲中供本身使用。html

進行第一次設置

首先,你須要安裝web3py。Web3py是一個用於鏈接以太坊區塊鏈的Python庫。你須要事先知道的是,沒有能夠從中下載數據的中央管理系統。彼此共享資源的內連節點(「對等體」)存儲經驗證的數據副本(或其一部分)。網絡執行以太坊協議,該協議定義節點彼此之間的交互規則及網絡上的智能合約。node

若是要訪問有關交易,餘額,區塊或其餘任何被寫入區塊鏈的信息,協議須要你鏈接到節點。節點不斷地相互共享新數據並驗證數據,所以這樣你就能夠肯定那些是未被篡改的數據,那些是最新的數據。python

你能夠在第一次接觸以太坊的方法中使用兩種基本類型的節點:本地或託管。本地節點能夠在你的計算機上運行,這意味着你首先須要下載像geth這樣的客戶端,它會將區塊鏈同步到你的設備,要佔用存儲空間並花費大量時間來完成。對於第一次學習,託管節點是更好的選擇——它由其餘人控制,但你能夠輕鬆鏈接到它並本身玩區塊鏈。git

去Infura並建立本身的免費賬戶以訪問此類託管節點。當你完成後,你能夠看到mainnet主網(即以太坊區塊鏈)和一堆testnets測試網,它們基本上能夠測試你的智能合約,這樣你就能夠在將昂貴的代碼部署到mainnet以前犯錯誤,並糾正它們。github

這第一次咱們先導入Web3對象並創建HTTP鏈接。web

from web3 import Web3 
web3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/your-own-personal-number"))
複製代碼

如今你已經完成了!你可使用web3 API瀏覽查詢數據結構了。sql

查詢特定區塊信息

#current block number
>>> web3.eth.blockNumber
5658173
#get the content of the most recently mined block
>>> web3.eth.getBlock('latest')
複製代碼

此命令返回AttributeDict數據結構,該結構是key-value鍵值對的字典,以下所示:shell

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進行區塊鏈以太坊開發的詳解。

這裏是原文

相關文章
相關標籤/搜索