solana 离线转账的例子

使用场景假设使用用户a向用户b转账,做离线转账,机器1有user_a的私钥user_a.json,$solana-keygennew-ouser_a.json$solanaairdrop10user_a.json$solana-keygenpubkey

一、先理解:Solana 交易的「有效期瓶颈」(Nonce 要解决的核心问题)

Solana 原生交易有一个硬性规则:每笔交易必须包含「最近区块哈希(Recent Blockhash)」,这个哈希对应 Solana 网络最近生成的区块,作用是:

  1. 标记交易的「有效期」:区块哈希仅在约 2 分钟内有效(覆盖几个 Epoch 周期),超过则交易被网络拒绝(提示 Blockhash not found);
  2. 防止交易重放:不同区块哈希对应不同周期,旧区块哈希的交易无法被重复提交。 重放的意思是: 1)如果 用户A 签名了一笔转账给用户B, 2)用户B 收到这笔交易,把这笔交易重新发送到区块链节点。这是一种重放攻击, 因为交易的内容和签名都不用变, 有可能会出现 A 向B 发起了两次转账。 因此重放攻击受损的是签名交易的用户A. 3)solana的原来设计中, 交易里面要加入最近的blockhash, 因此当B重放交易blockhash没有改变, 因为blockhash过期会导致重放不会成功。

这个规则带来两个核心痛点:

  • 痛点 1:交易签名后易过期:比如离线签名交易(硬件钱包 / 冷钱包)、多签交易需要多人确认、跨链交互耗时较长,签名后还没提交,区块哈希就过期了,需重新签名;
  • 痛点 2:批量交易易部分失效:比如空投 1000 笔交易,依次提交时,后面的交易可能因区块哈希过期失败,导致批量操作中断。

Nonce 就是为解决这些痛点而生 —— 它用「Nonce 账户存储的一次性数值」替代「最近区块哈希」,让交易突破有效期限制,同时保留防重放能力。

二、Solana 中使用 Nonce 的核心意义

1. 核心意义:突破交易有效期限制(最主要价值)

使用 Nonce 后,交易不再依赖「时效性极强的区块哈希」,而是绑定到 Nonce 账户 中的唯一一次性数值:

  • 只要 Nonce 未被消耗,预签名的交易可以「长期有效」(几小时 / 几天甚至更久),无需担心区块哈希过期;
  • 尤其适合「离线签名交易」(比如硬件钱包冷签、批量预签名空投交易)、「多签交易」(多人确认耗时超过 2 分钟)等场景。

2. 关键意义:防止交易重放攻击(安全保障)

Nonce 是「一次性」的:

  • 当绑定 Nonce 的交易被网络确认后,Nonce 账户中的 nonce 值会自动更新(相当于「消耗」了该 nonce);
  • 同一个 nonce 对应的交易无法被重复提交,即使交易数据被恶意节点截取,也无法重放,避免资产被盗。

3. 附加意义:保障批量 / 原子交易的稳定性

对于需要批量提交的交易(如空投、批量转账),可以将多笔交易绑定到同一个 Nonce:

  • 只有所有交易都被确认,Nonce 才会被消耗;若某一笔交易失败,Nonce 不会被消耗,可复用该 Nonce 重新提交全部交易,确保「要么全部成功,要么全部重试」,避免批量操作部分失效。

三、使用案例

假设使用用户a 向用户b 转账 ,做离线转账,

虽然 anza.xyz 文档 给出的离线签名,但是执行例子会有问题, 我这里给出一个可用的例子

注意发起交易签名的用户A ,同时拥有nonce账户。 只有A签名后,nonce值会变化。

机器1 有 user_a 的私钥 user_a.json,

$ solana-keygen new -o user_a.json
$ solana airdrop 10 user_a.json

$ solana-keygen pubkey user_a.json
5PXGnujgn4krEznEg7QydU8YLEVJKfFEyJ46z3oZKRPt
机器1 知道 两个用户的公约USER_A,USER_B

创建nonce account

solana-keygen new -o nonce.json
solana create-nonce-account nonce.json 0.1

solana-keygen pubkey nonce.json

机器2 有user_b.json,

机器1 知道 两个用户的公约USER_A,USER_B

$ solana-keygen new -o user_b.json

