区块链技术结合分布式数据库实践

n

文章分类

l

评论数

日期

08/13/2018

前言

说到区块链技术,人们第一时间会联想到比特币,以及这些年一路上涨的比特币价格。但是比特币并不能代表区块链技术,它只是第一个提出区块链技术的数字货币。

实际上区块链技术最大的贡献在于为人们提供了一种去中心化的理念,让人们看到原来在无信任的网络环境下,数据依然可以确保正确,并且该系统还能够做到无法停止、防屏蔽的效果。

现在市场上很多的开发者都希望基于区块链技术搭建新的应用系统,但是限于区块链技术其诞生时间不太长,并且暂时也还没有被广大的开发者所熟知,所以普通开发者对于如何操作区块链里面的数据,以及如何使用它来设计数据结构和如何开发应用,这些都是困扰区块链开发者的技术难题。

笔者结合自身多年在数据库内核研发领域的实践,基于业界的一些开源技术将区块链底层作为存储,结合上层的SQL解析部分,能够使应用程序的开发者像使用传统数据库一样使用区块链技术,直接利用SQL命令操作区块链,并且应用的数据结构设计可以继续沿用过去成熟的范式设计。

这种方式一方面能够最大程度对现有开发人员降低学习成本,另一方面能够有机会将一些现有的应用迁移到区块链平台上,从而有效利用区块链技术中的公开透明以及不可抵赖性。

应用方向

过去,人们在构建大型、重要的应用系统时,考虑到公网的信息通信较容易遭受恶意攻击,所以大部分通信网络选型设计时都会采用一个较为封闭的网络环境。而封闭的网络环境,往往会使得应用系统向中心化方向发展。

但是应用系统中心化,对于某些特殊的应用场景并不适合,例如:跨境交易场景。如果该场景采用中心化的建设方式,则需要在跨境的多个系统中均搭建一套存储系统。在交易过程中,各个系统按照某种约定的规则进行数据处理,并且为了防止各系统的数据不一致现象出现,还需要定期对各个系统中的数据进行核对,如果发现不一致现象再进行相应的数据回滚。这种中心化的建设方式会给系统运维和数据核对带来不少的困难。

区块链技术是一种支持在无信任网络环境中、去中心化的技术。它可以通过数字签名手段确保运行在链上的应用系统通信网络的安全,并且采用Hash链技术确保已经写入的数据不可更改。过去受限于必须采用信任的网络的技术难题被区块链技术解决了,使得人们可以从更加符合业务场景的实际出发,来审视在规划应用系统时,是否应该继续采用中心化的模式来进行建设。

经过区块链技术短时间的发展,目前人们已经认识到类似银行信用征信、跨境交易、物联网IOT、全球专利登记等业务场景,更加适合采用去中心化的区块链技术进行设计和开发。

技术实现

在当前的数据库行业中,计算存储分离架构是未来的主流方向。笔者作为社区贡献者参与了SequoiaBC的开发,其同样使用计算存储分离的架构,将底层区块链作为标准的K/V存储,辅以上层的SQL解析层,从而做到在全兼容SQL、JDBC、ODBC等标准接口的前提下,有效利用底层区块链存储的一切优秀特性。

在SequoiaBC的整体架构中,主要包含3部分,分别是

  1. SQL引擎,目前支持MySQL和PostgreSQL两款主流的开源SQL引擎,该模块主要是为应用提供SQL服务和检查SQL语法命令;
  2. SQL Adapter,将SQL命令转换为对应区块链存储的操作命令的部分;
  3. 区块链存储层,能够以插件的形式支持目前主流的区块链,包括:以太坊、EOS、以及Hyperledger等。

SequoiaBC整体架构图如下。

区块链技术结合分布式数据库实践

图 1

SequoiaBC首创式将SQL引擎和区块链存储层进行分离,使得无论是面向应用的SQL引擎还是存储层中的区块链产品,都成为插拔式模块,开发者可以根据开发环境需要随时替换不同的产品进行开发使用。

SequoiaBC操作区块链实践

作者将以PostgreSQL Hyperledger fabric作为例子,向开发者介绍如何通过PostgreSQL 直接操作区块链里面的数据。

用户在使用Hyperledger fabric时,有两点需要用户注意

  1. Hyperledger fabric 区块链是以 “通道”–channel为单位进行数据通信,channel是区块链的“私有通道”概念,只有加入了该channel的节点才可以从chaincode中读取和修改数据;
  2. Hyperledger fabric的“智能合约”– chaincode是建立在channel 之上。

