![](https://hackmd.io/_uploads/B1RLMJMC3.png) **目录** [toc] :::success 欢迎对Aleo技术感兴趣的小伙伴加入社群! 注意哈,社群只讨论技术,所以非技术类小伙伴谨慎加入哦! 再次非常感谢大家的支持,谢谢! TG: https://t.me/+VATAn9z4x_9iOTc1 ::: # Aleo指令 ## 命令集 命令列表 :::info :information_source: 您可以通过运行打印命令列表snarkvm --help ::: * snarkvm new * snarkvm build * snarkvm run * snarkvm execute * snarkvm clean * snarkvm update Aleo 私钥、查看密钥和地址将打印到控制台。请参阅concepts/accounts获取更多信息。 **snarkvm new** 要创建新包,请运行: ```php= snarkvm new {$NAME} ``` 有效的包名称为snake_case:小写字母和数字,下划线分隔。此命令将使用给定的包名称创建一个新目录。新包的目录结构如下: ```php= package-name/ ├── program.json # Your program manifest ├── README.md # Your program description └── main.leo # Your program file ``` **snarkvm build** :::info :information_source: 从 SnarkVM 开始,此命令已被弃用v0.14.5。它将在未来版本中删除。 ::: 要编译您的程序并验证它是否正确构建,请运行: ```php= snarkvm build ``` 要在离线模式下编译程序,请运行: ```php= snarkvm build --offline ``` **snarkvm run** 要运行 Aleo 程序功能,请运行: ```php= snarkvm run {$FUNCTION} {$INPUTS} // Example snarkvm run hello 2u32 3u32 ``` 要在离线模式下运行 Aleo 程序功能,请运行: ```php= snarkvm run {$FUNCTION} {$INPUTS} --offline ``` 要将 Aleo 程序函数运行到指定端点,请运行: ```php= snarkvm run {$FUNCTION} {$INPUTS} --endpoint {$ENDPOINT} ``` **snarkvm execute** 要执行 Aleo 程序功能,请运行: ```php= snarkvm execute {$FUNCTION} {$INPUTS} // Example snarkvm run hello 2u32 3u32 ``` 要在离线模式下执行 Aleo 程序功能,请运行: ```php= snarkvm execute {$FUNCTION} {$INPUTS} --offline ``` 要将 Aleo 程序函数执行到指定端点,请运行: ```php= snarkvm execute {$FUNCTION} {$INPUTS} --endpoint {$ENDPOINT} ``` **snarkvm clean** 要清理 Aleo 包构建目录,请运行: ```php= snarkvm clean ``` **snarkvm update** 要将 SnarkVM 更新到最新版本,请运行: ```php= snarkvm update ``` 要列出 Aleo 的可用版本,请运行: ```php= snarkvm update --list ``` 要更新 SnarkVM 并且不要输出到终端,请运行: ```php= snarkvm update --quiet ``` ## 语法 Aleo 指令语法 本章包含 Aleo 指令的高级语法。[更详细的 ABNF 语法](https://github.com/AleoHQ/grammars)可以在这里找到。 ```php= program = *import "program" program-id ";" 1*( mapping / struct / record / closure / function ) import = "import" program-id ";" mapping = "mapping" identifier ":" mapping-key mapping-value mapping-key = "key" identifier "as" finalize-type ";" mapping-value = "value" identifier "as" finalize-type ";" struct = "struct" identifier ":" 1*tuple tuple = identifier "as" plaintext-type ";" record = "record" identifier ":" "owner" "as" ( "address.public" / "address.private" ) ";" *entry entry = identifier "as" entry-type ";" closure = "closure" identifier ":" *closure-input 1*instruction *closure-output closure-input = "input" register "as" register-type ";" closure-output = "output" operand "as" register-type ";" function = "function" identifier ":" *function-input *instruction *function-output [ finalize-command finalize ] function-input = "input" register "as" value-type ";" function-output = "output" operand "as" value-type ";" finalize = "finalize" identifier ":" *finalize-input 1*command *finalize-output finalize-input = "input" register "as" finalize-type ";" finalize-output = "output" operand "as" finalize-type ";" finalize-command = "finalize" *( operand ) ";" command = contains / get / get-or-use / set / remove / random / position / branch / instruction contains = "contains" identifier "[" operand "]" "into" register ";" get = "get" identifier "[" operand "]" "into" register ";" get-or-use = "get.or_use" identifier "[" operand "]" operand "into" register ";" set = "set" operand "into" identifier "[" operand "]" ";" remove = "remove" identifier "[" operand "]" ";" random = "rand.chacha" *2( operand ) "into" register "as" literal-type ";" label = identifier position = "position" label ";" branch-op = "branch.eq" / "branch.neq" branch = branch-op operand operand label ";" instruction = ( unary / binary / ternary / is / assert / commit / hash / cast / call ) ";" unary = unary-op ( operand ) "into" register unary-op = "abs" / "abs.w" / "double" / "inv" / "neg" / "not" / "square" / "sqrt" binary = binary-op 2( operand ) "into" register binary-op = "add" / "add.w" / "sub" / "sub.w" / "mul" / "mul.w" / "div" / "div.w" / "rem" / "rem.w" / "mod" / "pow" / "pow.w" / "shl" / "shl.w" / "shr" / "shr.w" / "and" / "or" / "xor" / "nand" / "nor" / "gt" / "gte" / "lt" / "lte" ternary = ternary-op 3( operand ) "into" register ternary-op = "ternary" is = is-op operand operand "into" register is-op = "is.eq" / "is.neq" assert = assert-op operand operand assert-op = "assert.eq" / "assert.neq" commit = commit-op operand operand "into" register "as" ( address-type / field-type / group-type ) commit-op = "commit.bhp" ( "256" / "512" / "768" / "1024" ) / "commit.ped" ( "64" / "128" ) hash = hash-op operand "into" register "as" ( arithmetic-type / address-type ) hash-op = "hash.bhp" ( "256" / "512" / "768" / "1024" ) / "hash.ped" ( "64" / "128" ) / "hash.psd" ( "2" / "4" / "8" ) / "hash_many.psd" ( "2" / "4" / "8" ) cast = cast-op 1*( operand ) "into" register "as" cast-destination cast-op = "cast" cast-destination = register-type / "group.x" / "group.y" call = "call" ( locator / identifier ) *( operand ) "into" 1*( register ) operand = literal / "group::GEN" / register-access / program-id / "self.caller" / "block.height" literal = arithmetic-literal / address-literal / boolean-literal arithmetic-literal = integer-literal / field-literal / group-literal / scalar-literal integer-literal = signed-literal / unsigned-literal signed-literal = [ "-" ] 1*( digit *"_" ) signed-type unsigned-literal = [ "-" ] 1*( digit *"_" ) unsigned-type field-literal = [ "-" ] 1*( digit *"_" ) field-type group-literal = [ "-" ] 1*( digit *"_" ) group-type scalar-literal = [ "-" ] 1*( digit *"_" ) scalar-type address-literal = "aleo1" 1*( address-char *"_" ) address-char = "0" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "a" / "c" / "d" / "e" / "f" / "g" / "h" / "j" / "k" / "l" / "m" / "n" / "p" / "q" / "r" / "s" / "t" / "u" / "v" / "w" / "x" / "y" / "z" boolean-literal = "true" / "false" register = "r" 1*digit register-access = register *( "." identifier ) unsigned-type = "u8" / "u16" / "u32" / "u64" / "u128" signed-type = "i8" / "i16" / "i32" / "i64" / "i128" integer-type = unsigned-type / signed-type field-type = "field" group-type = "group" scalar-type = "scalar" arithmetic-type = integer-type / field-type / group-type / scalar-type address-type = "address" boolean-type = "boolean" literal-type = arithmetic-type / address-type / boolean-type / string-type plaintext-type = literal-type / identifier value-type = plaintext-type ".constant" / plaintext-type ".public" / plaintext-type ".private" / identifier ".record" / locator ".record" finalize-type = plaintext-type ".public" / identifier ".record" / locator ".record" entry-type = plaintext-type ( ".constant" / ".public" / ".private" ) register-type = locator ".record" / identifier ".record" / plaintext-type digit = "0"-"9" uppercase-letter = "A"-"Z" lowercase-letter = "a"-"z" letter = uppercase-letter / lowercase-letter identifier = letter *( letter / digit / "_" ) lowercase-identifier = lowercase-letter *( lowercase-letter / digit / "_" ) program-name = lowercase-identifier program-domain = lowercase-identifier program-id = program-name "." program-domain locator = program-id "/" identifier ``` ## 工具 Aleo 指令工具 :::info :information_source: 如果您已经安装了 Leo 语法插件 ,那么您应该已经能够看到<kbd>.aleo</kbd> Aleo 指令的语法突出显示。 ::: Aleo 维护了多种跨不同平台的语法突出显示实现。 如果您在此列表中没有看到您最喜欢的编辑器,请访问[GitHub](https://github.com/AleoHQ/welcome/issues/new)。 * Sublime Text. * Visual Studio Code. * Intellij. **Sublime Text** ![](https://hackmd.io/_uploads/B1rtqGKih.png) 在此处下载编辑器: https: //www.sublimetext.com/download。 Aleo 指令对 Sublime 的 LSP 插件的支持是通过语言服务器提供的。 **安装** * 从 Package Control安装[LSP](https://packagecontrol.io/packages/LSP)和[LSP-aleo-developer](https://packagecontrol.io/packages/LSP-leo) 。 * 重新启动 Sublime。 **使用** 请按照以下步骤切换Aleo instructions语法高亮显示。 * 打开Sublime Text。 * 从首选项 > 选择配色方案... > LSP-aleo-developer **VSCode** ![](https://hackmd.io/_uploads/BkVmiGYsh.png) 在此处下载编辑器: https: //code.visualstudio.com/download。 **安装** 从 VSCode 市场安装[Leo for VSCode](https://marketplace.visualstudio.com/items?itemName=aleohq.leo-extension) 。 正确的扩展 ID 是<kbd>aleohq.leo-extension</kbd> **使用** * 打开VSCode。 * 从首选项 > 颜色主题... > Aleo 主题 **Intellij** ![](https://hackmd.io/_uploads/SyFFjzYon.png) 在此处下载编辑器: https: //www.jetbrains.com/idea/download/。 **安装** 从 JetBrains 市场安装[Aleo 开发者插件](https://plugins.jetbrains.com/plugin/19890-aleo-developer)。 # 概念 ## 账户 Aleo 帐户由账户私钥(account private key)、帐户查看密钥(account view key)和帐户地址(account address)组成。 * ==**账户私钥**用于授权交易,更新账户记录的全局状态==。 * ==**帐户查看密钥**用于解密帐户记录==,这些记录在用户帐户地址下加密。 * 帐户地址使用户能够相互交互,发送和接收对值和应用程序数据进行编码的记录。 为了保护用户资产和记录数据,切勿将自己的账户私钥泄露给任何第三方。对于 Aleo 上的实际应用程序,用户应从其帐户私钥派生计算密钥,以允许第三方以无需信任的方式运行应用程序并代表用户生成交易。 在[这里](https://aleo.tools/)生成一个新的 Aleo 帐户。 **账户私钥** 帐户私钥是根据随机采样的==帐户种子==构造的。该帐户种子用于生成: * 帐户签名方案的密钥, * 交易序列号的伪随机函数种子 * 账户承诺方案的承诺随机性 **私钥格式** > APrivateKey1zkp4X9ApjTb7Rv8EABfZRugXBhbPzCL245GyNtYJP5GYY2k 帐户私钥的格式为 Base58 字符串,由 59 个字符组成。账户私钥使用私钥前缀编码<kbd>APrivateKey1</kbd>,表示它是私钥,不应与其他用户共享。 **账户查看密钥** Aleo 帐户查看密钥源自帐户私钥,使用户能够从全局账本中解密其记录。由于帐户查看密钥能够访问用户帐户中的每条记录,因此第三方审核员可以使用此密钥来验证帐户的完整历史记录。 帐户查看密钥由以下部分组成: * 帐户加密方案的密钥 **查看密钥格式** > AViewKey1nKB4qr9b5gK8wQvmM5sTPEuBwshtDdkCZB1SPWppAG9Y 帐户查看密钥的格式为 Base58 字符串,由 53 个字符组成。帐户查看密钥使用查看密钥前缀<kbd>AViewKey1</kbd>进行编码,表示它是查看密钥,并且只能与授权方共享。 **账户地址** Aleo 账户地址是一种唯一标识符,允许用户在交易中相互转移价值并记录数据。 帐户地址由以下部分组成: * 帐户加密方案的公钥 **地址格式** > aleo1dg722m22fzpz6xjdrvl9tzu5t68zmypj5p74khlqcac0gvednygqxaax0j 帐户地址的格式为 Bech32 字符串,由 63 个字符组成。帐户地址使用地址前缀<kbd>aleo1</kbd>进行编码。 **进阶话题** **账户前缀** ![](https://hackmd.io/_uploads/BJv7kmYjn.png) **离线账户** 在许多情况下(例如企业设置),建议在隔离的离线计算机上处理敏感密钥和数据。Aleo 帐户可以在离线计算机上创建并可以立即使用。与帐户证明密钥结合使用,用户可以确保其私钥即使在创建交易时也保持离线状态。 虽然没有完美的解决方案,但建议在断开连接的设备上创建新的 Aleo 帐户,以最大程度地降低将帐户私钥泄露给意外方的风险。 **账户承诺输出(Account Commitment Outputs)** 帐户承诺输出用于创建帐户查看密钥,该密钥由加密密钥组成。该加密密钥是从帐户承诺输出派生的标量域元素。为了确保帐户视图密钥的有效性,帐户承诺输出应该可以在标量域中表示。 **创建账户** 给定全局实例化 Aleo 参数和子例程。 **生成私钥** 1. 从随机中采样 32 字节的 seed 2. 构建私钥组件 * sk_sig = BLAKE2s(seed | 0) * sk_prf = BLAKE2s(seed | 1) * r_pk = BLAKE2s(seed | counter) 其中 | 表示串联,其中BLAKE2s表示未加密的 BLAKE2s-256,如RFC 7693中所定义。 3. private_key= ( seed, sk_sig, sk_prf, r_pk) 用于计算 sk_sig 和 sk_prf 的 0 和 1 分别被编码为无符号 16 位整数,并按小端顺序转化为两个字节,然后与种子右侧的字节序列连接,再将生成的字节序列传递给 BLAKE2s。用于计算 r_pk 的 counte 是一个无符号的 16 位整数,在与种子右边的两个字节按小内位顺序连接之前,先将其变成两个字节,然后将得到的字节序列传递给 BLAKE2s;计数器从 2 开始迭代,直到可以从私钥导出一个有效的 view_key(见下文)。 在[此处](https://www.rfc-editor.org/rfc/rfc7693)了解有关 BLAKE2 的更多信息。 **生成查看密钥** 1. 构造 pk_sig = AccountSignature.GeneratePublicKey(ppaccount_sig, sk_sig) 2. view_key = AccountCommitment.Commit(ppaccount_cm, (pk_sig, sk_prf), r_pk) **生成地址** 1. address = AccountEncryption.GeneratePublicKey(ppaccount_enc, view_key) **账户图** ```php= graph TD A["Seed (32 Bytes)"] A --> |"BLAKE2s(Seed, 0)" | B(sk_sig) A --> |"BLAKE2s(Seed, 1)" | C(sk_prf) A --> |"BLAKE2s(Seed, counter)" | D(r_pk) B --> E(Account Private Key) C --> E(Account Private Key) D --> E(Account Private Key) E --> F(Account View Key) F --> G(Account Address) ``` ## 程序 程序是表示应用程序逻辑和应用程序状态的基本数据结构。 Aleo 引入了一种名为Aleo 指令的新编程语言,使开发人员能够编写私有 Web 应用程序。Aleo 指令是一种静态类型编程语言,用于在 Aleo 上编写保护隐私的安全程序。通过利用零知识证明,Aleo 指令为现实世界的应用程序提供计算完整性。 **程序逻辑** Aleo 指令为开发人员提供了一个易于使用的程序编写环境。通过设计一种具有开发人员熟悉的语法和可组合功能的汇编语言,Aleo 指令非常适合与现有的开发人员框架集成,以增强 Web 应用程序的隐私性和完整性。 ```php= program token.aleo; record token: // The token owner. owner as address.private; // The Aleo balance (in microcredits). microcredits as u64.private; // The token balance. amount as u64.private; // The `mint` function initializes a new record with the // specified number of tokens in `r1` for the receiver in `r0`. function mint: input r0 as address.private; input r1 as u64.private; cast r0 0u64 r1 into r2 as token.record; output r2 as token.record; // The `transfer` function sends the specified number of tokens // to the receiver from the provided token record. function transfer: // Input the sender's record. input r0 as token.record; // Input the token receiver. input r1 as address.private; // Input the token amount. input r2 as u64.private; // Checks the given token record has sufficient balance. // This `sub` operation is safe, and the proof will fail // if an underflow occurs. The output register `r3` holds // the change amount to be returned to the sender. sub r0.amount r2 into r3; // Produces a token record for the specified receiver. cast r1 0u64 r2 into r4 as token.record; // Produces a token record with the change amount for the sender. cast r0.owner r0.microcredits r3 into r5 as token.record; // Output the receiver's record. output r4 as token.record; // Output the sender's change record. output r5 as token.record; ``` **程序数据** **程序ID(Program ID)** 每个程序都有一个唯一的程序 ID,该 ID 存储在程序清单中program.json。该程序ID用于指示在消费或生产记录(records)中运行的程序。 **程序输入** 要运行一个程序,需要以程序输入的形式提供用户定义的输入。除非用户有意公开,否则用户提供的输入是完全保密的,不会泄露给公共网络。 **程序状态** 每个程序都根据用户提供的程序状态在 Aleo 上运行。为了在 Aleo 上产生有效的状态转换,用户需要满足一系列以记录编码的程序,这些记录(records)组成了一个交易(transaction)。 **程序输出** 程序一经评估,就会产生程序输出以及证明输出有效性的零知识证明。 ## 记录 记录(record)是用于编码用户资产和应用程序状态的基本数据结构。 每个账户记录都包含指定记录所有者、存储值和应用状态的信息。Aleo 中的记录是通过过度函数(transition function)消耗和新建的。一个交易会存储多个过度,每个过度负责消耗和创建其单个记录。如果记录的可见性是私有的,还可以选择使用所有者的地址密钥对其进行加密。 **记录的组成** Aleo 记录按以下格式序列化: ![](https://hackmd.io/_uploads/Sy5d7XFjh.png) **Owner** > aleo1r0dry2tlhjt0yplctz85692kjpqsadn7xgxsmrehkasykjxynypqza3fpl 记录所有者是一个帐户地址,指定有权使用该记录的一方。 **Gates** > 4130 微积分记录指定记录中存储的 Aleo 积分数量。 **数据** > [ RECORD BYTE MAP ] 记录数据对任意应用信息进行编码。 **随机数** > 3024738992072387217402876176731225730589877991873828351104009809002984426287group 序列号随机数用于为每条记录创建唯一标识符,通过对所有者的地址密钥询问和记录序列号进行 PRF 评估计算得出。 **记录加密(可选)** 具有私人可见性的记录会在转换过程中进行可验证的加密,并存储在账本上。这样,用户之间就能通过公共网络安全、私密地传输记录数据和数值。只有拥有相应账户视图密钥的发送方和接收方才能解密这些记录。 ## 交易 交易(transaction)是在账本上发布状态转换的基本数据结构。 **交易类型** **部署交易** 部署交易向网络发布 Aleo 程序。 | 参数 | 类型 | 中文描述 | 英文描述 | | ---------- | ------ | ------------------------------------------------------------------------------------------------------------------------------ | --- | | type | string | 交易类型(部署) | The type of transaction (deploy) | | id | string | 交易 ID,通过对过度 ID 的默克尔树摘要计算得出 | The ID of transaction, computed via the Merkle Tree Digest of the transition IDs | | owner | object | 所有者地址和签名 | The owner address and signature | | deployment | object | 部署的交易信息 | The deployment transaction info | | fee | object | 部署的交易费 |The deployment transaction fee | **部署信息** | 参数 | 类型 | 中文描述 | 英文描述 | | ---- | ---- | -------- | -------- | | global_state_root | u16 | 默克尔树的全局状态根 | The global state root of the merkle tree | | transitions | array | 过度 | The transitions | **执行交易** 执行交易代表对 Aleo 程序的调用。 | 参数 | 类型 | 中文描述 | 英文描述 | | -------- | -------- | --- | -------- | | type | string | 交易类型(执行) | The type of transaction (execute) | | id | string | 交易 ID,通过对过度 ID 的默克尔树摘要计算得出 | The ID of transaction, computed via the Merkle Tree Digest of the transition IDs | | execution | object | 执行交易信息 | The execution transaction info | | fee (optional) | object | 可选的执行交易费 | The optional execution transaction fee | **执行信息** | 参数 | 类型 | 中文描述 | 英文描述 | | -------- | -------- | --- | -------- | | global_state_root | u16 | 默克尔树的全局状态根 | The global state root of the merkle tree | | transitions | Tarray | 过度 | The transitions | **交易费用** 交易费用代表支付给网络的费用,用于被拒绝的交易 | 参数 | 类型 | 中文描述 | 英文描述 | | -------- | -------- | --- | -------- | | type | string | 交易类型(费用)| The type of transaction (fee) | | id | string | 交易 ID,通过对过度 ID 的默克尔树摘要计算得出 | The ID of transaction, computed via the Merkle Tree Digest of the transition IDs| | fee | object| 被拒绝的交易费 | The rejected transaction fee| **交易结构** | 参数 | 类型 | 中文描述 | 英文描述 | | -------- | -------- | --- | -------- | | type | string | 交易类型 | The type of transaction | | id | string | 交易 ID(at1 prefix) | The ID of transaction (at1 prefix)| | deployment | object | 部署交易信息 | The deployment transaction info | | additional_fee | object | 交易的额外费用 | The additional fee for the transaction| ## 交易费用 交易费是在 Aleo 网络上处理交易所需的费用。目前,每种交易类型对应的交易费用有两种:部署和执行。 Aleo积分面额表 | 面额 | 交易大小 | 值 | 例子 | | -------- | -------- | --- | -------- | | microcredit | Byte | 1 | 最小面额 | | millicredit | Kilobyte (KB) | 1000 microcredits | 大多数交易平均在 3 至 10 millicredits之间 | | credit | Megabyte (MB) | 1000 millicredits | 最大面额 | 请注意,交易大小是使用[ Big O 表示法(按顺序)](https://en.wikipedia.org/wiki/Big_O_notation)的平均值。 **交易费用的类型** **部署交易费用** 在 Aleo 区块链上部署应用程序时产生的费用 **结构** | 部署交易的部分 | 大小 | 乘法器 | 成本 | | ------------------- | ---- | ------ | -------------- | | Transaction wrapper | 0KB | 1 | 0 millicredits | | | Transition wrapper | 0KB | 1 | 0 millicredits | | Certificate | 1KB | 2 | 2 millicredits | | Verifying key | 1KB | 2 | 2 millicredits | | Program bytecode | 1KB | 1 | 1 millicredit | | 总计 | 大小 | 乘法器 | 总成本 | | -------- | -------- | --- | -------- | | Transaction -> Transition | 5KB | 1000* | 5 credits | ![](https://hackmd.io/_uploads/rJliY4Kjh.png) 注意: * 为防止恶意行为者在网络上进行多余的交易,所有部署交易都将添加一个可变的部署交易乘数。 **执行交易费用** 在 Aleo 区块链上执行应用程序时产生的费用 **结构(最小成本案例)** | 执行交易的部分 | 大小 | 乘法器 | 成本 | | ------------------- | ---- | ------ | -------------- | | Transaction wrapper | 0KB | 1 | 0 millicredits | | | Transition wrapper | 0KB | 1 | 0 millicredits | | Input | 1KB | 2 | 2 millicredits | | Output | 1KB | 2 | 2 millicredits | | Proof | 1KB | 1 | 1 millicredit | | 总计 | 大小 | 乘法器 | 总成本 | | -------- | -------- | --- | -------- | | Transaction -> Transition | 5KB | 1 | 5 millicredits | ![](https://hackmd.io/_uploads/S1thFNto3.png) **结构(最大成本案例)** | 执行交易的部分 | 大小 | 乘法器 | 成本 | | ------------------- | ---- | ------ | -------------- | | Transaction wrapper | 1KB | 65 | 65 millicredits | | | Transition wrapper | 1MB | 32 | 32 credits | | Input | 1KB | 16 * 32 | 512 millicredits | | Output | 1KB | 16 * 32 | 512 millicredits | | Proof | 1KB | 1 | 1 millicredit | | 总计 | 大小 | 乘法器 | 总成本 | | -------- | -------- | --- | -------- | | Transaction -> Transition | 32MB | 1 | 32 credits | ![](https://hackmd.io/_uploads/ryw6YEFj2.png) 注意: * 为防止垃圾邮件,最低执行交易费可能会提高;目前,基本的<kbd>credits.aleo</kbd>转账的最低执行交易费稳定在 3 至 5 millicredits 之间。 ## 过度 **过度的组成部分** Aleo的过度按以下格式序列化: | 参数 | 类型 | 中文描述 | 英文描述 | | ------------- | -------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | id | finite field element | 过度ID,由Input ID和Output ID形成的默克尔树摘要计算得出 | The transition id, which is computed via the Merkle tree digest formed from the Input and Output IDs | | program_id | string | 程序 ID,它与账本上全局维护映射上的验证密钥相关联。 | The program ID, which is associated with a verification key on a globally maintained map on the ledger. | | function_name | string | 函数名称,用于使用 program_id 计算 function_id。 | The function name, which is used to compute a function_id using the program_id. | | inputs | array of Inputs | 过度的Input,可以是constant、public、private或inputRecord | The transition Inputs, which can be a constant, public, private, or inputRecord | | outputs | array of Outputs | 过度的Output,可以是constant、public、private或outputRecord | The transition Outputs, which can be a constant, public, private, or outputRecord | | finalize | array | 为了最终化的输入 | The inputs for finalize | | tpk | group element | 公共密钥,用于验证owner在交易中提供的数字签名 | The transition public key, which is used to verify the digital signature provided by the owner in a transaction | | tcm | finite field element | 过度的承诺 | The transition commitment | **输入记录** inputRecord 是由serial_number和tag组成的元组。回想一下,由于序列号会在账本上公布,这就公开宣布了正在使用的记录。回顾一下,序列号被公布在账本上,以宣布之前未支出的记录现已支出。每条记录都有一个相关的tag,用来追踪用户可以使用的记录。标签通过 tag = CRH.Eval(sk_tag, record_commitment) 计算得出。 **输出记录** outputRecord 由记录承诺(record_commitment)、校验(checksum)和记录密文(record_ciphertext)组成。 记录承诺(record_commitment)通过 ``` Pedersen.Commit(pp, apk || data || nonce || microcredits ; r) ``` 计算。 record_encryption 通过 ``` SymmEnc.Eval(pp, apk || data || nonce || microcredits ; r) ``` 计算。 校验用于验证记录承诺的完整性,通过 record_commitment = CRH.Eval(record_encryption) 计算。 ## 区块 区块是组织 Aleo 交易的基本数据结构。 **区块的组成** Aleo的区块按以下格式序列化: | 参数 | 类型 | 中文描述 | 英文描述 | | ---- | ---- | -------- | -------- | | block_hash | string | 区块的哈希值 | The hash of the block| | previous_hash | string | 上一个区块的哈希值 | The hash of the previous block| | header | object | 区块头 | The header of the block| | transactions | array | 区块中的交易 | The transactions in the block| | ratificactions | array | 证明区块奖励的批准书 | The ratifications for proving rewards in the block| | coinbase | string | 通过累积单个证明人的解决方案,构建出 coinbase谜题的解决方案。 | The coinbase puzzle solution constructed by accumulating the individual prover solutions.| | signature | string |区块的签名 | The signature for the block| **交易(Transactions)** 交易是指定区块中包含的所有交易的列表。 **区块头(Block Header)** 区块头包含的组件概括了指定区块的状态,以及历史上此刻账本的状态。更多详情,请参阅区块头的组成部分。 **区块头的组成** Aleo的区块头按以下格式序列化: | 参数 | 类型 | 中文描述 | 英文描述 | | -------- | -------- | --- | -------- | | previous_state_root | string | 默克尔根代表账本中直到前一个区块的所有区块。 | The Merkle root representing the blocks in the ledger up to the previous block.| | transactions_root | string | 代表区块中交易的默克尔根。 | The Merkle root representing the transactions in the block.| | finalize_root | string | 代表链上最终化(包括当前区块)的默克尔根。 | The Merkle root representing the on-chain finalize including the current block.| | ratifications_root | string | 代表区块中批准信息的默克尔根。 | The Merkle root representing the ratifications in the block.| | coinbase_accumulator_point | string | coinbase谜题的累积点。 | The accumulator point of the coinbase puzzle.| | metadata | object | 区块的元数据 | The metadata of the block.| **元数据** | 参数 | 类型 | 中文描述 | 英文描述 | | -------- | -------- | --- | -------- | | network | u16 | 区块的网络 ID | The network ID of the block| | round | u64 | 产生此区块的轮次 - 8 字节 | The round that produced this block - 8 bytes| | height | u32 | 该区块的高度 - 4 字节 | The height of this block - 4 bytes| | total_supply_in_microcredits | u64 | 微积分的总供应量 - 8 个字节 | The total supply of microcredits - 8 bytes| | cumulative_weight | u128 | 该区块的累计权重 - 16 字节 | The cumulative weight for this block - 16 bytes| | cumulative_proof_weight | u128 | 该区块的累计校验目标 - 16 字节 | The cumulative proof target for this block - 16 bytes| | coinbase_target | u64 | 该区块的coinbase目标 - 8字节 | The coinbase target for this block - 8 bytes| | proof_target | u64 | 该区块的证明目标 - 8字节 | The proof target for this block - 8 bytes| | last_coinbase_target | u64 | 前一个区块的coinbase目标 - 8字节 | The coinbase target for the last coinbase - 8 bytes| | last_coinbase_timestamp | u64 | 前一个coinbase的UTC格式时间戳 - 8字节 | The Unix timestamp (UTC) for the last coinbase - 8 bytes| | timestamp | i64 | 该区块的UTC格式时间戳 - 8字节 | The Unix timestamp (UTC) for this block - 8 bytes| # Aleo SDK ## 概述 [@aleohq/sdk](https://www.npmjs.com/package/@aleohq/sdk) Aleo高级实用程序在 JavaScript 中处理浏览器中的帐户、记录和节点连接。 在底层使用[@aleohq/wasm ](https://www.npmjs.com/package/@aleohq/wasm)。 **构建指南** 1. 要构建项目,请转到项目的根目录并执行<kbd>npm install && npm run build</kbd>. **文档** 1. 要查看文档,请打开docs/index.html. 2. 要重新生成文档,请运行<kbd>npx jsdoc --configure jsdoc.json --verbose</kbd> **Aleo工具** [Aleo SDK account generator](https://aleo.tools/) [Aleo Home](https://www.aleo.org/) 您可以访问[SnarkVM代码库](https://github.com/AleoHQ/snarkVM)和[SnarkOS代码库](https://github.com/AleoHQ/snarkOS)来深入了解 aleo 基础设施的代码 ## 账户 **概述** 密钥管理类。允许创建新的 Aleo 帐户、从现有私钥或种子导入现有帐户以及消息签名和验证功能。 Aleo 帐户是根据随机生成的种子(数字)生成的,帐户私钥、查看密钥和公共帐户地址均从中派生。私钥位于 Aleo 帐户的根目录中。这是一个高度敏感的秘密,应该受到保护,因为它允许创建 Aleo 程序执行和任意价值转移。查看密钥允许解密用户在区块链上的活动。该地址是 Aleo 的其他用户可以向其发送 Aleo 积分和其他记录的公共地址。该类只能在可以保证底层密钥材料安全的环境中使用。 Kind: global class **Account** * instance .encryptAccount(ciphertext) ⇒ PrivateKeyCiphertext .decryptRecord(ciphertext) ⇒ Record .decryptRecords(ciphertexts) ⇒ Array.\<Record> .ownsRecordCiphertext(ciphertext) ⇒ boolean .sign(message) ⇒ Signature .verify(message, signature) ⇒ boolean * static .fromCiphertext(ciphertext, password) ⇒ PrivateKey | Error **account.encryptAccount(ciphertext) ⇒ PrivateKeyCiphertext** 用密码加密账户的私钥 | Param | Type | | -------- | -------- | | ciphertext | string | 示例: ```php= let account = new Account(); let ciphertext = account.encryptAccount("password"); ``` **account.decryptRecord(ciphertext) ⇒ Record** 将密文形式的记录解密为明文 | Param | Type | | -------- | -------- | | ciphertext | string | 示例: ```php= let account = new Account(); let record = account.decryptRecord("record1ciphertext"); ``` **account.decryptRecords(ciphertexts) ⇒ Array.\<Record>** 将密文形式的记录数组解密为明文 | Param | Type | | -------- | -------- | | ciphertext | Array.\<string> | 示例: ```php= let account = new Account(); let record = account.decryptRecords(["record1ciphertext", "record2ciphertext"]); ``` **account.ownsRecordCiphertext(ciphertext) ⇒ boolean** 判断账户是否拥有密文记录 ![](https://hackmd.io/_uploads/H1BICl9i2.png) 示例: ```php= // Create a connection to the Aleo network and an account let connection = new NodeConnection("vm.aleo.org/api"); let account = Account.fromCiphertext("ciphertext", "password"); // Get a record from the network let record = connection.getBlock(1234); let recordCipherText = record.transactions[0].execution.transitions[0].id; // Check if the account owns the record if account.ownsRecord(recordCipherText) { // Then one can do something like: // Decrypt the record and check if it's spent // Store the record in a local database // Etc. } ``` **account.sign(message) ⇒ Signature** 使用帐户的私钥签署消息。返回签名。 | Param | Type | | -------- | -------- | | message | Uint8Array | 示例: ```php= let account = new Account(); let message = Uint8Array.from([104, 101, 108, 108, 111 119, 111, 114, 108, 100]) account.sign(message); ``` **account.verify(message, signature) ⇒ boolean** 验证消息上的签名。 | Param | Type | | ------- | ---------- | | signature | Signature | | message | Uint8Array | 示例: ```php= let account = new Account(); let message = Uint8Array.from([104, 101, 108, 108, 111 119, 111, 114, 108, 100]) let signature = account.sign(message); account.verify(message, signature); ``` **Account.fromCiphertext(ciphertext, password) ⇒ PrivateKey | Error** 尝试从私钥密文创建帐户 Kind:静态方法Account ![](https://hackmd.io/_uploads/r1OSAg5jh.png) 示例: ```php= let ciphertext = PrivateKey.newEncrypted("password"); let account = Account.fromCiphertext(ciphertext, "password"); ``` ## Aleo网络客户端 **概述** 连接管理类,用于封装对 Aleo 节点公开暴露的端点的 REST 调用。该类提供的方法可提供有关 Aleo 区块链的信息。 Kind: global class **AleoNetworkClient** * new AleoNetworkClient(host) * .setAccount(account) * .getAccount() * .getBlock(height) * .getBlockRange(start, end) * .getProgram(programId) * .getProgramMappingNames(programId) * .getMappingValue(programId, mappingName, key) * .getLatestBlock() * .getLatestHash() * .getLatestHeight() * .getStateRoot() * .getTransaction(id) * .getTransactions(height) * .getTransactionsInMempool() * .getTransitionId() * .findUnspentRecords() **new AleoNetworkClient(host)** | Param | Type | | -------- | -------- | | host | String | 示例: ```php= // Connection to a local node let local_connection = new AleoNetworkClient("http://localhost:3030"); // Connection to a public beacon node let public_connection = new AleoNetworkClient("https://vm.aleo.org/api"); ``` **aleoNetworkClient.setAccount(account)** 设置账户 | Param | Type | | -------- | -------- | | account | Account | 示例: ```php= let account = new Account(); connection.setAccount(account); ``` **aleoNetworkClient.getAccount()** 返回节点连接中使用的Aleo账户 示例: ```php= let account = connection.getAccount(); ``` **aleoNetworkClient.getBlock(height)** 返回指定块高度处的块的块内容 | Param | Type | | -------- | -------- | | height | number | 示例: ```php= let block = connection.getBlock(1234); ``` **aleoNetworkClient.getBlockRange(start, end)** 返回指定块高度之间的块范围 | Param | Type | | ------ | ------ | | start | number | | end | number | 示例: ```php= let blockRange = connection.getBlockRange(2050, 2100); ``` **aleoNetworkClient.getProgram(programId)** 返回程序的源代码 | Param | Type | | -------- | -------- | | programId | string | 示例: ```php= let program = connection.getProgram("foo.aleo"); ``` **aleoNetworkClient.getProgramMappingNames(programId)** 返回程序映射的名称 | Param | Type | | -------- | -------- | | programId | string | 示例: ```php= let mappings = connection.getProgramMappingNames("credits.aleo"); ``` **aleoNetworkClient.getMappingValue(programId, mappingName, key)** 返回特定键的程序映射值 | Param | Type | | --------- | ------ | | programId | string | | mappingName | string | | key | string | 示例: ```php= ## Get public balance of an account let mappingValue = connection.getMappingValue("credits.aleo", "account", "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px"); ``` **aleoNetworkClient.getLatestBlock()** 返回最新区块的区块内容 示例: ```php= let latestHeight = connection.getLatestBlock(); ``` **aleoNetworkClient.getLatestHash()** 返回最新区块的哈希值 示例: ```php= let latestHash = connection.getLatestHash(); ``` **aleoNetworkClient.getLatestHeight()** 返回最新的区块高度 示例: ```php= let latestHeight = connection.getLatestHeight(); ``` **aleoNetworkClient.getStateRoot()** 返回 Aleo 区块链最新的 状态/默克尔 根 示例: ```php= let stateRoot = connection.getStateRoot(); ``` **aleoNetworkClient.getTransaction(id)** 通过其唯一标识符返回交易 | Param | Type | | -------- | -------- | | id | string | 示例: ```php= let transaction = connection.getTransaction("at1handz9xjrqeynjrr0xay4pcsgtnczdksz3e584vfsgaz0dh0lyxq43a4wj"); ``` **aleoNetworkClient.getTransactions(height)** 返回指定区块高度处存在的交易 | Param | Type | | -------- | -------- | | height | number | 示例: ```php= let transactions = connection.getTransactions(654); ``` **aleoNetworkClient.getTransactionsInMempool()** 返回内存池中的事务。 示例: ```php= let transactions = connection.getTransactionsInMempool(); ``` **aleoNetworkClient.getTransitionId()** 通过其唯一标识符返回过度id 示例: ```php= let transition = connection.getTransitionId("2429232855236830926144356377868449890830704336664550203176918782554219952323field"); ``` **aleoNetworkClient.findUnspentRecords()** 尝试在 Aleo 区块链中查找指定私钥的未使用记录 示例: ```php= // Find all unspent records const privateKey = "[PRIVATE_KEY]"; let records = connection.findUnspentRecords(0, undefined, privateKey); // Find specific amounts const startHeight = 500000; const amounts = [600000, 1000000]; let records = connection.findUnspentRecords(startHeight, undefined, privateKey, amounts); // Find specific amounts with a maximum number of cumulative microcredits const maxMicrocredits = 100000; let records = connection.findUnspentRecords(startHeight, undefined, privateKey, undefined, maxMicrocredits); ``` ## 开发客户端 **概述** Kind: global class **DevelopmentClient** * new DevelopmentClient(baseURL) * .deployProgram(program, fee, privateKey, password, feeRecord) ⇒ string | Error * .executeProgram(programId, programFunction, fee, inputs, privateKey, password, feeRecord) ⇒ string | Error * .transfer(amount, fee, recipient, transfer_type, privateKey, password, feeRecord, amountRecord) ⇒ string | Error **new DevelopmentClient(baseURL)** 创建一个新的 DevelopmentClient 以与 Aleo 开发服务器交互。 | Param | Type | Description | | ----- | ------ | --- | | baseURL | string | Aleo 开发服务器的 URL | **developmentClient.deployProgram(program, fee, privateKey, password, feeRecord) ⇒ string | Error** 通过 Aleo 开发服务器在 Aleo 网络上部署程序。要求 Aleo 开发服务器在远程或本地运行。如果一个开发服务器未运行,该函数将抛出错误。 有关如何运行 Aleo 开发服务器的信息,请访问:https://github.com/AleoHQ/sdk/rust/develop/README.md。 Kind:实例化DevelopmentClient 返回:string | Error - 如果成功,则返回部署交易的 transaction_id | Param | Type | Description | | ------- | ------ | --------------------- | | program | string | 要部署的程序的文本表示 | | fee | number | 程序部署费用(必填) | | privateKey | string \| undefined | 部署程序用户的可选私人密钥 | | password | string \| undefined | 如果使用加密私钥启动开发服务器,则需要输入密码 | | feeRecord | string \| undefined | 用于支付费用的可选文本格式记录。如果没有提供,服务器将在网络中搜索合适的记录来支付费用。 | 示例: ```php= const Program = 'program yourprogram.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n'; const client = new DevelopmentClient("http://0.0.0.0:4040"); const transaction_id = await client.deployProgram(Program, 6000000, privateKeyString); ``` **developmentClient.executeProgram(programId, programFunction, fee, inputs, privateKey, password, feeRecord) ⇒ string | Error** 通过 Aleo 开发服务器在 Aleo 网络上执行程序。要求 Aleo 开发服务器在远程或本地运行。如果开发服务器未运行,该函数将出错。 有关如何运行 Aleo 开发服务器的信息,请访问:https://github.com/AleoHQ/sdk/rust/develop/README.md。 Kind:实例化DevelopmentClient 返回:string | Error - 如果成功,则返回部署交易的 transaction_id | Param | Type | Description | | --------------- | ------------------- | ---------------------------------------------------------------------------------------- | | programId | string | 要执行的程序的程序 ID(例如 hello.aleo) | | programFunction | string | 程序中要执行的函数(如 hello) | | fee | number | 为执行交易支付的可选费用,指定 0 表示无费用 | | inputs | Array.\<string> | 数组格式输入传递给程序 | | privateKey | string \| undefined | 执行程序用户的可选私人密钥 | | password | string \| undefined | 如果使用加密私钥启动开发服务器,则需要输入密码 | | feeRecord | string \| undefined | 用于支付费用的可选文本格式记录。如果没有提供,服务器将在网络中搜索合适的记录来支付费用。 | 示例: ```php= const privateKey = "your private key"; const client = new DevelopmentClient("http://0.0.0.0:4040"); const transaction_id = await client.executeProgram("hello.aleo", "hello", 0, ["5u32", "5u32"], privateKeyString); ``` **developmentClient.transfer(amount, fee, recipient, transfer_type, privateKey, password, feeRecord, amountRecord) ⇒ string | Error** 通过 Aleo 开发服务器向 Aleo 网络上的指定收件人转账积分。要求 Aleo 开发服务器在远程或本地运行。如果开发服务器未运行,该函数将出错。 有关如何运行 Aleo 开发服务器的信息,请访问:https://github.com/AleoHQ/sdk/rust/develop/README.md。 Kind:实例化DevelopmentClient 返回:string | Error - 如果成功,则返回部署交易的 transaction_id | Param | Type | Description | | ------- | ------ | --------------------- | | amount | string | 要转账的积分数(例如 1.5) | | fee | number | 可选的转账费用,指定 0 表示无费用 | | recipient | string | 转账接收人 | | transfer_type | string | 传输类型(可能的值有 "private"、"public"、"private_to_public"、"public_to_private")。| | privateKey | string \| undefined | 转账用户的可选私人密钥 | | password | string \| undefined | 如果使用加密私钥启动开发服务器,则需要输入密码 | | feeRecord | string \| undefined | 用于支付费用的可选文本格式记录。如果没有提供,服务器将在网络中搜索合适的记录来支付费用。 | | amountRecord | string \| undefined | 用于转账的可选文本格式记录。如果没有提供,服务器将在网络中搜索合适的记录来为该金额提供资金。 | 示例: ```php= const privateKey = "your private key"; const recipient = "recipient's address"; const client = new DevelopmentClient("http://0.0.0.0:4040"); const transaction_id = await client.transfer(1.5, 0, recipient, privateKey); ``` # Aleo Wasm ## 概述 [@aleohq/wasm](https://www.npmjs.com/package/@aleohq/wasm) Aleo JavaScript 和 WebAssembly 绑定用于构建零知识 Web 应用程序。 Rust编译很容易,WebAssembly但创建使用其他语言(例如 JavaScript)编译的 WebAssembly 二进制文件所需的粘合代码是一项具有挑战性的任务。wasm-bindgen是一个工具,通过自动生成与已编译到 WebAssembly 中的 Rust 代码的 JavaScript 绑定来简化此过程。 该板条箱用于wasm-bindgen创建与 Aleo 源代码的 JavaScript 绑定,以便它可用于直接在web browsers和中创建零知识证明NodeJS。 该板条箱公开的功能包括: Aleo 帐户管理对象 Aleo 原语,例如Records、Programs和Transactions及其关联的辅助方法 ProgramManager包含创作、部署 Aleo 程序以及与 Aleo 程序交互的方法的对象 有关这些概念的更多信息,请访问Aleo 开发人员中心。 Aleo JavaScript 和 WebAssembly 绑定,用于构建零知识网络应用程序。 Rust 很容易编译到 WebAssembly,但要创建使用其他语言(如 JavaScript)编译的 WebAssembly 二进制文件所需的粘合代码却是一项具有挑战性的任务。 这个板块使用 wasm-bindgen 为 Aleo 源代码创建 JavaScript 绑定,这样就可以直接在网络浏览器和 NodeJS 中创建零知识证明。 该板块提供的功能包括: * Aleo 帐户管理对象 * 记录(Records)、程序(Programs)和交易(Transactions )等 Aleo原语及其相关辅助方法 * 程序管理器(ProgramManager)对象,包含用于编写、部署和与 Aleo 程序交互的方法 有关这些概念的更多信息,请访问 [Aleo Developer Hub](https://developer.aleo.org/concepts)。 **使用** wasm-pack 工具用于将该板块中的 Rust 代码编译成 JavaScript 模块,这些模块可以导入到其他 JavaScript 项目中。 **安装Wasm-Pack** > curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh **编译说明** 使用wasm-pack将 rust 编译为基于 WebAssembly 的 JavaScript 模块的一般语法 如下: > wasm-pack build --target \<target> --out-dir \<out-dir> -- --features \<crate-features> 调用此命令将在当前目录中使用默认名称pkg(可以根据需要使用--out-dir标志进行更改)构建一个 JavaScript 模块。然后,其他 JavaScript 模块可以将该文件夹作为 JavaScript 模块直接导入。 wasm-pack可用于生成 3 个可能的 JavaScript 模块 当在此板块中运行时: * NodeJS 模块:用于构建 NodeJS 应用程序。 * 单线程浏览器模块:用于构建基于浏览器的 Web 应用程序。 * 多线程浏览器模块:用于构建基于浏览器的 Web 应用程序,该应用程序使用基于 Web Worker 的多线程来实现显著的性能提升。 下面更详细地解释了这 3 个模块以及如何构建它们。 **1. NodeJS模块** 该模块内置 NodeJS 环境的功能。由于目前 Aleo 协议的限制,该模块是单线程的,目前还不能用于生成 Aleo 程序执行或部署。不过,它仍可用于执行 Aleo 账户、记录和程序管理任务。 编译指导: > wasm-pack build --release --target nodejs -- --features "serial" --no-default-features **2. 单线程浏览器模块(Single-Threaded browser module)** 该模块与 NodeJS 模块非常相似,但它是为使用基于浏览器的 JavaScript 环境而构建的,可用于程序执行和部署。 如果用于程序执行或部署,建议在网络工作站上进行,因为这些操作需要长时间运行,如果在主线程中运行,会导致浏览器窗口挂起。 编译指导: > wasm-pack build --release --target web 如果您打算将其用于程序执行或部署,建议使用最大或接近最大的内存分配(wasm 为 4 GB)进行编译。 ```php= RUSTFLAGS='-C link-arg=--max-memory=4294967296' wasm-pack build --release --target web ``` **3. 多线程浏览器模块(Multi-Threaded browser module)** 该模块也是为基于浏览器的 JavaScript 环境而构建的,但它是通过网络工作者(使用 rayon-wasm-bindgen crate 中概述的方法)来使用 Rust 本机线程的。它的使用最为复杂,但在执行 Aleo 程序执行和部署时运行速度明显更快,因此是性能关键型应用程序的首选。 要启用线程构建,必须使用 nightly Rust 并设置某些 RUSTFLAGS 以启用必要的线程功能。wasm-pack 构建命令如下所示。 ```php= # Set rustflags to enable atomics, # bulk-memory, and mutable-globals. # Also, set the maximum memory to # 4294967296 bytes (4GB). export RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals -C link-arg=--max-memory=4294967296' # Use rustup to run the following commands # with the nightly version of Rust. rustup run nightly \ # Use wasm-pack to build the project. # Specify the 'parallel' feature for # multi-threading and the 'browser' # feature to enable program execution # and include necessary unstable options # using -Z wasm-pack build --release --target web --out-dir pkg-parallel \ -- --features "parallel, browser" --no-default-features -Z build-std=panic_abort,std ``` **测试** 在 NodeJS 中运行测试 > wasm-pack test --node 在浏览器中运行测试 > wasm-pack test --[firefox/chrome/safari] **构建网络应用程序** 有关如何使用从此板块构建的模块来构建 Web 应用程序的更多文档和教程将在未来构建。然而,与此同时,aleo.tools网站是如何使用这些模块构建 Web 应用程序的一个很好的示例。其源代码可以在Aleo SDK repo 文件夹中找到 website。 关于如何使用本板块中的模块来构建网络应用程序,我们将在未来编写更多的文档和教程。不过,在此期间,[aleo.tools](https://aleo.tools/) 网站是如何使用这些模块构建网络应用程序的良好范例。其源代码可在<kbd>website</kbd>文件夹下的 [Aleo SDK](https://github.com/AleoHQ/sdk) 仓库中找到。 ## NodeJs + 浏览器 NodeJS + 浏览器(单线程) **Classes** * Address * ExecutionResponse Aleo 函数执行响应的 Webassembly 表示。该对象由 Aleo 离链函数的执行返回。它提供了检索函数执行输出的方法。 * KeyPair * PrivateKey * PrivateKeyCiphertext 密文形式的私钥 * Program Aleo 程序的 WebAssembly 表示。创建执行或部署事务需要该对象。它包括几种方便的方法,用于枚举 javascript 对象中的可用函数和每个函数的输入,以便在创建用于输入捕获的 Web 表单时使用。 * ProvingKey * RecordCiphertext 加密的 Aleo 记录 * RecordPlaintext Aleo 记录明文 * Signature * Transaction Aleo 事务的 WebAssembly 表示。该对象是在生成链上功能部署或执行时创建的,并且是应该提交到 Aleo 网络以部署或执行功能的对象。 * VerifyingKey * ViewKey **Address** Kind: global class **Address** * instance .to_string() ⇒ string .verify(message, signature) ⇒ boolean * static .from_private_key(private_key) ⇒ Address .from_view_key(view_key) ⇒ Address .from_string(address) ⇒ Address **address.to_string() ⇒ string** Kind: 实例化Address address.verify(message, signature) ⇒ boolean Kind: 实例化Address | Param | Type | | ----- | ---- | | message | Uint8Array | | signature | Signature | **Address.from_private_key(private_key) ⇒ Address** Kind: 实例化Address | Param | Type | | ----- | ---- | | private_key | PrivateKey | **Address.from_view_key(view_key) ⇒ Address** Kind: 实例化Address | Param | Type | | ----- | ---- | | view_key | ViewKey | **Address.from_string(address) ⇒ Address** Kind: 实例化Address | Param | Type | | ----- | ---- | | address | string | **执行响应(ExecutionResponse)** Aleo 函数执行响应的 WebAssembly 表示。该对象由链下执行 Aleo 函数返回。它提供了检索函数执行输出的方法。 Kind: global class **executionResponse.getOutputs() ⇒ Array.\<any>** 获取执行函数的输出 Kind: 实例化ExecutionResponse **KeyPair** Kind: global class * KeyPair new KeyPair(proving_key, verifying_key) .provingKey() ⇒ ProvingKey .verifyingKey() ⇒ VerifyingKey **new KeyPair(proving_key, verifying_key)** 通过证明和验证密钥创建新的密钥对 | Param | Type | | ------- | ------ | | proving_key | ProvingKey | | verifying_key | VerifyingKey | **keyPair.provingKey() ⇒ ProvingKey** 获取证明密钥 Kind: 实例化KeyPair **keyPair.verifyingKey() ⇒ VerifyingKey** 获取验证密钥 Kind: 实例化KeyPair **PrivateKey** Kind: global class **PrivateKey** * new PrivateKey() * instance .to_string() ⇒ string .to_view_key() ⇒ ViewKey .to_address() ⇒ Address .sign(message) ⇒ Signature .toCiphertext(secret) ⇒ PrivateKeyCiphertext * static .from_seed_unchecked(seed) ⇒ PrivateKey .from_string(private_key) ⇒ PrivateKey .newEncrypted(secret) ⇒ PrivateKeyCiphertext .fromPrivateKeyCiphertext(ciphertext, secret) ⇒ PrivateKey **new PrivateKey()** 生成新的私钥 **privateKey.to_string() ⇒ string** 获取私钥的字符串表示形式。使用此函数时应非常小心,因为它会暴露私钥明文。 Kind: 实例化PrivateKey **privateKey.to_view_key() ⇒ ViewKey** 获取私钥对应的查看密钥 Kind: 实例化PrivateKey **privateKey.to_address() ⇒ Address** 获取私钥对应的地址 Kind: 实例化PrivateKey **privateKey.sign(message) ⇒ Signature** 使用私钥签署消息 Kind: 实例化PrivateKey | Param | Type | | ----- | ---- | | message | Uint8Array | **privateKey.toCiphertext(secret) ⇒ PrivateKeyCiphertext** 用秘密加密私钥。该秘密很敏感,稍后需要解密私钥,因此应安全存储。 Kind: 实例化PrivateKey | Param | Type | | ----- | ---- | | secret | string | **PrivateKey.from_seed_unchecked(seed) ⇒ PrivateKey** 从一系列未经检查的字节中获取私钥 Kind: 静态方法PrivateKey | Param | Type | | ----- | ---- | | seed | Uint8Array | **PrivateKey.from_string(private_key) ⇒ PrivateKey** 从字符串表示形式创建私钥。如果文本不是有效的私钥,此函数将失败。 Kind: 静态方法PrivateKey | Param | Type | | ----- | ---- | | private_key | string | **PrivateKey.newEncrypted(secret) ⇒ PrivateKeyCiphertext** 使用秘密获取私钥密文。该秘密很敏感,稍后需要解密私钥,因此应安全存储。 Kind: 静态方法PrivateKey | Param | Type | | ----- | ---- | | secret | string | **PrivateKey.fromPrivateKeyCiphertext(ciphertext, secret) ⇒ PrivateKey** 使用秘密从私钥密文中获取私钥。 Kind: 静态方法PrivateKey | Param | Type | | ------ | ------ | | ciphertext | PrivateKeyCiphertext | | secret | string | **私钥密文(PrivateKeyCiphertext)** 密文形式的私钥 Kind: global class **PrivateKeyCiphertext** * instance .decryptToPrivateKey(secret) ⇒ PrivateKey .toString() ⇒ string * static .encryptPrivateKey(private_key, secret) ⇒ PrivateKeyCiphertext .fromString(ciphertext) ⇒ PrivateKeyCiphertext **privateKeyCiphertext.decryptToPrivateKey(secret) ⇒ PrivateKey** 使用密文字符串解密私人密文。这必须与用于加密私人密钥的密文相同。 Kind: 实例化PrivateKeyCiphertext | Param | Type | | ----- | ---- | | secret | string | **privateKeyCiphertext.toString() ⇒ string** 返回密文字符串 Kind: 实例化PrivateKeyCiphertext **PrivateKeyCiphertext.encryptPrivateKey(private_key, secret) ⇒ PrivateKeyCiphertext** 使用秘密字符串加密私钥。该秘密很敏感,稍后将需要解密私钥,因此应安全存储。 Kind: 静态方法PrivateKeyCiphertext | Param | Type | | ------ | ------ | | private_key | PrivateKey | | secret | string | **PrivateKeyCiphertext.fromString(ciphertext) ⇒ PrivateKeyCiphertext** 从字符串创建私钥密码文本 Kind: 静态方法PrivateKeyCiphertext | Param | Type | | ----- | ---- | | ciphertext | string | **Program** Aleo 程序的 Webassembly 表示。创建执行或部署事务需要该对象。它包括几个方便的方法,用于在 javascript 对象中枚举可用函数和每个函数的输入,以便创建用于捕获输入的网络表单。 Kind: global class **Program** * instance .toString() ⇒ string .getFunctions() ⇒ Array.\<any> .getFunctionInputs(function_name) ⇒ Array.\<any> .getMappings() ⇒ Array | Array.\<any> .getRecordMembers(record_name) ⇒ object .getStructMembers(struct_name) ⇒ Array.\<any> .id() ⇒ string .isEqual(other) ⇒ boolean .getImports() ⇒ Array.\<any> * static .fromString(program) ⇒ Program .getCreditsProgram() ⇒ Program **program.toString() ⇒ string** 获取程序的字符串表示形式 Kind: 实例化Program **program.getFunctions() ⇒ Array.\<any>** 获取程序中函数名称的javascript数组 Kind: 实例化Program **program.getFunctionInputs(function_name) ⇒ Array.\<any>** 获取函数输入和类型的 javascript 对象表示。这可用于生成网络表单,为函数的执行捕捉用户输入。 Kind: 实例化Program | Param | Type | | ----- | ---- | | function_name | string | **program.getMappings() ⇒ Array | Array.\<any>** 获取程序的映射列表及其键和值的名称/类型。 Kind:实例化Program 返回:Array - - 表示 programArray.\<any> 中映射的对象数组 示例: ```php= const expected_mappings = [ { name: "account", key_name: "owner", key_type: "address", value_name: "microcredits", value_type: "u64" } ] const credits_program = aleo_wasm.Program.getCreditsProgram(); const credits_mappings = credits_program.getMappings(); console.log(credits_mappings === expected_mappings); // Output should be "true" ``` **program.getRecordMembers(record_name) ⇒ object** 获取程序记录及其类型的 javascript 对象表示 Kind:实例化Program | Param | Type | | ----- | ---- | | record_name | string | **program.getStructMembers(struct_name) ⇒ Array.\<any>** 获取程序结构及其类型的 javascript 对象表示 Kind:实例化Program | Param | Type | | ----- | ---- | | struct_name | string | **program.id() ⇒ string** 获取程序的id Kind:实例化Program **program.isEqual(other) ⇒ boolean** 确定与另一个程序的相等性 Kind:实例化Program | Param | Type | | ----- | ---- | | other | Program | **program.getImports() ⇒ Array.\<any>** 获取程序导入 Kind:实例化Program Program.fromString(program) ⇒ Program 从程序字符串创建程序 Kind:实例化Program | Param | Type | | ----- | ---- | | program | string | **Program.getCreditsProgram() ⇒ Program** 获取 Credits.aleo 程序 Kind:实例化Program **证明密钥(ProvingKey)** Kind: global class **ProvingKey** * instance .toBytes() ⇒ Uint8Array * static .fromBytes(bytes) ⇒ ProvingKey **provingKey.toBytes() ⇒ Uint8Array** 从证明密钥创建字节数组 Kind:实例化ProvingKey ProvingKey.fromBytes(bytes) ⇒ ProvingKey 从字节数组构造一个新的证明密钥 Kind:静态方法ProvingKey | Param | Type | | ----- | ---- | | bytes | Uint8Array | **记录密文(RecordCiphertext)** 加密的 Aleo 记录 Kind: global class **RecordCiphertext** * instance .toString() ⇒ string .decrypt(view_key) ⇒ RecordPlaintext .isOwner(view_key) ⇒ boolean * static .fromString(record) ⇒ RecordCiphertext **recordCiphertext.toString() ⇒ string** 返回记录密文字符串。 Kind:实例化RecordCiphertext **recordCiphertext.decrypt(view_key) ⇒ RecordPlaintext** 使用查看密钥将记录密文解密为明文。 Kind:实例化RecordCiphertext | Param | Type | | ----- | ---- | | view_key | ViewKey | **recordCiphertext.isOwner(view_key) ⇒ boolean** 如果查看密钥可以解密记录密文,返回true Kind:实例化RecordCiphertext | Param | Type | | ----- | ---- | | view_key | ViewKey | **RecordCiphertext.fromString(record) ⇒ RecordCiphertext** 从字符串返回记录密文。 Kind:静态方法RecordCiphertext | Param | Type | | ----- | ---- | | record | string | **记录明文(RecordPlaintext)** Aleo 记录明文 Kind: global class **RecordPlaintext** * instance .toString() ⇒ string .microcredits() ⇒ bigint .serialNumberString(private_key, program_id, record_name) ⇒ string * static .fromString(record) ⇒ RecordPlaintext **recordPlaintext.toString() ⇒ string** 返回记录明文字符串 Kind:实例化RecordPlaintext **recordPlaintext.microcredits() ⇒ bigint** 返回记录中的微积分金额 Kind:实例化RecordPlaintext **recordPlaintext.serialNumberString(private_key, program_id, record_name) ⇒ string** 尝试获取记录的序列号以确定是否已被花费 Kind:实例化RecordPlaintext | Param | Type | | ------ | ------ | | private_key | PrivateKey | | program_id | string | | record_name | string | **RecordPlaintext.fromString(record) ⇒ RecordPlaintext** 从字符串返回记录明文。 Kind:静态方法RecordPlaintext | Param | Type | | ----- | ---- | | record | string | **签名(Signature)** Kind: global class **Signature** * instance .verify(address, message) ⇒ boolean .to_string() ⇒ string * static .sign(private_key, message) ⇒ Signature .from_string(signature) ⇒ Signature **signature.verify(address, message) ⇒ boolean** Kind:实例化Signature | Param | Type | | ------ | ------ | | address | Address | | message | Uint8Array | **signature.to_string() ⇒ string** Kind:实例化Signature **Signature.sign(private_key, message) ⇒ Signature** Kind:静态方法Signature | Param | Type | | ------ | ------ | | private_key | PrivateKey | | message | Uint8Array | **Signature.from_string(signature) ⇒ Signature** Kind:静态方法Signature | Param | Type | | ------ | ------ | | signature | string | **交易(Transaction)** Aleo 交易的 Webassembly 表示。该对象在生成链上功能部署或执行时创建,是部署或执行功能时应提交给 Aleo 网络的对象。 Kind: global class **Transaction** * instance .toString() ⇒ string .transactionId() ⇒ string .transactionType() ⇒ string * static .fromString(transaction) ⇒ Transaction **transaction.toString() ⇒ string** 以字符串形式获取交易。如果要将该交易提交到 Aleo 网络,该函数将创建一个字符串,并以POST数据格式提交。 Kind:实例化Transaction **transaction.transactionId() ⇒ string** 获取交易的 ID。这是交易包含证明的默克尔根。 此值可用于查询交易在 Aleo 网络上的状态,查看交易是否成功。如果成功,交易将被包含在一个区块中,此值可用于查询链上的交易数据。 Kind:实例化Transaction **transaction.transactionType() ⇒ string** 获取交易的类型(将返回“deploy”或“execute”) Kind:实例化Transaction **Transaction.fromString(transaction) ⇒ Transaction** 从字符串创建交易 Kind:静态方法Transaction | Param | Type | | ------ | ------ | | transaction | string | **验证密钥(VerifyingKey)** Kind: global class **VerifyingKey** * instance .toBytes() ⇒ Uint8Array * static .fromBytes(bytes) ⇒ VerifyingKey **verifyingKey.toBytes() ⇒ Uint8Array** 从验证密钥创建字节数组 Kind: 实例化VerifyingKey **VerifyingKey.fromBytes(bytes) ⇒ VerifyingKey** 从字节数组构造一个新的验证密钥 Kind: 静态方法VerifyingKey | Param | Type | | ------ | ------ | | bytes | Uint8Array | **查看密钥(ViewKey)** Kind: global class **ViewKey** * instance .to_string() ⇒ string .to_address() ⇒ Address .decrypt(ciphertext) ⇒ string * static .from_private_key(private_key) ⇒ ViewKey .from_string(view_key) ⇒ ViewKey **viewKey.to_string() ⇒ string** Kind: 实例化ViewKey **viewKey.to_address() ⇒ Address** Kind: 实例化ViewKey | Param | Type | | ------ | ------ | | ciphertext | string | **ViewKey.from_private_key(private_key) ⇒ ViewKey** Kind: 静态方法ViewKey | Param | Type | | ------ | ------ | | private_key | PrivateKey | **ViewKey.from_string(view_key) ⇒ ViewKey** Kind: 静态方法ViewKey | Param | Type | | ------ | ------ | | view_key | string | ## 浏览器(多线程) :::info :information_source: Aleo Wasm 包的多线程版本包括单线程版本中的所有类,以及更多类。 ::: **Classes** * wbg_rayon_PoolBuilder **Functions** * initThreadPool(num_threads) ⇒ Promise.\<any> * wbg_rayon_start_worker(receiver) **wbg_rayon_PoolBuilder** Kind: global class wbg_rayon_PoolBuilder * .numThreads() ⇒ number * .receiver() ⇒ number * .build() **wbg_rayon_PoolBuilder.numThreads() ⇒ number** Kind: 实例化wbg_rayon_PoolBuilder **wbg_rayon_PoolBuilder.receiver() ⇒ number** Kind: 实例化wbg_rayon_PoolBuilder **wbg_rayon_PoolBuilder.build()** Kind: 实例化wbg_rayon_PoolBuilder **initThreadPool(num_threads) ⇒ Promise.\<any>** Kind: global function | Param | Type | | ------ | ------ | | num_threads | number | **wbg_rayon_start_worker(receiver)** Kind: global function | Param | Type | | ------ | ------ | | receiver | number | # 测试网三 ## 概述 :::info :information_source: Aleo Testnet III 还不能用于生产,在投入生产前将进行彻底的审核和测试。Aleo Testnet III 是一个可信测试网--后续测试网将经过可信设置过程。 ::: Aleo Testnet III 是一个实验网络,供开发人员开始在 Aleo 上构建和测试应用程序。核心团队使用 Testnet III 设计和评估新程序、规划和试运行网络升级,以及运行实验功能以纳入主网。 **网络** Aleo Testnet3 API 是围绕REST组织的。 要连接到网络,请向 Aleo Testnet III 启动节点发出请求。 | Status | Region | URL | | -------- | -------- | -------- | | Live | Americas | vm.aleo.org/api/| **snarkOS** snarkOS 是一个用于匿名网络应用程序的去中心化操作系统。它是 Aleo 的支柱,使开发人员能够以公开可验证的方式检查点和最终确定应用程序状态。 **源代码** snarkOS是开源的并在[GitHub](https://github.com/AleoHQ/snarkOS)上公开托管。 **API** * Latest Height * Latest Hash * Latest Block * Latest State Root * Get Block * Get Blocks * Get Height * Get Block Transactions * Get Transaction * Get Memory Pool Transactions * Get Program * Get Mapping Names * Get Mapping Value * Get State Path for Commitment * Get Beacons * Get Peers Count * Get Peers All * Get Peers All Metrics * Get Node Address * Find Block Hash * Find Transaction ID from Program ID * Find Transaction ID from Transition ID * Find Transition ID * Get Environment Information * Transaction Broadcast * Edit this page ## 部署和执行程序 这些更改支持在 Aleo 网络上部署和执行程序的首次迭代。 *如果您有任何 Bug、可用性建议和反馈意见,我们将不胜感激。* **概述** 程序的部署和执行是通过的四个新的CLI 命令完成的:<kbd>snarkOS - decrypt, deploy, execute, scan, and transfer</kbd>。 这些 CLI 命令目前存在于 snarkOS 中,但也可以迁移到 Aleo SDK 中。 *注意:所有操作都在客户端完成,无需向第三方发送私钥或查看密钥。* **使用指南** 1. 安装snarkOS ```php= git clone https://github.com/AleoHQ/snarkOS.git cd snarkOS git checkout testnet3 cargo install --path . ``` 2. 在开发模式下运行节点 ```php= snarkos start --nodisplay --dev 0 --beacon "" ``` 3. 扫描节点,查找可消费记录(Scan the node for spendable records) 这很可能是与开发信标相关的查看密钥。 (This will likely be the view key associated with the development beacon.) ```php= snarkos developer scan -v <VIEW_KEY> --start 0 --end 1 --endpoint "http://localhost:3030" ``` 4. 转移积分(执行credits.aleo程序) 将积分转到另一个账户,这样就不会被信标生成区块所消耗。 (信标会不断消耗记录来生成新的区块,因此您的记录有可能在做这一步之前就被消耗掉了)。 ```php= snarkos developer execute credits.aleo transfer <INPUT_RECORD> <RECIPIENT_ADDRESS> "<AMOUNT_TO_TRANSFER>u64" --private-key <PRIVATE_KEY> --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" ``` 或者 ```php= snarkos developer transfer <AMOUNT_TO_TRANSFER> --input-record <INPUT_RECORD> --recipient <RECIPIENT_ADDRESS> --private-key <PRIVATE_KEY> --query "<http://localhost:3030>" --broadcast "<http://localhost:3030/testnet3/transaction/broadcast>" ``` 此步骤可以用水龙头代替。 5. 部署程序 部署一个具有未使用记录的程序。 ```php= snarkos developer deploy fibonacci.aleo --private-key <PRIVATE_KEY> --query "http://localhost:3030" --path "../leo/examples/fibonacci/build/" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" --fee 600000 --record <INPUT_RECORD> ``` 6. 执行一个已部署程序的函数 ```php= snarkos developer execute fibonacci.aleo fibonacci "1u8" --private-key <PRIVATE_KEY> --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" ``` *注意:费用(以微积分为单位)必须大于交易大小(以字节为单位)。执行交易可以不包含费用,但如果指定了费用,则必须遵守上述规则。* **命令行** **解密** 使用查看密钥解密记录密文。 参数: * ciphertext- The record ciphertext to decrypt shortcut: -c * view_key - The view key used to decrypt the ciphertext shortcut: -v 示例: > snarkos developer decrypt -v <VIEW_KEY> -c <RECORD_CIPHERTEXT> **部署** 创建 Aleo 程序部署。 参数: * program_id - 要部署的程序的 ID * path - 包目录的路径 optional - 默认为当前目录 * private_key - 用于生成部署的私钥 shortcut -p * query - 查询节点状态的起始端点 shortcut - -q * fee - 部署费用(微积分单位) optional - 默认为 0 * record - 费用支出记录 * display - 显示生成的交易 optional - 默认为 false * broadcast - 将交易广播到指定端点 optional * store - 将交易存储到指定的文件路径 optional 示例: ```php= snarkos developer deploy fibonacci.aleo --private-key <PRIVATE_KEY> --query "http://localhost:3030" --path "./leo/examples/fibonacci/build/" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" --fee 550000 --record <INSERT_RECORD_HERE> ``` **执行** 创建 Aleo 程序执行。 参数: * program_id - 要部署的程序的 ID * function - 函数名称 * inputs - 函数的输入参数 * private_key - 用于生成部署的私钥 shortcut -p * query - 查询节点状态的起始端点 shortcut - -q * fee - 执行费用(微积分单位) optional * record - 费用支出记录 optional * display - 显示生成的交易 optional - 默认为 false * broadcast - 将交易广播到指定端点 optional * store - 将交易存储到指定的文件路径 optional 示例: ```php= snarkos developer execute fibonacci.aleo fibonacci "1u8" --private-key <PRIVATE_KEY> --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" ``` **扫描(Scan)** 扫描节点以查找给定块范围内的拥有记录。 *注意:这是一种简单的扫描,不会考虑已用的记录。* 参数: * view_key - 用于解密找到的记录的查看密钥 shortcut: -v * start - 查询的起始区块高度 * end - 查询的结束区块高度 * endpoint - 取块的起始端点 示例: ```php= snarkos developer scan -v <VIEW_KEY> --start 0 --end 1 --endpoint "http://localhost:3030" ``` **转账** 通过credits.aleo程序执行转账。 参数: * input_record - 用于转账的记录 * recipient - 接收人地址 * amount - 转账金额(微积分单位) * private_key - 用于生成部署的私钥 shortcut -p * query - 查询节点状态的起始端点 shortcut - -q * fee - 转账费用(微积分单位) optional * record - 费用支出记录 optional * display - 显示生成的交易 optional - 默认为 false * broadcast - 将交易广播到指定端点 optional * store - 将交易存储到指定的文件路径 optional 示例: ```php= snarkos developer transfer <AMOUNT_TO_TRANSFER> --input-record <INPUT_RECORD> --recipient <RECIPIENT_ADDRESS> --private-key <PRIVATE_KEY> --query "<http://localhost:3030>" --broadcast "<http://localhost:3030/testnet3/transaction/broadcast>" ``` **在测试网 3 上的使用(第 2 阶段)** 在 Testnet3 上部署和执行程序 * 将步骤 3(扫描节点,查找可消费记录) 替换为使用 Aleo 龙头获取可消费积分。您可从龙头处申请积分使用 * 用 https://vm.aleo.org/api 取代 http://localhost:3030 部署交易有一个额外要求,即所含费用必须至少有 deployment_size_in_bytes 微积分。 执行交易目前没有任何费用要求。 如果您想尝试部署 Aleo 应用程序,可以按照下一节 "部署和执行演示 "中的演示进行操作。 ## 部署和执行Demo 这些更改支持在 Aleo 网络上部署和执行程序的首次迭代。 如果您有任何 Bug、可用性建议和反馈意见,我们将不胜感激。 **概述** 学习如何使用 Leo 和 snarkOS 在 Aleo 网络上部署和执行基本的 "hello world! **使用指南** **1. 前提条件** 确保你的机器上同时安装了Leo和snarkOS。 * 要验证是否安装了 Leo,请打开终端并输入 leo。如果你没有看到类似<kbd>zsh: command not found: leo</kbd>这样的提示,那就说明你安装了 * 要验证是否安装了 snarkOS,请执行与 Leo 相同的操作,但将 leo 替换为 snarkos 可选:安装 [JSON Beautifier & Editor ](https://chrome.google.com/webstore/detail/json-beautifier-editor/lpopeocbeepakdnipejhlpcmifheolpl) Chrome 扩展。 注意: * 您可以在[这里](https://github.com/AleoHQ/leo)找到在机器上安装 Leo 的说明,在[这里](h[ttps://](https://github.com/AleoHQ/snarkos))找到安装 snarkOS 的说明 * 确保将最新版本的 snarkos 和 leo 从 GitHub 拉到本地机器上 **2. 生成您的测试密钥和钱包地址** * 在您喜欢的浏览器中,导航到 [https://aleo.tools/](https://aleo.tools/),然后单击 "Generate "按钮 * 将您的地址、查看密钥和私人密钥保存在安全的地方,以后会用到它们 **3a. 为您的钱包注入积分** 要为钱包注入积分,您需要从 Aleo 的龙头(网址:[faucet.aleo.org ](https://faucet.aleo.org )⛲️)或者发送国际短信到+1 (867) 888-5688,格式为“Send 50 credits to XXXXX”申请测试积分。 **3b. 创建Leo应用程序 我们需要部署一些东西,因此让我们创建一个简单的测试 Leo 应用程序。 打开终端,连续输入以下命令: * 创建一个目录来存储您的 Leo 应用程序 - 您可以为该目录或位置使用不同的名称 ```php= cd $HOME/Desktop mkdir demo_deploy_Leo_app && cd demo_deploy_Leo_app ``` * ⚠️ 将 $WALLETADDRESS 分配给您保存的钱包地址 ```php= WALLETADDRESS="" ``` * 创建一个新的测试 Leo 应用程序 ```php= leo new "${APPNAME}" ``` * 运行您的 Leo 应用程序以确保一切正常 ```php= cd "${APPNAME}" && leo run && cd - ``` **保存应用程序的路径 - 这在以后很重要** ```php= PATHTOAPP=$(realpath -q $APPNAME) ``` **4. 确认Aleo水龙头⛲️已发送您的钱包积分并获取您的密文记录** 此时,Aleo 水龙头应该已经向您发送了钱包积分。接下来,您需要通过解密发送给您的执行转账的密文记录来验证您的积分余额。 如果您通过使用电话号码发送短信来请求积分,您还应该收到一封确认邮件,其中包含前缀为'vm.aleo.org/api/testnet3/transaction...'(目前应该是没有了,之前是有的) 或者,您可以通过转到水龙头并搜索提供的表格(当前仅在桌面上支持)查找您的地址来找到执行交易确认。返回结果后,单击该Transaction ID字段。如果您在表中没有看到结果,则您的积分尚未发送。 您应该会在新的浏览器窗口中看到一个 JSON 对象。如果您还没有安装,我们强烈建议您安装JSON Beautifier & Editor Chrome 扩展程序。 导航到object.execution.transitions[0].outputs[0].value并复制存储在那里的密文。 **5. 获取您的记录明文** * 导航到[https://aleo.tools/](https://aleo.tools/)并单击页面顶部导航栏中的“记录”选项卡 * 将您在上一步中复制的记录密文放入该Record (Ciphertext)字段中 * 将您的查看键放在字段View Key中 * 复制提供的明文记录。如果您没有看到它,则可能是您在步骤 4 中复制了错误的密文记录。请考虑重新访问或联系hello@aleo.org。 * 将明文记录保存在与地址、查看密钥和私钥相同的位置。您稍后会需要它。 **6. 部署您的测试应用** 现在我们已经掌握了所需的所有详细信息,我们可以部署您的第一个 Leo 应用程序。 打开与之前相同的终端实例并连续输入以下命令: * 导航到您的应用程序的路径 > cd $PATHTOAPP && cd .. * ⚠️ 将 $PRIVATEKEY 分配给您之前保存的私人地址 > PRIVATEKEY="" * ⚠️ 将 $RECORD 分配给您之前保存的明文记录 > RECORD="" * 部署您的 Leo 应用程序(如果所有变量都已正确分配,您应该能够复制/粘贴以下内容 ```php= snarkos developer deploy "${APPNAME}.aleo" --private-key "${PRIVATEKEY}" --query "https://vm.aleo.org/api" --path "./${APPNAME}/build/" --broadcast "https://vm.aleo.org/api/testnet3/transaction/broadcast" --fee 1000000 --record "${RECORD}" ``` 您应该已经看到一条确认信息,表明您的 Aleo 应用程序已以交易 ID 的形式部署,如下所示<kbd>at1rkkpqu5k4rt86zzccczw6cxeyvrl7hxydvvv7dhl7zr7p9w40c8s70kwm8</kbd>。请务必复制此字符串,因为最后一步将需要它。 **7. 执行您的测试应用** 最后,是时候执行您刚刚部署的应用程序了! * 您需要使用--record与您的钱包余额相关联的最新交易来更新该标志。在这种情况下,您可以通过访问以下 URL 来获取该信息:https://vm.aleo.org/api/testnet3/transaction/$DEPLOY_TX_ID, 但将 $DEPLOY_TX_ID 替换为部署应用程序后提供给您的交易 ID (或来自链接到您的钱包地址的最近交易)。示例 URL 如下所示: https: //vm.aleo.org/api/testnet3/transaction/at1rkkpqu5k4rt86zzccczw6cxeyvrl7hxydvvv7dhl7zr7p9w40c8s70kwm8 * 在https://vm.aleo.org/api/testnet3/transaction/$DEPLOY_TX_ID提供的 JSON 对象中,导航至:object.fee.transition.outputs[0].value并复制记录密文值。 * 前往aleo.tools并导航至“记录”选项卡,然后粘贴您刚刚复制的记录密文以及钱包的查看密钥 * 与我们在部署交易中遵循的步骤类似,通过RECORD执行以下操作,使用您刚刚解密的记录明文更新您的变量: ⚠️ 将 $RECORD 分配给您之前保存的明文记录 > RECORD="" 然后只需将以下命令粘贴到终端中 ```php= snarkos developer execute "${APPNAME}.aleo" "main" "1u32" "2u32" --private-key "${PRIVATEKEY}" --query "https://vm.aleo.org/api" --broadcast "https://vm.aleo.org/api/testnet3/transaction/broadcast" --fee 1000000 --record "${RECORD}" ``` 您已成功将 Leo 应用程序部署并执行到 Testnet III,多么令人兴奋 🎉 ## API参考 **Latest Height** ENDPOINT: > GET /testnet3/latest/height 返回最新的块高度。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | u32 | 链中区块的数量 | **Latest Hash** ENDPOINT: > GET /testnet3/latest/hash 返回最新的块哈希。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | string | 最新区块的区块哈希值 | **Latest Block** ENDPOINT: > GET /testnet3/latest/block 返回最新的块。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | object | 最新区块 | **Latest State Root** ENDPOINT: > GET /testnet3/latest/stateRoot 返回最新的状态根。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | string | 最新的状态根 | **Get Block** ENDPOINT: > GET /testnet3/block/{height_or_hash} 返回给定块高度或块哈希的块。 参数: | Parameter | Type | Required | Description | | --------- | ------ | --- | ------------ | | height or hash | u32 or string | Yes | 请求的区块高度或哈希值 | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | object | 请求的块 | **Get Blocks** ENDPOINT: > GET /testnet3/blocks?start={start_height}&end={end_height} 返回给定块范围的块。 参数: | Parameter | Type | Required | Description | | -------------- | ------------- | -------- | ---------------------- | | start_height | u32 | Yes | 所申请区块的起始高度 | | end_height | u32 | Yes | 所申请区块的末端高度| 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | array | 请求的区块 | **Get Height** ENDPOINT: > GET /testnet3/height/{blockHash} 返回给定块哈希的高度。 参数: | Parameter | Type | Required | Description | | --------- | ------ | --- | ------------ | | blockHash | string | Yes | 请求的区块高度的哈希值 | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | u32 | 请求的区块高度 | **Get Block Transactions** ENDPOINT: > GET /testnet3/transactions/{height}/transactions 返回给定区块高度的交易。 参数: | Parameter | Type | Required | Description | | --------- | ------ | --- | ------------ | | height | u32 | Yes | 请求交易的区块高度。 | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | array | 区块中的交易数组 | **Get Transaction** ENDPOINT: > GET /testnet3/transaction/{transactionID} 返回给定交易 ID 的交易。 参数: | Parameter | Type | Required | Description | | --------- | ------ | --- | ------------ | | transactionID | string | Yes | 所请求交易的交易 ID 十六进制 | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | object | 请求的交易 | **Get Memory Pool Transactions** ENDPOINT: > GET /testnet3/memoryPool/transactions 返回内存池中的交易。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | array | 交易数组 | **Get Program** ENDPOINT: > GET /testnet3/program/{programID} 返回给定程序 ID 的程序。 参数: | Parameter | Type | Required | Description | | --------- | ------ | --- | ------------ | | programID | string | Yes | 请求程序的程序 ID | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | object | 请求的程序 | **Get Mapping Names** ENDPOINT: > GET /testnet3/program/{programID}/mappings 返回给定程序 ID 的程序中的映射名称。 参数: | Parameter | Type | Required | Description | | --------- | ------ | --- | ------------ | | programID | string | Yes | 请求映射的程序 ID | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | object | 请求的映射名称 | **Get Mapping Value** ENDPOINT: > GET /testnet3/program/{programID}/mapping/{mappingName}/{mappingKey} 返回与提供的映射键对应的键值映射中的值。 参数: | Parameter | Type | Required | Description | | --------- | ------ | -------- | ----------------- | | programID | string | Yes | 请求映射的程序 ID | | mappingName | string | Yes | 要访问的映射的名称 | | mappingKey | string | Yes | 映射中键值对的键| 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | object | 映射中键值对的值 | **Get State Path For Commitment** ENDPOINT: > GET /testnet3/statePath/{commitment} 返回给定承诺的状态路径。状态路径证明存在通向全局或本地状态根的过度叶。 参数: | Parameter | Type | Required | Description | | --------- | ------ | --- | ------------ | | commitment | string | Yes | 最佳有效链中的记录承诺 | 返回: | Parameter | Type | Description | | --------- | ------ | -------------- | | global_state_root | string | 全局状态根 | | block_path | string | 区块哈希的默克尔路径 | | block_hash | string | 区块哈希 | | previous_block_hash | string | 前一个区块哈希 | | header_root | string | 区块头根 | | header_path | string | 区块头叶的默克尔路径 | | header_leaf | string | 区块头叶 | | transactions_path | string | 交易ID的默克尔路径 | | transaction_id | string | 交易ID | | transaction_path | string | 交易树叶的默克尔路径 | | transaction_leaf | string | 交易树叶 | | transition_path | string | 过度树叶的默克尔路径 | | transition_leaf | string | 过度树叶| **Get Beacons** ENDPOINT: > GET /testnet3/beacons 返回当前信标节点地址的列表。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | array | 信标节点的Aleo地址 | **Get Peers Count** ENDPOINT: > GET /testnet3/peers/count 返回连接到该节点的对等节点的数量。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | number | 连接到节点的对等节点数量 | **Get Peers All** ENDPOINT: > GET /testnet3/peers/all 返回连接到该节点的所有对等节点。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | array | 已连接的对等节点的 IP 列表 | **Get Peers All Metrics** ENDPOINT: > GET /testnet3/peers/all/metrics 返回连接到该节点的对等点及其类型。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | array | 已连接的对等节点的 IP 和节点类型列表 | **Get Node Address** ENDPOINT: > GET /testnet3/node/address 返回节点的地址。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | string | 节点地址 | **Find Block Hash** ENDPOINT: > GET /testnet3/find/blockHash/{transactionID} 返回包含给定交易 ID 的区块的区块哈希值。 参数: | Parameter | Type | Description | | ------------- | ------ | ----------------- | | transactionID | string | 交易ID | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | String | 包含交易 ID 的区块哈希值 | **Find Transaction ID From Program ID** ENDPOINT: > GET /testnet3/find/transactionID/deployment/{programID} 返回包含给定程序 ID 的交易 ID。 参数: | Parameter | Type | Description | | ------------- | ------ | ----------------- | | programID | string | 程序 ID | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | String | 交易 ID | **Find Transaction ID From Transition ID** ENDPOINT: > GET /testnet3/find/transactionID/{transitionID} 返回包含给定过度 ID 的交易 ID。 参数: | Parameter | Type | Description | | ------------- | ------ | ----------------- | | result | string | 过度 ID | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | String | 交易 ID | **Find Transition ID** ENDPOINT: > GET /testnet3/find/transitionID/{inputOrOutputID} 返回与输入或输出的 ID 对应过度的过度 ID。 参数: | Parameter | Type | Description | | ------------- | ------ | ----------------- | | inputOrOutputID | string | 输入或输出的 ID | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | String | 过度 ID | **Get Environment Info** ENDPOINT: > GET /testnet3/node/env 返回节点的环境信息。snarkOS 命令行参数用于启动节点以及 GitHub 分支并提交哈希。。 参数:None 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | Object | 环境信息 | **Transaction Broadcast** ENDPOINT: > POST /testnet3/transactions/broadcast 将交易广播到账本。 Body: | Type | Description | | ------ | --------------- | | string | 要广播的序列化事务 | 返回: | Parameter| Type | Description | | -------- | -------- | -------- | | result | String | 尝试交易广播的状态 | :::success 欢迎对Aleo技术感兴趣的小伙伴加入社群! 注意哈,社群只讨论技术,所以非技术类小伙伴谨慎加入哦! 再次非常感谢大家的支持,谢谢! TG: https://t.me/+VATAn9z4x_9iOTc1 :::