EOS柚子币Web3.js开发教程:环境搭建与库选择

阅读:40 分类: 问答

柚子币 (EOS) Web3.js 开发教程

简介

本文档旨在提供一份关于使用 Web3.js 与柚子币 (EOS) 区块链交互的教程。EOS 区块链采用委托权益证明 (DPoS) 共识机制,其底层架构与以太坊等使用工作量证明 (PoW) 或权益证明 (PoS) 的区块链存在显著差异。这些差异体现在 API 调用、账户模型和数据处理方式上,因此,不能直接使用以太坊的 Web3.js 库与 EOS 网络进行交互。EOS 需要专门适配的 JavaScript 库来简化与区块链的通信,例如 eosjs eosjs2 。这些库提供了用于创建交易、查询链上数据、管理账户以及与其他智能合约(在 EOS 中称为合约)进行交互的函数。 本文将介绍适用于 EOS 的替代方案,并详细说明如何使用它们连接和操作 EOS 网络,包括配置连接参数、签署交易和处理异步回调。

必要的准备工作

  1. 选择合适的加密货币交易所: 在开始交易之前,仔细研究并选择一个信誉良好、安全可靠的加密货币交易所。考虑交易所的交易费用、支持的加密货币种类、用户界面友好程度、以及客户支持质量。评估交易所的安全措施,例如双因素认证(2FA)、冷存储解决方案和定期安全审计,以确保您的资产安全。
