本文以 0.2.27 版本的 JS SDK 为例,通过示例阐述如何快速使用 JS SDK 进行合约开发。
JS SDK 0.3.8 与 0.2.27 版本保持兼容,本快速开始同时适用于以上两个版本。
准备环境
安装 SDK
从 Node.js 官网 下载并安装 Node.js(推荐使用v10以上v16以下版本)。
安装 JS SDK。下载 JS SDK V0.2.27 安装包 至项目目录,然后在项目目录中安装。
npm i alipay-mychain-0.2.27.tgz --save
准备 SSL 连接文件
要与 BaaS 平台建立 SSL 连接,需准备三个证书文件:ca.crt
、client.key
、client.crt
。
如果您尚未在合约链申请证书,可按照 试用合约体验链 的操作说明去生成和申请证书相关文件。
文件 | 说明 | 来源 |
ca.crt | 合约链的认证 CA,客户端用来验证合约链服务身份 | 通过 BaaS 平台下载。 |
client.key | RSA 密钥 | 通过 BaaS 提供的 密钥生成工具 生成。 |
client.crt | RSA 证书,与 | 使用 BaaS 提供的 密钥生成工具 生成证书请求文件 |
准备合约链的账户
在合约链上提交交易时,需要使用一个已经在链上存在的账户,JS SDK 需要使用账户的 账户名称 和 私钥文件。
账户可通过 BaaS 平台申请创建。参考 试用合约体验链 的过程,需要填写创建的账户名称、账户公钥和恢复公钥,其中与账户公钥对应的 user.key
文件就是账户的私钥文件,对此私钥文件进行转换,方便在 JS SDK 中使用。
openssl ec -in user.key -passin pass:${key_password} -passout pass:${key_password} -aes256 -out user.pem
将 ${key_password} 替换为私钥密码。
获取链节点 IP 和端口号
要与合约链交互,您需要获取链节点的 IP 地址和端口号。在 BaaS 平台,通过查看目标合约链详情,在区块浏览器中查看节点详情,可获取链节点的 IP 地址和端口号。
使用 JS SDK
快速创建一个访问区块链的实例 chain
,并使用 QueryLastBlock
验证该实例与区块链节点的连接状况。
const Chain = require("@alipay/mychain/index.node") //在 node 环境使用 TLS 协议
const fs = require("fs")
const accountKey = fs.readFileSync("./certs/user.pem", { encoding: "utf8" })
const accountPassword = "123abc" //需要替换为自定义的 user.pem 密码
const keyInfo = Chain.utils.getKeyInfo(accountKey, accountPassword)
//可打印私钥和公钥,使用 16 进制
//console.log('private key:', keyInfo.privateKey.toString('hex'))
//console.log('public key:', keyInfo.publicKey.toString('hex'))
const passphrase = "123abc" //需要替换为自定义的 client.key 密码
//配置选项
let opt = {
host: '127.0.0.1', //目标区块链网络节点的 IP
port: 18130, //端口号
timeout: 30000, //连接超时时间配置
cert: fs.readFileSync("./certs/client.crt", { encoding: "utf8" }),
ca: fs.readFileSync("./certs/ca.crt", { encoding: "utf8" }),
key: fs.readFileSync("./certs/client.key", { encoding: "utf8" }),
userPublicKey: keyInfo.publicKey,
userPrivateKey: keyInfo.privateKey,
userRecoverPublicKey: keyInfo.publicKey,
userRecoverPrivateKey: keyInfo.privateKey,
passphrase: passphrase
}
//初始化一个连接实例
const chain = Chain(opt)
//调用 API 查询最新的一个区块数据
chain.ctr.QueryLastBlock({}, (err, data) => {
console.log('raw data:', data) //区块结构数据
console.log('block hash:', data.block.block_header.hash) //区块哈希
console.log('block number:', data.block.block_header.block_number) //区块高度
})
成功运行结果参考:
raw data: { msg_type: 58,
sequence: 1,
return_code: 0,
group_id: '0x0000000000000000000000000000000000000000',
block:
{ block_header:
{ hash:
'0xe99d8958a45e8c87a7b10efc259828f06fe083995be52997f5d310f2b6d073a6',
version: 2,
block_number: 84265,
parent_hash:
'0x918b263a8e6c6fff594b89570970ef4bef24cf93aeed5347f7b250b070857c4b',
transaction_root:
'0x0000000000000000000000000000000000000000000000000000000000000000',
receipt_root:
'0x0000000000000000000000000000000000000000000000000000000000000000',
state_root:
'0x9f71cb9ce960e5637bad6da5be8daa2d7e557942208f241a60589b2de98e6c71',
gas_used: 0,
timestamp: 1547382477852,
log_bloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
block_body:
{ transaction_list: [],
receipt_list: [],
consensus_proof:
'0xf8f2f8c9b8419746989382c1613c6c3ce98bf79ac92a8d69952c22f4064194869c53b4075d517cfc98eda861212687e49b186c08d196770bd356762fa2a88d0288c0556f271a01b84138a97446a75c76a31d24880c343407bd7bc24608685c494240ac603cad62201a01a423718661b24e517ee6f6b2fee6d356b57833305860700cca81b0238f870400b841eaf508392d9098a3e7fb46f6f7aa4b53311e5a0d13e300d02025af7453ea130a6c27407c1da254578cae80ed498d4807587883f837c1716b0be8ae02cf955d6000e61e83014929a0e200d8bee723d820022d5c5a1f8fe6b521c0a4fff0b5ec03a7c6061276d68b58' } },
api: 'QueryLastBlock' }
block hash: 0xe99d8958a45e8c87a7b10efc259828f06fe083995be52997f5d310f2b6d073a6
block number: 84265
运行结果示例中包含字段 return_code,此字段结果为 0,表示执行成功,否则其值为错误码。后文介绍的交易回执(receipt)中 result 字段也是类似含义,详细错误码信息参见合约链错误码。
JS SDK 引用说明
不同运行环境下, JS SDK 的引用方式稍有不同:
Node 环境:
const Chain = require("@alipay/mychain/index.node")
Web 环境:
const Chain = require("@alipay/mychain")
配置项说明
在初始化与区块链连接的实例之前,可进行选项配置,各配置项的具体说明如下。
如无特别说明,配置项的数据类型默认为 string 类型。 配置项中配置了账户相关的 Key 信息,包括账户公私钥、账户恢复公私钥。链的连接实例默认使用配置项中的账户 Key 信息进行交易签名。如果要切换账户,需要重新配置账户 Key 相关选项。详情参见创建账户中切换账户配置的使用示例。
配置项 | 必填 | 配置说明 | 示例值 |
host | true | 区块链节点的 IP 或者主机名。使用 TLS 时为 IP 地址;使用 HTTPS 时为主机名。 |
|
port | true | 区块链节点开放连接的端口号,类型为 number。 | 18130 |
clients | false | 可设置多个 | [{host:’127.0.0.1’,port:18130}, {host:’127.0.0.2’,port:18130}] |
timeout | true | 与区块链节点连接的超时时间配置,单位毫秒,类型为 number。 | 30000 |
ca | true | 目标合约链的根证书。 | 在 BaaS 平台申请通过后下载,详情参考 试用合约体验链 |
cert | true | 客户端证书文件。 | 在 BaaS 平台申请通过后下载,详情参考 试用合约体验链 |
key | true | 客户端生成的私钥文件,用于生成证书请求文件,进而申请证书。 | |
userPublicKey | true | 账户公钥,字符串内容为 16 进制。 |
|
userPrivateKey | true | 账户私钥,字符串内容为 16 进制。 |
|
userRecoverPublicKey | true | 账户恢复公钥,字符串内容为 16 进制。 |
|
userRecoverPrivateKey | true | 账户恢复私钥,字符串内容为 16 进制。 |
|
passphrase | true | TLS 或 HTTPS 链接的 | 123abc |
checkServerIdentity | false | 针对 TLS 协议的配置,类型为 boolean,含义为是否启用对服务端 hostname 的检查,即对比服务端证书的 | false |
tx_querycount | false | 对于交易类型,提交交易后会调用 | 5 |
tx_querytime | false | 对于交易类型,提交交易后会调用 | 200 |