Rust地址处理库cw-address-like的使用:支持类地址字符串的高效解析与验证

Rust地址处理库cw-address-like的使用:支持类地址字符串的高效解析与验证

CW Address Like

这个crate提供了一个AddressLike trait,用于标记可以在CosmWasm中作为地址使用的类型,即Stringcosmwasm_std::Addr

背景

在CosmWasm中,通常有两种类型用于表示地址:

  • String - 表示一个未验证的地址,用于合约API中,如消息和查询响应
  • cosmwasm_std::Addr - 表示一个验证过的地址,用于合约内部逻辑

当合约从消息中接收到一个地址(作为String)时,不能简单地假设它是有效的。相反,应该使用deps.api.addr_validate方法进行验证,该方法返回一个Addr。然后合约可以在业务逻辑中使用这个Addr或者将其保存在存储中。

同样,当在查询响应中返回地址时,合约也应该将Addr转换回String

问题

当我们需要定义一个既用于API又用于内部逻辑的结构体或枚举时,问题就出现了。例如,考虑一个合约在其存储中保存一个"config",其中使用Addr来表示合约所有者的地址,同时也提供一个查询方法来获取配置,该方法使用String

在这种情况下,开发者可能有两种做法:

第一种是定义两种类型,每种情况一种:

struct Config {
    pub owner: Addr,
}

struct ConfigResponse {
    pub owner: String,
}

这种方法可行,但当配置包含更多字段时会有些繁琐。

另一种方法是定义一个包含泛型的单一类型:

struct Config<T> {
    pub owner: T,
}

然后在API中使用Config<String>,在内部逻辑中使用Config<Addr>

这种方法的主要缺点是T没有限制。理论上,任何类型都可以作为T插入,不限于StringAddr

如何使用

在这个crate中我们提供了一个AddressLike trait,它简单地定义为:

pub trait AddressLike {}

impl AddressLike for Addr {}
impl AddressLike for String {}

开发者可以这样定义他们的类型:

struct Config<T: AddressLike> {
    pub owner: T,
}

这样就限制了只有StringAddr可以用作T

完整示例

下面是一个完整的使用示例:

use cw_address_like::AddressLike;
use cosmwasm_std::Addr;

// 定义一个通用的配置结构体
struct Config<T: AddressLike> {
    pub owner: T,
    pub admin: T,
    pub description: String,
}

// 用于存储的内部配置
struct StorageConfig {
    config: Config<Addr>,
}

// 用于查询响应的配置
struct QueryConfig {
    config: Config<String>,
}

impl StorageConfig {
    pub fn new(owner: Addr, admin: Addr, description: String) -> Self {
        Self {
            config: Config {
                owner,
                admin,
                description,
            }
        }
    }
    
    // 将存储配置转换为查询配置
    pub fn to_query(&self) -> QueryConfig {
        QueryConfig {
            config: Config {
                owner: self.config.owner.to_string(),
                admin: self.config.admin.to_string(),
                description: self.config.description.clone(),
            }
        }
    }
}

// 合约消息处理示例
fn handle_message(
    deps: DepsMut,
    owner: String,  // 从消息中接收的未验证地址
    admin: String,  // 从消息中接收的未验证地址
    description: String,
) -> Result<Response, ContractError> {
    // 验证地址
    let owner_addr = deps.api.addr_validate(&owner)?;
    let admin_addr = deps.api.addr_validate(&admin)?;
    
    // 创建存储配置
    let config = StorageConfig::new(owner_addr, admin_addr, description);
    
    // 存储配置...
    
    Ok(Response::new())
}

// 合约查询处理示例
fn handle_query(
    deps: Deps,
) -> Result<QueryConfig, ContractError> {
    // 从存储中读取配置
    let storage_config = read_config_from_storage(deps.storage)?;
    
    // 转换为查询配置
    Ok(storage_config.to_query())
}

许可证

此crate在版本1.0.3或之前的内容发布在GNU Affero General Public License v3或更高版本下;该版本之后的内容发布在Apache-2.0许可证下。


1 回复

Rust地址处理库 cw-address-like 使用指南

cw-address-like 是一个专门用于处理类地址字符串的Rust库,提供高效的解析和验证功能,特别适合区块链地址、哈希值等类地址格式的处理。

主要特性

  • 轻量级高性能的地址解析
  • 灵活的验证规则配置
  • 支持多种编码格式(Base16, Base58, Bech32等)
  • 提供标准化的地址格式化输出

安装方法

Cargo.toml中添加依赖:

[dependencies]
cw-address-like = "0.3.0"

基本使用方法

1. 简单验证地址

use cw_address_like::AddressLike;

fn main() {
    let addr = "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02";
    
    if addr.is_address_like() {
        println!("有效的类地址字符串");
    } else {
        println!("无效的地址格式");
    }
}

