12. 程序交互:读写链上数据

程序交互

程序部署成功后,它就静静地躺在区块链上。为了使用它,我们需要编写客户端代码来构造和发送交易。

假设程序已部署在地址 DVapU9kv...K5E(实际地址以你的部署结果为准)。


1. 写入数据 (Write)

写入数据是一个状态变更操作,必须发送交易 (Transaction) 并支付 Gas 费。

我们使用 Python 的 pxsol 库来演示。你需要构造一个包含所有必要信息的“指令包”:

python
import base64 import pxsol # 开启日志方便调试 pxsol.config.current.log = 1 # 加载你的钱包私钥 (用于签名和付费) ada = pxsol.wallet.Wallet(pxsol.core.PriKey.int_decode(0x01)) def save(user: pxsol.wallet.Wallet, data: bytearray) -> None: prog_pubkey = pxsol.core.PubKey.base58_decode('DVapU9kvtjzFdH3sRd3VDCXjZVkwBR6Cxosx36A5sK5E') # 1. 客户端计算 PDA # 这一步必须和链上 Rust 代码的算法完全一致! # 如果算法对不上,链上验证会失败 (InvalidSeeds) data_pubkey = prog_pubkey.derive_pda(user.pubkey.p) # 2. 构造指令 (Instruction) rq = pxsol.core.Requisition(prog_pubkey, [], bytearray()) # 传入账户列表:[Payer, PDA, System, Rent] rq.account.append(pxsol.core.AccountMeta(user.pubkey, 3)) # 3 = Signer + Writable rq.account.append(pxsol.core.AccountMeta(data_pubkey, 1)) # 1 = Writable rq.account.append(pxsol.core.AccountMeta(pxsol.program.System.pubkey, 0)) # 0 = ReadOnly rq.account.append(pxsol.core.AccountMeta(pxsol.program.SysvarRent.pubkey, 0)) # 传入数据 rq.data = data # 3. 构造并签名交易 tx = pxsol.core.Transaction.requisition_decode(user.pubkey, [rq]) tx.message.recent_blockhash = pxsol.base58.decode( pxsol.rpc.get_latest_blockhash({})['blockhash']) tx.sign([user.prikey]) # 4. 发送并等待确认 txid = pxsol.rpc.send_transaction( base64.b64encode(tx.serialize()).decode(), {}) print(f"Tx Sent: {txid}") pxsol.rpc.wait([txid]) if __name__ == '__main__': save(ada, b'The quick brown fox jumps over the lazy dog')

2. 读取数据 (Read)

读取数据不需要发送交易,也不需要花钱。我们只需要向 RPC 节点发送一个 getAccountInfo 请求。

python
def load(user: pxsol.wallet.Wallet) -> bytearray: prog_pubkey = pxsol.core.PubKey.base58_decode('DVapU9kvtjzFdH3sRd3VDCXjZVkwBR6Cxosx36A5sK5E') # 1. 同样需要先计算 PDA 地址 # 因为我们想知道 "User A 的数据存在哪里?" data_pubkey = prog_pubkey.derive_pda(user.pubkey.p) # 2. 查询账户信息 (RPC) info = pxsol.rpc.get_account_info(data_pubkey.base58(), {}) # 3. 解码数据 (Base64 -> Bytes -> String) if info['data']: return base64.b64decode(info['data'][0]) return b'' if __name__ == '__main__': content = load(ada).decode() print(f"链上数据: {content}")

3. 更新数据

更新数据只需再次调用 save 函数传入新内容。 我们在链上编写的 realloc 逻辑会自动处理空间调整和租金差额:

  • 如果新数据更长,交易会自动从你的钱包扣除更多 SOL。
  • 如果新数据更短,你会惊喜地发现钱包里多了退回的 SOL。
python
save(ada, 'Hello, Solana!'.encode()) print(load(ada).decode()) # 输出: Hello, Solana! save(ada, '片云天共远,永夜月同孤。'.encode()) print(load(ada).decode()) # 输出: 片云天共远,永夜月同孤。
PYPlayground
EDITOR ACTIVE
Initializing PY Environment...

客户端全栈交互

Client App (Python/JS)
Derived PDA
...
Display Data
...
RPC Node
Solana Blockchain
PDA Storage
Data (Bytes)
00 00 00...
Decoded View
Empty
Logs will appear here...