关于区块链介绍性的研讨会一般以易于理解的点对点网络和银行分类帐这类故事开头,而后直接跳到编写智能合约,这显得很是突兀。所以,想象本身走进丛林,想象以太坊区块链是一个你即将研究的奇怪生物。今天咱们将观察该生物,并与其进行交互而后将有关它的全部数据收集到一个集中存储中供本身使用。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')]})
复制代码
并不是全部这些变量都会当即对你有用,由于有些变量很是技术性,只有当你对区块链的实际工做方式有了更深刻的了解时,它们的含义才有意义。你能够在所谓的黄皮书中阅读有关它们的更多信息,或暂时跳过它们并使用易于理解的方法。数据库
简而言之,一个包含区块头部信息的区块,一个写入它的已验证交易列表和一个未确认列表(矿工的块标识符,他们的区块太慢,没法进入主区块链,但仍因其计算工做量而得到以太奖励)。下面你能够看到每一个变量的含义,我把它分红子类别。数组
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结合使用来证实已对此块执行了足够的计算量 |
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个表:
变量的命名约定相对于原始的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()
复制代码
若是要构建大型数据库,则应下载geth并同步节点。同步能够在3种基本模式下完成:
若是你不须要过去的账户状态,则能够在快速模式下同步节点6。
下面的图表显示了此代码写入数据库的速度,与本地彻底同步的节点(IPC)与Infura(Infura)上的地址进行通讯。正如你所看到的,在本地节点上运行此代码是值得的,由于你能够将速度提高近2个数量级(即100x)!
如今你已拥有本身的本地数据库,了解区块链上发生的事情,能够开始探索它。例如,你能够计算自其起源以来的交易数量,查看做为时间函数生成的地址数量——天空是你能够了解的有关区块链的限制。咱们为你的数据科学游乐场奠基了基础。所以,请继续探讨,或查看下一篇文章,了解潜在的应用。
python用web3.py库开发以太坊来讲很是的方便,有兴趣的用户能够关注咱们的python以太坊教程,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
这里是原文