2. 带前缀的地址验证

use cw_address_like::{AddressLike, Prefix};

fn main() {
    let addr = "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02";
    let prefix = Prefix::new("cosmos");
    
    match addr.validate_with_prefix(&prefix) {
        Ok(_) => println!("地址格式和前缀都有效"),
        Err(e) => println!("验证失败: {}", e),
    }
}

3. 解析地址获取详细信息

use cw_address_like::AddressLike;

fn main() {
    let addr = "0x71C7656EC7ab88b098defB751B7401B5f6d8976F";
    
    if let Some(info) = addr.parse_address_like() {
        println!("地址类型: {:?}", info.address_type());
        println!("原始数据: {:?}", info.raw_data());
        println!("格式化输出: {}", info.to_string());
    }
}

高级用法

自定义验证规则

use cw_address_like::{AddressLike, ValidationOptions};

fn main() {
    let options = ValidationOptions::new()
        .with_min_length(20)
        .with_max_length(40)
        .with_allowed_chars("0123456789abcdefABCDEF");
    
    let addr = "0x1a2b3c4d5e";
    
    match addr.validate_with_options(&options) {
        Ok(_) => println!("符合自定义验证规则"),
        Err(e) => println!("验证失败: {}", e),
    }
}

Bech32地址处理

use cw_address_like::{Bech32Address, Prefix};

fn main() {
    let prefix = Prefix::new("cosmos");
    let addr = Bech32Address::new(
        "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02",
        &prefix
    ).unwrap();
    
    println!("HRP: {}", addr.hrp());
    println!("数据部分: {:?}", addr.data());
}

性能提示

对于批量地址验证,建议使用AddressLikeBatchValidator以提高性能:

use cw_address_like::{AddressLikeBatchValidator, Prefix};

fn main() {
    let prefix = Prefix::new("cosmos");
    let mut validator = AddressLikeBatchValidator::new().with_prefix(&prefix);
    
    let addresses = vec![
        "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02",
        "cosmos1invalidaddress",
        "cosmos1anothervalidone",
    ];
    
    let results = validator.validate_all(&addresses);
    
    for (addr, result) in addresses.iter().zip(results.iter()) {
        println!("{}: {}", addr, if *result { "有效" } else { "无效" });
    }
}

完整示例

下面是一个完整的示例,展示了如何使用cw-address-like库进行地址的创建、验证和解析:

use cw_address_like::{
    AddressLike, 
    Prefix, 
    Bech32Address, 
    ValidationOptions,
    AddressLikeBatchValidator
};

fn main() {
    // 1. 简单地址验证
    let cosmos_addr = "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02";
    println!("验证地址 {}: {}", cosmos_addr, cosmos_addr.is_address_like());
    
    // 2. 带前缀的地址验证
    let prefix = Prefix::new("cosmos");
    match cosmos_addr.validate_with_prefix(&prefix) {
        Ok(_) => println!("前缀验证通过"),
        Err(e) => println!("前缀验证失败: {}", e),
    }
    
    // 3. 解析以太坊地址
    let eth_addr = "0x71C7656EC7ab88b098defB751B7401B5f6d8976F";
    if let Some(info) = eth_addr.parse_address_like() {
        println!("解析以太坊地址成功:");
        println!("类型: {:?}", info.address_type());
        println!("原始数据: {:?}", info.raw_data());
    }
    
    // 4. 自定义验证规则
    let options = ValidationOptions::new()
        .with_min_length(20)
        .with_max_length(40)
        .with_allowed_chars("0123456789abcdefABCDEF");
    
    let test_addr = "0x1a2b3c4d5e";
    match test_addr.validate_with_options(&options) {
        Ok(_) => println!("自定义规则验证通过"),
        Err(e) => println!("自定义规则验证失败: {}", e),
    }
    
    // 5. Bech32地址处理
    let bech32_addr = Bech32Address::new(cosmos_addr, &prefix).unwrap();
    println!("Bech32地址解析:");
    println!("HRP: {}", bech32_addr.hrp());
    println!("数据: {:?}", bech32_addr.data());
    
    // 6. 批量验证
    let mut validator = AddressLikeBatchValidator::new().with_prefix(&prefix);
    let addresses = vec![
        "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02",
        "cosmos1invalidaddress",
        "cosmos1anothervalidone",
    ];
    
    let results = validator.validate_all(&addresses);
    for (addr, result) in addresses.iter().zip(results.iter()) {
        println!("地址 {} 验证结果: {}", addr, if *result { "有效" } else { "无效" });
    }
}

这个完整示例演示了cw-address-like库的主要功能,包括地址验证、前缀检查、地址解析、自定义规则验证、Bech32地址处理以及批量验证等功能。

回到顶部