蚂蚁区块链第14课 如何在TEE硬件隐私加密链上搭建一个DAPP应用(以姓名年龄为例)

蚂蚁区块链第14课 如何在TEE硬件隐私加密链上搭建一个DAPP应用(以姓名年龄为例)_第1张图片

1,摘要

本文介绍通过调用蚂蚁BAAS的TEE硬件隐私链的JS SDK,完成智能合约读取,编译和加密部署功能。然后通过基于EXPRESS框架搭建的前端页面完成该姓名/年龄前端系统的写入/查询功能,演示隐私链的接口基本功能。

2,需求和代码介绍

2.1 需求

本需求主要是作为入门级DAPP,主要能读取智能合约中的姓名/年龄信息,同时也能写入更新姓名/年龄。该智能合约需要部署在TEE硬件隐私链上。
部署在标准合约链的参考文章《蚂蚁区块链第13课 如何搭建一个DAPP应用(以姓名年龄为例)》。

2.2 智能合约

InfoContract.sol智能合约:

pragma solidity ^0.4.23;

contract InfoContract {
    string name;
    uint age;

    event Instructor(string name, uint age);

    function setInfo(string _name, uint _age) public {
        name = _name;
        age = _age;
        emit Instructor(name, age);
    }

    function getInfo() public view returns(string, uint) {
        return (name, age);
    }
}

2.3 前端UI和代码

蚂蚁区块链第14课 如何在TEE硬件隐私加密链上搭建一个DAPP应用(以姓名年龄为例)_第2张图片

功能说明
(1)输入“姓名”,“年龄”,点击更新,完成加密更新智能合约的数据;
(2)输入AESS密钥,点击“解密查询”,查询结果数据。

对应的“home.ejs”的前端代码如下:




  
  
  
  Document



This is my homepage

姓名:

年龄:

aes密码:

<%= name[0] %>

<%= name[1] %>

<%= info %>

2.4 JS SDK接口调用文件

JS SDK接口调用文件app.js的代码如下:

let express = require("express");
let app = express();

const Chain = require("@alipay/mychain/index.node") //在 node 环境使用 TLS 协议
const fs = require("fs")
const solc = require('@alipay/solc')
 
const accountKey = fs.readFileSync("./certs/duncanwang-user.pem", { encoding: "utf8" })
const accountPassword = "2018ceshi"  //需要替换为自定义的 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 = "2018ceshi" //需要替换为自定义的 client.key 密码
//配置选项
let opt = {
  host: '139.196.136.94',    //目标区块链网络节点的 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) //区块高度
})*/

const contract = fs.readFileSync('./contracts/InfoContract.sol', {encoding: 'ascii'})

// 第二个参数设定为 1 ,会开启编译优化 optimiser
const output = solc.compile(contract, 1)
const abi = JSON.parse(output.contracts[':InfoContract'].interface)
const bytecode = output.contracts[':InfoContract'].bytecode

// 读取 TEE 合约链节点的公钥文件 tee_rsa_public_key.pem
let rsa2048 = {
  public: fs.readFileSync('./certs/tee_rsa_public_key.pem')
}
// 自定义的 aes 密码,此密码与加密交易的 hash 联合计算生成最终的 aes 密钥
let aes_key = '0x1c4f2919963e8dc040cfddf7d27227de'
 
contractName = 'contract'+Date.now()

// 初始化一个合约实例
let myContract = chain.ctr.contract(contractName, abi) 

// 基础数据
let basicInfo = {
  from: 'duncanwang',
  encrypt: true,
  rsaPublicKey: rsa2048.public,
  aesKey: aes_key
}