Node.js 环境: 确保你已安装 Node.js 和 npm (Node Package Manager)。你可以从官方网站下载并安装:https://nodejs.org/
  • EOS 开发环境: 需要安装 EOS 的开发工具,例如 eosio.cdtcleos (命令行钱包和区块链交互工具)。 这些工具允许你编译智能合约、部署它们到本地测试网络以及与链进行交互。
  • 账户和权限: 在 EOS 上,所有操作都需要账户。 你需要创建一个 EOS 账户,并在该账户下部署智能合约或执行交易。 如果你正在使用本地测试网络,你可以使用 cleos create account 命令来创建新账户。
  • 替代方案: 由于标准 Web3.js 不直接支持 EOS,我们需要使用一些替代库, 例如 eosjs 或者 dfuse JSeosjs 是一个轻量级的 JavaScript 库,用于与 EOSIO 区块链交互。 dfuse JS 则是 dfuse 提供的 JavaScript 库,能够更高效地查询 EOS 区块链的历史数据。 在本教程中,我们将主要使用 eosjs
  • 安装 eosjs

    eosjs 是一个用于与 EOSIO 区块链进行交互的 JavaScript 库。 使用 npm (Node Package Manager) 可以轻松安装 eosjs ,它是 Node.js 的默认包管理器,允许您方便地安装、更新和管理项目依赖。

    使用 npm 安装 eosjs 的步骤如下:

    npm install eosjs

    在命令行或终端中运行上述命令。npm 将会自动下载并安装 eosjs 及其所有依赖项到您的项目目录的 node_modules 文件夹中。 确保您的项目目录中存在 package. 文件, 或者使用 npm init 命令初始化一个新的 Node.js 项目。 这将创建一个 package. 文件,用于跟踪您的项目依赖。

    安装完成后,您就可以在您的 JavaScript 代码中引入 eosjs 模块,并开始与 EOSIO 区块链进行交互。 例如:

    const { Api, JsonRpc, Serialize, JsSignatureProvider } = require('eosjs');
    

    该代码片段展示了如何从 eosjs 模块中引入 Api , JsonRpc , Serialize JsSignatureProvider 类, 这些类是与 EOSIO 区块链交互时常用的组件。 确保你的 Node.js 环境已经配置好,并且你已经安装了 Node.js 和 npm。

    连接到 EOS 网络

    以下代码示例展示了如何利用 eosjs 库连接至 EOS 区块链网络,并配置必要的组件以进行链上交互。

    
    const { Api, JsonRpc, Serialize } = require('eosjs');
    const { JsSignatureProvider } = require('eosjs/dist/eosjs-jssig'); // 仅用于本地开发环境,请勿在生产环境使用
    
    // 配置与 EOS 节点的 RPC 连接
    const rpc = new JsonRpc('http://127.0.0.1:8888', { fetch }); // 将 'http://127.0.0.1:8888' 替换为您的 EOS 节点 URL,例如:'https://eos.greymass.com' 或您的私有节点。 确保该节点已同步并可访问。
    
    // 配置签名提供者 (仅用于本地开发和测试),**切勿在生产环境中使用硬编码的私钥**
    const privateKeys = ['5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyEgKYrjUc6Y']; //  **重要提示:** 使用您自己的私钥替换此示例私钥。 并且,强烈建议仅在测试和开发环境中使用此方法。
    const signatureProvider = new JsSignatureProvider(privateKeys);
    
    // 创建 Api 实例,用于构建和签名交易
    const api = new Api({
        rpc,
        signatureProvider,
        textDecoder: new TextDecoder(),
        textEncoder: new TextEncoder(),
    });
    

    上述代码片段中,首先通过 require('eosjs') 引入 eosjs 库的关键模块: Api JsonRpc Serialize JsonRpc 类负责建立与指定 EOS 节点(通过其 URL)的通信通道,从而允许应用程序发送远程过程调用 (RPC) 请求。 Api 类构建于 JsonRpc 之上,提供了一组更高级的接口,用于构造、签名和广播交易至 EOS 区块链。

    JsSignatureProvider 作为一个本地签名提供者,用于在客户端对交易进行签名。在示例中,它直接使用硬编码的私钥。 请务必注意,将私钥直接嵌入代码中极不安全,强烈建议在生产环境中使用更安全的密钥管理方案,例如硬件钱包 (Ledger, Trezor)、软件钱包 (Scatter, Anchor) 或企业级密钥管理服务 (KMS,如 AWS KMS, Google Cloud KMS)。这些方案允许安全地存储和管理私钥,避免私钥泄露的风险。 对于生产环境,可以使用 eosjs 提供的 PrivateKey 类或集成其他安全签名方案。

    textDecoder textEncoder 用于处理文本编码和解码,确保交易数据的正确处理。 在 Api 实例中, rpc 指定了用于与 EOS 节点通信的 JsonRpc 实例, signatureProvider 指定了用于对交易进行签名的签名提供者。

    发送交易

    以下代码演示了如何使用 eosjs 库发送交易到 EOS 区块链网络。EOSJS 作为一个强大的 JavaScript SDK,简化了与 EOSIO 兼容区块链的交互,包括交易的构建、签名和广播。

    transfer 函数示例:

    
    async function transfer(from, to, quantity, memo) {
      try {
        const result = await api.transact(
          {
            actions: [
              {
                account: 'eosio.token',
                name: 'transfer',
                authorization: [
                  {
                    actor: from,
                    permission: 'active',
                  },
                ],
                data: {
                  from: from,
                  to: to,
                  quantity: quantity,
                  memo: memo,
                },
              },
            ],
          },
          {
            blocksBehind: 3,
            expireSeconds: 30,
          }
        );
        console.log('Transaction ID: ', result.transaction_id);
      } catch (e) {
        console.error('交易失败: ', e);
      }
    }
    

    // 调用转账函数 transfer('alice', 'bob', '1.0000 EOS', '测试转账');

    上述代码中, transfer 函数接受四个关键参数: from (发送者账户名), to (接收者账户名), quantity (转账数量,包含精度和代币符号), 和 memo (可选的备注信息,用于描述交易)。 该函数的核心是调用 api.transact 方法,该方法负责创建并广播交易到网络。 交易对象包含了 actions 数组,允许在单个交易中执行多个动作。在本例中,只包含一个 "transfer" 动作,其结构如下:

    • account : 指定合约账户,这里是 'eosio.token' ,即 EOS 系统代币合约,负责处理代币转账。
    • name : 指定合约动作名称,这里是 'transfer' ,对应于代币合约中处理转账的函数。
    • authorization : 授权信息,指定哪个账户和权限授权执行该动作。 actor 是授权账户 ( from ), permission 通常设置为 'active' ,表示使用账户的活跃权限。
    • data : 动作参数,包含转账的具体信息:发送者 ( from ), 接收者 ( to ), 转账数量 ( quantity ), 和备注 ( memo )。

    blocksBehind expireSeconds 是交易的配置参数,用于指定交易的有效时间。 blocksBehind: 3 表示交易引用的区块必须在最新的区块之前至少3个区块, expireSeconds: 30 表示交易在30秒后过期。 这些参数有助于防止交易被无限期地延迟执行。

    quantity 参数需要特别注意。它必须包含正确的精度和代币符号。例如, '1.0000 EOS' 表示 1 个 EOS 代币,精度为 4。EOSIO 上的代币通常具有固定的精度,需要在转账时正确指定。

    错误处理:代码中包含 try...catch 块来捕获交易执行过程中可能出现的错误,例如权限不足、账户不存在等。 捕获错误可以帮助开发者更好地调试和处理交易失败的情况。

    读取链上数据

    以下代码演示了如何使用 eosjs 库读取区块链上的账户数据。 eosjs 是一个JavaScript库,专门用于与基于EOSIO的区块链进行交互,提供了丰富的功能,包括账户管理、交易构建和链上数据读取。

    get_account 方法是 eosjs 中一个重要的函数,它允许开发者通过账户名称检索并获取该账户的详细信息,包括但不限于余额、权限设置、RAM使用情况、CPU和NET资源抵押情况等。这些信息对于理解账户的状态和行为至关重要。

    javascript

    
    async function getAccountInfo(accountName) {
      try {
        const accountInfo = await rpc.get_account(accountName);
        console.log('Account Info: ', accountInfo);
      } catch (e) {
        console.error('获取账户信息失败: ', e);
      }
    }
    

    该函数 getAccountInfo 接受一个字符串类型的 accountName 作为输入参数。这是一个异步函数,使用了 async 关键字,允许在函数内部使用 await 关键字等待异步操作的结果。 rpc.get_account(accountName) 是一个异步调用,它向区块链节点发起请求,查询指定账户的信息。如果请求成功, accountInfo 变量将包含账户的所有相关数据。如果请求失败, catch 代码块会捕获错误并打印到控制台,方便开发者进行调试。

    // 调用获取账户信息函数

    getAccountInfo('alice');

    这行代码通过调用 getAccountInfo 函数,并传入账户名 'alice' 作为参数,来检索名为 'alice' 的账户信息。需要注意的是,'alice' 只是一个示例账户名,在实际应用中,需要替换为需要查询的真实账户名称。 rpc 对象需要预先配置好,指向有效的EOSIO节点,才能正确执行 get_account 方法。配置过程包括指定节点地址、链ID等参数,确保能够与目标区块链网络进行通信。

    通过 rpc.get_account 方法返回的信息是JSON格式的数据结构,包含了账户的各种属性和状态。开发者可以根据实际需求,解析这些数据并进行相应的处理,例如,展示账户余额、验证账户权限、监控资源使用情况等。

    部署智能合约

    部署智能合约是将已编写并编译的智能合约上传到区块链网络,使其能够在链上运行并被其他账户调用的过程。它通常涉及以下关键步骤:

    1. 编写智能合约: 需要使用如 C++ 等支持智能合约开发的编程语言编写合约代码。对于 EOSIO 区块链,开发者通常选择 C++ ,因为它提供了更好的性能和控制能力。合约代码定义了合约的状态变量和可供外部调用的函数(actions)。例如,一个简单的合约可能包含用于存储用户余额的变量和用于转账的函数。编写时需要仔细考虑安全性和gas消耗,避免潜在的漏洞。
    2. 编译智能合约: 编写完成后,需要将 C++ 代码编译成 WebAssembly (WASM) 文件和 ABI (Application Binary Interface) 文件。 eosio.cdt (EOSIO Contract Development Toolkit) 是一个专门用于编译 EOSIO 智能合约的工具链。WASM 文件包含了可在 EOSIO 虚拟机上执行的字节码,而 ABI 文件则描述了合约的接口,包括 actions 和数据结构,方便外部应用与合约交互。编译过程是将人类可读的代码转换为机器可执行的代码的关键步骤。
    3. 部署智能合约: 编译完成后,使用 cleos set contract 命令将 WASM 文件和 ABI 文件部署到 EOS 网络。 cleos 是 EOSIO 的命令行接口工具,允许用户与 EOSIO 区块链进行交互。该命令需要指定合约账户的名称以及 WASM 和 ABI 文件的路径。部署过程会将合约代码上传到区块链,并在指定的账户下注册该合约,使其可以被其他账户调用。部署后,合约的状态就会持久化在区块链上,并且所有操作都将受到共识机制的约束。

    由于篇幅限制,这里不再详细介绍智能合约的编写和编译过程。包括但不限于合约的结构设计、action 的参数定义、数据持久化方案、错误处理机制以及安全审计最佳实践。您可以参考 EOSIO 的官方文档及社区资源,如 EOSIO developer portal 和 EOSIO Stack Exchange,了解更多关于智能合约编写、编译和部署的详细信息。 同时,建议参考最新的 EOSIO 版本文档,以获取最准确和及时的信息。

    调用智能合约

    智能合约成功部署后,与合约交互的核心在于调用合约中的动作(Actions)。 eosjs 库提供了便捷的方式来实现这一目标。以下代码示例展示了如何使用 eosjs 调用智能合约中的具体动作函数,并包含了错误处理机制,确保调用的可靠性。

    javascript

    
    async function callContract(contractName, actionName, data, accountName) {
        try {
            const result = await api.transact({
                actions: [{
                    account: contractName, // 部署合约的账户名,即合约账户
                    name: actionName,      // 要调用的合约动作的名称
                    authorization: [{
                        actor: accountName,  // 执行调用的账户名
                        permission: 'active', // 账户权限,通常使用 'active' 权限
                    }],
                    data: data,              // 传递给合约动作的数据,通常是 JSON 对象
                }]
            }, {
                blocksBehind: 3,             // 指定交易广播前需要等待的区块数,防止分叉
                expireSeconds: 30,            // 交易过期时间,单位为秒
            });
            console.log('Transaction ID: ', result.transaction_id); // 输出交易ID,用于追踪交易状态
        } catch (e) {
            console.error('调用合约失败: ', e); // 捕获并输出错误信息,便于调试
            // 可以在此处添加更详细的错误处理逻辑,例如重试机制、通知用户等
        }
    }
    

    上述代码定义了一个 callContract 异步函数,它接受四个参数: contractName (智能合约部署的账户名)、 actionName (要调用的合约动作名称)、 data (传递给合约动作的数据对象)和 accountName (执行调用的账户名)。 api.transact 方法用于构造并广播交易。 blocksBehind expireSeconds 参数用于确保交易在有效时间内被打包到区块链上。 如果调用失败, catch 块会捕获异常并输出错误信息,方便开发者进行调试和问题排查。

    以下是调用合约函数的示例:

    javascript

    
    // 构造要传递给合约的数据
    const contractData = {
        user: 'alice',      // 用户名
        message: 'Hello, EOS!' // 消息内容
    };
    
    // 调用合约函数
    callContract('mycontract', 'sayhello', contractData, 'alice');
    

    在此示例中, contractData 对象包含了要传递给 sayhello 动作的数据,包括 user message 字段。 callContract 函数被调用,并传入了合约名称 ( mycontract ),动作名称 ( sayhello ),数据对象 ( contractData ) 和账户名称 ( alice )。请务必替换示例中的 mycontract 为你实际的合约账户名, sayhello 为合约中定义的动作名,并根据合约动作的参数要求调整 contractData 的内容。

    其他注意事项

    • 错误处理: 在实际开发中,需要对各种可能发生的错误进行周全的处理。这不仅包括简单的异常捕获,更要细致到每一步操作可能出现的网络连接中断、API调用失败、交易广播延迟或失败、智能合约执行异常(例如资源不足、权限验证失败、合约逻辑错误等)等情况。针对不同的错误类型,应当设计相应的重试机制、回滚策略、以及用户友好的错误提示,确保应用在各种异常情况下都能保持稳定性和可用性。详细的错误日志记录对于问题排查和系统监控至关重要。
    • 安全性: 私钥是访问和控制区块链账户的唯一凭证,务必采取一切可能的措施保护私钥的安全,避免任何形式的泄露。切勿将私钥存储在明文文件中、硬编码到应用程序中、或通过不安全的渠道传输。推荐使用硬件钱包、安全的密钥管理系统(如HashiCorp Vault)或加密的软件钱包来存储和管理私钥。定期更换私钥、启用多重签名、以及进行安全审计等措施也能有效提升私钥安全性。
    • 测试: 在将智能合约部署到主网或在主网上进行任何实际交易之前,务必在EOSIO测试网络(例如Jungle Testnet、Kylin Testnet)上进行全面、充分的测试。测试内容应包括所有可能的交易场景、边界条件、以及潜在的攻击向量。通过模拟不同的用户角色、交易量、网络环境等因素,验证智能合约的功能正确性、性能表现、以及安全性。自动化测试框架可以帮助提高测试效率和覆盖率。
    • 文档: EOSIO 生态系统拥有丰富的官方文档和社区资源,请务必参考 EOSIO 的官方文档、 eosjs 的 API 文档、以及相关的开发者论坛和博客,深入了解 EOSIO 区块链的底层原理、智能合约开发规范、以及 eosjs 的使用方法。查阅最新的技术文档和示例代码,可以帮助你更好地理解和应用 EOSIO 技术,避免常见的错误和陷阱。同时,积极参与社区讨论,与其他开发者交流经验,共同推动 EOSIO 生态系统的发展。

    这些示例代码仅仅是与 EOS 区块链进行交互的起点,旨在帮助你快速入门 eosjs 的基本使用方法。请牢记,真实的生产环境应用远比示例代码复杂,需要考虑更多因素,例如:身份验证、授权管理、数据验证、并发处理、性能优化、以及系统监控。根据实际业务需求,你需要设计更复杂的智能合约逻辑、更完善的错误处理机制、以及更安全的密钥管理方案。深入学习 EOSIO 的高级特性(例如RAM管理、权限系统、延迟执行交易等),可以帮助你构建更加强大和高效的区块链应用。