August 14, 2025
Rust 里 thread::park() 与 thread::yield_now() 的区别
"\u003cp\u003e在看 tokio 调度源码时,会有一些操作线程park的函数,而在rust标准库里也同样有类似的方法,那就是 \u003ca href=\"https://doc.rust-lang.org/std/thread/fn.park.html\"\u003ethread::park()\u003c/a\u003e ,同时还有一个咋一看效果类似的函数 \u003ca href=\"https://doc.rust-lang.org/std/thread/fn.yield_now.html\"\u003ethread::yield_new()\u003c/a\u003e, 两个函数都有实现 **\u003ccode\u003e类似\u003c/code\u003e**暂停执行代码的效果,那它们到底又何区别呢?\u003c/p\u003e\n\u003cp\u003e希望通过这篇文章可以让大家搞明白它们两者的区别和使用场景。\u003c/p\u003e\n\u003cp\u003e我们先看一下 \u003ccode\u003ethread::park() \u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"threadpark\"\u003ethread:park()\u003c/h2\u003e\n\u003cp\u003e对于 park 函数的作用主要是实现当前线程的阻塞,并出让CPU,这时OS调度器会将其它线程调度到CPU,继续执行其它任务。但是一旦调用这个函数后,后续线程将一直处于阻塞状态,也就是说此线程将无法获取CPU处理任务,直到调用 unpark() 函数,才恢复正常。\u003c/p\u003e\n\u003cp\u003e从线程状态角度来看,它的转换\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erunning ---\u0026gt; [thread::park()] ---\u0026gt; blocked (等待唤醒)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eblocked ---\u0026gt; [thread::unpark()]---\u0026gt; runnable ---\u0026gt; running (被unpark唤醒后)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e总结\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e …\u003c/li\u003e\u003c/ul\u003e"
July 10, 2025
从Vec的 swap_remove 方法中学到的性能优化
"\u003cp\u003e今天在看 tokio 源码时,发现一个 \u003ca href=\"https://github.com/tokio-rs/tokio/blob/master/tokio/src/runtime/scheduler/multi_thread/idle.rs#L129-L145\"\u003eunpark_worker_by_id\u003c/a\u003e 函数里调用了标准库Vec 的 \u003ca href=\"https://github.com/rust-lang/rust/blob/master/library/alloc/src/vec/mod.rs#L2014-L2036\"\u003eswap_remove\u003c/a\u003e方法,\u003ccode\u003eswap_remove\u003c/code\u003e 实现如下\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eswap_remove\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003emut\u003c/span\u003e self, index: \u003cspan style=\"color:#66d9ef\"\u003eusize\u003c/span\u003e) -\u0026gt; \u003cspan style=\"color:#a6e22e\"\u003eT\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e#[cold]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e#[cfg_attr(not(panic = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;immediate-abort\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e), inline(never))]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e#[optimize(size)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eassert_failed\u003c/span\u003e(index: \u003cspan style=\"color:#66d9ef\"\u003eusize\u003c/span\u003e, len: \u003cspan style=\"color:#66d9ef\"\u003eusize\u003c/span\u003e) -\u0026gt; \u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#a6e22e\"\u003epanic!\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;swap_remove index (is \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{index}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e) should be \u0026lt; len (is \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{len}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e len \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e self.len();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e index \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e len { …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
June 10, 2025
理解 Solana 中的 Slot、Block、Epoch、Entry、Shred 和 PoH
"\u003cp\u003e对于刚刚接触Solana的开发者来讲,会经常遇到 Slot Block Epochs Entry 和 Shred等一些概念术语,但很验证记住它们的意思和作用。\u003c/p\u003e\n\u003cp\u003e本篇将通过 Solana 的交易原理,让大家轻记信它们并了解它们之间的联系,并加深对Solana交易的理解。由于能力有限,文章中难免有误,大家可以在评论区留言,共同学习进步!\u003c/p\u003e\n\u003cp\u003e好了,下面让我们开始彻底搞明白这些术语及它们在Solana交易中的作用吧!\u003c/p\u003e\n\u003cp\u003e在开始之前我们先看一下在Soalna链中一笔交易是如何进行的。\u003c/p\u003e\n\u003ch2 id=\"交易流程\"\u003e交易流程\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://www.helius.dev/_next/image?url=%2Fapi%2Fmedia%2Ffile%2Fturbine-in-solana-transaction-lifecycle.webp\u0026amp;w=3840\u0026amp;q=90\" alt=\"Visualization of where Turbine lies in the lifecycle of a Solana transaction\"\u003e\u003c/p\u003e\n\u003ch3 id=\"交易流程-1\"\u003e\u003cstrong\u003e交易流程\u003c/strong\u003e\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e用户客户端发起一笔交易,并使用钱包私钥进行签名\u003c/li\u003e\n\u003cli\u003e通过rpc协议将交易发送到用户指定的 Solana RPC 节点。这里RPC节点在区块链网络中存在多个,起到了负载均衡的作用\u003c/li\u003e\n\u003cli\u003eRPC节点验证交易合法性,如进行一系列的检查 ,一般指签名验证/账户检查(账户是否存在,读取权限合法)/账户余额是否足够支付手续费等,最后进行交易模拟执行,就是我们经常说的模拟交易阶段(这一步可以手动配置 \u003ccode\u003e--skip-preflight\u003c/code\u003e 或 \u003ccode\u003ekipPreflight: true\u003c/code\u003e 跳过)。如果这一步失败,则整个交易直接失败, …\u003c/li\u003e\u003c/ol\u003e"
May 17, 2025
零拷贝bytemuck与 borsh
"\u003cp\u003e在上一篇博文《\u003ca href=\"https://blog.haohtml.com/posts/serde-vs-bincode-vs-borsh-in-the-rust/\"\u003e深入理解 Serde、Bincode 与 Borsh 的关系与区别\u003c/a\u003e》介绍了常用的几种解析二进制数据的方法,主要有 bincode 与 borsh, 并提到过在区块链领域里一般推荐使用 borsh 解析数据。但随着合约的开发使用borsh的地方越来越多,会经常遇到提示超出 4K Stack 大小的错误。这是因为在solana里,虚拟机 sbf 限制了一个合约最大允许使用的statck大小上限为 4k。尽管我们使用完一个大变量通过一些方法,如变量作用域、通过Box将内存移动到heap、或手动drop立即释放内存。但仍有些场景是没有采用这种办法的,这时应该如何办呢?\u003c/p\u003e\n\u003cp\u003e如果经常看一些优秀的开源项目的话,会发现有一个 \u003ccode\u003ebytemuck\u003c/code\u003e 的crate,它是一个 \u003ccode\u003ezerocopy\u003c/code\u003e 库,可以避免内存复制带来的开销,加速解析数据速度,这里给出一个测试代码\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse\u003c/span\u003e borsh::{BorshDeserialize, BorshSerialize};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse\u003c/span\u003e bytemuck::{Pod, Zeroable};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse\u003c/span\u003e solana_program::pubkey::Pubkey;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
April 22, 2025
深入理解 Serde、Bincode 与 Borsh 的关系与区别
"\u003cp\u003e在Rust开发中,无论是构建网络服务、存储数据还是开发区块链程序,**序列化(Serialization)和反序列化(Deserialization)**都是不可或缺的操作。序列化是将内存中的数据结构(struct)转换成字节序列或者其他格式(JSON, vec\u003cu8\u003e),以便存储或传输;反序列化则是将字节序列还原成原来的数据结构。\u003c/p\u003e\n\u003cp\u003eRust 生态中常用的序列化工具包括 \u003cstrong\u003eSerde\u003c/strong\u003e、\u003cstrong\u003eBincode\u003c/strong\u003e 和 \u003cstrong\u003eBorsh\u003c/strong\u003e。初学者在阅读文档或实际开发中可能会发现它们名字都很熟悉,但它们的定位、使用方式和特点却不完全相同。\u003c/p\u003e\n\u003cp\u003e本文将系统梳理三者的关系、差异和使用场景。\u003c/p\u003e\n\u003ch2 id=\"serde\"\u003eSerde\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eSerde(Serialization / Deserialization)\u003c/strong\u003e 是 Rust官方生态最流行的序列化框架。它提供了一种 \u003cstrong\u003e抽象接口\u003c/strong\u003e,让你可以将 Rust 类型序列化为多种格式,而不关心底层具体实现。\u003c/p\u003e\n\u003ch3 id=\"特点\"\u003e特点\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e通用性强\u003c/strong\u003e:支持 JSON、YAML、TOML、Bincode 等多种格式。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e灵活\u003c/strong\u003e:可以自定义序列化逻辑。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e宏支持\u003c/strong\u003e:通过 \u003ccode\u003e#[derive(Serialize, Deserialize)]\u003c/code\u003e 自动生成序列化代码。 …\u003c/li\u003e\u003c/ul\u003e"
March 28, 2025
solana中MEV监听交易的几种方法
"\u003ch1 id=\"策略分类\"\u003e策略分类\u003c/h1\u003e\n\u003cp\u003e在 Solana 上 \u003cstrong\u003eMEV(最大可提取价值)\u003c/strong\u003e 的几种策略主要有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e套利(Arbitrage)\u003c/li\u003e\n\u003cli\u003e清算(Liquidation)\u003c/li\u003e\n\u003cli\u003e抢跑(Front-Running)\u003c/li\u003e\n\u003cli\u003e三明治攻击(Sandwich Attack)\u003c/li\u003e\n\u003cli\u003e后置插队(Back-Running)\u003c/li\u003e\n\u003cli\u003eJito MEV 竞标\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"套利arbitrage\"\u003e套利(Arbitrage)\u003c/h2\u003e\n\u003cp\u003e价格差异猎手 想象你是一个精明的商人,在不同的市场上发现同一件商品价格不同。比如,在A市场一个苹果卖1元,在B市场卖1.2元。你会怎么做?立即在A市场买入,然后在B市场卖出,赚取0.2元的差价。\u003c/p\u003e\n\u003cp\u003e在加密世界中,这就是套利。交易员快速在不同交易所或流动性池之间捕捉加密货币价格差异,瞬间完成买卖,赚取微小但稳定的利润。\u003c/p\u003e\n\u003ch2 id=\"清算liquidation\"\u003e清算(Liquidation)\u003c/h2\u003e\n\u003cp\u003e充当风险管理者角色。想象银行放贷时,借款人需要提供抵押物品,如果抵押物品价值下跌到无法覆盖贷款,银行会立即收回资产。\u003c/p\u003e\n\u003cp\u003e在加密借贷平台,当用户的抵押品价值跌破安全线,MEV机器人(\u003cstrong\u003e清算人Liquidator)\u003c/strong\u003e 通常可以以折扣价买入资产。这是因为在借贷平台(如 \u003cstrong\u003eSolend\u003c/strong\u003e、\u003cstrong\u003eMango Markets\u003c/strong\u003e)中,如果用户的抵押资产价值不足以覆盖 …\u003c/p\u003e"
March 27, 2025
SPL-Token CLI 使用入门教程
"\u003cp\u003e本篇文章将对官方教程的基本上进行整理和完善,同时对一些官方未提到的一些知识点和实践进行一些介绍,方便一些刚入门solana开发的同学能够对solana开发有更完整的了解。\u003c/p\u003e\n\u003cp\u003e本篇文章使用 \u003ccode\u003espl-token\u003c/code\u003e 命令行进行演示操作,分别介绍 Mint Account 和 token Account 的创建、转账、关闭账户并回收租金SOL等操作。\u003c/p\u003e\n\u003cp\u003e这里假如用户本机已经安装好solana命令行,并通过 \u003ccode\u003esolana-test-validator\u003c/code\u003e 命令在本地启动开发集群。\u003c/p\u003e\n\u003ch1 id=\"环境准备\"\u003e环境准备\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e打开一个终端,在本地创建一个新集群\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003ebase\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e ➜ ~ solana-test-validator --ledger test-ledger -r\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLedger location: test-ledger\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLog: test-ledger/validator.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e⠠ Initializing... …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
February 25, 2025
Solana中的 Native Programs
"\u003cp\u003e在Solana中有一些少量的内置原生程序,它们的程序ID格式一般为 \u003ccode\u003exxx11111111111111111111111111111111\u003c/code\u003e。它们与第三方自定义程序不同,原生程序是 \u003cstrong\u003evalidator node\u003c/strong\u003e 运行所必须的一部分。同时它们也是集群升级的一部分,这些升级可能包括新功能的添加、BUG修复,又或者是性能的优化提升。这些内置原生程序极少的发生变化,目前提供的所有内置原生程序可以在 \u003ca href=\"https://docs.anza.xyz/runtime/programs\"\u003ehttps://docs.anza.xyz/runtime/programs\u003c/a\u003e 找到。\u003c/p\u003e\n\u003cp\u003e其中有两个非常重要的程序很值得我们关注,因为我们在开发中,需要经常用到他们。\u003c/p\u003e\n\u003ch1 id=\"system-program\"\u003eSystem Program\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e作用:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e创建新帐户\u003c/li\u003e\n\u003cli\u003e分配帐户数据\u003c/li\u003e\n\u003cli\u003e将帐户分配给所属的程序,即指定账户与程序的对应关系\u003c/li\u003e\n\u003cli\u003e转账最小 lamports 给账户(租金),防止账户被系统回收\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eProgram id: \u003ccode\u003e11111111111111111111111111111111\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eInstructions: \u003ca href=\"https://docs.rs/solana-program/2.2.0/solana_program/system_instruction/enum.SystemInstruction.html\"\u003eSystemInstruction\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"bpf-loader\"\u003eBPF Loader\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e作用:\n\u003cul\u003e\n\u003cli\u003e部署所有自定义程序, …\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e"
February 15, 2025
Solana中 PDA、ATA 与 普通Account 的区别与关系
"\u003ch1 id=\"普通账户地址\"\u003e普通账户地址\u003c/h1\u003e\n\u003cp\u003e对于账户地址的创建是由一个密钥对来生成的,但在Solana中账户地址与以太坊中的账户地址还是有一些区别的。\u003c/p\u003e\n\u003ch2 id=\"以太坊账户地址\"\u003e以太坊账户地址\u003c/h2\u003e\n\u003cp\u003e以太坊账户地址的生成过程:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e通过私钥生成公钥\u003c/li\u003e\n\u003cli\u003e对公钥进行 Keccak-256 哈希\u003c/li\u003e\n\u003cli\u003e取哈希值的最后 160 位(20 字节)作为地址\u003c/li\u003e\n\u003cli\u003e将地址以 \u003ccode\u003e0x\u003c/code\u003e 开头,并根据需要选择是否使用 EIP-55 格式\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003e地址中通常是小写字母,但也有大写字母的变种,称为 \u003cstrong\u003eEIP-55\u003c/strong\u003e 格式。在 EIP-55 中,某些字符会根据哈希值的大小写进行区分,从而增加地址的错误检查能力。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"solana-账户地址\"\u003eSolana 账户地址\u003c/h2\u003e\n\u003cp\u003eSolana账户地址的生成过程:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e通过私钥生成公钥,一般通过调用 Keypair.generate() 生成\u003c/li\u003e\n\u003cli\u003e公钥直接映射为账户的地址,长度为 32 字节\u003c/li\u003e\n\u003cli\u003e为了使用方便,一般对其进行 Base58 编码,将公钥转换为地址字符串\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e代码:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-typescript\" data-lang=\"typescript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e { \u003cspan style=\"color:#a6e22e\"\u003eKeypair\u003c/span\u003e } \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003erequire\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;@solana/web3.js\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// 生成一个新的密钥对\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ekeypair\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eKeypair\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003egenerate\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// 获取公 …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
January 10, 2025
Solana中如何实现转账
"\u003cp\u003e在 Solana 中转账有两种方式。\u003c/p\u003e\n\u003ch1 id=\"修改结构体字段\"\u003e修改结构体字段\u003c/h1\u003e\n\u003cp\u003e一种是在不调用(\u003ccode\u003einvoking\u003c/code\u003e )系统程序( \u003ccode\u003eSystem Program\u003c/code\u003e )的情况下,将 \u003ccode\u003elamports\u003c/code\u003e 从一个账户转移到另一个账户。它的实现是直接通过修改结构体的 \u003ccode\u003elamports\u003c/code\u003e 字段值来实现的。\u003c/p\u003e\n\u003cp\u003e这种方法可以实现将 lamports 从任何由您的程序\u003cstrong\u003e拥有\u003c/strong\u003e的账户转移到任何账户。\u003ca href=\"https://solana.com/zh/developers/cookbook/programs/transfer-sol\"\u003e文档\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e/// Transfers lamports from one account (must be program owned)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e/// to another account. The recipient can by any account\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etransfer_service_fee_lamports\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e from_account: \u003cspan style=\"color:#66d9ef\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eAccountInfo\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e to_account: \u003cspan style=\"color:#66d9ef\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eAccountInfo\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e amount_of_lamports: \u003cspan style=\"color:#66d9ef\"\u003eu64\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e) -\u0026gt; \u003cspan style=\"color:#a6e22e\"\u003eProgramResult\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e// Does the from account have enough …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
December 22, 2024
Solana中账户类型 Account、AccountInfo与 SystemAccount 的区别
"\u003cp\u003e在Solana中 Account 的角色很重要,它就像Linux中\u003ccode\u003e一切皆文件\u003c/code\u003e的概念一样,无处不在。了解它也是开发Solana的基础,本节主要介绍我们最经常使用的 \u003ccode\u003eAccount\u003c/code\u003e 、\u003ccode\u003eAccountInfo\u003c/code\u003e 和 \u003ccode\u003eSystemAccount\u003c/code\u003e 这三种账户类型的区别与使用场景。\u003c/p\u003e\n\u003cp\u003e当然除此之外还有一些账户类型也很重要,如 \u003ccode\u003eUncheckedAccount\u003c/code\u003e、\u003ccode\u003eSigner\u003c/code\u003e、\u003ccode\u003eTokenAccount\u003c/code\u003e、\u003ccode\u003eMint\u003c/code\u003e、\u003ccode\u003eCpiAccount\u003c/code\u003e、\u003ccode\u003eLoader\u003c/code\u003e、\u003ccode\u003eProgram\u003c/code\u003e、\u003ccode\u003eAssociatedToken\u003c/code\u003e 等,我们这里就不再一一讲解,有兴趣的话可以参考官方相关文档。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e由于多数情况下都是使用anchor框架开发Solana合约,因此本文主要是根据 anchor-lang 文档里介绍账户来讲解\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"账户类型\"\u003e账户类型\u003c/h1\u003e\n\u003cp\u003e以下我们分别对这三种账户类型做一些简单的介绍。\u003c/p\u003e\n\u003ch2 id=\"accountinfo\"\u003eAccountInfo\u003c/h2\u003e\n\u003cp\u003e在 Solana 中 \u003ccode\u003eAccountInfo\u003c/code\u003e 是最基础的账户类型。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com/uploads/2025/accountinfo.svg\" alt=\"AccountInfo\"\u003e\u003c/p\u003e\n\u003cp\u003e其它几种账户类型都是对它的封装,它的\u003ca href=\"https://docs.rs/anchor-lang/0.30.1/anchor_lang/prelude/struct.AccountInfo.html\"\u003e定义\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#[repr(C)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eAccountInfo\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003e\u0026#39;a\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e key: …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
December 6, 2024
什么是Layer2网络
"\u003cp\u003e我们平时提到的比特币、以太坊、Solana,它们都属于Layer 1网络,而Layer 2(L2) 网络是指基于Layer1网络之上构建的一层网络,它很类似于Layer 1 网络,也是一个独立的区块链。但它的主要目的并不是为了代替 Layer 1 ,而是为了通过扩展 Layer 1 层网络从而解决一些在 Layer 1 网络中存在的一些问题,它同时继承了 Layer 1 网络的安全性和去中心化性。\u003c/p\u003e\n\u003ch1 id=\"以太坊存在的问题\"\u003e以太坊存在的问题\u003c/h1\u003e\n\u003cp\u003e这里以以太坊为例,在 L1 网络上随着交易量越来越大,交易频率也越来越频繁,导致Gas(网络交易费)越来越高,一笔交易可能在网络繁忙的时候高达十几美元,导致一些交易可能需要花费好久才可以真正成交到区块网络。\u003c/p\u003e\n\u003cp\u003e这两个问题大大提高了用户使用门槛,那有没有好的解决办法呢?\u003c/p\u003e\n\u003ch1 id=\"解决方案\"\u003e解决方案\u003c/h1\u003e\n\u003cp\u003e区块链的三个核心特性是 \u003ccode\u003e去中心化\u003c/code\u003e、\u003ccode\u003e安全性\u003c/code\u003e和\u003ccode\u003e可扩展性\u003c/code\u003e,一般简单的区块链架构只能实现其中两个特性(这一点很类似于分布式中的CAP理论)。想要一个安全且去中心化的区块链的话,只能牺牲可扩展性,而这也正是第二层网络发挥作用的地方。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e以太坊生态系统坚定认为,第 2 层扩展是解决可扩展性三难问题的唯一途径,同时保 …\u003c/strong\u003e\u003c/p\u003e"
December 4, 2024
Solana中如何解析指令
"\u003cp\u003e开发过Solodity的同学都知道在合约开发中,不同指令对应的不同前端Endpoint(API接口),这种开发模式特别的清晰且易维护。那在开发Solana合约时没有有对应的方法呢?\u003c/p\u003e\n\u003ch1 id=\"solana开发方式\"\u003eSolana开发方式\u003c/h1\u003e\n\u003cp\u003e开发 Solana 合约,一般分 Native 和 Anchor 框架开发。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eNative\u003c/code\u003e 主要是开发者通过SDK 手动实现所有业务逻辑。 这种模式一般对开发者要求比较高,除了需要了解相关概念外,最重要的还需要知道对应的SDK实现,如PDA账户的创建。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eAnchor框架\u003c/code\u003e 推荐使用,只需要一些宏即可以实现一些逻辑,不需要用户关心底层实现。这种开发方式对于指令的处理基本与Solidity中一致,开发者只要搞明白了基本用法就可以了。\u003c/p\u003e\n\u003cp\u003e下面主要讲一下在 Native 这种方式下,如何实现指令或附加数据的解析。\u003c/p\u003e\n\u003cp\u003e如果你对 \u003ccode\u003e指令\u003c/code\u003e这个概念不太理解的话,可以将其视为路由。其类于似在mvc开发中控制器路由,如 \u003ccode\u003e/user/info\u003c/code\u003e、 \u003ccode\u003e/user/base\u003c/code\u003e、\u003ccode\u003e/user/changepwd\u003c/code\u003e 之类。\u003c/p\u003e\n\u003ch1 id=\"示例介绍\"\u003e示例介绍\u003c/h1\u003e\n\u003cp\u003e我们先看一个在 \u003ca href=\"https://beta.solpg.io\"\u003ehttps://beta.solpg.io\u003c/a\u003e 网站上创建的一个 Native …\u003c/p\u003e"
December 3, 2024
解决编译solana程序 rustc版本号过低的问题
"\u003cp\u003e本方主要介绍在编译solana程序时,提示 rustc 版本号过低无法编译通过的问题。\u003c/p\u003e\n\u003ch1 id=\"问题描述\"\u003e问题描述\u003c/h1\u003e\n\u003cp\u003e在参考官方教程 \u003ca href=\"https://github.com/solana-developers/program-examples/tree/main/basics/favorites/native\"\u003ehttps://github.com/solana-developers/program-examples/tree/main/basics/favorites/native\u003c/a\u003e 在本地执行命令\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e➜ native git:\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003emain\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e ✗ cargo build-sbf --manifest-path\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e./program/Cargo.toml --sbf-out-dir\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e./program/target/so\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e报错\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e➜ native git:\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003emain\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e ✗ cargo build-sbf --manifest-path\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e./program/Cargo.toml --sbf-out-dir\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e./program/target/so\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eerror: package \u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003esolana-program v2.1.7\u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003e cannot be built because it requires rustc 1.79.0 or newer, \u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e the currently active …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
December 2, 2024
在Solana中为什么Token Account没有owner属性
"\u003cp\u003e在上一篇\u003ca href=\"https://blog.haohtml.com/posts/understanding-the-difference-between-ata-accounts-and-token-accounts-in-solana/\"\u003e《了解 Solana 中ATA账户与普通账户的关系》\u003c/a\u003e中,我们介绍了在Solana中,ATA账户与Token Account 的区别,其中在浏览器记录查看 user2 用户详细的时候,发现它与前两个账户有所区别,它没有 Owner 属性,这在正常情况下是不应该出现的,所以,我们来分析一下,为什么Token Account没有 \u003ccode\u003eOwner\u003c/code\u003e 属性?\u003c/p\u003e\n\u003cp\u003e在 Soalna中,默认情况下所有的新账户都属于 \u003ca href=\"https://solana.com/docs/core/accounts#system-program\"\u003eSystem Program\u003c/a\u003e,也只有系统程序拥有的账户才可以作为交易费用支付者(也就是账户里必须的原生币sol)。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com/uploads/2025/system-account.svg\" alt=\"系统账户\"\u003e\u003c/p\u003e\n\u003cp\u003e因此示例中正常的 Token Account\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com/uploads/2025/image-20250107144557450.png\" alt=\"Token Accoun\"\u003e\u003c/p\u003e\n\u003cp\u003e异常账号\n\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com/uploads/2025/image-20250107145307758.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e出现我这种情况主要有两种情况:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e交易还在处理中,尚未完成,这种情况下一般只需要等待一会就会正常。\u003c/li\u003e\n\u003cli\u003e账户未被初始化,需要初始化后才恢复正常。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e常见的初始化方法:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e空投原生币\u003c/li\u003e\n\u003cli\u003e转账原生币\u003c/li\u003e\n\u003cli\u003e通过 SystemProgram.createAccount 创建账号·\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e在上篇文章里,我们为了演示转账记录,对 payer 和 user1 用户都进行了空投,在空投时将自动对账户进行初始化操作, …\u003c/p\u003e"