// 加密部署合约,保护隐私
let autoDeploy = (info) => {
  return new Promise((resolve, reject)=>{
    myContract.new(bytecode,info,(err, contract, data) => {
      resolve(data)
    })
  })
}
// 加密 (查询\获取) 信息
let setInfo = (func_parml, info) => {
  return new Promise((resolve, reject)=>{
    func_parml.type === 'set' ? myContract.setInfo(func_parml.name, func_parml.age, info, (err, contract, data) =>{resolve(data)}) : myContract.getInfo(info,(err, contract, data) =>{resolve({contract,data})})
  })
}
//初始化方法
let initialize = async () => {
  let initial = await autoDeploy(basicInfo)
  let setData = await setInfo({type: 'set', name :'duncanwang' , age : 35}, basicInfo)
  //初始化成功,开启服务
  let server = require('http').createServer(app);
      server.listen(5000);{
        console.log("Sever Ready! open on http://localhost:5000");
      }
}
//获取方法
let getData = async (msg) => {
  let userInfo = await setInfo({type: 'get'}, msg)
  let info = myContract.getOutput('getInfo', Chain.utils.decryptAESWithPassword(userInfo.contract, aes_key, userInfo.data.txhash))
  return info
}
//设置方法
let setData = async (msg) => {
  let setData = await setInfo({type: 'set', name : msg.from , age : msg.age >> 0}, msg)
  let userInfo = await setInfo({type: 'get'}, msg)
  let info = myContract.getOutput('getInfo', Chain.utils.decryptAESWithPassword(userInfo.contract, aes_key, userInfo.data.txhash))
  return info
}
//初始化
console.log('服务开启中...')
initialize()

//初始返回一个home页面
app.get("/", function(req ,res) {
  res.render("home.ejs",{
    name: "",
    info: ''
  });
});

//更新接口
app.get("/update", async function(req, res){
  let msg = basicInfo
  msg.age = req.query.age
  let info = await setData(msg)
  res.render("home.ejs",{
    name: info,
    info: '更新成功'
  }); 
});

//获取接口
app.get("/search", async (req ,res) => {
  let info = await getData(basicInfo)
  console.log('-----info-----', info)
  res.render("home.ejs",{
    name: info,
    info: '获取成功'
  });
});

//加密查询接口

app.get("/encrypt", async (req ,res) => {
  let msg = basicInfo
  msg.aesKey = req.query.password
  if(req.query.password !== '0x1c4f2919963e8dc040cfddf7d27227de') {
    res.render("home.ejs",{
      name: ['', ''],
      info: '密码错误,请重新输入!'
    });
    return
  }
  let info = await getData(msg)
  res.render("home.ejs",{
    name: info,
    info: '加密查询成功'
  });
});

JS SDK 增加了特别的交易接口来支持 TEE 合约链的交易隐私保护,具体参考以下接口说明介绍。

合约相关的加密交易

同样,考虑到对合约操作相关接口使用最为广泛,JS SDK 让合约操作相关接口直接支持加密交易,具体使用方式如下。

new

new 用来加密部署合约,保护合约隐私。

请求参数

将以下参数整体封装为 object 传入。

参数 必填 类型 说明
bytecode true string 目标合约的字节码,为 16 进制表示
data true object 包含 from、parameters 等配置

data 字段内容

字段 必填 类型 说明
encrypt true bool 说明此交易是否要加密,true:加密;false/不指定:不加密。
rsaPublicKey true string 目标 TEE 合约链环境的节点 RSA 公钥, 从 BaaS 平台 TEE 合约链下载。
aesKey true string 或 Buffer 此参数将作为一个 password 形式与目标加密的交易 hash 一起计算生成最终的 AES 对称密钥,如果使用 string 类型,会区分前缀是否包含“0x”来解释内容,包含“0x”则使用 16 进制读取,否则按照 ASCII 编码读取。
from true string 需要配置的当前账户名。
parameters true Array 如果合约包含初始化函数,并且此函数需要参数列表,可以通过 parameters 传递。

说明

  • 相比于普通的合约方法 new 增加了加密需要的 3 个参数:encrypt、rsaPublicKey、aesKey。类似的,合约方法调用、合约升级也是增加 3 个参数配置而已,其它参数配置与非加密使用方式一致。
  • 其中 aesKey 参数将作为一个password形式与目标加密的交易hash一起计算,生成最终的aes对称密钥,因此每个加密交易由于hash不同,即使用相同的aesKey,最终生成的aes对称密钥也不同,这样生成方式便于交易发送者未来对部分交易的最终aes密钥进行分享,而不需要分享aesKey。

2.5 工程文件

辉哥建立了一个name-age-tee的文件夹,里面的目标结构如下所示。

