第十篇 墨客区块链(MOAC BlockChain) 如何将自定义数据写到区块链中

区块链的一个显著特点是,数据一旦写入链中,就不可篡改重写。

在墨客区块链中,每一笔交易(transaction),都有一个保存数据的data空间,本文主要讲解如何将自定义数据(可以是一句话、一篇文章等)写入区块链的交易中,并读取出来。

当然,保存数据到区块链是会消耗gas费的,且gas费跟数据量是正相关的。

本文内容不适用于有强逻辑性和关系型的大数据存储。

1.做一笔交易,将数据写入区块链

该笔交易没有发送mc,或者其他token,仅将数据写到区块链。

代码文档sendData.js如下:

var Chain3 = require('chain3');
var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));

var address = "0x745c57ca5318093115d61bbca368XXXXXXXXXXXX";
var account = {address:"0x745c57ca5318093115d61bbca368XXXXXXXXXXXX",secret:"bb673026deda3c3cd0c63f6ccddfb02a7aXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"};

send(chain3, account.address, account.secret, txCount = -1);

function send(chain3, fromAddress, fromSecret, txCount = -1){
  var mc = chain3.mc;
  var txcount = txCount >= 0 ? txCount : chain3.mc.getTransactionCount(fromAddress);
  console.log("Get tx account", txcount);

  var gasPrice = 25000000000;
  var gasLimit = 100000;
  var gasTotal = gasPrice * gasLimit;
  console.log(gasPrice, gasLimit, chain3.fromSha(gasTotal, 'mc'));
  
  //以下为写入数据log
  let log = {
    time:(new Date).getTime(),
    type:"info",
    msg:"Hello MOAC!!!"
  };
  //转换log数据格式
  let str = JSON.stringify(log);
  console.log(str);
  let data = Buffer.from(str).toString('hex');
  data = '0x'+data;
  console.log(data);  

  var rawTx = {
    from: fromAddress,
    nonce: chain3.intToHex(txcount),
    gasPrice: chain3.intToHex(gasPrice),
    gasLimit: chain3.intToHex(gasLimit),
    data: data ,
    shardingFlag: 0, //default is global contract
    chainId: chain3.version.network
  };

  var signedTx = chain3.signTransaction(rawTx, fromSecret);
  mc.sendRawTransaction(signedTx, function(err, hash) {
      if (!err){
          console.log("succeed: ", hash);
          return hash;
      }else{
          console.log("error:", err);
          console.log('raw tx:', rawTx);
      }
  });
}

代码使用sendRawTransaction时需要私钥签名,得到本地节点账号的私钥方法见:

第八篇 墨客区块链(MOAC BlockChain) 程序猿怎么部署和调用智能合约》的第三节“3.部署智能合约”。

直接node,运行结果如下:

返回信息中包含:

本次交易写入数据“Hello MOAC!!!”及其十六进制表示。

本次交易的hash值:0x7834667df3890d0a4bc2fc949d45206fec8fe4b63853181dd9cc20c1b6c009dc。

浏览器查询hash:

其中的Input Data就是本次交易写入的数据。与node sendData.js时显示的hex格式数据内容一致。

 

2.查看区块链里的数据字段

当前,每笔交易里的数据在浏览器还显示为hex。因此需要自己写代码解读出其中的内容。

读数据代码callData.js如下:

var Chain3 = require('chain3');
var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));  //设置API访问moac节点方式

//获取交易信息
hash = "0x7834667df3890d0a4bc2fc949d45206fec8fe4b63853181dd9cc20c1b6c009dc";
var receipt = chain3.mc.getTransaction(hash);
console.log('get transaction from hash  :'+ JSON.stringify(receipt));

console.log();
//获取交易内保存的数据data,需要提前写入
hash = "0x7834667df3890d0a4bc2fc949d45206fec8fe4b63853181dd9cc20c1b6c009dc";
chain3.mc.getTransaction(hash,function(error, result){
    //console.log(result);
    inputData = result.input;
    res_str = Buffer.from(inputData.replace('0x',''),'hex').toString();
    res_json = JSON.parse(res_str);
    console.log('your data :',res_json);
    console.log('your msg  :',res_json.msg);
});

直接node,运行结果如下:

通过交易hash得到交易的所有信息,并分析出data数据。

 

3.将数据批量写入区块链

结合对excel表格的读写操作,可以简单地将批量数据写入到区块链中去。

首先设计一个excel文件,保存要写到区块链的数据。命名为testMessage.xlsx。

本实例用到message。id和name不在代码里使用,仅用于文档记录。time用于返回时间,在成功后会新建一个文件,返回每次信息发送的时间。

代码文件goMessage.js。node执行即可。

注意:1. 将数据上链的交易会收取gas费,且收取的费用跟数据大小正相关;
           2. 该代码里包含手动设置nounce完成tx的实例。

var Chain3 = require('chain3');
var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));

//通过node-xlsx读取的excel文件就是一个json数据
var xlsx = require('node-xlsx');    //定义xlsx,自行npm install node-xlsx
var fs = require('fs');             //定义fs,自行npm install fs

var address = "0x745c57ca5318093115d61bbca36XXXXXXXXXXXX";
var account = {
    address: "0x745c57ca5318093115d61bbca36XXXXXXXXXXXX",
    secret: "bb673026deda3c3cd0c63f6ccddfb02a7ae320078aa8XXXXXXXXXXXXXXXXXXXX"
};

//主要参数
var thisTxCount = -1;               //nounce值,本例手动设置,初始为-1,读取实际值后,每次自增1
var interval = 2;                   //发送一次信息的间隔时间,秒
var message = "Hello MOAC!!!";      //定义要发送的信息,从cxcel文件读取

