文章目录
- 3.1 区块和交易的结构
- 3.1.1 基础知识
- 3.1.2 重点案例:构建简单的区块链
- 3.1.3 拓展案例 1:验证交易签名
- 生成密钥对
- 签名交易
- 验证签名
- 完整的交易签名与验证演示
- 3.1.4 拓展案例 2:监听和解析区块链事件
- 代币合约示例(Solidity)
- Python 脚本监听和解析事件
- 结论
- 3.2 智能合约数据解析
- 3.2.1 基础知识
- 3.2.2 重点案例:读取以太坊智能合约状态
- 步骤1:准备智能合约
- 步骤2:安装Web3.py
- 步骤3:编写Python脚本读取合约状态
- 结论
- 3.2.3 拓展案例 1:监听智能合约事件
- 智能合约示例(Solidity)
- 步骤1:安装 Web3.py
- 步骤2:编写 Python 脚本以监听事件
- 注意事项
- 3.2.4 拓展案例 2:向智能合约发送交易
- 智能合约示例(Solidity)
- 步骤1:准备环境
- 步骤2:编写Python脚本发送交易
- 注意事项
- 3.3 链上与链下数据
- 3.3.1 基础知识
- 3.3.2 重点案例:链上验证链下数据
- 步骤1: 智能合约编写
- 步骤2: 部署智能合约
- 步骤3: 使用Python存储和验证数据哈希
- 结论
- 3.3.3 拓展案例 1:使用 IPFS 存储链下数据
- 步骤1: 安装IPFS和Python客户端
- 步骤2: 启动IPFS守护进程
- 步骤3: 使用Python脚本存储数据到IPFS
- 步骤4: 将IPFS哈希值存储到以太坊智能合约
- 结论
- 3.3.4 拓展案例 2:链下数据的链上验证
- 步骤1: 智能合约编写
- 步骤2: 部署智能合约
- 步骤3: 使用Python存储和验证数据哈希
- 结论
3.1 区块和交易的结构
3.1.1 基础知识
在区块链的世界里,一切都始于区块和交易。这两个概念是构成任何区块链网络基础的核心元素。
-
区块:区块是区块链数据结构的主体,它包含了一系列的交易。每个区块都有一个唯一的区块头,其中包含了重要的元数据,如前一个区块的哈希值(确保区块之间的连接)、时间戳(记录区块创建的时间)、难度目标(用于工作量证明算法)和一个称为nonce的值(使区块的哈希值满足网络难度要求)。
-
交易:交易是区块链网络中传输资产或数据的基本单位。每笔交易都包含了一系列的输入和输出,输入指的是资产的来源,输出指的是资产的去向。交易一旦被网络验证并加入到一个区块中,就会被永久记录在区块链上。
3.1.2 重点案例:构建简单的区块链
让我们使用Python来模拟构建一个包含基本区块和交易结构的简单区块链。这个示例将帮助我们理解区块链是如何一步步构建并将交易记录在区块中的。
import hashlib
import json
from time import time
class Blockchain:
def __init__(self):
self.chain = []
self.current_transactions = []
self.new_block(previous_hash='1', proof=100) # 创世区块
def new_block(self, proof, previous_hash=None):
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'proof': proof,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
self.current_transactions = []
self.chain.append(block)
return block
def new_transaction(self, sender, recipient, amount):
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
@staticmethod
def hash(block):
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
@property
def last_block(self):
return self.chain[-1]
# 实例化Blockchain
blockchain = Blockchain()
# 创建一个新交易
blockchain.new_transaction(sender="Alice", recipient="Bob", amount=100)
# 挖掘一个新区块
blockchain.new_block(proof=12345)
print(blockchain.chain)
3.1.3 拓展案例 1:验证交易签名
在区块链系统中,交易签名是确保交易安全性和完整性的关键。签名机制允许网络验证交易是否真的由交易发起者发起,而没有被第三方篡改。在这个扩展案例中,我们将使用Python演示如何生成密钥对、签名交易以及验证交易签名。
首先,确保安装了必要的Python库:
pip install ecdsa
生成密钥对
我们将使用椭圆曲线数字签名算法(ECDSA),这是比特币和许多其他加密货币使用的签名算法。
from ecdsa import SigningKey, SECP256k1
# 生成ECDSA密钥对
sk = SigningKey.generate(curve=SECP256k1) # 私钥
vk = sk.verifying_key # 公钥
private_key = sk.to_string().hex()
public_key = vk.to_string().hex()
print(f"Private Key: {private_key}")
print(f"Public Key: {public_key}")
签名交易
使用生成的私钥对一条交易信息进行签名。
message = "Alice pays Bob 1 BTC"
signature = sk.sign(message.encode()).hex()
print(f"Message: {message}")
print(f"Signature: {signature}")
验证签名
最后,我们将展示如何使用公钥和签名来验证消息。
from ecdsa import VerifyingKey
# 将公钥和签名转换回相应格式
vk = VerifyingKey.from_string(bytes.fromhex(public_key), curve=SECP256k1)
signature_bytes = bytes.fromhex(signature)
# 验证签名
try:
is_valid = vk.verify(signature_bytes, message.encode())
print("Signature is valid." if is_valid else "Signature is invalid.")
except Exception as e:
print(f"Signature verification failed: {str(e)}")
完整的交易签名与验证演示
将上述片段组合起来,我们就得到了一个完整的交易签名与验证的演示。这个过程从生成密钥对开始,接着用私钥签名一条简单的消息(模拟交易),最后使用公钥验证签名的有效性。
通过这个案例,我们可以深入理解数字签名在区块链交易安全中的关键作用。数字签名不仅确保了交易的非抵赖性,还验证了交易的完整性和发起人的身份,是区块链技术核心安全机制的重要组成部分。
3.1.4 拓展案例 2:监听和解析区块链事件
监听和解析区块链事件,尤其是在以太坊这样的支持智能合约的平台上,对于开发去中心化应用(DApps)非常关键。它允许应用实时响应合约中发生的特定活动,如代币转移、投票结果或其他自定义事件。以下案例将展示如何使用 Python 和 Web3.py 监听以太坊智能合约事件,并对事件数据进行解析。
首先,确保你已经安装了 Web3.py 库:
pip install web3
假设我们有一个简单的 ERC-20 代币合约,其中包含一个Transfer
事件,每当代币被转移时都会触发该事件。
代币合约示例(Solidity)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleToken {
event Transfer(address indexed from, address indexed to, uint256 value);
// 假设的代币转移函数
function transfer(address _to, uint256 _value) external {
// ...执行转移逻辑
emit Transfer(msg.sender, _to, _value);
}
}
Python 脚本监听和解析事件
以下Python脚本示例展示了如何连接到以太坊网络,订阅Transfer
事件,并打印事件详情。
from web3 import Web3
# 使用Infura的WebSocket服务连接到以太坊主网络
w3 = Web3(Web3.WebsocketProvider('wss://mainnet.infura.io/ws/v3/YOUR_INFURA_PROJECT_ID'))
# 假设合约地址和ABI
contract_address = '0xYourContractAddress'
contract_abi = json.loads('''[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]''')
# 创建合约对象
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
# 创建事件过滤器
transfer_event_filter = contract.events.Transfer.createFilter(fromBlock='latest')
print("Listening for Transfer events...")
while True:
# 检查新的事件
for event in transfer_event_filter.get_new_entries():
handle_event(event)
time.sleep(10)
def handle_event(event):
print(f"New Transfer event:\n From: {event['args']['from']}\n To: {event['args']['to']}\n Value: {event['args']['value']} tokens")
在上述代码中,YOUR_INFURA_PROJECT_ID
需要替换为你的Infura项目ID,0xYourContractAddress
需要替换为你的代币合约地址。contract_abi
是合约的ABI,其中应包含你想要监听的事件定义。
这个脚本使用了Web3.py的事件过滤器功能来监听特定的Transfer
事件,并在新事件到达时通过handle_event
函数进行处理。这个处理函数简单地打印了事件的详细信息,包括转账的发送方、接收方和转移的代币数量。
结论
通过这个案例,我们展示了如何在以太坊区块链上监听和解析智能合约事件。这种能力对于开发实时响应链上活动的DApps至关重要。无论是追踪代币交易,还是其他基于事件的合约逻辑,使用Web3.py监听事件提供了一个强大且灵活的方法来增强应用的功能和用户体验。
通过这些案例,我们探索了区块链的基础数据结构,从构建和记录交易到验证交易的完整性和监听链上事件。这些操作是构建任何区块链应用的基石,理解它们对于任何 aspiring 区块链开发者来说都是必不可少的。
3.2 智能合约数据解析
智能合约是区块链技术的一项革命性创新,它允许在没有中介的情况下自动执行合约条款。这一切都是通过在区块链上编写和部署代码实现的。了解如何解析智能合约数据对于开发去中心化应用(DApp)、执行自动化测试或进行区块链数据分析至关重要。
3.2.1 基础知识
- 智能合约:是存储在区块链上的一段程序,它能够在满足预设条件时自动执行预定义的操作。
- 事件(Events):智能合约可以定义和触发事件,这些事件会被记录在区块链上,应用程序可以监听和响应这些事件。
- 函数调用:智能合约包含可被外部或合约内部调用的函数,这些函数可以读取或修改合约的状态。
3.2.2 重点案例:读取以太坊智能合约状态
假设我们有一个部署在以太坊上的智能合约,该合约包含一个可以公开访问的状态变量storedData
,以及一个函数getStoredData
用于返回这个变量的值。我们的目标是使用Python和Web3.py库来读取这个智能合约状态变量的当前值。
步骤1:准备智能合约
首先,假设智能合约代码如下(Solidity语言):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleStorage {
uint storedData;
constructor(uint initialValue) {
storedData = initialValue;
}
function setStoredData(uint x) public {
storedData = x;
}
function getStoredData() public view returns (uint) {
return storedData;
}
}
智能合约部署在以太坊网络上后,我们可以通过它的ABI和地址与之交互。
步骤2:安装Web3.py
确保你已经安装了Web3.py库:
pip install web3
步骤3:编写Python脚本读取合约状态
以下是使用Web3.py读取智能合约状态的Python脚本示例。在这个示例中,我们将连接到以太坊网络(通过Infura),使用合约的ABI和地址来创建一个合约对象,然后调用getStoredData
函数来获取storedData
变量的值。
from web3 import Web3
import json
# 连接到以太坊节点
infura_url = 'https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'
w3 = Web3(Web3.HTTPProvider(infura_url))
# 确认连接成功
if w3.isConnected():
print("Connected to Ethereum network")
# 智能合约ABI和地址
contract_abi = json.loads('[YOUR_CONTRACT_ABI_HERE]')
contract_address = 'YOUR_CONTRACT_ADDRESS_HERE'
# 创建智能合约对象
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
# 调用合约的getStoredData函数
stored_data = contract.functions.getStoredData().call()
print(f"The stored data is: {stored_data}")
在上面的代码中,你需要替换YOUR_INFURA_PROJECT_ID
、YOUR_CONTRACT_ABI_HERE
和YOUR_CONTRACT_ADDRESS_HERE
为你自己的Infura项目ID、智能合约的ABI和合约地址。
结论
通过这个案例,我们演示了如何使用Python和Web3.py库来读取以太坊智能合约中的状态变量。这种方法可以用来访问智能合约的任何公开状态或执行其任何公开函数,为开发去中心化应用(DApps)提供了强大的基础。了解如何与智能合约交互并解析其数据对于构建复杂的区块链应用至关重要。
3.2.3 拓展案例 1:监听智能合约事件
在许多去中心化应用(DApps)中,实时监听智能合约事件并对其做出响应是一个常见且关键的需求。这可以用于追踪代币转移、用户投票、状态更新等重要活动。以下案例演示了如何使用Python和Web3.py监听以太坊智能合约的事件。
假设我们有一个智能合约,它定义了一个ValueChanged
事件,每当合约中的某个值被更新时就会触发这个事件。
智能合约示例(Solidity)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract SimpleStorage {
uint public storedData;
event ValueChanged(uint oldValue, uint newValue);
function set(uint x) public {
emit ValueChanged(storedData, x);
storedData = x;
}
}
步骤1:安装 Web3.py
确保你的环境中已安装Web3.py:
pip install web3
步骤2:编写 Python 脚本以监听事件
接下来,我们将编写一个Python脚本,该脚本通过Infura连接到以太坊网络,并监听ValueChanged
事件。
from web3 import Web3
# 使用Infura的WebSocket服务连接到以太坊网络
w3 = Web3(Web3.WebsocketProvider('wss://mainnet.infura.io/ws/v3/YOUR_INFURA_PROJECT_ID'))
# 智能合约地址和ABI
contract_address = '0xYourContractAddress'
contract_abi = json.loads('[YOUR_CONTRACT_ABI]')
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
# 创建事件过滤器
value_changed_filter = contract.events.ValueChanged.createFilter(fromBlock='latest')
print("Listening for ValueChanged events...")
# 轮询以检查新事件
while True:
for event in value_changed_filter.get_new_entries():
print(f"Old Value: {event['args']['oldValue']}, New Value: {event['args']['newValue']}")
time.sleep(10)
在这段代码中,将YOUR_INFURA_PROJECT_ID
替换为你的Infura项目ID,0xYourContractAddress
替换为智能合约的地址,[YOUR_CONTRACT_ABI]
替换为合约的ABI。这段脚本首先创建了一个事件过滤器,然后进入一个循环,不断检查并打印新的ValueChanged
事件。
注意事项
- 使用WebSocket提供者(
WebsocketProvider
)对于监听事件是必需的,因为它支持订阅和实时更新,而HTTP提供者不支持这些功能。 - 在生产环境中,你可能需要考虑错误处理和重新连接逻辑,以确保应用能够持续稳定地监听事件。
通过这个案例,我们展示了如何监听并处理以太坊智能合约中的事件,这对于构建响应式和交互式的DApps至关重要。监听智能合约事件是区块链开发中的一个强大工具,它可以帮助开发者实时捕捉到链上发生的关键活动,并据此执行相应的逻辑。
3.2.4 拓展案例 2:向智能合约发送交易
在以太坊上,向智能合约发送交易是一种常见的操作,用于执行合约的函数。这种操作可以改变合约的状态或触发链上的某些活动。以下案例演示了如何使用Python和Web3.py向以太坊智能合约发送交易。
假设我们有一个简单的智能合约,它允许存储和更新一个数值。
智能合约示例(Solidity)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract SimpleStorage {
uint public storedData;
function set(uint x) public {
storedData = x;
}
}
此合约包含一个名为set
的函数,允许更新storedData
变量的值。
步骤1:准备环境
确保你已安装Web3.py库:
pip install web3
步骤2:编写Python脚本发送交易
接下来,我们将编写一个Python脚本,通过Infura连接到以太坊网络,并发送一个交易来调用set
函数。
from web3 import Web3
from web3.middleware import geth_poa_middleware
# 使用Infura的HTTP服务连接到以太坊网络
w3 = Web3(Web3.HTTPProvider('https://rinkeby.infura.io/v3/YOUR_INFURA_PROJECT_ID'))
w3.middleware_onion.inject(geth_poa_middleware, layer=0)
# 智能合约地址和ABI
contract_address = '0xYourContractAddress'
contract_abi = json.loads('[YOUR_CONTRACT_ABI]')
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
# 发送交易需要的账户和私钥
account = '0xYourAccountAddress'
private_key = 'YourPrivateKey'
# 构建交易
nonce = w3.eth.getTransactionCount(account)
tx = contract.functions.set(123).buildTransaction({
'chainId': 4, # Rinkeby测试网络的chain ID
'gas': 2000000,
'gasPrice': w3.toWei('50', 'gwei'),
'nonce': nonce,
})
# 签名交易
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
# 发送交易
tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
# 获取交易哈希值
print(f"Transaction hash: {tx_hash.hex()}")
在这个脚本中,替换YOUR_INFURA_PROJECT_ID
、0xYourContractAddress
、[YOUR_CONTRACT_ABI]
、0xYourAccountAddress
和YourPrivateKey
为你自己的值。
注意事项
- 安全性:处理私钥时要非常小心,确保不要在公共代码库或不安全的地方暴露私钥。
- Gas费用:发送交易需要支付Gas费用,因此确保你的账户有足够的以太币来支付。
- 测试网络:在实际将交易发送到主网之前,强烈推荐在测试网络(如Rinkeby)上进行测试。
通过这个案例,我们演示了如何向以太坊智能合约发送交易以执行其函数,这是开发去中心化应用(DApps)的一个重要环节。理解如何与智能合约交互、发送交易和管理Gas费用对于区块链开发者来说是基本技能。
通过这些案例,我们展示了如何与以太坊智能合约进行交互,包括读取合约状态、监听事件以及发送交易以调用合约函数。这些技能是开发去中心化应用和进行区块链数据分析的基础,为开发者提供了强大的工具来构建复杂和高效的区块链应用。
3.3 链上与链下数据
在区块链应用开发中,理解链上和链下数据的区别及其应用是至关重要的。这不仅关乎数据的存储和处理方式,也影响到应用的设计和性能。
3.3.1 基础知识
- 链上数据:直接存储在区块链上的数据。它的特点是不可篡改、透明且永久保存,适合存储交易记录、智能合约状态等关键信息。但由于存储成本较高,通常不适合存储大量数据。
- 链下数据:存储在区块链外部的数据。链下数据可以存储在传统数据库、文件系统或任何其他形式的数据存储系统中。它适合存储大量数据,如应用日志、复杂的文档等,但不享有区块链数据的安全性和不可篡改性。
3.3.2 重点案例:链上验证链下数据
在区块链应用开发中,经常面临一个问题:如何有效地存储和验证大量数据。由于直接在链上存储数据成本较高,一种常见的解决方案是将数据存储在链下(如在服务器或分布式文件系统中),同时在链上存储数据的指纹(通常是数据的哈希值)以保证数据的不可篡改性和可验证性。
以下案例演示了如何使用Python和Web3.py以及以太坊智能合约来实现链上验证链下数据的完整性。
步骤1: 智能合约编写
首先,编写一个简单的智能合约,该合约允许用户存储和检索数据哈希值。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract DataHashStorage {
mapping(bytes32 => bool) public hashExists;
event HashStored(bytes32 dataHash);
function storeDataHash(bytes32 dataHash) public {
require(!hashExists[dataHash], "Data hash already stored.");
hashExists[dataHash] = true;
emit HashStored(dataHash);
}
function verifyDataHash(bytes32 dataHash) public view returns (bool) {
return hashExists[dataHash];
}
}
该合约包含一个storeDataHash
函数用于存储数据哈希值,和一个verifyDataHash
函数用于验证给定的哈希值是否已经被存储。
步骤2: 部署智能合约
使用Remix或Truffle等工具部署智能合约到以太坊网络,并记录合约地址。
步骤3: 使用Python存储和验证数据哈希
首先,安装Web3.py库。
pip install web3
接下来,编写Python脚本来计算链下数据的哈希值,存储这个哈希值到智能合约,并验证它。
from web3 import Web3
import hashlib
# 连接到以太坊节点
w3 = Web3(Web3.HTTPProvider('https://rinkeby.infura.io/v3/YOUR_INFURA_PROJECT_ID'))
# 智能合约地址和ABI
contract_address = '0xYourContractAddress'
contract_abi = json.loads('[YOUR_CONTRACT_ABI]')
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
# 链下数据
data = "This is an example of off-chain data."
data_hash = hashlib.sha256(data.encode()).hexdigest()
# 发送交易存储数据哈希到智能合约
# 注意: 这里需要账户和私钥进行交易签名
account = w3.eth.account.privateKeyToAccount('YourPrivateKey')
nonce = w3.eth.getTransactionCount(account.address)
tx = contract.functions.storeDataHash(data_hash).buildTransaction({
'chainId': 4, # Rinkeby测试网络的chain ID
'gas': 200000,
'gasPrice': w3.toWei('50', 'gwei'),
'nonce': nonce,
})
signed_tx = w3.eth.account.sign_transaction(tx, 'YourPrivateKey')
tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
# 等待交易被挖矿
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
# 验证数据哈希
verified = contract.functions.verifyDataHash(data_hash).call()
print(f"Data hash verified: {verified}")
在这个脚本中,替换YOUR_INFURA_PROJECT_ID
、0xYourContractAddress
、[YOUR_CONTRACT_ABI]
和YourPrivateKey
为你自己的值。
结论
通过这个案例,我们展示了如何将链下数据的哈希值存储到以太坊智能合约中,并实现了一个机制来验证链下数据的完整性和真实性。这种方法结合了区块链的不可篡改性和链下数据存储的灵活性与成本效益,为开发复杂的区块链应用提供了一种有效的数据管理策略。
3.3.3 拓展案例 1:使用 IPFS 存储链下数据
IPFS(InterPlanetary File System)是一个分布式文件系统,它允许存储和访问大量的数据,同时提供了一个唯一的哈希值用于数据的访问和验证。IPFS是链下数据存储的理想选择,因为它提供了去中心化和持久性,同时能够通过链上存储的哈希值来验证数据的完整性。以下案例演示了如何使用Python将数据存储到IPFS,并将对应的哈希值记录在以太坊智能合约中。
步骤1: 安装IPFS和Python客户端
首先,确保你的系统中安装了IPFS。你可以从IPFS官网下载并安装IPFS。
然后,安装Python的IPFS客户端库:
pip install ipfshttpclient
步骤2: 启动IPFS守护进程
在终端运行以下命令来启动IPFS守护进程:
ipfs daemon
步骤3: 使用Python脚本存储数据到IPFS
接下来,我们将使用Python脚本来存储数据到IPFS,并获取数据的唯一哈希值。
import ipfshttpclient
# 连接到本地IPFS节点
client = ipfshttpclient.connect('/ip4/127.0.0.1/tcp/5001/http')
# 要存储到IPFS的数据
data = "Hello, IPFS and Ethereum!"
# 添加数据到IPFS
res = client.add_str(data)
ipfs_hash = res
print(f"Data stored on IPFS with hash: {ipfs_hash}")
步骤4: 将IPFS哈希值存储到以太坊智能合约
现在,我们有了存储在IPFS上的数据哈希值,下一步是将这个哈希值存储到以太坊智能合约中,以便链上验证。
假设我们已经有一个智能合约,它有一个函数可以存储和验证IPFS哈希值。我们将使用Web3.py来与以太坊交互。
from web3 import Web3
# 连接到以太坊
w3 = Web3(Web3.HTTPProvider('https://rinkeby.infura.io/v3/YOUR_INFURA_PROJECT_ID'))
# 智能合约地址和ABI
contract_address = '0xYourContractAddress'
contract_abi = '[YOUR_CONTRACT_ABI]'
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
# 账户和私钥
account = '0xYourAccountAddress'
private_key = 'YourPrivateKey'
# 构建交易
nonce = w3.eth.getTransactionCount(account)
tx = contract.functions.storeIPFSHash(ipfs_hash).buildTransaction({
'chainId': 4, # Rinkeby测试网络的chain ID
'gas': 200000,
'gasPrice': w3.toWei('50', 'gwei'),
'nonce': nonce,
})
# 签名交易
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
# 发送交易
tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
# 获取交易哈希值
print(f"Transaction hash: {tx_hash.hex()}")
在这个脚本中,替换YOUR_INFURA_PROJECT_ID
、0xYourContractAddress
、[YOUR_CONTRACT_ABI]
、0xYourAccountAddress
和YourPrivateKey
为你自己的值。
结论
通过这个案例,我们演示了如何结合使用IPFS和以太坊来存储和验证大量的链下数据。这种方法利用了IPFS的分布式存储能力和以太坊智能合约的不可篡改性,为构建去中心化应用提供了一个高效、安全的数据存储和验证解决方案。
3.3.4 拓展案例 2:链下数据的链上验证
链下数据的链上验证是确保数据完整性和真实性的关键机制,特别是在去中心化应用(DApp)中处理大量数据时。这个过程通常涉及两个步骤:首先将数据存储在链下,然后将数据的哈希值或数字指纹存储在链上。当需要验证数据时,可以重新计算其哈希值并与链上存储的哈希值进行比对。
在本案例中,我们将使用Python演示如何实现链下数据的链上验证,包括如何通过智能合约存储和验证数据哈希。
步骤1: 智能合约编写
假设我们有一个简单的智能合约,用于存储和验证数据哈希:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract DataVerifier {
mapping(bytes32 => bool) private hashes;
// 事件,用于记录数据哈希已存储
event HashStored(bytes32 dataHash);
// 存储数据哈希
function storeHash(bytes32 dataHash) public {
require(!hashes[dataHash], "Hash already stored.");
hashes[dataHash] = true;
emit HashStored(dataHash);
}
// 验证数据哈希
function verifyHash(bytes32 dataHash) public view returns (bool) {
return hashes[dataHash];
}
}
步骤2: 部署智能合约
使用你偏好的工具(如Truffle、Hardhat或Remix)将智能合约部署到以太坊网络(主网或测试网)。
步骤3: 使用Python存储和验证数据哈希
首先,确保安装了Web3.py库:
pip install web3
接下来,我们将计算链下数据的哈希值,通过智能合约存储这个哈希值,然后验证它。
from web3 import Web3
import hashlib
# 连接到以太坊
w3 = Web3(Web3.HTTPProvider('https://rinkeby.infura.io/v3/YOUR_INFURA_PROJECT_ID'))
# 智能合约地址和ABI
contract_address = '0xYourContractAddress'
contract_abi = '[YOUR_CONTRACT_ABI]'
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
# 链下数据
data = "This is an example of off-chain data."
data_hash = hashlib.sha256(data.encode()).hexdigest()
# 转换哈希值为bytes32
data_hash_bytes32 = w3.toBytes(hexstr=data_hash)
# 发送交易存储数据哈希到智能合约
account = '0xYourAccountAddress'
private_key = 'YourPrivateKey'
nonce = w3.eth.getTransactionCount(account)
tx = contract.functions.storeHash(data_hash_bytes32).buildTransaction({
'chainId': 4, # Rinkeby测试网络的chain ID
'gas': 2000000,
'gasPrice': w3.toWei('50', 'gwei'),
'nonce': nonce,
})
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
print(f"Transaction hash: {tx_hash.hex()}")
# 等待交易被挖掘
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
# 验证数据哈希
verified = contract.functions.verifyHash(data_hash_bytes32).call()
print(f"Data hash verified: {verified}")
在这个脚本中,替换YOUR_INFURA_PROJECT_ID
、0xYourContractAddress
、[YOUR_CONTRACT_ABI]
、0xYourAccountAddress
和YourPrivateKey
为你自己的值。
结论
这个案例展示了如何利用智能合约在链上存储和验证链下数据的哈希值。这种机制增加了数据处理的透明度和安全性,同时依然能够利用链下存储的高效性和低成本。这对于那些需要处理大量数据的去中心化应用尤其有用,例如在供应链管理、版权认证和数据市场等领域。
通过这些案例,我们探讨了链上与链下数据的不同用途和如何将它们结合使用。存储关键验证信息到链上,同时将大量数据存储到链下,是一种既能利用区块链技术的安全性和透明度,又能有效管理成本和性能的方法。