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(())
}

最佳实践

  1. 重用客户端实例以减少连接开销
  2. 对频繁调用的数据实现缓存
  3. 使用异步API提高性能
  4. 在生产环境中添加适当的重试逻辑
  5. 监控API调用频率以避免被限流

starknet_api库为Rust开发者提供了强大而灵活的工具来构建StarkNet应用,结合Rust的安全性和性能优势,是开发高质量StarkNet dApps的理想选择。

回到顶部