PostgreSQL引擎安装SequoiaBC SQL Adapter

用户为PostgreSQL安装SequoiaBC 的SQL Adapter时,首先需要将SequoiaBC的SQL Adapter配置文件 sbc_fabric—1.0.sql、sbc_fabric.control 拷贝到 PostgreSQL的安装目录上。

例如PostgreSQL 的安装路径为/usr/local/pgsql,则用户需要将相关的配置文件拷贝到 /usr/local/pgsql/share/extension/ 目录

cp sbc_fabric-1.0.sql /usr/local/pgsql/share/extension/ ;cp sbc_fabric.control /usr/local/pgsql/share/extension/ ;

再将 sbc_fabric.so 程序拷贝到 /usr/local/pgsql/lib 目录,然后重启PostgreSQL 服务。

cp sbc_fabric.so /usr/local/pgsql/lib ;

完成以上步骤,开发者就成功为PostgreSQL 安装了操作Hyperledger fabric的SQL Adapter。

Hyperledger fabric 设置chaincode

在Hyperledger fabric 的部署步骤中,其中一个重要步骤是为区块链安装 “智能合约”– chaincode。“智能合约”是Hyperledger fabric区块链描述业务逻辑的具体代码。开发者可以根据自身业务需要,编写不同的“智能合约”代码,以实现对应的业务逻辑。

SequoiaBC为开发者提供了一个符合SQL Adapter规范的chaincode,以下命令为Hyperledger fabric 安装一个名为mycc 的chaincode 的命令。

peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/ chaincode/go/sequoiabc

PostgreSQL 操作区块链数据

假设Hyperledger fabric 区块链中已经存在两个名字为product和bill 的channel,并且chaincode 的名字分别为product_cc和bill_cc,则用户在PostgreSQL 中创建名为 product和 bill 的表的命令为

CREATE FOREIGN TABLE product(id int, name text, price int, des text) SERVER sbc_fabric_svr OPTIONS(channelname ‘product’, chaincodename ‘product_cc’);

CREATE FOREIGN TABLE

CREATE FOREIGN TABLE bill(id int, product_id int, amount int) SERVER sbc_fabric_svr OPTIONS(channelname ‘bill’, chaincodename ‘bill_cc’);

CREATE FOREIGN TABLE

用户在SequoiaBC中向product “通道”写入4条记录。

insert into product values (1, ‘apple’, 10, ‘苹果’);

INSERT 0 1

insert into product values (2, ‘banana’, 3, ‘香蕉’);

INSERT 0 1

insert into product values (3, ‘orange’, 2, ‘橘子’);

INSERT 0 1

insert into product values (4, ‘pear’, 7, ‘梨’);

INSERT 0 1

用户通过SequoiaBC获取product “通道”的所有记录。

select * from product;

id | name | price | des

—- ——– ——- ——

1 | apple | 10 | 苹果

2 | banana | 3 | 香蕉

3 | orange | 2 | 橘子

4 | pear | 7 | 梨

(4 rows)

用户在SequoiaBC中向bill “通道”写入3条记录。

insert into bill values (1, 1, 20);

INSERT 0 1

insert into bill values (2, 1, 3);

INSERT 0 1

insert into bill values (3, 4, 15);

INSERT 0 1

用户可以通过SequoiaBC从bill “通道”中获取数据

select * from bill;

id | product_id | amount

—- ———— ——–

1 | 1 | 20

2 | 1 | 3

3 | 4 | 15

(3 rows)

用户可以通过SequoiaBC对product “通道”里的数据进行条件过滤

select id, name, price from product where price > 5;

id | name | price

—- ——- ——-

1 | apple | 10

4 | pear | 7

(2 rows)

用户可以通过SequoiaBC对product 和bill 两个“通道”数据进行关联查询

select product.id as product_id, bill.id as bill_id, product.name as name, product.price as price, bill.amount as amount from bill inner join product on bill.product_id = product.id;

product_id | bill_id | name | price | amount

———— ——— ——- ——- ——–

1 | 1 | apple | 10 | 20

1 | 2 | apple | 10 | 3

4 | 3 | pear | 7 | 15

(3 rows)

实现机制

在PG Hyperledger的体系中,Hyperledger的智能合约需要以go语言的方式进行实现。而在其他例如以太坊等公链上则可以用Solidity实现类似同样的逻辑。

例如,在Hyperledger中一个insert操作可以用如下代码简单实现。

