Ohhnews

分类导航

$ cd ..
foojay原文

Java实现加密货币地址离线验证

#java#区块链#地址验证#加密资产#离线校验

后端验证通常从一些简单问题开始:

输入是否为空?是否符合预期结构?能否被解析?是否属于所选领域?

加密货币钱包地址也不例外,只不过不同链上的格式各不相同,简单的正则表达式往往不足以胜任。

如果 Java 后端接受加密提现地址、地址簿条目、CSV 导入、支持工具输入或交易预检请求,它应该在调用 RPC 节点、浏览器、交易所 API 或内部资金流转系统之前,先拒绝明显无效的地址。

这第一层验证可以在离线状态下完成。

本文介绍哪些内容可以在本地验证、哪些内容无法在离线状态下证明,以及如何使用 Chainwarden(一个发布在 Maven Central 上的开源库)在 Java 中实现一个实用的验证层。

哪些内容可以在离线状态下验证?

离线验证检查的是完全包含在地址字符串本身的属性。

例如:

  • 语法
  • 允许的字符集
  • 编码长度
  • 解码后的字节长度
  • 网络前缀
  • 地址版本
  • 校验和
  • EVM 地址的 EIP-55 大小写

这些检查是确定性的,不需要网络访问。

因此它们非常适合用于:

  • 请求验证
  • 表单验证
  • 提现预检
  • 地址簿验证
  • 导入任务
  • 支持工具
  • 日志和诊断

哪些内容无法在离线状态下验证?

离线验证并不是完整的安全检查。

它无法证明:

  • 账户是否存在
  • 余额
  • 所有权
  • 智能合约状态
  • 是否能够接收代币
  • 托管地址是否需要备注或目的地标签
  • 交易所是否接受转账

例如,XRP 在许多托管流程中都有目的地标签要求。离线验证器可以检查 XRP 地址格式是否有效,但无法知道接收平台是否要求该特定存款附带标签。

这一区别在生产系统中非常重要。

离线验证应该是第一道门槛,而不是最终决策。

添加 Chainwarden

从 Maven Central 添加高层门面依赖:

$ xml
<dependency>
    <groupId>org.chainwarden</groupId>
    <artifactId>chainwarden-core</artifactId>
    <version>0.1.0</version>
</dependency>

Gradle 方式:

$ kotlin
implementation("org.chainwarden:chainwarden-core:0.1.0")

验证地址

主要 API 是:

$ java
AddressValidators.validate(chain, address)

以下是一个比特币示例:

$ java
import org.chainwarden.AddressValidators;
import org.chainwarden.Chain;
import org.chainwarden.common.validation.AddressValidationResult;

public class ValidateBitcoinAddress {
    public static void main(String[] args) {
        AddressValidationResult result = AddressValidators.validate(
                Chain.BITCOIN,
                "bc1qpjult34k9spjfym8hss2jrwjgf0xjf40ze0pp8"
        );

        if (result.valid()) {
            System.out.println("Valid " + result.chain() + " address");
            System.out.println("Format: " + result.format());
        } else {
            System.out.println("Invalid address");
            System.out.println("Error: " + result.error());
            System.out.println("Reason: " + result.reason());
        }
    }
}

可能的输出:

Valid bitcoin address
Format: BECH32

结果包含:

  • valid() —— 验证是否成功
  • chain() —— 规范的链 ID
  • format() —— 检测到的地址格式
  • error() —— 稳定的机器可读错误码
  • reason() —— 人类可读的诊断信息

返回结构化结果在生产环境中非常有用,因为验证失败可以被记录、计数、转换为面向用户的消息,或映射到 API 错误响应。

按链 ID 验证

许多系统会从 API 请求、数据库字段或配置文件中接收字符串形式的链名称。

Chainwarden 也接受规范 ID 和别名:

$ java
import org.chainwarden.AddressValidators;
import org.chainwarden.common.validation.AddressValidationResult;

public class ValidateByChainId {
    public static void main(String[] args) {
        AddressValidationResult result = AddressValidators.validate(
                "ethereum",
                "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
        );

        System.out.println(result.valid());
        System.out.println(result.chain());
        System.out.println(result.format());
    }
}

输出:

true
ethereum
EIP55

例如,BNB Smart Chain 可以使用 bnb-smart-chainbscBNB_SMART_CHAIN 进行验证:

$ java
boolean valid = AddressValidators.isValid(
        "bsc",
        "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
);

映射验证错误

对于快速检查来说,布尔值已经足够,但应用程序通常需要更好的反馈信息。

$ java
import org.chainwarden.AddressValidators;
import org.chainwarden.common.validation.AddressValidationResult;

public class ValidationMessage {
    public static String messageFor(String chain, String address) {
        AddressValidationResult result = AddressValidators.validate(chain, address);

        if (result.valid()) {
            return "Address is valid";
        }

        return switch (result.error()) {
            case UNSUPPORTED_CHAIN -> "This chain is not supported yet";
            case EMPTY -> "Address is required";
            case SURROUNDING_WHITESPACE -> "Remove leading or trailing spaces";
            case INVALID_CHECKSUM -> "Address checksum is invalid";
            case INVALID_PREFIX -> "Address prefix does not match the selected chain";
            case INVALID_LENGTH -> "Address length is invalid";
            case INVALID_CHARACTER -> "Address contains invalid characters";
            case INVALID_WORKCHAIN -> "TON workchain is not supported";
            case INVALID_ENCODING -> "Address encoding is invalid";
            case INVALID_FORMAT -> "Address format is invalid";
            case NONE -> "Address is valid";
        };
    }
}

这样既能让验证层保持确定性,又能在验证失败时向 API 消费者提供有用的原因。

支持的格式

Chainwarden 目前支持:

格式
BitcoinBase58Check、Bech32、Bech32m
EthereumEVM 0x 地址、EIP-55
BNB Smart ChainEVM 0x 地址、EIP-55
BaseEVM 0x 地址、EIP-55
Arbitrum OneEVM 0x 地址、EIP-55
Polygon PoSEVM 0x 地址、EIP-55
Avalanche C-ChainEVM 0x 地址、EIP-55
TRON带 TRON 前缀的 Base58Check
SolanaBase58 编码的 32 字节公钥
XRP Ledger经典地址、主网 X-address
TON原始格式和用户友好格式

EVM 链共享相同的地址格式:0x 前缀加 20 字节,编码为 40 个十六进制字符。混合大小写地址会通过 EIP-55 进行校验。

结论

加密货币地址验证非常适合作为简单、确定性的基础设施。第一层验证不应该需要网络调用。它应该解码地址、检查本地规则、返回结构化结果,并清楚说明自身的局限性。

Chainwarden 为 Java 应用提供了这一层验证,同时刻意不承诺任何无法在离线状态下证明的内容。

项目链接:

原文发布于 Offline Crypto Address Validation in Java,首发于 foojay