Rust StarkNet API库starknet_api的使用:与StarkNet区块链交互的高效开发工具
Rust StarkNet API库starknet_api的使用:与StarkNet区块链交互的高效开发工具
关于starknet_api
starknet_api
是一个用Rust编写的StarkNet通用类型定义库。
许可证
该项目采用Apache 2.0许可证。
安装
在项目目录中运行以下Cargo命令:
cargo add starknet_api
或者在Cargo.toml中添加以下行:
starknet_api = "0.11.0"
完整示例代码
use starknet_api::{
block::{BlockHash, BlockNumber},
core::{ContractAddress, Nonce},
hash::StarkFelt,
state::ThinStateDiff,
transaction::{
DeployTransaction, InvokeTransaction, Transaction, TransactionHash,
TransactionReceipt,
},
};
// 示例:创建StarkNet交易
fn create_transaction() -> Transaction {
// 创建一个调用交易
Transaction::Invoke(InvokeTransaction {
// 交易哈希
transaction_hash: TransactionHash(StarkFelt::from(123456789u64)),
// 合约地址
contract_address: ContractAddress::from(StarkFelt::from(987654321u64)),
// 调用数据
calldata: vec![StarkFelt::from(1u64), StarkFelt::from(2u64)],
// 最大费用
max_fee: 1000u64,
// 签名
signature: vec![StarkFelt::from(111u64), StarkFelt::from(222u64)],
// 随机数
nonce: Nonce(StarkFelt::from(5u64)),
})
}
// 示例:处理区块数据
fn process_block(block_number: BlockNumber, block_hash: BlockHash) {
println!(
"处理区块 #{} 哈希: {:?}",
block_number.0,
block_hash.0
);
// 这里可以添加处理区块数据的逻辑
// 例如查询状态差异、交易等
}
// 示例:解析交易收据
fn parse_receipt(receipt: TransactionReceipt) {
println!("交易状态: {:?}", receipt.status);
println!("区块哈希: {:?}", receipt.block_hash);
println!("交易索引: {}", receipt.transaction_index);
}
fn main() {
// 创建示例交易
let tx = create_transaction();
println!("已创建交易: {:?}", tx);
// 示例区块处理
let block_num = BlockNumber(123);
let block_hash = BlockHash(StarkFelt::from(987654321u64));
process_block(block_num, block_hash);
// 示例交易收据
let receipt = TransactionReceipt {
transaction_hash: TransactionHash(StarkFelt::from(123456789u64)),
status: starknet_api::transaction::TransactionStatus::AcceptedOnL2,
block_hash: BlockHash(StarkFelt::from(987654321u64)),
block_number: BlockNumber(123),
transaction_index: 0,
};
parse_receipt(receipt);
}
扩展示例代码
use starknet_api::{
block::{BlockHash, BlockNumber, BlockTimestamp},
core::{ClassHash, ContractAddress, Nonce},
hash::StarkFelt,
state::{StateDiff, StorageKey, ThinStateDiff},
transaction::{
DeclareTransaction, DeployAccountTransaction, DeployTransaction,
InvokeTransaction, Transaction, TransactionHash, TransactionReceipt,
TransactionStatus,
},
};
// 扩展示例:处理完整的StarkNet状态差异
fn process_state_diff(state_diff: ThinStateDiff) {
println!("处理状态差异:");
// 处理部署的合约
for (address, class_hash) in &state_diff.deployed_contracts {
println!("部署合约: {:?}, 类哈希: {:?}", address, class_hash);
}
// 处理存储更新
for (address, storage_updates) in &state_diff.storage_diffs {
println!("合约地址: {:?}", address);
for (key, value) in storage_updates {
println!(" 存储键: {:?} -> 值: {:?}", key, value);
}
}
}
// 扩展示例:声明交易
fn create_declare_transaction() -> Transaction {
Transaction::Declare(DeclareTransaction {
transaction_hash: TransactionHash(StarkFelt::from(1122334455u64)),
sender_address: ContractAddress::from(StarkFelt::from(5566778899u64)),
max_fee: 2000u64,
signature: vec![
StarkFelt::from(333u64),
StarkFelt::from(444u64),
],
nonce: Nonce(StarkFelt::from(6u64)),
contract_class: vec![1, 2, 3, 4], // 简化的合约类数据
})
}
// 扩展示例:完整区块信息处理
fn process_full_block(
block_number: BlockNumber,
block_hash: BlockHash,
timestamp: BlockTimestamp,
transactions: Vec<Transaction>,
) {
println!("\n处理完整区块信息:");
println!("区块号: {}", block_number.0);
println!("区块哈希: {:?}", block_hash.0);
println!("时间戳: {}", timestamp.0);
for (index, tx) in transactions.iter().enumerate() {
println!("交易 {}: {:?}", index, tx);
}
}
fn main() {
// 创建并处理状态差异
let state_diff = ThinStateDiff {
deployed_contracts: vec![(
ContractAddress::from(StarkFelt::from(111111111u64)),
ClassHash(StarkFelt::from(222222222u64)),
)],
storage_diffs: vec![(
ContractAddress::from(StarkFelt::from(333333333u64)),
vec![(
StorageKey(StarkFelt::from(444444444u64)),
StarkFelt::from(555555555u64),
)],
)],
..Default::default()
};
process_state_diff(state_diff);
// 创建声明交易
let declare_tx = create_declare_transaction();
println!("\n已创建声明交易: {:?}", declare_tx);
// 处理完整区块
let block_num = BlockNumber(456);
let block_hash = BlockHash(StarkFelt::from(999888777u64));
let timestamp = BlockTimestamp(1630000000);
let transactions = vec![
create_transaction(),
declare_tx,
];
process_full_block(block_num, block_hash, timestamp, transactions);
}
文档
可以在docs.rs上查看完整文档。
1 回复
Rust StarkNet API库starknet_api的使用:与StarkNet区块链交互的高效开发工具
介绍
starknet_api
是一个Rust库,用于与StarkNet区块链进行交互。StarkNet是以太坊上的Layer 2扩容解决方案,使用ZK-Rollup技术实现高吞吐量和低交易成本。这个库提供了与StarkNet节点通信的API接口,使开发者能够构建去中心化应用(dApps)、查询区块链数据、发送交易等。
主要特性
- 完整的StarkNet JSON-RPC API实现
- 类型安全的请求和响应数据结构
- 异步/同步请求支持
- 合约交互工具
- 交易构造与签名
- 事件监听功能
安装
在Cargo.toml中添加依赖:
[dependencies]
starknet_api = "0.1"
tokio = { version = "1.0", features = ["full"] } # 如果需要异步支持
基本使用方法
1. 连接到StarkNet节点
use starknet_api::StarknetApiClient;
#[tokio::main]
async fn main() {
// 连接到本地StarkNet节点
let client = StarknetApiClient::new("http://localhost:9545").unwrap();
// 或者连接到公共节点
// let client = StarknetApiClient::new("https://starknet-mainnet.infura.io/v3/YOUR_API_KEY").unwrap();
}
2. 查询区块链信息
async fn get_block_info(client: &StarknetApiClient) {
// 获取最新区块号
let block_number = client.block_number().await.unwrap();
println!("Latest block number: {}", block_number);
// 获取特定区块信息
let block = client.get_block_by_number(block_number).await.unwrap();
println!("Block info: {:?}", block);
}
3. 调用合约
use starknet_api::contract::{ContractCall, Felt};
async fn call_contract(client: &StarknetApiClient) {
let contract_address = Felt::from_hex("0x123...").unwrap(); // 合约地址
let entry_point_selector = Felt::from_hex("0x234...").unwrap(); // 函数选择器
let call = ContractCall {
contract_address,
entry_point_selector,
calldata: vec![Felt::from(42u64)], // 函数参数
};
let result = client.call_contract(call).await.unwrap();
println!("Call result: {:?}", result);
}
4. 发送交易
use starknet_api::transaction::{Transaction, InvokeFunction};
async fn send_transaction(client: &StarknetApiClient) {
let tx = Transaction::InvokeFunction(InvokeFunction {
contract_address: Felt::from_hex("0x123...").unwrap(),
entry_point_selector: Felt::from_hex("0x234...").unwrap(),
calldata: vec![Felt::from(42u64)],
max_fee: Felt::from(100000u64),
signature: vec![/* 签名数据 */],
nonce: Felt::from(1u64),
});
let tx_hash = client.add_transaction(tx).await.unwrap();
println!("Transaction hash: {:?}", tx_hash);
}
5. 监听事件
use starknet_api::event::{EventFilter, Event};
async fn listen_events(client: &StarkNetApiClient) {
let filter = EventFilter {
from_block: Some(1000),
to_block: Some(2000),
address: Some(Felt::from_hex("0x123...").unwrap()),
keys: vec![vec![Felt::from_hex("0x456...").unwrap()]],
};
let events = client.get_events(filter).await.unwrap();
for event in events {
println!("Event: {:?}", event);
}
}
高级用法
批量请求
use starknet_api::batch::BatchRequest;
async fn batch_requests(client: &StarknetApiClient) {
let batch = BatchRequest::new()
.add_block_number()
.add_block_by_number(1000)
.add_contract_call(/* 合约调用 */);
let results = client.batch(batch).await.unwrap();
println!("Batch results: {:?}", results);
}
错误处理
use starknet_api::error::StarknetApiError;
async fn handle_errors(client: &StarknetApiClient) {
match client.block_number().await {
Ok(number) => println!("Block number: {}", number),
Err(StarknetApiError::RpcError(e)) => {
eprintln!("RPC error: {}", e);
},
Err(e) => {
eprintln!("Other error: {:?}", e);
}
}
}
完整示例代码
下面是一个完整的示例,展示了如何使用starknet_api库与StarkNet区块链进行交互:
use starknet_api::{
StarknetApiClient,
contract::{ContractCall, Felt},
transaction::{Transaction, InvokeFunction},
event::{EventFilter, Event},
batch::BatchRequest,
error::StarknetApiError
};
use tokio;
#[tokio::main]
async fn main() {
// 1. 连接到StarkNet节点
let client = match StarknetApiClient::new("http://localhost:9545") {
Ok(client) => client,
Err(e) => {
eprintln!("Failed to connect to StarkNet node: {:?}", e);
return;
}
};
// 2. 查询区块链信息
match query_blockchain_info(&client).await {
Ok(_) => (),
Err(e) => eprintln!("Error querying blockchain info: {:?}", e),
}
// 3. 调用合约
match call_example_contract(&client).await {
Ok(_) => (),
Err(e) => eprintln!("Error calling contract: {:?}", e),
}
// 4. 发送交易
match send_example_transaction(&client).await {
Ok(_) => (),
Err(e) => eprintln!("Error sending transaction: {:?}", e),
}
// 5. 监听事件
match listen_for_events(&client).await {
Ok(_) => (),
Err(e) => eprintln!("Error listening for events: {:?}", e),
}
// 6. 批量请求
match execute_batch_requests(&client).await {
Ok(_) => (),
Err(e) => eprintln!("Error executing batch requests: {:?}", e),
}
}
async fn query_blockchain_info(client: &StarknetApiClient) -> Result<(), StarknetApiError> {
// 获取最新区块号
let block_number = client.block_number().await?;
println!("Latest block number: {}", block_number);
// 获取特定区块信息
let block = client.get_block_by_number(block_number).await?;
println!("Block info: {:?}", block);
Ok(())
}
async fn call_example_contract(client: &StarknetApiClient) -> Result<(), StarknetApiError> {
let contract_address = Felt::from_hex("0x123...").unwrap(); // 替换为实际合约地址
let entry_point_selector = Felt::from_hex("0x234...").unwrap(); // 替换为实际函数选择器
let call = ContractCall {
contract_address,
entry_point_selector,
calldata: vec![Felt::from(42u64)], // 函数参数
};
let result = client.call_contract(call).await?;
println!("Call result: {:?}", result);
Ok(())
}
async fn send_example_transaction(client: &StarknetApiClient) -> Result<(), StarknetApiError> {
let tx = Transaction::InvokeFunction(InvokeFunction {
contract_address: Felt::from_hex("0x123...").unwrap(), // 替换为实际合约地址
entry_point_selector: Felt::from_hex("0x234...").unwrap(), // 替换为实际函数选择器
calldata: vec![Felt::from(42u64)],
max_fee: Felt::from(100000u64),
signature: vec![Felt::from(1u64), Felt::from(2u64)], // 替换为实际签名
nonce: Felt::from(1u64),
});
let tx_hash = client.add_transaction(tx).await?;
println!("Transaction hash: {:?}", tx_hash);
Ok(())
}
async fn listen_for_events(client: &StarknetApiClient) -> Result<(), StarknetApiError> {
let filter = EventFilter {
from_block: Some(1000),
to_block: Some(2000),
address: Some(Felt::from_hex("0x123...").unwrap()), // 替换为实际合约地址
keys: vec![vec![Felt::from_hex("0x456...").unwrap()]], // 替换为实际事件key
};
let events = client.get_events(filter).await?;
for event in events {
println!("Event: {:?}", event);
}
Ok(())
}
async fn execute_batch_requests(client: &StarknetApiClient) -> Result<(), StarknetApiError> {
// 创建合约调用示例
let contract_call = ContractCall {
contract_address: Felt::from_hex("0x123...").unwrap(), // 替换为实际合约地址
entry_point_selector: Felt::from_hex("0x234...").unwrap(), // 替换为实际函数选择器
calldata: vec![Felt::from(42u64)],
};
let batch = BatchRequest::new()
.add_block_number()
.add_block_by_number(1000)
.add_contract_call(contract_call);
let results = client.batch(batch).await?;
println!("Batch results: {:?}", results);
Ok(())
}
最佳实践
- 重用客户端实例以减少连接开销
- 对频繁调用的数据实现缓存
- 使用异步API提高性能
- 在生产环境中添加适当的重试逻辑
- 监控API调用频率以避免被限流
starknet_api
库为Rust开发者提供了强大而灵活的工具来构建StarkNet应用,结合Rust的安全性和性能优势,是开发高质量StarkNet dApps的理想选择。