func (t *SimpleChaincode) insert(stub shim.ChaincodeStubInterface, args []string) pb.Response {

var name, info string

//var buffer bytes.Buffer

var err error

var marbleJSON map[string]interface{}

if len(args) != 2 {

return shim.Error(“Incorrect number of arguments. Expecting 2″)

}

name = args[0]

info = args[1]

valbytes, err := stub.GetState(name)

if err != nil {

return shim.Error(“Failed to get state”)

}

if valbytes != nil {

errInfo := fmt.Sprintf(“%s already exist”, name)

return shim.Error(errInfo)

}

if err := json.Unmarshal([]byte (info), &marbleJSON); err != nil {

return shim.Error(err.Error())

}

marbleJSON[“type”] = “fdw”

marbleJSONasBytes, err := json.Marshal(marbleJSON)

if err != nil {

return shim.Error(err.Error())

}

err = stub.PutState(name, marbleJSONasBytes)

if err != nil {

return shim.Error(err.Error())

}

return shim.Success(nil)

}

而PG端对应INSERT逻辑的代码则可以通过FDW简单实现。

static TupleTableSlot *

fabricExecForeignInsert(EState *estate,

ResultRelInfo *resultRelInfo,

TupleTableSlot *slot,

TupleTableSlot *planSlot)

{

Relation rel = resultRelInfo->ri_RelationDesc;

Oid foreignTableId = InvalidOid;

fabric_opt *options;

FabricFdwExecState *fmstate;

ListCell *lc;

Datum value = 0;

int n_params = 0;

void * returnValue;

bool first = true;

bool second = true;

char cmd [1024];

char info [1024];

FILE *fp;

foreignTableId = RelationGetRelid(rel);

fabric_get_options(foreignTableId);

options = fabric_get_options(foreignTableId);

fmstate = (FabricFdwExecState *) resultRelInfo->ri_FdwState;

n_params = list_length(fmstate->retrieved_attrs);

strcpy (cmd, “docker-compose -f /opt/gopath/src/github.com/hyperledger/fabric/examples/e2e_cli/docker-compose-test.yaml run –rm –no-deps cli peer chaincode invoke -o orderer.example.com:7050 –tls true –cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem –logging-level CRITICAL -C “);

strcat (cmd, options->svr_channelname);

strcat (cmd, ” -n “);

strcat (cmd, options->svr_chaincodename);

strcat (cmd, ” -c ‘{”Args”:[“insert”,”);

strcpy (info, “{“);

foreach(lc, fmstate->retrieved_attrs)

{

int attnum = lfirst_int(lc) – 1;

char * colname = (char *) list_nth (fmstate->column_attrs, attnum);

bool *isnull = (bool*) palloc0(sizeof(bool) * n_params);

Oid type = slot->tts_tupleDescriptor->attrs[attnum]->atttypid;

value = slot_getattr(slot, attnum 1, &isnull[attnum]);

fabric_bind_sql_var(type, attnum, value, &isnull[attnum], &returnValue);

if (!first)

{

strcat (info, “,”);

}

else

{

strcat (cmd, “””);

strcat (cmd, (char *) returnValue);

strcat (cmd, “””);

strcat (cmd, MESSEPACHAR);

strcat (cmd, “””);

first = false;

}

strcat (info, “””);

strcat (info, colname);

strcat (info, “”:”);

strcat (info, “””);

strcat (info, (char *) returnValue);

strcat (info, “””);

}

strcat (info, “}”);

strcat (cmd, info);

strcat (cmd, “”]}’”);

fp = popen (cmd, “r”);

if (fp == NULL)

{

pclose (fp);

ereport(ERROR,

(errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION),

errmsg(“fail to exec: %s”, cmd)

));

}

return slot;

}

在一个正式实现中可以直接构造Hyperledger的PEER端消息包替代docker的peer调用,可以达到更好的性能与健壮性。

总结

区块链是第一个试图自带信任化和防止篡改的分布式记录系统。它的出现,让大家意识到,除了互联网这样尽力而为的基础设施外,人们还能打造一个彼此信任的基础设施。

区块链技术的出现,让人们对新的应用形态有了更多的想象力,而将区块链与传统数据库开发技术相结合,则让区块链应用开发更加简单。开发者可以直接像过去操作数据库的方式直接操作区块链,降低开发难度的同时,还能对过去已经稳定、成熟的应用系统做应用迁移。使用这种区块链 数据库的联合解决方案,既加快了区块链应用的实施速度,也有效保护过去的程序资产,避免了重复造轮子的尴尬。

作者:Jun Tung