$ solana-keygen pubkey user_b.json
DmpyfL7ZQCETqixTWVNEX44QusrezjmQDzAZg3cQoWUf

两个机器都配置公用地址

export USER_A=5PXGnujgn4krEznEg7QydU8YLEVJKfFEyJ46z3oZKRPt
export USER_B=DmpyfL7ZQCETqixTWVNEX44QusrezjmQDzAZg3cQoWUf
export NONCE=ZJuCQkpqgXisayp3KCAdPsMuXcCsxvoRo7M8v6zVyfn

离线转账的考虑

假设此时没有solana网络, a 向b 转账 1 sol。 如果a 签名好, 把签名信息和公约

block hash show example

$ solana nonce-account $NONCE

Balance: 0.1 SOL
Minimum Balance Required: 0.00144768 SOL
Nonce blockhash: 4NXnh5LHdEMyFZU6ogWyveaQ64xKYn38hGAKT6CJuYA5
Fee: 5000 lamports per signature
Authority: 5PXGnujgn4krEznEg7QydU8YLEVJKfFEyJ46z3oZKRPt

export BLOCK_HASH (这个需要在线的时候获得)

export BLOCK_HASH=`solana nonce-account $NONCE |grep blockhash |awk -F ': ' '{gsub(/[[:space:]]/, "", $2); print $2}'`
echo "blockhash is [$BLOCK_HASH]"

机器1离线签名交易 transer a =>b

command

$ solana transfer $USER_B 1 \
    --blockhash $BLOCK_HASH \
    --nonce $NONCE \
    --nonce-authority $USER_A \
    --sign-only \
    --keypair user_a.json \
    --from $USER_A  \
    --fee-payer user_a.json \
    > a2b.txt

offline output

 cat a2b.txt

Blockhash: Eo8YJRk6BhzGE2LZ44i1ebTRsFgD3uNvRguHPsPuP4Ww
Signers (Pubkey=Signature):
 5PXGnujgn4krEznEg7QydU8YLEVJKfFEyJ46z3oZKRPt=5psu7QbhJFHcy4uoH7cDgk8jSj1YcxRb96bdSjzd5wDfrA3TiKZjZBhSsA7TzDZa3SD9ytantSPXnk4wv6HJEiZn

define SIGNATURE_A2B

export SIGNATURE_A2B=`cat a2b.txt |grep -A 1 Signers |grep $USER_A `
export SIGNATURE_A2B=`echo $SIGNATURE_A2B|xargs `
echo "SIGNATURE_A2B=[$SIGNATURE_A2B]"

机器1 生成变量, 以便在另一台机器使用 (可以考虑在机器2 扫描机器1 的密钥,获得公用地址和nonce, blockhash)

echo "export BLOCK_HASH=$BLOCK_HASH"
echo "export USER_A=$USER_A"
echo "export USER_B=$USER_B"
echo "export NONCE=$NONCE"
echo "export SIGNATURE_A2B='$SIGNATURE_A2B'"
  • output sample

    export BLOCK_HASH=Eo8YJRk6BhzGE2LZ44i1ebTRsFgD3uNvRguHPsPuP4Ww
    export USER_A=5PXGnujgn4krEznEg7QydU8YLEVJKfFEyJ46z3oZKRPt
    export USER_B=DmpyfL7ZQCETqixTWVNEX44QusrezjmQDzAZg3cQoWUf
    export NONCE=ZJuCQkpqgXisayp3KCAdPsMuXcCsxvoRo7M8v6zVyfn
    export SIGNATURE_A2B='5PXGnujgn4krEznEg7QydU8YLEVJKfFEyJ46z3oZKRPt=5psu7QbhJFHcy4uoH7cDgk8jSj1YcxRb96bdSjzd5wDfrA3TiKZjZBhSsA7TzDZa3SD9ytantSPXnk4wv6HJEiZn'
    

机器2 签名交易提交

执行上面输出的字符串

机器2 提交

solana transfer $USER_B 1 \
--blockhash $BLOCK_HASH \
--nonce $NONCE \
--nonce-authority $USER_A \
--signer $SIGNATURE_A2B \
--from $USER_A \
--fee-payer $USER_A \
--allow-unfunded-recipient
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
科学减肥
科学减肥
0xf54D...aDcd
http://github.com/nextuser