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

区块链技术巴比特2018-07-31 21:16:04  阅读 -评论 0

前言

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

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

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

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

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

应用方向

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

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

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

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

技术实现

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

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

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

SequoiaBC整体架构图如下。

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

图 1

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

SequoiaBC操作区块链实践

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

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

Hyperledger fabric 区块链是以 “通道”–channel为单位进行数据通信,channel是区块链的“私有通道”概念,只有加入了该channel的节点才可以从chaincode中读取和修改数据; 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

声明:链世界登载此文仅出于分享区块链知识,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不构成投资建议。投资者据此操作,风险自担。此文如侵犯到您的合法权益,请联系我们100@7234.cn

    参与讨论 (0 人参与讨论)

    相关推荐

    区块链投资趋势报告:巨头入场布局行业趋于成熟

    区块链投资趋势报告:巨头入场布局行业趋于成熟

    来自:https://mp.weixin.qq.com/s?__biz=MzI4NzIxOTY1NA==&mid=2650632639&idx=1&sn=e6d1c29731d992a80410aaee82ec3ea6&chksm=f3d8db16c4af520097e4a64a71b1d4743ac326b9f027

    重新发明货币

    重新发明货币

    一、货币的演化过程 先简单回顾一下人类货币的演化过程,大概有以下阶段: a. 1.0版本:自然货币(贝壳、牲口、金银……) 这个阶段,货币基于一般等价物的稀有性或者实用性,货币不可能出现人为操纵的超发。 b. 2.0版本:早期纸币、银票到本位纸币 当贸易量越来越大,实物货币太不方便了,而且大家发现其实并不在意货币本身有什么价值,在意的只是这么多的货币能不能交换到足够的物品,于是纸币这种信用货

    从比特币交易看欧洲央行虚拟货币分类

    从比特币交易看欧洲央行虚拟货币分类

      互联网对传统社会的颠覆从未停止,在其完成对信息流、商流、物流、资金流的初步改造之后,或将以虚拟货币的形式打破现有货币体系   4月18日,在中国极客张沈鹏创办的比特币交易平台(42BTC.com)上,比特币对人民币的平均交易价为576元。当天,该平台完成了100个比特币的交易量。仅仅过去一周,4月25日上午,比特币对人民币的平均交易价已达到906元。据42BTC网站统计:在过去的32个月

    欧洲央行-比特币报告

    3.1 比特币 3.1.1 基本特征          比特币可能是最成功的,也可能是最有争议的虚拟货币方案,由日本程序员中本聪(译者注:事实上,中本聪是不是日本人,甚至是不是单个人无从考证)在2009年设计并实现。该计划基于一个类似于BitTorrent的P2P网络。BitTorrent是互联网上著名的共享文件协议,应用在电影,游戏和音乐领域。比特币在全球层面上运作,可用于各类货币交易(虚

    彻底玩转比特币地址和私匙

    彻底玩转比特币地址和私匙

    比特币地址和私匙是所有比特币初学者面对的一大难题,再加上那一串超长的字符串,让人更是摸不到头脑。 现在编者以问答的形式,带你一步步的揭开比特币地址和私匙的面纱。 还不知道什么是比特币地址和私匙的同学请点这里 问题一、比特币钱包由什么组成? 答 我们知道,比特币地址和私匙组成了比特币钱包,而私匙则决定了比特币地址上比特币的归属。 地址和私匙 问题二、如果只记得私匙我们还能还原比特币地址么? 答

    用GO语言实现比特币算法

    用GO语言实现比特币算法

    本节的这个例子展示一点点高精度数学包math/big、一点点散列包hash、一点点加密包crypto,还有一点点测试包testing的知识。这里不介绍bitcoin协议和算法——尽管它们很有趣,而是试图指出,Go对多种操作系统的支持,是实现这种跨平台应用的理想语言。 位钱(bitcoin)是一种使用加密手段制作的分布式电子货币。它最初于1998年由Wei Dai提出,并由中本聪(Satoshi

    详解比特币的找零机制

    详解比特币的找零机制

    比特币的找零机制一直让人有些迷惑,明明只向一个地址发送了比特币为什么 blockchain 上面的显示的有时是1个地址对多个地址,有时是多个地址对1个地址,有时又显示多个地址对多个地址? 为什么比特币资深用户要提醒大家当比特币钱包交易100次以上时再次交易后要重新备份钱包,恢复以前的钱包备份有可能会遭遇损失? 是的,这一切都是因为比特币的找零(Change)机制。本文参考 Bitcoin的维

    玩转比特币客户端之一:C盘转移和加速下载

    玩转比特币客户端之一:C盘转移和加速下载

    C盘空间不足?交易数据下载速度太慢?别着急,乐享比特币教你轻松玩转比特币官方客户端。 所有新人开始接触比特币时做的第一件事情大多数是安装比特币的官方客户端。 安全起见大家最好直接访问官方发布渠道sourceforge的地址进行下载:http://sourceforge.net/projects/bitcoin/files/Bitcoin/ 该网页列出了各版本的官方比特币客户端,目前

    麦妖榜
    更新日期 2019-06-19
    排名用户贡献值
    1BitettFan24007
    2等待的宿命23809
    3六叶树20309
    4区块大康18727
    5牛市来了16781
    6天下无双16192
    7linjm122716073
    8lizhen00215114
    9让时间淡忘14475
    10冷风大q11188
    返回顶部 ↑