提到区块链科技,人们第一时间会想到比特币,以及这些年来比特币不断上涨的价格。但比特币并不代表区块链技术。它只是第一个提出区块链技术的数字货币。
其实区块链技术最大的贡献就是给人们提供了一个去中心化的思路,让人们看到在不可信的网络环境下,仍然可以保证数据的正确,系统也可以达到无法阻止和防止屏蔽的效果。
现在市场上很多开发者都想基于区块链技术构建新的应用系统,但仅限于诞生时间不长的区块链技术,暂时还没有被广大开发者所熟知。所以普通开发者对于如何操作区块链的数据,如何用它来设计数据结构,如何开发应用都有技术问题,这些都是困扰区块链开发者的问题。
结合本人多年在数据库内核研发领域的实践,作者基于业界一些开源技术,使用区块链底层作为存储,结合上层的SQL解析部分,使得应用开发者可以像传统数据库一样使用区块链技术,直接使用SQL命令操作区块链,应用的数据结构设计可以继续沿用过去成熟的范式设计。
这种方式一方面可以最大程度的降低现有开发者的学习成本;另一方面,它可以有机会将一些现有的应用程序迁移到区块链平台,从而有效地利用区块链技术的开放性、透明性和不可否认性。
过去人们在构建大型、重要的应用系统时,考虑到公网上的信息和通信容易受到恶意攻击,大多数通信网络都是在相对封闭的网络环境中选择和设计的。然而,封闭的网络环境往往使应用系统向中心化方向发展。
但是应用系统集中化并不适合一些特殊的应用场景,比如跨境交易场景。如果这种场景采用集中式的构建方式,就需要在多个跨界系统中构建一套存储系统。在交易的过程中,各个系统按照一些约定的规则处理数据,并且为了防止各个系统的数据不一致,需要定期检查各个系统的数据,如果发现有不一致的地方,就会回滚相应的数据。这种集中式的构建方式会给系统运行和数据验证带来很多困难。
区块链技术是一种在不受信任的网络环境中支持去中心化的技术。它可以通过数字签名的方式保证链上运行的应用系统通信网络的安全性,采用哈希链技术保证写入的数据不可更改。过去受限于需要采用信任网络的技术问题,被区块链技术解决了,使人们从更符合业务场景的现实出发,审视在规划应用系统时,是否应该继续采用集中式的模式进行建设。
区块链技术经过短暂的发展,人们已经意识到银行征信、跨境交易、物联网IOT、全球专利注册等业务场景。更适合分散式区块链技术的设计和开发。
在目前的数据库行业中,计算和存储分离的架构是未来的主流方向。作为社区贡献者,笔者参与开发的SequoiaBC也采用了计算与存储分离的架构,以底层区块链作为标准K/V存储,辅以上层SQL解析层,在完全兼容SQL、JDBC、ODBC等标准接口的前提下,有效利用底层区块链存储的所有优秀特性。
在SequoiaBC的整体架构中,主要有三个部分,即
SQL引擎。目前支持MySQL和PostgreSQL两大主流开源SQL引擎。该模块主要为应用提供SQL服务,检查SQL语法命令;SQL适配器,它将SQL命令转换成op红杉BC整体架构图如下。
?
图1
红杉aBC首创了SQL引擎和区块链存储层的分离,使面向应用的SQL引擎和存储层的区块链产品都成为插件模块,开发者可以根据开发环境的需要随时更换不同的产品进行开发和使用。
笔者将以PostgreSQL Hyperledger fabric为例,向开发者展示如何通过PostgreSQL直接操作区块链的数据。
用户在使用Hyperledger fabric时,有两点需要用户注意
Hyperledger fabric区块链使用“通道”——通道作为数据通信的单位。信道是区块链的“私有信道”概念,只有加入了这个信道的节点才能从chaincode读取和修改数据;Hyperledger fabric的“智能合约”——链码基于渠道。当用户安装SequoiaBC SQL Adapter for 尚力财经小编2022 PostgreSQL时,首先需要将sequoia BC的配置文件sbc_fabric—1.0.sql和sbc_fabric.control复制到PostgreSQL的安装目录中。
比如PostgreSQL的安装路径为/usr/local/pgsql,用户需要将相关配置文件复制到/usr/local/pgsql/share/extension/directory
cpsbc _ 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/pg SQL/lib;完成上述步骤后尚力财经小编2022,开发人员成功安装了SQL Adapter operating Hyperledger fabric for PostgreSQL。
在Hyperledger fabric的部署步骤中,其中一个重要的步骤就是安装“智能合约”——区块链的链码。“智能合同”是Hyperledger fabric区块链描述业务逻辑的特定代码。开发者可以根据自己的业务需求编写不同的“智能合约”代码,实现相应的业务逻辑。
SequoiaBC为开发者提供了符合SQL Adapter规范的链码。以下命令为Hyperledger fabric安装名为mycc的chaincode。
对等链代码install-n mycc-v 1.0-p github.com/hyperledger/fabric/链代码/go/sequoia BC
假设在Hyperledger fabric区块链中已经有两个名为product和bill的通道,链代码的名称分别为product_cc和bill_cc。然后用户在PostgreSQL中创建名为product和bill的表的命令是
创建外表product (id int,name text,price int,destext)server SBC _ fabric _ SVR options(渠道名' product ',链代号' product _ cc ');
创建外表
创建外表bill(id int,product_id int,amount int)服务器sbc_fabric_svr选项(channelname 'bill ',chain codename ' bill _ cc ');
创建外部表
用户在SequoiaBC中将4条记录写入产品“channel”。
插入产品值(1,'苹果',10,'苹果');
insert 0 1
insert into product values(2,'香蕉',3,'香蕉');
insert 0 1
insert into product values(3,'橙色',2,'橙色');
insert 0 1
insert into产品值(4,' pear ',7,' pear ');
INSERT 0 1
用户通过SequoiaBC获得产品“渠道”的所有记录。
select * from product;
id |?名字?| price | des
—-————-——
1 |苹果?|?马鞭马鞭10 |苹果
2 |香蕉|?马鞭马鞭马鞭3 |香蕉
3 |橘子|?马鞭马鞭马鞭2 |橙
4 |梨?马鞭|?马鞭马鞭马鞭7 | Pear
(4行)
用户在SequoiaBC中向bill的“频道”写入3条记录。
插入账单值(1,1,20);
INSERT 0 1
INSERT into bill values(2,1,3);
INSERT 0 1
INSERT into bill values(3,4,15);
插入0 1
用户可以通过红杉字母表从比尔"通道"中获取数据
select * from bill;
id | product _ id | amount
—-———— ———
1 |??1 |?20
2 |??1 |?3
3 |??4 |?第15
(3行)
用户可以通过红杉字母表对产品"通道"里的数据进行条件过滤
select id,name,price from product where price 5;
id |名称?|价格
—- ——- ——-
1 |苹果|?10
4 |梨?|?7
(2行)
用户可以通过红杉字母表对结果和账单两个"通道"数据进行关联查询
选择产品。id为product _ id,bill.id为bill_id,product.name为名称,product.price为价格,bill。作为帐单上的帐单内部联接产品的金额。product _ id=产品。id;
产品标识|账单标识|名称?|价格|金额
———— —————-——-———
1 |?1 |苹果|?10 |?20
1 |?2 |苹果|?10 |?3
4 |?3 |梨?|?7 |?第15
(3行)
在宜在家长指导下观看的总账的体系中,总账的智能合约需要以走语言的方式进行实现。而在其他例如以太坊等公链上则可以用固态实现类似同样的逻辑
例如,在超级分类帐中一个插入操作可以用如下代码简单实现.func(t * SimpleChaincode)插入(存根垫片.ChaincodeStubInterface,args []string) pb .Response {
var name,info string
//var缓冲区字节buffer
var err error
var marbleJSON map[string]interface { }
if len(args)!=2 {
返回垫片。错误("参数数量不正确。应为2 "
}
name=args[0]
info?=args[1]
valbytes,err :=stub .GetState(name)
if err!=nil {
返回填充符错误(“获取状态失败" "
}
if valbytes!=nil {
errInfo :=fmt .Sprintf("%s已经存在",名称)
返回垫片.error(errInfo)
}
if err:=JSON .解组([]byte (info),marble JSON);呃!=nil {
返回填充符。错误(错误error())
}
marbleJSON[' type ']=" fdw "
marbleJSONasBytes,err :=json .Marshal(marbleJSON)
if err!=nil {
返回填充符。错误(错误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
标签: 呈