| alipay-mychain-0.2.27.tgz
| app.js
|
+---certs
| ca.crt
| client.crt
| client.key
| duncanwang-user.key
| duncanwang-user.pem
| package-lock.json
| tee_rsa_public_key.pem
|
+---contracts
| InfoContract.sol
|
+---node_modules
|
---views
home.ejs
说明下:
(1)alipay-mychain-0.2.27.tgz 为蚂蚁的JS-SDK包,解压文件会到node_modules。
(2)app.js 调用JS-SDK的代码。
(3)certs为duncanwang账号对应的各种证书和公私钥文件。
(4)contracts/InfoContract.sol 为name-age智能合约文件。
(5)node_modules的内容很多,为NPM安装的各种依赖包。
(6)views/home.ejs 为采用采用node.js实现的前端页面。

3,部署测试

3.1 安装solc

npm i alipay-solc-0.1.12.tgz --save

成功结果:

【结果】
D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee>npm i alipay-solc-0.1.12.tgz --save
npm WARN saveError ENOENT: no such file or directory, open 'D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee\package.json'
npm WARN enoent ENOENT: no such file or directory, open 'D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee\package.json'
npm WARN name-age-tee No description
npm WARN name-age-tee No repository field.
npm WARN name-age-tee No README data
npm WARN name-age-tee No license field.

+ @alipay/solc@0.1.12
added 65 packages from 35 contributors and audited 2409 packages in 6.74s
found 0 vulnerabilities

3.2 安装JS SDK

npm i alipay-mychain-0.2.27.tgz --save

【成功结果】

D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee>npm i alipay-mychain-0.2.27.tgz --save

> secp256k1@3.6.2 install D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee\node_modules\secp256k1
> npm run rebuild || echo "Secp256k1 bindings compilation fail. Pure JS implementation will be used."


> secp256k1@3.6.2 rebuild D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee\node_modules\secp256k1
> node-gyp rebuild
...

npm WARN name-age-tee No description
npm WARN name-age-tee No repository field.
npm WARN name-age-tee No README data
npm WARN name-age-tee No license field.

+ @alipay/mychain@0.2.27
added 50 packages from 32 contributors and audited 710 packages in 53.948s
found 0 vulnerabilities

3.3 安装EXPRESS模块

npm install express
npm install express-generator
成功输出结果:

D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee>npm install express
npm WARN saveError ENOENT: no such file or directory, open 'D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee\package.json'
npm WARN enoent ENOENT: no such file or directory, open 'D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee\package.json'
npm WARN name-age-tee No description
npm WARN name-age-tee No repository field.
npm WARN name-age-tee No README data
npm WARN name-age-tee No license field.

+ express@4.16.4
added 46 packages from 35 contributors and audited 2884 packages in 10.871s
found 0 vulnerabilities

D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee>npm install express-generator
npm WARN saveError ENOENT: no such file or directory, open 'D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee\package.json'
npm WARN enoent ENOENT: no such file or directory, open 'D:\jusanban\doc\26-培训分享\01-研发运营销售\01-区块链\05-蚂蚁区块链\8. Solidity-JS SDK-错误码\DAPP\name-age-tee\package.json'
npm WARN name-age-tee No description
npm WARN name-age-tee No repository field.
npm WARN name-age-tee No README data
npm WARN name-age-tee No license field.

+ express-generator@4.16.0
added 6 packages from 11 contributors and audited 3044 packages in 4.964s
found 0 vulnerabilities

3.4 运行NODE.JS服务

node app

输出结果:

蚂蚁区块链第14课 如何在TEE硬件隐私加密链上搭建一个DAPP应用(以姓名年龄为例)_第3张图片

3.5 界面操作

输入“duncanwang”,18,然后点击“更新”按钮,完成加密更新函数调用。

蚂蚁区块链第14课 如何在TEE硬件隐私加密链上搭建一个DAPP应用(以姓名年龄为例)_第4张图片

输入aes密码“0x1c4f2919963e8dc040cfddf7d27227de”,点击“解密查询”,可得结果:

蚂蚁区块链第14课 如何在TEE硬件隐私加密链上搭建一个DAPP应用(以姓名年龄为例)_第5张图片

在TEE硬件隐私加密链上搭建一个DAPP应用(以姓名年龄为例)的任务成功完成。

4,参考

(1)TEE 硬件隐私合约链 JS SDK 说明
https://tech.antfin.com/docs/2/107140

你可能感兴趣的:(蚂蚁区块链第14课 如何在TEE硬件隐私加密链上搭建一个DAPP应用(以姓名年龄为例))