开发者入门
手把手带你拆解密码学与智能合约的底层逻辑,完成从“看不懂区块浏览器”到“能独立部署主网 DApp”的跨越,用中文把区块链写进未来。
41个主题在此版面
-
为什么选择 Solana?Solana 作为新一代高性能公链,以其每秒处理 65,000 笔交易的速度和低至 $0.00025 的手续费,正在重新定义区块链开发的可能性。对于中文开发者而言,掌握 Solana 开发技术意味着: 进入 Web3 高薪领域:Solana 生态项目平均薪资比传统开发高 50% 低门槛创业机会:DeFi、NFT、GameFi 应用层出不穷 技术前瞻性:并行处理、POH 共识机制等创新技术 教程目录(点击链接进入相关教程)Week 1 Solana 基础知识 Solana 介绍 Solana 核心概念 SPL 代币 命令行工具 钱包使用 课后练习 Week 2 通过 RPC 与 Solana 交互 Solana 的 RPC 介绍 接口 RPC 推送 RPC 课后练习 Week 3 与 Solana 合约交互 Solana 的 Web3.js 与钱包交互 合约调用 课后练习 Week 4 Rust 基本知识 Hello World Rust 基本语法 通过 Cargo 管理工程 Rustaceans 的理解 课后练习 Week 5 Solana 合约开发 Part.1 Hello World Solana 合约基础概念 Solana 合约处理逻辑 Solana 合约错误定义 课后练习 Week 6 Solana 合约开发 Part.2 使用 VS Code 开发合约 PDA 账号 合约间调用 CPI 系统变量 课后练习 Week 7 Solana 合约开发进阶 ALTs 交易 Solana 序列化标准 Anchor …
-
- 0 篇回复
- 27 次查看
-
-
区块链相关术语(中英对照)说明:阅读英文文档是编程开发过程中最常做的一件事,英文阅读也是一个程序员的基本能力。区块链刚刚起步,每天各种新概念层出不穷,为方便大家学习和使用,这里收录了巴比特论坛上的一个帖子内容。该帖子仍在持续更新,更多新内容请点击下面的地址阅读原帖。 原文标题:《数字货币翻译术语(中英对照)》 原文地址:http://8btc.com/thread-17286-16-1.html 版权归巴比特论坛,也感谢社区小伙伴们的参与和贡献。 English 中文 account level(multiaccountstructure) 账户等级(多账户结构) accounts 账户 adding blocks to 增加区块至 addition operator 加法操作符 addr message 地址消息 Advanced Encryption Standard(AES) 高级加密标准(AES) aggregating 聚合 aggregating into blocks 聚集至区块 alert messages 警告信息 altchains 竞争币区块链 altcoins 竞争币 AML 反洗钱 anonymity focused 匿名的 antshares 小蚁 appcoins 应用币 API 应用程序接口 App Coins 应用币 architecture 架构 assembling 集合 attacks 攻击 attack vectors 攻击向量 Autonomous Decentralized Peer-to-P…
-
- 0 篇回复
- 21 次查看
-
-
前言 #最近对在上 HKU 的<COMP7408 Distributed Ledger and Blockchain Technology>课程,对区块链的基础概念有了更系统的认知,结合之前上过的北京大学肖臻老师《区块链技术与应用》公开课,深知区块链知识体系之庞大,打算更新系列文章对区块链、比特币、以太坊等进行系统的知识梳理,如有错漏,欢迎交流指正。 区块链中的密码学原理 #区块链和密码学紧密相关,如比特币采用的核心的公私钥加密技术、数字签名、哈希等,包括很多共识算法也是基于复杂的密码学概念,因此,在开始学习区块链之前,要先了解几个核心的密码学概念,从而能够更深入理解其在区块链体系中的应用。 哈希函数 #哈希函数是把一个任意长度的源数据经过一系列算法变成一个固定长度输出值的方法,概念很简单,但其具备的几个特性使它被各个领域广泛应用。 可以访问这个 Demo 体验一下哈希函数的工作原理(以SHA256为例)! 第一个特性是单向不可逆性。将一个输入 x 进行哈希运算得到值 H(x),这一过程很容易,但是如果给定一个值 H(x),几乎不可能逆推得到 x 的取值,这一特性很好地保护了源数据。 第二个特性是抗碰撞性。给定一个值 x 和另一个值 y,如果 x 不等于 y,那 H(x) 几乎不可能等于 H(y),并非完全不可能,但是几率非常低,因此,一个数据的 Hash 值几乎是唯一的,这可以很好地用于身份验证等场景。 第三个特性是哈希计算不可预测。很难根据现有条件推导出哈希值,但是很容易检验是否正确,这一机制主要应用于PoW挖矿机制中。 …
-
- 0 篇回复
- 12 次查看
-
-
推送RPC推送RPC,其实是RPC节点允许连接的一个WebSocket长连接。通过在该长连接上发送订阅请求, RPC节点会将相关事件在长连接上推送过来。当前订阅主要分为: accountSubscribe : 订阅Account的变化,比如lamports logsSubscribe : 订阅交易的日志 programSubscribe : 订阅合约Account的变化 signatureSubscribe : 订阅签名状态变化 slotSubscribe : 订阅slot的变化 每个事件,还有对应的Unsubscribe动作,取消订阅。将上面的Subscribe替换成Unsubscribe即可。 这里我们通过wscat命令行工具来模拟wss客户端。首先安装工具: Copynpm install -g ws wscat然后建立连接: Copywscat -c wss://api.devnet.solana.com下面举例说明: 订阅Account变化这里的Account就是每个地址的Account元数据。主要变化的就是data部分和lamports部分。 比如我们要订阅我们的账号余额的变化。 Copy{ "jsonrpc": "2.0", "id": 1, "method": "accountSubscribe", "params": [ "CnjrCefFBHmWnKcwH5T8DFUQuVEmUJwfBL3Goqj6YhKw", …
-
- 0 篇回复
- 25 次查看
-
-
合约开发安全注意点签名安全我们需要对敏感的数据修改做权限校验,比如如下程序 Copypub fn process_create( program_id: &Pubkey, accounts: &[AccountInfo], msg: String, ) -> ProgramResult { let accounts_iter = &mut accounts.iter(); let greeting_account = next_account_info(accounts_iter)?; // Increment and store the number of times the account has been greeted let mut greeting_info = GreetingInfo { message: "".to_string(), }; greeting_info.message = msg; greeting_info.serialize(&mut *greeting_account.data.borrow_mut())?; msg!("set note to {} !", greeting_info.message); Ok(()) }…
-
- 0 篇回复
- 14 次查看
-
-
经典科学家手段假Token前面介绍的cashio,本质上就是个假Token的案例。 假Token最出名的,是从EOS时代。ERC20规范导致,大家都会去检查ERC20的地址,或者说写合约的时候 判断条件就是地址。而EOS包括现在的Solana,地址条件不是那么明显,比如EOS的name,Solana 需要 用户传递进来Mint Account。 因此如果没有做相关check就有可能出现假Token 闪电贷闪电贷本身是没有什么问题,但是闪电贷可能被科学家用于辅助。比如正常情况下,用户是没有那么多的 某个Token的,但是他可以去闪电贷服务里面,临时借入大量这种Token,然后操作我们的逻辑,影响这里的 数据,典型的是DeFi里面,通过外借Token,进行砸盘。然后同一个Tx里面再跟上科学家自己的Token 低价买入。 CPI普通合约都是针对普通玩家来执行动作的,也就是发起交易的是一个owner为system的Account。这个Account 最多就是将多个指令串在一个交易里面执行,但是他没法做到其他更多的功能。 通过CPI,我们可以让发起动作的是一个合约,在这个合约里面,我们就可以编程了,Sui 提出了一个叫做 "Programmable Transaction"的概念,其实就类似这个。或者ETH里面的MultiCall也是类似的概念。 在这里我们就可以借助合约的执行,来做一些逻辑,比如判断当前执行的时候,Blocke Height,Slot信息。 权限检查权限检查是个老生常谈的问题,在任何链上都是存在的。但是在Solana上,可能会更明…
-
- 0 篇回复
- 11 次查看
-
-
Cashio 攻击事件分析Cashio是一个去中心化的稳定币平台,完全由计息的Saber美元流动性提供者代币支持。允许用户做两件事:一是通过存入相应价值的稳定对 LP 代币作为抵押品,打印与美元挂钩的稳定币 - $CASH;二是燃烧$CASH 以赎回基础 LP 代币。 Cashio 提供了一种无需信任、去中心化的稳定币,由于通过 Sunny、Sabre 和 COW 上的 Tribeca Protocol Gauges 战略性地针对 CASH LP 农场的奖励代币激励措施,提高了 CASH LP 对的收益。 Cashio 应用程序提供了一个简单的界面来增加稳定币对的收益: 将稳定的货币流动性存入 Sabre 以换取 LP 代币。 将 LP 代币存入 Cashio 以打印 $CASH 将 $CASH 与其他稳定币存入 Sabre 以获得 $CASH LP 代币 在北京时间2022年3月23日,Cashio 称遭到黑客攻击,合约存在铸造故障,声明用户不要铸造任何资金,并督促用户提取池中的资产。 攻击分析攻击交易为4fgL8D6QXKH1q3Gt9GPzeRDpTgq4cE5hxf1hNDUWrJVUe4qDJ1xmUZE7KJWDANT99jD8UvwNeBb1imvujz3Pz2K5 攻击者的基本逻辑是 S1: 铸造Token,作为LP token S2: 用这个LP Token去抵押得到$CASH S3: 将$CASH套现为$USDT/$USDC 这里的基本逻辑就是用了一个fack的LP Token,可以正常兑换出来$CASH。 攻击者调…
-
- 0 篇回复
- 24 次查看
-
-
Solana 的 NFT 事实标准 Metaplex我来看下当前 Solana 官方对于 NFT 的定义Non-Fungible tokens: 这段话出自 SPL Token 的官方文档。也就是说,Solana 上的 NFT 标准,也是由"SPL Token"来实现的,但是他是一个特殊的 Token,这个 Token 的 supply 一定为 1 精度为 0 mint Authority 为空,也就是不能再 mint 新的 token 根据我们前面的介绍,大家已经知道了 "SPL Token" 的几个基本属性,但是这里作为 NFT,他最典型的小图片地址在哪里呢?总的供应量在哪里呢? 我们来看 Solana 域名的下的 NFT 在这个页面,随便点击,我们会发现,官方站点将我们引导到了 Metaplex。这个 metaplex 是什么呢? 简而言之,就是 Metaplex 是一套 NFT 系统,他包含了一套 NFT 标准,一个发布 NFT 的工具和一套 NFT 交易市场协议。 从这里我们可以看到,Solana 官方基本是认可这里定义的这套 NFT 标准了。那么我们就来介绍下这个标准是怎样的。 NFT 标准首先 Metaplex 也一样要遵循前面 Solana 官方的"SPL Token"里面说的,一个 NFT 就是一个特殊的"SPL Token" 这个基础原则。然后 Metaplex 在这个基础之上做了一些扩展,为这个 supply 为 1 的 token 增加了如下属性: 用 JSON 表示就是: Copy{ "name":…
-
- 0 篇回复
- 20 次查看
-
-
TokenSwap合约走读Solana官方在SPL里面给了一个AMM的参考实现,其代码在 Token Swap 相应的文档在 Token Swap Program。 这个Swap合约允许在没有集中限价订单簿的情况下进行代币对的简单交易。该程序使用称为“curve”的数学公式来计算所有交易的价格。曲线旨在模仿正常的市场动态:例如,当交易者大量购买一种代币类型时,另一种代币类型的价值就会上涨。 Pool中的存款人为代币对提供流动性。这种流动性使得交易能够以现货价格执行。作为流动性的交换,储户收到矿池代币,代表他们在矿池中的部分所有权。在每次交易期间,程序都会扣留一部分输入代币作为费用。该费用通过存储在池中而增加了池代币的价值。 基本操作创建新的代币PairPool的创建展示了 Solana 上的帐户、指令和授权模型,这与其他区块链相比可能有很大不同。 两种代币类型之间的池的初始化(为简单起见,我们将其称为“A”和“B”)需要以下帐户: empty pool state account pool authority token A account token B account pool token mint pool token fee account pool token recipient account token program 只需使用 system_instruction::create_account正确的大小和足够的 lamport 来创建池状态帐户即可免租金。 Pool权限是一个 PDA地址 ,可以“签署”针对其他程序的指令…
-
- 0 篇回复
- 19 次查看
-
-
Anchor实践我们将之前的我们的记事本合约改成Anchor工程。同时为了模拟PDA,我们将记事本所在地,按照用户 改成其PDA地址。 首先创建工程: Copyanchor init note设计指令定义指令Account: Copy#[derive(Accounts)] pub struct Create<'info> { #[account( init, payer=user, space = 128, seeds = [user.key().as_ref()], bump )] pub note: Account<'info, Note>, #[account(mut)] pub user: Signer<'info>, pub system_program: Program<'info, System>, }其中State定义为: Copy#[account] pub struct Note { pub message: String }存储消息。 这里 Copy#[account( init, payer=user, space = 128, seeds = [user.key().as_ref()], bump )]会新创建一个Account,该account…
-
- 0 篇回复
- 22 次查看
-
-
Anchor开发框架Anchor作为一款开发框架,提供了合约开发的基本结构,区别于我们之前介绍"instruction/stat/process" 基本程序结构,同时Anchor还提供了客户端相关的Typescript相关类库,以及"anchor"命令工具。 Anchor程序结构一个Anchor工程主要包含了 "declare_id"宏声明的合约地址,用于创建对象的owner #[derive(Accounts)] 修饰的Account对象,用于表示存储和指令 "program" 模块,这里面写主要的合约处理逻辑 对应到我们之前的HelloWorld,就是要将state和instruction部分用 #[derive(Accounts)] 修饰,将process逻辑放到program模块中,并增加一个合约地址的修饰。 #[program] 修饰的Module即为指令处理模块。其中有一个Context类型,来存放所有的指令参数。比如 ctx.accounts 所有的请求keys,也就是AccountMeta数组 ctx.program_id 指令中的program_id ctx.remaining_accounts 指令中,没有被下面说的"Accounts"修饰的成员的AccountMeta 处理指令对于指令,我们要通过#[derive(Accounts)]来修饰我们定义的指令部分的定义: Copy#[account] #[derive(Default)] pub struct MyAccount { data: u64 } …
-
- 0 篇回复
- 19 次查看
-
-
Solana序列化标准Anchor协议Anchor是什么? Anchor现在是Solana合约开发的一套框架,但是Anchor在建立之初,其实只是一个序列化协议。 Long Long Ago,我们来看之前的Token代码,关于Mint的对象的序列化存储是这样的: Copyfn pack_into_slice(&self, dst: &mut [u8]) { let dst = array_mut_ref![dst, 0, 82]; let ( mint_authority_dst, supply_dst, decimals_dst, is_initialized_dst, freeze_authority_dst, ) = mut_array_refs![dst, 36, 8, 1, 1, 36]; let &Mint { ref mint_authority, supply, decimals, is_initialized, ref freeze_authority, } = self; pack_coption_key(mint_authority, mint_authority_dst); *supply_dst = supply.to_le_bytes(); decimals_dst[0] = decimals; …
-
- 0 篇回复
- 16 次查看
-
-
ALTs 交易传输到 Solana 验证器的消息不得超过 IPv6 MTU 大小,以确保通过 UDP 快速可靠地进行集群信息网络传输。Solana 的网络堆栈使用 1280 字节的保守 MTU 大小,在考虑标头后,为数据包数据(如序列化事务)留下 1232 字节。 在 Solana 上构建应用程序的开发人员必须在上述交易大小限制约束内设计其链上程序接口。一种常见的解决方法是将状态临时存储在链上并在以后的交易中使用该状态。这是 BPF 加载程序用于部署 Solana 程序的方法。 然而,当开发人员在单个原子事务中编写许多链上程序时,这种解决方法效果不佳。组合越多,帐户输入就越多,每个帐户输入占用 32 个字节。目前没有可用的解决方法来增加单个事务中使用的帐户数量,因为每个事务必须列出正确锁定帐户以进行并行执行所需的所有帐户。因此,在考虑签名和其他交易元数据后,当前上限约为 35 个账户。 地址查找表通常简称为“查找表”或简称“ ALT ”,允许开发人员创建相关地址的集合,以便在单个事务中有效地加载更多地址。 由于 Solana 区块链上的每笔交易都需要列出作为交易一部分进行交互的每个地址,因此该列表实际上将限制每笔交易的 32 个地址。在地址查找表的帮助下,一笔交易现在可以将该限制提高到每笔交易 256 个地址。 ALT在这里,我们描述了一个基于程序的解决方案,协议开发人员或最终用户可以在链上创建相关地址的集合,以便在交易的帐户输入中简洁使用。 地址存储在链上地址查找表账户中后,可以使用 1 字节 u8 索引而不是完整的 32 字节地址在交…
-
- 0 篇回复
- 16 次查看
-
-
课后练习扩充 Token 合约,为 Token 合约增加 Meta 信息,如 icon: 代币图标 name: 代币名称 symbol: 代币符号缩写 home: 代币主页 参考答案我们实现一个合约,这个合约输入为一个 Mint 的 token 地址,然后我们在这个合约中用 SPL Token 地址这个 Mint 的地址为 seed 生成一个 PDA: Copylet (gen_ext_mint_key, bump) = Pubkey::find_program_address( &[ &spl_token_program_account.key.to_bytes(), &mint_account.key.to_bytes(), ], program_id, );以这个推导出来的地址作为 Token 的 Meta 信息,然后定义其中格式为: Copy#[derive(BorshSerialize, BorshDeserialize, Debug)] pub struct ExtMint { /// number of greetings pub mint: Pubkey, pub name: String, pub symbol: String, pub icon: String, }为这个合约定义一个 mint 的 ins…
-
- 0 篇回复
- 13 次查看
-
-
系统变量Solana作为一个24h小时运行的系统,其中一些系统变量可以通过接口直接获取,而另外一些变量 则要需要将特定的Account通过指令传递给合约。 Clock EpochSchedule Fees Rent 这几个变量,可以在合约里面直接通过get()方法得到。比如: Copylet clock = Clock::get()即可得到Clock对象。而其他的变量,则需要在指令中传入该变量的地址,然后再合约里面解析: Copylet clock_sysvar_info = next_account_info(account_info_iter)?; let clock = Clock::from_account_info(&clock_sysvar_info)?;ClockClock的内容为: Copy#[repr(C)] pub struct Clock { pub slot: Slot, pub epoch_start_timestamp: UnixTimestamp, pub epoch: Epoch, pub leader_schedule_epoch: Epoch, pub unix_timestamp: UnixTimestamp, }其意义有: Slot:当前槽位 epoch_start_timestamp:该纪元中第一个槽的 Unix 时间戳。 在纪元的第一个时隙中,此时间戳与 unix_timestamp(如下)相同。 epoch:当前纪元 leader_schedul…
-
- 0 篇回复
- 25 次查看
-
-
合约间调用Solana 运行时允许程序通过称为跨程序调用的机制相互调用。 程序之间的调用是通过一个程序调用另一个程序的指令来实现的。 调用程序将暂停,直到被调用程序完成对指令的处理。 还是以 ATA 账号来举例子。比如我们创建了代币 TokenA,这个时候我们要给某个人发放空投。那么根据我们前面的经验知道,处理方式是这样的,首先我们要为这个用户创建其对应的 TokenA 的 ATA 账号,比如叫 TokenA_ATA_Account。然后再给这个地址做 mint 操作。 那么我们首先按照前面文章的步骤,创建一个 TokenA_ATA_Account 地址,并将其 ower_pubkey 为该用户的交易。然后还要再创建一个给 TokenA_ATA_Account mint TokenA 代币的交易。 这里的两个交易有先后顺序关系,且第二个交易需要等待第一个交易执行完成,同时两次交易的 gas 费用也会更高。那么有没什么办法将两次交易进行合并呢? 答案就是用一个合约来实现这两个步骤,然后发送一个交易即可。在这个合约里面,实现对账号的创建,以及对 SPL-Token 的 mint 两个动作。这个合约需要跟 ATA 合约交互,调用 ATA 的创建账号指令,之后再和 Token 合约交互,执行其 mint 的指令。 合约之间调用分成两类,一类是不需要校验签名的invoke,另一类是目标合约需要校验操作权限的invoke_signed 方法,前者类似 router 路由到另外一个合约执行,后者则目标程序对相关的账号有操作权限,也就是我们前面说的 PD…
-
- 0 篇回复
- 21 次查看
-
-
PDA账号程序派生地址 (PDA:Program derived addresses) 是只有程序 program_id 有权签名的帐户密钥。 该地址与 Solana Pubkey 的形式相同,但确保它们不在 ed25519 曲线上,因此没有关联的私钥。 程序派生地址允许在程序之间调用时使用以编程方式生成的签名。 使用程序派生地址,程序可以被授予对帐户的权限,然后将该权限转移给另一个程序。 这是可能的,因为程序可以充当授予权限的交易中的签名者。 例如,如果两个用户想要对 Solana 中的游戏结果进行下注,他们必须将其下注资产转移给某个遵守协议的中介机构。 目前,无法在 Solana 中将此中介程序实施为程序,因为中介程序无法将资产转移给获胜者。 此功能对于许多 DeFi 应用程序来说是必要的,因为它们需要将资产转移到托管代理,直到发生确定新所有者的事件为止。 在匹配的买价和卖价订单之间转移资产的去中心化交易所。 将资产转移给获胜者的拍卖。 收集奖品并将其重新分配给获胜者的游戏或预测市场。 程序派生地址: 允许程序控制特定地址(称为程序地址),这样外部用户就无法生成带有这些地址签名的有效交易。 允许程序以编程方式对通过跨程序调用调用的指令中存在的程序地址进行签名。 满足这两个条件,用户可以安全地将链上资产的权限转移或分配给程序地址,然后程序可以自行将该权限分配到其他地方。 生成方式由于程序地址不得位于 ed25519 曲线上,因此可能存在无效的种子和程序 ID 组合。 因此,会计算一个额外的种子(凹凸种子),从而产生偏离曲线的点。找到有效…
-
- 0 篇回复
- 20 次查看
-
-
使用VS Code开发合约在前面的基础中,已经安装好了rust和solana cli。首先确定rust版本: Copyrustc --version rustc 1.70.0 (90c541806 2023-05-31)如果没有安装,可以通过: Copycurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh Current installation options: default host triple: x86_64-apple-darwin default toolchain: stable (default) profile: default modify PATH variable: yes 1) Proceed with installation (default) 2) Customize installation 3) Cancel installation 直接Enter采用默认方式 Rust is installed now. Great! To get started you may need to restart your current shell. This would reload your PATH environment variable to include Cargo's bin directory ($HOME/.cargo/bin). To configure your curre…
-
- 0 篇回复
- 19 次查看
-
-
-
Solana合约错误定义在前面的指令处理函数中,我们需要返回ProgramResult类型,其定义为: Copyuse { std::{ result::Result as ResultGeneric, }, }; pub type ProgramResult = ResultGeneric<(), ProgramError>;其实就是一个使用了ProgramError作为Err部分的Result类型枚举。 系统错误上面提到的ProgramError的定义为: Copy/// Reasons the program may fail #[derive(Clone, Debug, Deserialize, Eq, Error, PartialEq, Serialize)] pub enum ProgramError { /// Allows on-chain programs to implement program-specific error types and see them returned /// by the Solana runtime. A program-specific error may be any type that is represented as /// or serialized to a u32 integer. #[error("Custom program error: {0:#x}")] Custom(u32),…
-
- 0 篇回复
- 21 次查看
-
-
Solana合约处理逻辑我们这里说的处理逻辑,并不是Runtime是如何去处理逻辑的。而是在我们的合约里面,要 怎么安排逻辑。 在前面的文章中,我们已经规划了一个合约的代码结构,其中在"process.rs"文件中来放我们的 处理逻辑,每个处理逻辑处理对应的Instruction。并且Instruction的data部分是通过Borsh 来进行序列化的。 那么我们一个合约中怎么根据用户的输入来执行不同的逻辑呢?在前面我们知道一个合约只有通过 "entrypoint"宏定义的一个入口。那么我们是怎么区分不同的Instruction的呢? 本质上来说,只有一个Instruction,在客户端的不同的Instruction其实只是data部分存放的 数据不同而已。这里如果有应用开发经验的同学,立马就会联想到Protobuf里面定义的各种消息。 其实这里我们也是用类似的方法,在data部分的最开始,我们用来放cmd,cmd来表示后面的内容要按照 什么结构来解析。 结构化工程上面我们在同一个文件中,安排了一个合约的各个部分。当合约逻辑复杂的时候,我们可以将其一一拆分, 在书写的时候更清晰。来看token 合约的结构: Copy├── src │ ├── entrypoint.rs │ ├── error.rs │ ├── instruction.rs │ ├── lib.rs │ ├── processor.rs │ └── state.rs其中"entrypoint" 专门用来定义合约入口函数。 在entrypoint中,…
-
- 0 篇回复
- 24 次查看
-
-
Solana合约结构回到我们之前在Playground,这次我们直接用其给的模版创建项目。 里面看到合约代码: Copyuse borsh::{BorshDeserialize, BorshSerialize}; use solana_program::{ account_info::{next_account_info, AccountInfo}, entrypoint, entrypoint::ProgramResult, msg, program_error::ProgramError, pubkey::Pubkey, }; /// Define the type of state stored in accounts #[derive(BorshSerialize, BorshDeserialize, Debug)] pub struct GreetingAccount { /// number of greetings pub counter: u32, } // Declare and export the program's entrypoint entrypoint!(process_instruction); // Program entrypoint's implementation pub fn process_instruction( program_id: &Pubkey, // Public key of the accoun…
-
- 0 篇回复
- 21 次查看
-
-
HelloWorldSolana为了初学者可以快速入门,提供了一个 Playground 服务。 可以在不需要本地环境的情况下,进行DApp的开发。 创建项目在界面中,我们点击 "Create a New Project" 创建完项目后。在Explorer里可以看到文件列表,主要有: Copysrc/ lib.rs client/ clinet.ts test/ native.test.ts 对应的位置有 "Build":构建合约 "Run" : 运行客户端端,调试合约。 "Test": 执行测试代码 链接钱包在界面的左下角有个"unconnect"的提示,点击后,弹出: 在这里选择我们之前生成的"~/.config/solana/id.json"秘钥文件。导入后,可以看到钱包详情 开发合约打开这里的lib.rs,在里面贴上: Copyuse solana_program::{ account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, msg, }; // Declare and export the program's entrypoint entrypoint!(process_instruction); // Program entrypoint's implementation pub fn process_instruction( _pro…
-
- 0 篇回复
- 17 次查看
-
-
课后练习附件中的工程是一个"Tic-Tac-Toe"游戏。 CopyX, select a space 1 | 2 | 3 -------------- 4 | 5 | 6 -------------- 7 | 8 | 9运行后是这样的一个棋盘。两个玩家依次落子。先排成“横”,“竖”,“斜”一条线的赢。 代码中其他文件忽略,只关注 game.rs/board.rs 这两个文件。里面有“TODO”提示。在提示的地方填充函数内容。 最后运行cargo test 提示测试通过: Copyrunning 27 tests test board::tests::a_space_can_only_be_taken_once ... ok test board::tests::finds_available_spaces_in_full_board ... ok test board::tests::o_plays_next ... ok test board::tests::finds_available_spaces_in_empty_board ... ok test board::tests::a_space_above_the_board_cant_be_chosen ... ok test board::tests::a_negative_space_cant_be_chosen ... ok test board::tests::finds_available_spaces_in_an_in_progress_board…
-
- 0 篇回复
- 18 次查看
-
-
Rustaceans 的理解如果没有其他语言为基础。那么不建议首先学习 Rust。但是有了其他语言的基础,又会对 Rust 的语言中的一些不那么常见的语法所难倒。 这里 Rustaceans 是对 Rust 程序员的一种昵称,我们在写代码的时候,也需要尽量的用 Rust 的思维来写,而不是对其他语言的翻译。比如将已有的 Solidity 翻译成 Rust。 这里标题为 Rustaceans,其实内容是 Rust 的陷阱与缺陷。主要讲一些 Rust 里面比较难理解的语法。 内存管理rust 不是说不需要像 C++一样 new/delete,自己开辟/释放内存么?怎么还需要说内存管理。 所有权和借用智能指针rust 的智能指针,主要提供了 Box<T> 在堆上分配空间 Rc<T> 引用计数,可以使得一个对象有多个 owner Ref<T> and RefMut<T>, RefCell<T> 强制要求在运行时检查借用关系,而不是编译期间,就有点动态检查的意思 Box<T>box 顾名思义,就是装箱,在 Objective-C 中有相关概念。本质就类似 C 里面 alloc 一段内存,然后将值 copy 过去。 Copyfn main() { let b = Box::new(5); println!("b = {}", b); }这个时候,b 实际上存储的是一个指针,指向一段放了数字 5 的内存,这段内存在堆上面。 类似这样的定义: …
-
- 0 篇回复
- 18 次查看
-