var obj = xlsx.parse(__dirname + '/testMessage.xlsx');//配置excel文件的路径
var excelObj = obj[0].data;         //obj[i].data表示excel文件第i+1个sheet文档的全部内容

var data = [];
var promiseList = [];               //用于异步返回
for (var i in excelObj) {
    var arr = [];
    if (i > 0) {                    //数据从第二行开始,通常在excel中第一行(i=0)就是每一列的title
        sleep(interval * 1000);     //每隔2秒,发送一次信息
        message = excelObj[i][2];   //得到要发送的信息内容
        excelObj[i][3] = (new Date).toLocaleString();  //记录发送交易的时间
        promiseList.push(send(chain3, account.address, account.secret, message, thisTxCount, i));		
    }
}

Promise.all(promiseList).then(function (objList) {  //所有异步完成后回调
    //遍历objList
    objList.forEach(item=>{
        excelObj[item.index][4] = item.hash;        //记录发送交易的哈希
    })
    var buffer = xlsx.build([
        {
            name: 'sheet1',
            data: excelObj
        }
    ]);
    //创建新文件,将发送时间等记录到文件中
    fs.writeFileSync((new Date).toLocaleDateString() + '-' + (new Date).getTime() + '-' + 'hadSendMessage.xlsx', buffer, {'flag': 'w'});
});

//自己写的休眠函数
function sleep(numberMillis) {
    var now = new Date();
    var exitTime = now.getTime() + numberMillis;
    while (true) {
        now = new Date();
        if (now.getTime() > exitTime)
            return;
    }
}

function send(chain3, fromAddress, fromSecret, message, txCount = -1, index) {
    var mc = chain3.mc;
    var txcount = txCount >= 0 ? txCount : chain3.mc.getTransactionCount(fromAddress);//获取nounce值
    //console.log("Get tx account", txcount);
    thisTxCount = txcount + 1;        //手动设置nounce,每次自增1

    var gasPrice = 25000000000;
    var gasLimit = 100000;            //数据量越大,gas费应该设置得越高
    var gasTotal = gasPrice * gasLimit;
    //console.log(gasPrice, gasLimit, chain3.fromSha(gasTotal, 'mc'));

    //以下为写入数据log
    let log = {
        time: (new Date).getTime(),   //获取当前时间(从1970.1.1开始的毫秒数)
        type: "info",
        msg: message
    };
    //转换log数据格式,将数据转换为16进制字符串
    let str = JSON.stringify(log);
    console.log(str);
    let data = Buffer.from(str).toString('hex');
    data = '0x' + data;
    console.log(data);

    var rawTx = {
        from: fromAddress,
        nonce: chain3.intToHex(txcount),
        gasPrice: chain3.intToHex(gasPrice),
        gasLimit: chain3.intToHex(gasLimit),
        data: data,
        shardingFlag: 0, //default is global contract
        chainId: chain3.version.network
    };

    var signedTx = chain3.signTransaction(rawTx, fromSecret);
    return new Promise(function (resolve, reject) {                   //异步调用方法
        mc.sendRawTransaction(signedTx, function (err, hash) {
            if (!err) {                
                console.log('i=', index);
                console.log("succeed: ", hash);
                let objBack = {                                       //index及对应的hash
                    hash,
                    index
                }
                resolve(objBack);
            } else {
                console.log("error:", err);
                console.log('raw tx:', rawTx);
                reject(err);
            }
        });
    })
}

执行结果:返回所有交易的hash值。

并且建立一个新的文件2018-8-12-1534085632480-hadSendMessage.xlsx。

 

4.在交易里发送 mc + data

发送一笔交易,包含发送mc,同时把数据写到data字段。

var Chain3 = require('chain3');
var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));

var address = "0x745c57ca5318093115d61bbca368XXXXXXXXXXXX";
var account = {address:"0x745c57ca5318093115d61bbca368XXXXXXXXXXXX",secret:"bb673026deda3c3cd0c63f6ccddfb02a7ae320078aa8XXXXXXXXXXXXXXXXXXXX"};

var toAddress = "0x68986c1bcd54ae5dae69310fc64eXXXXXXXXXXXX";
var amount = 0.002;

send(chain3, account.address, account.secret, toAddress, amount, txCount = -1)

function send(chain3, fromAddress, fromSecret, toAddress, amount, txCount = -1){
  var mc = chain3.mc;
  var txcount = txCount >= 0 ? txCount : chain3.mc.getTransactionCount(fromAddress);
  console.log("Get tx account", txcount);

  var gasPrice = 25000000000;
  var gasLimit = 100000;
  var value = chain3.toSha(amount, 'mc');
  var gasTotal = gasPrice * gasLimit + Number(value);
  console.log(gasPrice, gasLimit, value, chain3.fromSha(gasTotal, 'mc'));
  
  //以下为写入数据log
  let log = {
    time:(new Date).getTime(),
    type:"info",
    msg:"MOAC GO!!!"
  };
  let str = JSON.stringify(log);
  console.log(str);
  let data = Buffer.from(str).toString('hex');
  data = '0x'+data;
  console.log(data);  

  var rawTx = {
    from: fromAddress,
    to: toAddress,
    nonce: chain3.intToHex(txcount),
    gasPrice: chain3.intToHex(gasPrice),
    gasLimit: chain3.intToHex(gasLimit),
    value: chain3.intToHex(value),
    data: data ,
    shardingFlag: 0, //default is global contract
    chainId: chain3.version.network
  };

  var signedTx = chain3.signTransaction(rawTx, fromSecret);
  mc.sendRawTransaction(signedTx, function(err, hash) {
      if (!err){
          console.log("succeed: ", hash);
          return hash;
      }else{
          console.log("error:", err);
	        console.log('raw tx:', rawTx);
      }
  });
}

 

阅读更多

更多精彩内容