精华内容
下载资源
问答
  • 上篇说到了部署智能合约,可以部署可以调用,但是现阶段官方没有提供查询FunctionCode返回值的方法,不过不要紧,AntShares是个不错的开源区块链项目,要自己加入获取FunctionCode结果值的方法不难。改开源项目不难...

    上篇说到了部署智能合约,可以部署可以调用,但是现阶段官方没有提供查询FunctionCode返回值的方法,不过不要紧,AntShares是个不错的开源区块链项目,要自己加入获取FunctionCode结果值的方法不难。改开源项目不难,但是改了之后还要兼容以后的升级,那就有点麻烦,所以我这篇文章是尽量最小程度修改AntShares项目,读者愿意大改也可以。

    本文修改的重点在于AntShares.dll,项目地址:https://github.com/AntShares/AntShares。本文的基本原理:智能合约的Storage.Get()执行会触发StateMachine.cs的private bool Storage_Get(ExecutionEngine engine) ,Storage.Get()会触发StateMachine.cs的private bool Storage_Put(ExecutionEngine engine) 。我的思路是,当智能合约调用Get方法时,就把Get方法的入参作为拦截对象,在AntShares.dll里面监听。所以,在写智能合约时故意使用Get变相作为智能合约往外传值(读者有兴趣的话,自己研究一下使用Put方法来拦截也可以,比Get方法修改量稍微多一点)。

    智能合约调用的流程重点关注LevelDBBlockchain.cs这个源文件,其中以下代码是重点之一,我稍微改过一丢点:

                        case TransactionType.InvocationTransaction:
                            {
                                InvocationTransaction itx = (InvocationTransaction)tx;
                                CachedScriptTable script_table = new CachedScriptTable(contracts);
                                StateMachine service = new StateMachine(accounts, validators, assets, contracts, storages);
                                ApplicationEngine engine = new ApplicationEngine(itx, script_table, service, itx.Gas);
                                engine.LoadScript(itx.Script, false);
                                if (engine.Execute() == true)
                                {
                                    //MySocket.send("log:engine.Execute()-->true");
                                    service.Commit();
                                }
                                else
                                {
                                    MySocket.send("log:engine.Execute()-->false");
                                }
                            }
                            break;

    大概的用法是当执行调用合约时,先执行Script,再写入leveldb一些Script指定的数据,可以是系统本身所需要的数据和用户使用Put方法想要存储的数据,这顺序很重要,因为使用Get()获取刚刚Put进去的数据会出错。

    接下来说说加入了哪些代码。1、在antshares新增SocketClient.cs,用于把数据通过TCP传到本机的其他软件系统,也可以用来打log,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;
    
    namespace AntShares
    {
        class MySocket
        {
            static SocketClient clientSocket;
            static public void send(String msg)
            {
                if (clientSocket == null) {
                    clientSocket = new SocketClient();
                    clientSocket.connect();
                }
                String newMsg = msg + "\r\n";
                clientSocket.send(newMsg);
            }
        }
        class SocketClient
        {
            Socket clientSocket = null;
            int port = 2017;
    
            /// <summary>
            /// 作为客户端,只主动连接指定端口的TCP Server
            /// </summary>
            public void connect()
            {
                IPAddress ip = IPAddress.Parse("127.0.0.1");
                if (clientSocket == null)
                    clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                try
                {
                    clientSocket.Connect(new IPEndPoint(ip, port));
                }
                catch{}
            }
    
            public Boolean isConnected()
            {
                if (clientSocket != null)
                    return clientSocket.Connected;
                return false;
            }
    
            public void send(String msg)
            {
                if (isConnected() == false)
                    connect();
                try
                {
                    clientSocket.Send(Encoding.UTF8.GetBytes(msg));
                }
                catch { }
            }
    
            public void close()
            {
                try
                {
                    clientSocket.Shutdown(SocketShutdown.Both);
                    //clientSocket.Close();
                }
                catch { }
            }
        }
    }
    

    PS:智能合约在VM上跑本来就是为了安全地黑盒里运行,这回突破了黑盒一点点,理应智能合约传数据到本机其他业务系统。

    2、修改StateMachine.cs。智能合约调用Storage.Get()方法触发private bool Storage_Get(ExecutionEngine engine),我们只讲对private bool Storage_Get(ExecutionEngine engine)的修改,对result=”的Storage.Get()入参进行捕获

            private bool Storage_Get(ExecutionEngine engine)
            {
                MySocket.send("log:Storage_Get...........");//纯粹打日志
                StorageContext context = (StorageContext)(byte)engine.EvaluationStack.Pop().GetBigInteger();
                UInt160 script_hash = CheckStorageContext(engine, context);
                if (script_hash == null) return false;
                byte[] key = engine.EvaluationStack.Pop().GetByteArray();
                StorageItem item = storages.TryGet(new StorageKey
                {
                    ScriptHash = script_hash,
                    Key = key
                });
                engine.EvaluationStack.Push(item?.Value ?? new byte[0]);
    
                string key1 = System.Text.Encoding.UTF8.GetString(key);
                if (key1.IndexOf("result=") == 0)//判断是否FunctionCode函数的返回值,对"result="监视
                {
                    key1 = key1.Remove(0, "result=".Length);
                    MySocket.send("FunctionCode Result--->" +key1);
                }
                return true;
            }


    3、接下来贴出智能合约的源码,更多智能合约的代码看项目主页

    using AntShares.SmartContract.Framework;
    using AntShares.SmartContract.Framework.Services.AntShares;
    
    namespace AntShares.SmartContract
    {
        public class HelloWorld : FunctionCode
        {
            public static void Main()
            {
                //修改AntShares.dll,通过监听get方法来获得FunctionCode的返回结果
                string text = "result={\"jsonrpc\":\"2.0\",\"i\":1}";
                Storage.Get(StorageContext.Current, text);
            }
    
        }
    }
    

    智能合约使用“result=”作为监视标记,在private bool Storage_Get(ExecutionEngine engine)捕获到“result=”就把后面的json通过TCP发出去。通过TCP工具(作为本机外部系统角色)可以收到智能合约主动发出的数据:




    展开全文
  • 最近陆续体验常见的区块链开源项目,例如小蚁OnChain出的AntSharesAntShares跟其他开源区块链项目不一样,他们家是使用C#开发,基于.NET Core运行在Linux,期待未来出Go语言版.... 接下来会详细讲解如何部署...
     最近陆续体验常见的区块链开源项目,例如小蚁OnChain出的AntShares。AntShares跟其他开源区块链项目不一样,他们家是使用C#开发,基于.NET Core运行在Linux,期待未来出Go语言版....

    接下来会详细讲解如何部署AntShares和搭建私有链,本文使用virtualbox + ubuntu16.04 + AntSharesCore v1.4.,参考了官方文档

    第一步,安装.net core,如果提示安装失败,则多刷“sudo apt-get update”几次,详见官方安装指导
    sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
    sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893
    sudo apt-get update
    sudo apt-get install dotnet-dev-1.0.4


    验证.net core是否安装成功,跑一下helloworld:

    dotnet new console -o hwapp
    cd hwapp
    dotnet restore
    dotnet run


    第二步,节点部署

    先下载并解压缩AntSharesCore(区块链客户端同时也是服务器端)

    wget https://github.com/AntShares/AntSharesCore/releases/download/v1.4.5/AntSharesCore-CLI-v1.4.5.zip
    unzip  AntSharesCore-CLI-v1.4.5.zip


    运行AntSharesDaemon.dll 去初始化。

    dotnet AntSharesDaemon.dll activates one bookkeeping node
    dotnet AntSharesDaemon.dll /rpc activates one bookkeeping node with rpc server

    第三步,准备好4个节点和4个钱包文件
    通过  AntSharesCore-GUI-v1.4.6291.25936.zip  生成4个钱包对应4台服务器,强烈建议断网运行这个GUI程序,不然会强制更新到最新的开发版(最新开发版有bug)
    钱包1:1.db3
    地址:AV1FjFdThXd6UeWPYzM2dmMwnJ79bdZxX1
    公钥:03f1d8df48cac340eaaf9ad5dfadac75fb45e2a48ba3c6c63721b340826f3daa18
    私钥WIF:L2D1orkQ8s1Ldg1XAQFJC82QcvbamVpex5D9MDDZvYgTjk64qgmE

    钱包2:2.db3
    地址:AWKxBoutR9VYKm1KhNvSTD5AhbSkDHC1A3
    公钥:0313f7d3d34b95d3dcf016d23ad4e22f2b6253dfafc54971cd55f678170f40a735
    私钥WIF:KyBv7S411MpSNQfcLqroxLFnQPdQvfjHsHcfGrkDyEVSr1hQjoch

    钱包3:3.db3
    地址:AYehAbETXbCRC2Hg4Wvy4ns9WcMbmZwYsU
    公钥:03cb28efdb867960536aec1d9ba395bbf639888062d6186863756425c741741608
    私钥WIF:L4Pe8boDac3Du93pRztcfoecy6S8hokk6nXjXtyttNNBfARWYbAk

    钱包4:4.db3
    地址:AJvkZbK9qK3uBxQrs56kx19GLuhtoxMDPG
    公钥:03a26ef67f370d618c76859723f0c987133bc4d2236c7824e0938a52b6e7d6a6e5
    私钥WIF:KxtYtdWh6qbwtGqAEMjhiMfM8Uop3bYvaTTo2JpfoPDBXKypazYp


    以上4个钱包文件都存放在一起,后面会把当前虚拟机复制3份

    第四步,使用virtualbox的“管理”->全局设定->网络->添加新的NAT网络
    复制出3份虚拟机,共4个虚拟机
    修改4个虚拟机的网络设置如下图:


    4个虚拟机运行后IP地址

    1.db3所在服务器的IP:10.0.2.4
    2.db3所在的服务器IP:10.0.2.5
    3.db3所在的服务器IP:10.0.2.6
    4.db3所在的服务器IP:10.0.2.7

    第五步,分别修改4个虚拟机的protocol.Json文件
    1.将节点文件及钱包文件拷贝至4台服务器中,找到配置文件protocol.json(...\AntSharesCore\protocol.json)
    2.更改magic值(Magic): 7630404
    3.更改后备共识节点(StandbyValidators),这里都是节点的公钥
    4.更改种子节点IP信息(SeedList) : 
    {
      "ProtocolConfiguration": {
        "Magic": 7630404,
        "CoinVersion": 23,
        "StandbyMiners": [
          "03f1d8df48cac340eaaf9ad5dfadac75fb45e2a48ba3c6c63721b340826f3daa18",
          "0313f7d3d34b95d3dcf016d23ad4e22f2b6253dfafc54971cd55f678170f40a735",
          "03cb28efdb867960536aec1d9ba395bbf639888062d6186863756425c741741608",
          "03a26ef67f370d618c76859723f0c987133bc4d2236c7824e0938a52b6e7d6a6e5"
        ],
        "SeedList": [
          "10.0.2.4:10333",
          "10.0.2.5:10333",
          "10.0.2.6:10333",
          "10.0.2.7:10333"
        ],
        "SystemFee": {
          "EnrollmentTransaction": 1000,
          "IssueTransaction": 500,
          "PublishTransaction": 500,
          "RegisterTransaction": 10000
        }
      }
    }

    第六步,在四台服务器中分别运行命令开启节点(同时开启rpc服务):
    cd hwapp
    cd AntSharesCore
    dotnet AntSharesDaemon.dll /rpc

    进入ant>模式
    在10.0.2.4的服务器输入
    open wallet /home/hellogv/hwapp/wallets/1.db3
    start consensus

    在10.0.2.5的服务器输入
    open wallet /home/hellogv/hwapp/wallets/2.db3
    start consensus

    在10.0.2.6的服务器输入
    open wallet /home/hellogv/hwapp/wallets/3.db3
    start consensus

    在10.0.2.7的服务器输入

    open wallet /home/hellogv/hwapp/wallets/4.db3
    start consensus


    展开全文
  • AntShares 区块链搭建私有链与部署智能合约

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

    也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

                   

     最近还在继续研究AntShares 区块链,可能是因为用C#实现,所以看起来特别怀旧,毕竟好久也没有写C#了。本文还会讲到搭建私有链,玩了一段时间,发现短期内是不能完全甩开Windows,所以干脆就3个Linux虚拟机(网络连接方式:桥接网卡)+一个Windows机器来搭私有链好了。本文的环境:ubuntu 16.04 ,AntSharesCore-CLI-v1.6.1 ,AntSharesCore-GUI-v1.6.6354.35073 ,net core 1.0.4。

    首先,在ubuntu安装.net core,详见上篇《AntShares区块链的节点部署与搭建私有链

    其次,创建4个钱包文件,用AntSharesCore-GUI来创建:

    钱包1,文件名 1111.db3: 
    公钥:02494f3ff953e45ca4254375187004f17293f90a1aa4b1a89bc07065bc1da521f6
    私钥WIF : Kzo8BkCuamp9LX6KEHQ7c49QNunYX1KqrL8NZxNqy9H77B76tNiF

    系统IP:192.168.0.105,IP自己查系统


    钱包2,文件名 2222.db3:
    0258104bb969fa7c5d82da43cd2c79ab65eea8d5cf659ebedaee4740bb5112b819
    L2yQ6JdFw9zQfWVER95Sgu9qfG6r5T5JkwkJCnHovmAUbxnTJaHa

    系统IP:192.168.0.108,IP自己查系统


    钱包3,文件名 3333.db3:
    03386062735a119574aedecafe3f4643ab0d0f448f24792468457413cb25fe2319
    L3m41zNEHb96cGjYRJb663yDVbEGQ5cV9Ueu13SrKDujsqJyK9oH

    系统IP:192.168.0.109,IP自己查系统


    钱包4,文件名 4444.db3:
    020a2cf0910ca684b1fcb2e4f55b8b2b8024aba5f28b17b8f0bfd8966ab4d1d30a
    L2s6eckoH6j9LTkAzqg7V4mJ6xxJaSPabysqVJPKkxPQyacXvk9F
    系统IP:192.168.0.107,IP自己查系统

    然后,4个节点上的AntSharesCore的procotol.json都修改成以下内容:
    {  "ProtocolConfiguration": {    "Magic": 20170603,    "AddressVersion": 23,    "StandbyValidators": [      "02494f3ff953e45ca4254375187004f17293f90a1aa4b1a89bc07065bc1da521f6",      "0258104bb969fa7c5d82da43cd2c79ab65eea8d5cf659ebedaee4740bb5112b819",      "03386062735a119574aedecafe3f4643ab0d0f448f24792468457413cb25fe2319",      "020a2cf0910ca684b1fcb2e4f55b8b2b8024aba5f28b17b8f0bfd8966ab4d1d30a"    ],    "SeedList": [      "192.168.0.105:10333",      "192.168.0.108:10333",      "192.168.0.109:10333",      "192.168.0.107:10333"    ],    "SystemFee": {      "EnrollmentTransaction": 0,      "IssueTransaction": 0,      "PublishTransaction": 0,      "RegisterTransaction": 0    }  }}


    准备工作结束后,可以开始跑起私有链,ubuntu的3个虚拟机分别执行以下命令,记得开RPC,注意分别修改 1111.db3、2222.db3、3333.db3:
    cd AntSharesCoredotnet AntSharesDaemon.dll /rpcopen wallet 1111.db3start consensus


    打开GUI版 AntSharesCore-GUI-v1.6.6354.35073,在PC版客户端中打开钱包 4444.db3,右键-》创建合约地址-》多放签名,输入 protocol.json 中的4个公钥,设置最小签名数量为3(共识节点数量/2 + 1), 如图所示


    然后,在菜单栏中点击“钱包”重建钱包索引, 4个节点运行结果如下图:


    接下来,讲解如何部署智能合约。
    第一步,菜单栏--高级--Deploy Contract

    第二步,把智能合约load进去,Information那部分随便填,区块链的“交易”可以是发布智能合约,私有链这里零花费直接交易。


    第三步,获取交易编号,TXID = b25f28d590d58b8e287d343afadc69b2029f55359f15d5b4b630971b42c3d0f3 


    拿着这个TXID可以通过第三方的post工具来使用AntShares的RPC服务,这里使用getrawtransaction 方法
    (根据指定的散列值,返回对应的交易信息),使用方法详见(http://docs.antshares.org/document/node/api/getrawtransaction.html),查看交易的详情,192.168.0.108是Linux虚拟机IP,10332是Http的RPC端口:


    部署智能合约没问题,接下来要研究一下如何查询某个智能合约执行的结果。

               

    给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

    这里写图片描述
    展开全文
  • 深入浅出区块链

    千次阅读 2018-04-12 10:44:17
    内容简介 2017年,是区块链爆发又冷静的一年。 如果你持续关注过区块链技术,这一年可能已经对没完没了的概念介绍、前景描绘、行业探讨和链圈新闻产生了审美疲劳。没错,区块链必须与行业紧密结合,它也有颠覆人类...

    内容简介

    2017年,是区块链爆发又冷静的一年。

    如果你持续关注过区块链技术,这一年可能已经对没完没了的概念介绍、前景描绘、行业探讨和链圈新闻产生了审美疲劳。没错,区块链必须与行业紧密结合,它也有颠覆人类协作方式之洪荒巨力,但是说到底它还是一个技术活,是要写代码的,在咖啡厅里整天坐而论道是造不出金链子来的。

    本期我们梳理了2017年区块链发展现状,从关键技术原理与实际应用出发,带你深入浅出探索区块链技术的方方面面。

    本书内容

    最小可行性区块链原理解析

    文/ Ilya Grigorik

    加密货币,特别是比特币,几乎从各个方面都得到了大量关注:规则、管理、税务、技术、产品创新等等,不胜枚举。“点对点(去中心化)电子现金系统”的概念颠覆了我们以前对货币和金融所持有的设想。

    图1

    图1

    即便如此,把数字货币方面搁到一边,还有一个可以说是更有趣更深远的创新,即底层的区块链技术。无论你对比特币或是它的山寨币衍生品有什么看法,作为一种货币和价值存储手段,它们背后的运作基础都来自于中本聪概括的区块链原理:

    我们运用点对点网络提出了重复花费问题的解决方案。网络通过将交易散列到一个进行中的基于散列的工作量证明链,来对交易进行时间戳标记,并形成一个记录,这个记录只有在重做工作量证明的情况下才能被改变。最长的链不仅作为它所见证事件发生时序的证据,而且也证明它来自最大的 CPU 功率池……网络本身要求架构最小化。

    区块链对任何“货币”都是不可知的。事实上,它可以适用于促成很多其他使用案例。因此,理解“最小可行区块链”背后的方法和原理是有好处的:

    以下将从头开始解释为什么需要特定的部分(数字签名、工作量证明、交易区块),以及它们如何集合起来形成具有卓越性能的“最小可行区块链”。

    用三式记账法保障交易安全

    Alice 和 Bob 是集邮爱好者,偶尔会做做交易。如果双方都看到喜欢的东西,可以当场协商完成交换。换言之,这是个简单的以物易物的系统。

    有一天 Bob 拿来一枚邮票,Alice 觉得她必须要收藏,但问题是 Bob 对 Alice 所提供的交换物不是特别感兴趣。Alice 沮丧不已,她继续和 Bob 协商,最后达成一致:他们做个单方交易,Bob 先把邮票给 Alice,Alice 承诺以后再偿还 Bob。

    Bob 和 Alice 已经认识有一阵子了, 但是为了确保两个人都信守承诺(主要是 Alice),他们同意让朋友 Chuck 来对交易“进行公证”。

    图2

    图2

    他们把图2这个可以表明 Bob 给了 Alice 一枚“红色邮票”的交易收据做了三个副本(三方各持一份)。Bob 和 Alice 可以用收据来记录他们的交易, Chuck 存储副本作为交易证据。这个设定很简单,但其中有一些很重要的属性:

    1. Chuck 可以鉴定 Alice 和 Bob 两个人的真实性,以确保不会有人在他们不知情的情况下蓄意伪造交易。
    2. Chuck 账簿中的收据证明了交易发生。如果 Alice 声称交易从未发生,那么 Bob 可以去找 Chuck,用他的收据来证明 Alice 说谎。
    3. 如果 Chuck 的账簿中没有收据,就证明交易未发生过。Alice 和 Bob 都不能伪造交易。他们可以伪造交易收据,声称对方说谎,但同样的,他们可以去找 Chuck,查看他的账簿。
    4. Alice 和 Bob 都不能篡改当前的交易。如果任意一方篡改了交易,他们可以去 Chuck 那儿,用储存在 Chuck 账簿中的副本核实他们的副本。

    以上操作就是“三式记账法”,操作简便,对参与双方都能提供很好的保障。但你也看到了它的缺点,对吧?我们对中间人寄予了很大的信任。如果 Chuck 决定和另一方串通,那么整个系统就土崩瓦解了。

    用公钥基础设施(PKI)保障交易安全

    Bob 不满于使用“可靠中间人”的不安全性,他决定研究一下,发现公钥密码可以免去使用中间人的需要!这里解释一下:

    公钥密码,也叫做不对称密码,指的是一种密码算法,它需要两个单独的钥匙,一个是秘密的(私有的),另一个是公共的。尽管这个钥匙对应的两部分不同,但有数学联系。公钥用于对纯文本加密或者查验数字签名;私钥用于解密密码文本或者创建数字签名。

    运用第三方(Chuck)的原本意图是要确认有三个属性:

    1. 验证真实性:不能有恶意的一方伪装成其他人。
    2. 不可否认性:事实发生后,参与方不能声称交易没有发生过。
    3. 完整性:事实发生后,不能再修改交易收据。


    结果是,公钥密码可以满足以上所有要求。简单地说,工作流程如图3所示。

    图3

    1. Alice 和 Bob 分别生成一个固定的公钥-私钥对。
    2. Alice 和 Bob 公布出他们的公钥。
    3. Alice 以纯文本的形式写一个交易收据。
    4. Alice 用她的私钥对交易信息的纯文本进行加密。
    5. Alice 在密码文本上添加一个“由……签名”的纯文本备注。
    6. Alice 和 Bob 都储存相应的输出结果。

    注意只有在多方参与的时候才需要第五步:如果你不知道是谁签署了信息,就不知道该用谁的公钥来解密,这个问题很快就会变得有关紧要。

    这看起来像是没什么特别理由的大量工作,但我们还是来检验一下新收据的属性:

    • Bob 不知道 Alice 的私钥,但问题不大,因为他可以查询她的公钥(公钥是全世界共享的),然后用公钥来解密交易的密码文本。
    • Alice 并不是真的在给交易内容“加密”,而是通过使用她的私钥给她“签名”的交易编码:任何人都可以用她的公钥对密码文本进行解密,由于她是唯一拥有私钥的人,这个机制保证了只有她能生成交易的秘密文本。

    Bob 或针对这个问题的任何其他人,如何获得 Alice 的公钥?有很多种方法来分发私钥——例如,Alice 公布在她的网站上。我们可以假定有这样的合适的机制。

    因此,使用公钥基础设施(PKI)可以满足我们之前所有的要求:

    • Bob 可以用 Alice 的公钥通过解密密码文本来证明签名交易的真实性。
    • 只有 Alice 知道她的私钥,因此 Alice 不能否认交易的发生——她已经签名了。
    • 没有 Alice 的私钥,Bob 或任何其他人都不能伪造或修改交易。

    • 注意第二条,Alice 可以否认她是那个有争议的公钥——私钥对的真正所有者。
    • Alice 和 Bob 只储存了签名交易的副本,消除了对中间人的需要。“神奇”的公钥密码和双方以物易物系统完美匹配。

    余额 = Σ(收据)

    随着公钥基础设施到位,Bob 和 Alice 又完成了一些交易:Alice 从 Bob 处得到另一张邮票,Bob 从 Alice 那儿也挑了一张邮票。它们都按照与之前相同的步骤,生成签名交易并将它们附加到各自的分类账簿中。

    图4

    记录是安全的,但有一个小问题:不清楚是否任何一方有未结余额。先前只有一个交易,很清楚是谁欠谁的(Alice 欠 Bob)以及欠了多少(一枚红色邮票),但是有多个交易以后,情况变得模糊起来。所有的邮票都是等值的吗?如果是,那么 Alice 有一个负余额。如果不是,那就谁也说不准了!为了解决这个问题,Alice 和 Bob 达成一致如下:

    1. 黄色邮票的价值是红色邮票的两倍。
    2. 蓝色邮票和红色邮票等值。

    最后为了确保他们新协议的安全性,他们用交易的相对值更新了每个交易,重新生成了分类账簿。新的账簿看起来像图5那样。

    图5

    图5

    这样,计算最终余额现在变成了一个简单的事,循环访问所有的交易,将适当的借贷记录应用于各方。最终结果是 Alice 欠 Bob 2个“价值单位”。什么是“价值单位”? 它是由 Alice 和 Bob 都同意的任意交换媒介,另外,由于“价值单位”并不耳熟能详,Alice 和 Bob 同意将1个价值单位称为1个 chroma(复数形式:chroms)。

    上面这些看起来都是小事,但每一个参与者的余额都是分类账簿中所有收据的一个函数这一事实有重要的意义:任何人都可以计算大家的余额。不需要任何可靠的中间人,也不必对系统进行审计。任何人都可以遍历整个分类账簿,核实交易,计算出每一方的未结余额。

    多方转移和验证

    接下来,Bob 无意中发现 John 有一枚邮票,他实在很喜欢。他告诉 John 他和 Alice 在使用的安全分类账簿,并问他是否愿意做个交易,Bob 把 Alice 欠他的余额作为支付手段转移给 John——即 Bob 从 John 那儿获得邮票,Alice 之前欠 Bob 的金额将变成她欠 John 的。John 同意了,但现在他们有个问题:Bob 如何能以安全和可验证的方式把他的余额“转移”给 John?经过一番协商,他们想出一个巧妙的计划(如图6所示)。

    图6

    图6

    Bob 按照与之前相同的步骤创建了一个新交易,不过他先计算出他想要转移的加密交易的 SHA-256 校验和(一个唯一的指纹),然后将校验和嵌入新收据中“是什么”一栏。事实上,他在将之前与 Alice 的交易与新的转移收据链接起来,这样就把它的价值转移给了 John。

    为了保持事物的简单性,我们假定所有的转移都会“消费掉”被转移交易的全部价值。要把这个系统扩展到使部分转移成为可能并不难,但此时没有必要考虑得那么复杂。

    随着新交易到位,John 为了安全起见,做了一个加密分类账簿的副本(现在有三个副本)并运行了一些检查来验证它的完整性:

    1. John 提取了 Alice 和 Bob 的公钥,验证前三个交易的真实性。
    2. John 证实了 Bob 转移的是一个“有效”交易:
      • 待转移交易的地址是 Bob。
      • Bob 此前没有把这个交易转移给任何其他人。

    如果所有检查都通过了,他们就完成交易,我们可以通过遍历分类账簿来计算新的余额:Bob 有一个净零数余额,Alice 有2个 chroma 的借额,John 有2个 chroma 的贷额(由 Alice 提供)。这样 John 现在就可以把他的新分类账簿拿给 Alice 并要求她支付,即使 Alice 没有出席交易,也没有问题:

    1. Alice 可以用 Bob 的公钥核实新转移交易的签名。
    2. Alice 可以核实转移的交易是对她和 Bob 一个有效交易的引用。

    以上转移和验证过程是系统一个了不起的属性!注意要让它全部能工作,我们需要两个使能技术:一个是公钥基础设施的运用,使数字签名验证成为可能;另一个是收据账簿,使我们能够查看完整的交易记录以验证余额并链接先前的交易来进行转移。

    John 和 Bob 对这个巧妙的解决办法很满意,然后两人分头回家:Bob 带着新邮票,John 有了新的分类账簿。表面上看一切完美,但是他们刚刚把自己暴露在了一个极具挑战性的安全问题之下……你发现了吗?

    重复消费和分布式一致性

    在与 John 完成交易后不久,Bob 意识到他们刚刚在他们的系统中引入了一个严重的漏洞,如果他迅速行动,就可以利用这个漏洞:Bob 和 John 都更新了他们的分类账簿来包括新的交易,但是 Alice 和其他任何人都不知道交易已经发生。结果是,没有什么能阻止 Bob 接近网络中的其他人,给他们展示旧的账簿副本,而旧的账簿副本里没有他和 John 的交易!如果 Bob 说服他们进行交易,就像他和 John 做的那样,他就可以“重复消费”同一个交易,想进行多少次都可以!

    图7

    当然,一旦多人拿着新的分类帐簿要求 Alice 支付,欺诈行为将被检测到,但这已经无济于事了——Bob 已经带着战利品跑掉了!

    只有两个参与者的时候,不可能受到双重消费攻击,因为要完成交易,你要验证并同时更新两个分类账簿,因此所有分类账簿始终保持同步。然而当我们再添加另外一个参与者时,我们就引入了各参与者之间账簿不完全和不一致的可能性,这就使双重消费成为可能。

    在计算机科学语言中,双方分类账簿具有“强一致性”,超过两方的分类账簿则需要某种形式的分布式一致性以解决双重消费的问题。

    这个问题最简单的可能的解决方案是要求分类账簿中列出的各方都必须在每个新交易发生时都在场,以便每个人可以同时更新他们的账簿。这个策略对小型的群组有效,但不能扩展到有大量参与者的情况。

    分布式一致性网络的要求

    我们来设想一下,我们想要将分类账簿扩展到全世界所有集邮者,这样任何人都可以用一种安全的方式交易他们喜欢的邮票。显然,由于地理位置,时区和其他限制,要求每个参与者在每个交易登记的时候都在场是不可能实现的。我们能建立一个不需要每个人都在场批准的系统吗?

    1. 地理位置算不上一个真正的问题:我们可以把交流转移到线上。

    2. 时区问题可以通过软件解决,我们不需要每个人手动更新分类账簿。相反,我们可以建立一个软件,它能在每个参与者的计算机上运行并代表他们自动接收、批准以及向分类账簿添加交易。

    事实上,我们可以建立一个点对点(P2P)网络,负责分发新的交易并获得每个人的批准! 但很可惜,说起来容易做起来难。例如,虽然 P2P 网络可以解决我们的地理位置和时区问题,但试想即便只有一个参与者离线,会出现什么情况? 我们是不是要阻止所有交易,直到他们再次上线?

    注意,“如何”构建 P2P 网络本身就是一个庞大的课题,构建这样一个网络的底层机制也远超出我们讨论的范围……我们把它作为一个练习留给读者。

    图8

    原来分布式一致性的问题在计算机科学中已经被深入研究过,并且已经提出了一些有希望成功的解决方案。例如,两阶段提交(2PC)和 Paxos 都使这样一种机制成为可能,即我们只需要参与者的大多数法定人数(50%以上)接受就能安全地提交新的交易:只要大多数人已经接受交易,就能保证群组中剩下的人最终汇合在同一个交易历史。

    即便如此,单单有 2PC 或 Paxos 是不够的。比如,在每天都有新参与者加入而其他人不预先通知就消失的情况下,2PC 或 Paxos 如何知道我们 P2P 集邮者网络中的参与者总数?如果有一个先前的参与者离线,他们是临时还是永久离线? 相似地,还有另一个我们必须考虑的更具挑战性的“Sybil 攻击”:没有办法阻止一个恶意参与者创建许多档案,以在我们的 P2P 网络中获取不公平的投票权份额。

    如果系统中的参与者数量是固定的,并且已经验证他们的身份真实有效(也就是说,这是一个可信网络),那么 2PC 和 Paxos 都会工作得很好。但我们不断变化的集邮者 P2P 网络并不是这样的情况。我们走进死胡同了吗? 嗯,并不尽然……

    这个问题有个明显的解决方案是从问题陈述中消除“分布的”部分。我们可以不建立一个 P2P 分布式系统,而是建立一个所有集邮者的全局注册表,记录他们的帐户信息,对他们进行验证并(尝试)确保没人能通过创建多个身份作弊,最重要的是,保证有一个共享的分类账簿副本!具体来说,我们可以建立一个网站,这些交易在网站上进行,网站将在它的集中式数据库里记录所有的交易,以此确保交易的完整性和正确排序。

    以上是一个实用的解决方案,但我们得承认,它不尽如人意,因为它迫使我们失去了分类账簿系统点对点的性质。它将所有的信任置于一个单一的集中式系统,这就带来了一组全新的问题:什么是系统的正常运行时间,安全性和冗余;谁来维护系统,他们维护系统的动因是什么;谁有管理访问权限等等。集中式带来了它自己的一系列挑战。

    让我们回顾一下在 P2P 设计中遇到的一些问题:

    1. 确保每个参与者始终保持更新状态(强一致性系统)会产生很高的协调成本,影响可用性。如果单个点不可达,整个系统都无法提交新交易。
    2. 在实践中,我们不知道 P2P 网络的全局状态:参与者人数,个体是暂时离线还是决定离开网络等。
    3. 假设我们可以解决上述限制,系统仍然可能受到 Sybil 攻击,恶意用户可以伪造许多身份行使不公平的投票权。

    不幸的是,解决上述所有限制是不可能的,除非我们放松一些要求: CAP 定理告诉我们,我们的分布式系统不能有很强的一致性,可用性和分区容忍性。因此在实践中,我们的 P2P 系统必须在(更)弱一致性的假设下操作并克服它可能带来的影响:

    1. 我们必须接受一些分类账簿不同步(至少是暂时不同步);
    2. 系统最终必须收敛于所有交易的整体序(线性一致性);
    3. 系统必须以可预测的方式解决分类账簿冲突;
    4. 系统必须强制执行全局不变量——例如,没有重复消费;
    5. 系统应该免受 Sybil 和类似的攻击。

    保护网络免受 Sybil 攻击

    在分布式系统中实现一致性,比如通过对每个参与者的投票计数,会出现很多关于各节点“投票权”的问题:允许谁参与,某些节点是否有更多的投票权,是否每个人都平等,以及我们如何强制执行这些规则?

    为了保持简单,我们假定每个人的投票是平等的。第一步,我们可以要求每个参与者用私钥在他们的投票上签名,就像在他们的交易收据上签名一样,并将投票传播到他们的节点上——在投票上签名确保了别人不能代表他们投票。然后我们可以制定一个规则,只允许提交一票。如果同一个钥匙签名了多个投票,那么所有的投票都作废——已经下定决心!到目前为止还好,现在难的部分来了……

    最开始我们怎么知道允许哪个特定的节点参与?如果只需要一个独特的私钥来签名投票,那么恶意用户可以简单地生成无限的新密钥充斥网络。根本问题是,当生成和使用伪造身份很便宜时,任何投票系统都很容易被颠覆。

    为了解决这个问题,我们需要使提交投票的过程变得“昂贵”。提高生成新身份的成本,或者提交投票的过程必须产生足够高的成本。为了让问题更明确,我们来想几个现实世界的例子:

    1. 你在当地政府选举中投票时,会要求你出示身份证件(例如护照),而伪造身份证件的成本很高(希望如此)。理论上,没什么能阻止你生成多个伪造的身份证件,但如果成本足够高(伪造的货币成本,被抓的风险等),那么运行 Sybil 攻击的成本将远大于其收益。
    2. 或者,假设提交投票给你带来了一些其他成本(例如支付费用)。如果成本足够高,那么再次的,运行大规模 Sybil 攻击的障碍也增强了。

    注意,上述例子都不能完全“解决”Sybil 攻击,但它们也不需要被完全解决。只要我们将攻击的成本提高到大于成功破坏系统所能得到的值,那么系统就是安全的,会按照预期运行。

    注意,我们所使用的“安全”的定义是很宽松的。系统仍然会受到操纵,确切的投票计数会受到影响,但关键是恶意参与者不能影响最终的结果。

    参与所要求的工作量证明

    任何用户都可以通过生成新的私钥—公钥对来轻易地(并且花很少的钱)在我们的 P2P 网络中生成新的“身份”。同样,任何用户都可以用他们的私钥签名投票并将其发送到 P2P 网络——这也很便宜,我们的收件箱中大量的垃圾邮件清楚地说明了这一点。 因此,提交新的投票很便宜,恶意用户可以轻易地用尽可能多的投票淹没网络。

    但是,如果将以上其中一个步骤变得昂贵,使你不得不消耗更多的精力、时间或金钱,情况会怎样呢? 这就是工作量证明背后的核心思想:

    1. 工作量证明步骤对于发送者来说应该是“昂贵的”。
    2. 他人验证工作量证明的步骤应该是“便宜的”。

    这样一种方法有很多种可能的执行方式,但是为了达到我们的目的,我们可以再次使用之前遇到的密码散列函数的属性(如图9所示)。

    图9

    图9

    • 很容易计算任何给定消息的散列值。

    • 生成具有给定散列值的消息很昂贵。
我们可以在我们的系统中施加一个新规则,要求每个签名投票必须具有以特定子串开始的散列值,即需要部分散列冲突,比如两个零的前缀。如果这看起来完全是任意的,那是因为它确实是任意的。跟着我的思路,我们通过几个步骤来看看这是如何生效的:

    • 我们假定一个有效的投票陈述是个简单的字符串:"I vote for Bob" (“我投票给 Bob”)。

    • 我们可以用同样的 SHA-256 算法来为我们的投票生成一个散列值。

    sha256("I vote for Bob") → b28bfa35bcd071a321589fb3a95cac...
    • 生成的散列值无效因为它没有以我们要求的两个零子串开头。
    • 我们修改一下投票陈述,附加一个任意字符串再试一下:
    sha256("I vote for Bob - hash attempt #2") → 7305f4c1b1e7...
    • 生成的散列值也不满足我们的条件,我们更新值,一次又一次地尝试…… 155次尝试之后我们最终得到了:
    sha256("I vote for Bob - hash attempt #155") → 008d08b8fe...

    上述工作流程的关键属性是,每次我们修改完输入,加密散列函数(在这种情况下是 SHA-256)的输出是完全不同的:当我们增加计数时,前一次尝试的散列值并不能透露下一次尝试所得到的散列值的任何信息。因此,生成有效投票并不仅仅是个“难的问题”,我们可以把它比喻成彩票,每次新尝试都会给你一个随机的输出。同时我们也可以通过更改所需前缀的长度来调整彩票的赔率:

    • SHA-256 校验和中的每个字符都有16个可能的值: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f.
    • 为了生成有两个零前缀的有效散列,发送者平均需要256 (16^2)次尝试。
    • 将要求变为5个零平均会需要1,000,000 (16^5) 多次尝试……关键是,我们可以轻易提高成本,让发送者找到一个有效散列需要耗费更多 CPU 周期。

    我们可以在一个现代 CPU 上计算多少个 SHA256 校验和?它的成本取决于信息大小,CPU 架构和其他变量。如果你对此感到好奇,可以打开控制台,运行一个基准测试程序: $> openssl speed sha.

    最终结果是,生成有效投票对于发送者来说是“昂贵的”,但对于接收者验证仍然是微不足道的。接收者散列交易(一次运算)并且核实校验和中包含所需的散列冲突前缀……太好了,那么这对我们的 P2P 系统有什么用呢?上述工作证明机制使我们能够调整提交投票的成本,从而使破坏系统的总成本(即假冒足够多的有效投票来确保特定结果)高于攻击系统能够获得的价值。

    注意,“生成消息的高成本”在很多其他环境中是个有用的属性。例如,垃圾邮件能够运作恰恰是因为生成信息特别便宜。如果我们可以提高发送电子邮件的成本,例如要求工作量证明签名,那么我们可以通过使成本高于利润来打破垃圾邮件的商业模式。

    建立最小可行区块链

    我们已经谈到了很多基础内容。在讨论区块链如何帮助我们构建安全的分布式账簿之前,我们来快速地扼要概述一下我们的网络设定,属性和待解决的挑战(如图10所示):

    图10

    图10

    1. Alice 和 Bob 完成交易并记录在各自的分类账簿中。 完成后,Bob 有一个来自 Alice 的受公钥基础设施保障的借据。
    2. Bob 和 John 完成一个交易,他将 Alice 的收据转移给 John。Bob 和 John 都更新了账簿,但是 Alice 对交易尚不知情。
      • 皆大欢喜的情景:John 要求 Alice 偿还他的新借据,然后 Alice 得到 Bob 的公钥,核实了他的交易,如果交易有效,她向 John 支付所需金额。
      • 不太欢乐的情景:Bob 用没有记录他和 John 交易的旧账簿与 Katy 创建了一个重复消费交易,然后 Katy 和 John 同时出现在 Alice 家却发现只有一个人能得到报偿。

    由于分布式账簿的“弱一致性”,重复消费是有可能的:Alice 和 Katy 都不知道 John 和 Bob 之间的交易,这就使 Bob 利用了不一致性为自己谋利。有解决办法吗?如果网络很小,所有参与者都是已知的,那么我们可以要求每个交易在被认定为有效前必须被网络“接受”:

    1. 全体一致:每当交易发生时,双方联系所有其他参与者,告知他们交易的有关内容,等所有参与者“同意”后才能提交交易。因此,所有分类账簿同时更新,不可能发生重复消费。
    2. 法定人数一致:提高网络的处理速度和可用性(即如果有人离线,仍然可以处理交易),我们可以将上述全体一致的情况放宽到法定人数一致(整个网络的50%)。

    对于参与者已知且已核实的小型网络,以上任何一个策略都能立即解决问题。然而,两种策略都不能扩展应用于更大型的动态网络,因为在任何时间点都无法得知参与者的总数和他们的身份:

    1. 我们不知道要联系多少人来获得他们的同意。
    2. 我们不知道要联系谁来获得他们的同意。
    3. 我们不知道在与谁通话。

    注意我们可以用任意通信手段来满足上述工作流程:当面,通过网络,信鸽通讯等等!

    由于缺乏网络参与者的身份和对他们的全局认识,我们必须要放宽限制。虽然我们不能保证任意特定交易都有效,那并不能阻止我们对接受交易有效的可能性做出陈述:

    1. 零确认交易:我们可以在不联系任何其他参与者的情况下接受交易。这是对交易付款方诚信的完全信任——相信他们不会重复消费。
    2. N 确认交易:我们可以联系网络中(已知)参与者的一部分子集,让他们验证我们的交易。 我们联系的节点越多,抓住企图欺诈我们的恶意方的可能性越大。

    “N”的值多大为好?答案取决于要转移的金额以及你与对方的信任度和关系。如果金额很小,你可能愿意接受更高的风险级别,或者你会根据对另一方的了解程度来调整风险容忍度。或者,你会做些额外的工作,联系其他参与者验证你的交易。在任一情况下,处理交易速度(零确认是瞬时发生的),额外工作和交易无效的风险之间都存在一个折衷。

    图11

    到目前为止一切顺利。不过,有个额外的并发问题我们必须考虑:我们的系统依赖于来自其他节点的交易确认,但是没有什么能阻止恶意用户按照所需生成尽可能多的伪造身份(回想一下,我们系统中的“身份”仅仅是个公钥—私钥对,随便就能生成)来满足 Katy 的验收标准。

    Bob 是否要进行攻击是一个简单的经济学问题:如果收益高于成本,他就会考虑实行攻击。相反,如果 Katy 可以使运行攻击的成本高于交易的价值,那么她应该是安全的(除非 Bob 和她有私仇或者愿意在交易上赔钱。但这不在考虑范围内)。为了让问题更明确,我们做出如下假设:

    1. Bob 转移10个 chroma 给 Katy。
    2. 生成伪造身份和交易响应的成本是0.001 chroma:维持电脑运行的能源成本,支付网络连接等。

    如果 Katy 要求1001次确认,对于 Bob 来说实行攻击就没有(经济)意义了。反之,我们可以为每次确认增加一个工作量证明要求,将每次有效响应的成本从0.001 chroma 增加到 1 chroma,即找到一个有效散列会占用 CPU 时间,转化为更高的能源费用。因此,Katy 只要求11次确认就可以达到同样效果的安全保障。

    注意,Katy 每次请求确认也会导致一些成本:她必须耗费努力来发出请求,然后验证响应。此外,如果生成确认和验证的成本是一对一的,那么 Katy 将承担与交易价值相等的总成本来验证交易……当然,这没有任何经济意义。这就是为什么工作量证明的不对称很关键。

    很好,问题解决了,对吧?在这个过程中,我们似乎……造成了另一个经济困境。我们的网络现在验证每个交易产生的成本与交易本身的价值相等甚至更高。虽然这是对恶意参与者的经济威慑,但合法参与者怎么会愿意为他人承担成本?理性的参与者根本不会,这毫无意义。

    添加“区块”和交易费用激励

    如果网络中的参与者必须承担成本来验证彼此的交易,那我们必须为他们提供经济激励。事实上,我们至少要抵消他们的成本,否则一个“空闲”参与者(任何没有提交自己交易的人)将会代表网络继续累积成本——这样是行不通的。还有一些我们需要解决的其他问题:

    1. 如果验证交易的成本等于或高于交易价值本身(为了制止恶意参与者),那么总交易价值是净零,或负数!例如,Bob 把10个 chroma 转移给 Katy, Katy 又花了10个 chroma 来补偿其他节点来验证交易,Katy 很伤心。
    2. Katy 如何为确认进行支付?如果那是它自己的交易,就会有一个递归问题。

    让我们从显而易见的问题开始:交易费用不能和交易本身的价值一样高。当然,Katy 不必原封不动地把所有价值都用于确认交易(比如,她可以分配一半的价值用于确认),但这样又变成了一个利润问题:如果剩余利润(交易价值减去验证费)足够高,欺诈的动机仍然存在。相反,理想情况下,我们希望承担最低的交易费用,并仍然对恶意参与者有强大的威慑,有解决方案吗?

    我们可以通过允许网络中的参与者一次性汇集和确认多个交易来激励他们,也就是对一个交易“区块”进行确认。这样做能让他们汇总交易费用,从而降低每个单独交易的验证成本。

    图12

    一个区块仅仅是(一个或多个)有效交易的集合——把它想象成等同于物理分类账簿中的一个页面。反过来,每个区块包含对前一交易区块(上一页)的引用,整个分类账簿是区块的链接序列,也就是,区块链。想想上面的案例:

    1. Alice 和 Bob 生成新交易并公布到网络上。
    2. Chris 正在等着听新交易通知,每个交易通知包含发送方愿意支付于网络验证和确认交易的交易费用:
      • 直到有直接的经济激励(交易费用总额大于他的成本)来完成必要工作来验证未决交易,Chris 对未确认的交易进行汇总。
      • 一旦过了这个门槛,Chris 首先验证每个未决交易,方法是核实所有的输入都不是重复消费。
      • 所有交易都被核实后,Chris 在未决列表上再添加一个交易(上图中用绿色标识),将所发布交易的费用额转移给他自己。
      • Chris 生成一个包含未决交易列表的区块,引用前一区块(使我们可以遍历区块并看到整个分类账簿),并执行工作量证明挑战,来生成符合网络既定规则的区块散列值,例如 N 个前导零的部分散列冲突。
      • 最后一旦 Chris 发现有效区块,他就分发给所有的其他参与者。
    3. Alice 和 Bob 在等着监听新的区块公告,寻找他们在列表中的交易:
      • Alice 和 Bob 验证区块的完整性,也就是验证工作量证明和区块所包含的交易。
      • 如果区块有效,他们的交易在列表中,那么交易就被确认了!

    我们在这里前进了一大步。以前我们的网络中只记录了一种类型——签名的交易。现在我们签名了交易和区块。前者由参与交易的个人生成,后者由有意通过验证和确认交易收费的各方生成。

    另外请注意,上述方案需要系统中的最小交易量来维持个人创建区块的动机:交易越多,单个交易所需的费用越低。

    Alice 宣布了一个新的交易,并收到一个 Chris 确认它的有效区块。有了一个确认,那其余的呢? 而且 Chris(但愿)不是唯一一个受到激励来生成区块的参与者。如果其他人同时生成了另外一个区块,这两个区块哪个“有效”?

    竞争以赢取交易费用

    通过验证交易区块来引入汇总费用的能力,它了不起的部分在于,为网络中的新参与者创造了一个角色,他们有直接的经济激励来保障网络。你现在可以通过验证交易赚取利润,可以盈利的地方,竞争就随之而来,这只会加强网络——一个良性循环和聪明的社会工程!

    即便如此,验证交易的竞争动机又产生了另一个有趣的困境:我们如何在分布式网络中协调区块生成工作?简短的回答,你可能已经猜到了,我们不会去协调。我们在系统中再额外添加一些规则,看看它们如何解决这个问题:

    1. 允许任意数量的参与者参加(“竞赛”)创建有效区块。不需要协调,感兴趣的参与者反而会去找新的交易,决定是否想要以及何时想要尝试生成有效区块,领取交易费用。
    2. 生成有效区块时,立即广播到网络中。
      • 其他节点检验区块的有效性(检查每个交易和区块本身的有效性),如果有效,就将其添加到他们的分类账簿中,然后最终重新广播到网络中的其他节点。
      • 添加以后,新的区块成为分类账簿的“最高档”。如果同一个节点也在生成区块,那么他们需要中止之前的工作重新开始:他们现在需要更新对最新区块的引用,并且从最新区块中包含的未确认列表里删除所有交易。
      • 完成以上步骤后,开始创建新区块,希望他们第一个发现下一有效区块,这样他们能够领取交易费。
    3. 重复以上步骤直到宇宙热寂。

    生成区块的所有参与者之间缺乏协调意味着网络中会有重复的工作,这也 OK!虽然不能保证单个参与者获得特定区块,只要参与网络的预期价值(获得区块的概率乘以预期支出,减去成本)是正的,系统就可以自我维持。

    注意,接下来要验证交易的节点之间没有一致性。每个参与者汇总自己的列表,运用不同策略来使预期收益最大化。此外,由于我们工作量证明函数(为区块 SHA-256 校验和找到一个部分散列冲突)的属性,增加获得区块概率的唯一方法是耗费更多的 CPU 周期。

    图13

    还有一个需要应对的警告:两个节点可能会几乎同时发现一个有效区块,并开始在网络中传播——例如上表中的 Kent 和 Chris。因此,一部分网络最终可能会接收Kent的区块作为最高区块,其余的会接受 Chris 的区块。现在怎么办?

    解决链冲突

    再次的,我们将采取一种不干涉的手段,让区块生成过程中的任意属性来解决冲突,虽然还有另外一个规则:如果检测到多个链,参与者应立即切换到最长的链,并在其顶部创建。我们来看看这在实践中如何工作:

    图14

    1. 一些节点会开始在 Kent 的区块上建立新区块,其他人在 Chris 的区块上建立。
    2. 在某一时刻,有人会发现新的区块,开始在网络中传播。
      • 其他节点接受新的区块时,与一个不同的最高区块合作的那部分网络将检测到现在有一个更长的链可替换,这意味着它们需要切换到更长的链上面。
      • 作为被丢弃区块的一部分但尚未被确认的任何交易都被放在未决列表中,重新开始这个过程。
      • 可能的情况是,竞争状况会持续多个区块,但最终某个分支会超过另一个,网络的其余部分将收敛到同一个最长的链上。

    很好,我们现在有了一个策略来解决网络中不同链之间的冲突。具体来说,网络通过将交易记录在链接的区块列表中来允诺交易的线性化。但至关重要的是,它没有允诺个别区块可以“保证”任意一个交易的状态。想想上面的案例:

    1. Alice 将她的交易发送到网络。
    2. Chris 生成一个确认她交易的有效区块。

    但是链中有一个分叉,当稍后网络收敛在 Kent 的分支链上时,Chris 的区块会被“移除”。因此,即使当 Alice 接收到一个有她交易的区块,她也不能确定这个区块将来不会被撤消!

    没有哪个区块是“最后一个”

    没有哪个区块是“最后一个”,永远不会有。 如果检测到更长的链,任何区块都可以被“撤消”。实际上,检测分叉相当快速,但总是存在出现替代链的可能。但是,我们唯一能说的是,特定区块在链中的位置“更深”,它被撤销的可能性就更小。因此,也没有哪个交易可以被视为“最终一个”,我们只能陈述它被撤销的概率。

    1. 0确认交易:不必等待任何包含交易的区块就可以进行交换。
    2. 1确认交易:最新的有效区块包含交易。
    3. N 确认交易:有一个包含交易的有效区块,以及 N-1 个区块建立在那个有效区块上。

    如果愿意接受风险,你可以总是选择采用0确认交易:没有交易费用,也不必等待确认,不过你要对对方抱有极大的信任。

    但如果你想降低风险,就要等待一个或多个区块建立在你交易所在的区块上。你等的时间越长,在包含你交易的区块上建立的区块越多,出现一个撤销你交易的替代链的可能性越低。

    “撤消”指的是参与者使网络接受一个替代交易,将资金转移到除你以外的其他帐户上的情形——例如,你完成交易,移交组件,获得收据,但攻击者接着会注入一个交易,把同样的资金“双重消费”到另一帐户。

    为什么区块链的长度可以很好地代表交易“安全性”?如果攻击者想要撤消一个特定交易,那么他需要建立一个链,链开始于列出交易区块的前一区块,然后建立一个由其他区块组成的、比网络当前所用链更长的链。因此,区块越深,通过创建新链来替换它所需要的计算量就越大。链条越长,运行攻击的代价就越昂贵。

    在接受交易之前,你要等待多少个区块?它没有一个明确的数字,答案取决于网络的特性(生成每个区块的时间,交易和区块的传播延时,网络大小等)以及交易本身:它的价值,你对另一方的了解,你的风险预测等。

    (最小可行)区块链的属性

    个体交易的安全受公钥基础设施保障

    验证交易真实性:恶意方不能伪装成他人,代表他人签名交易。

    交易真实性认证只与公钥—私钥对有关。不需要将密钥对与参与者其他数据链接的“强认证”。事实上,单个参与者可以生成和使用多个密钥对!从这一层面上看,网络允许匿名交易。

    不可否认性:事实发生后,参与方不能声称交易没有发生过。

    完整性:事实发生后,交易不能被修改。

    交易一旦被创建,就被广播到点对点网络中

    参与者形成一个网络,交易和区块在参与节点之中转播。不存在一个中央权威。

    一个或多个交易聚集在“区块”上

    • 一个区块可以验证一个或多个交易并领取交易费用。

    这使得交易费用与每个交易的价值相比仍然是很低的。有效区块必须有有效的工作量证明解决方案。

    • 有效的工作量输出很难生成,但验证起来很便宜。

    工作量证明用于提高生成有效区块的成本,使运行对网络的攻击成本更高。

    • 任意节点都能用于生成有效区块,一旦有效区块生成,就被广播到网络中。

    • 每个区块有一个与前一有效区块之间的链接,使我们能够遍历网络中所有交易记录的完整历史。

    节点们寻找新的交易通知,将它们并入分类账簿中

    在区块中包含交易,作为交易“确认”,但这一事实本身不会将交易“最终化”。相反,我们以链的长度代表交易的“安全性”。每个参与者可以选择自己的风险承受水平,从0确认交易到等待任意数量的区块。

    所有上述规则和基础设施的组合提供了一个去中心化、点对点的区块链,用于实现签名交易排序的分布式一致性。说得有点多,我知道,但它也为一个大难题提供了巧妙的解决方法。区块链的单个部分(会计,密码技术,网络,工作量证明)并不新颖,但所有这些部分结合起来形成的新属性很值得关注。

    如何使用区块链技术进行项目开发

    文/陈浩

    区块链是目前一个比较热门的新概念,蕴含了技术与金融两层概念。从技术角度来看,这是一个牺牲一致性效率且保证最终一致性的分布式数据库,当然这是比较片面的。从经济学的角度来看,这种容错能力很强的点对点网络,恰恰满足了共享经济的一个必须要求——低成本的可信环境。

    本文以联盟链为例,描述了实践一个联盟链的基本过程。

    总体思路

    首先要确定这个区块链的类型,是公证型区块链还是价值型?

    公证型区块链是指仅限一些关键数据自证、披露、防篡改等功能的区块链,通常是在价值型区块链中附带的功能,也可以单独扩展,用于公示公开等。价值型区块链是指可以进行资产所有权转移的一种记账账本。

    如果确定是价值型区块链,我们又需要确定目标区块链的总体定位:到底是一个普适的价值传输区块链,还是特定场景下的区块链?如果是特定场景下的区块链,我们通常推荐超级账本作为技术原型,如果是比较通用的价值区块链,我们推荐以太坊的思路。

    业务场景的构建与初步分析

    首先要明确的观点是,区块链不是万能的。很多场景其实是不需要区块链技术也能解决的。像跨境支付领域,区块链能很好的发挥是因为存在很多点对点的跨境机构有大量的支付清算需求,而又不希望中间机构参与,区块链是很好的选择。但是在一些集团内部,大型公司内部,区块链解决方案基本上远远不如传统的企业资源解决方案。

    需求痛点分析

    一般需求痛点在满足以下条件的时候,可以考虑使用区块链:

    • 存在一个不相互信任的 P2P 网络环境;
    • 节点之间是对等的,不存在一个绝对仲裁者;
    • 节点之间是博弈行为。

    P2P 网络可能包含输入和输出,当包含输入和输出时,区块链不再封闭。

    对于某个节点一般有以下几种行为(包括但不限于):

    • 不信任其他节点;
    • 保证自己的收益最大化;
    • 自私获取但不贡献资源。

    针对以上情景的业务建模,需要针对具体的业务逻辑结合博弈论推导出满足自己需求的方案。

    非区块链技术能否解决

    案例1:

    通常我们有不同的机构 A、B、C,存在不对称的信息交换需求,即 A、B、C 分别具有部分数据,但三者组合到一起具有市场的全量数据。但是作为 A,想知道 B、C 是否拥有自己数据集合中的某个点数据,根据这个结果来调整自己的购买策略。

    案例2:

    有不同的机构 X、Y、Z,存在信息反馈的需求,当 Z 收到 Y 的服务时,会给 Y 一个信息反馈,这种反馈可能是信用评价,也可能只是响应反馈。总之这种反馈需要记录在案,X 会根据Z的信息反馈结果调整自己的购买策略。当 X 购买服务时,同样会给 Y 一个反馈,Z 也会收到反馈。

    以上两个案例首先考虑使用非区块链是否可以解决:

    针对案例1,敏感数据和私有数据是不会公开的,即使加密也不会被允许上传到区块链。所以产生了一个数据输入输出区块链的过程,该过程是区块链不可控制的。

    那么使用传统的技术是否可以控制呢?貌似也不行,能够满足不暴露敏感数据的方案也只有 HASH 计算和同态加密。但是这两者都要求数据传输到指定位置。

    通常我们会考虑使用零知识证明作为解决方案,然而具体的算法可能需要根据具体业务逻辑进行构建,结合简单智能合约,根据查询结果产生不同输出。

    针对案例2,反馈信息容易被篡改,可刷单等问题是最大的,如何保证这种信息反馈是客观中立不可篡改的,可以结合区块链代币的币龄使交易具有方向性来防止作弊行为。

    业务场景建模

    针对第二节中的两个案例,我们接下来要进行建模,除去核心痛点,我们必然还有记账的需求,本质上任何案例中每个节点都既是服务方,也是客户方,那么怎么衡量自己贡献和索取了多少呢?

    所以任何区块链平台上,必须是要有代币系统的,否则记账将非常困难。在业务场景建模过程中,我们主要关注如何使节点之间达成帕累托改进,而不是因为每个节点是自私行为,让区块链服务名存实亡。

    开发路径

    区块链原型选取

    根据本文开头的叙述,如果是特定场景的区块链解决方案,建议 Hyperledger fabric,当然搭建以太坊私有链也是可以的。

    下面是一些以太坊和 Fabric 的比较:

    以太坊与 HyperLedger 相同点:

    1. 都是提供区块链业务实现的平台,业务实现都是通过智能合约来完成,以达到最大的灵活性和对底层的不修改。
      • 以太坊是:EVM 虚拟机,Solidity 合约语言;
      • HyperLedger 是:Shim 链码容器,用 GO 编写合约。
    2. 官方版本都使用 GO 语言实现。
    3. 因为都是提供第三方可编程能力,由于难度大,内部难免存在漏洞。对外则存在恶意程序攻击的威胁。尤其是在做为公有链时,威胁将会更大。上个月以太坊已有报合约 solidity 语言漏洞。

    以太坊与 HyperLedger 不同点:

    1. 以太坊只提供智能合约能力。也恰好吻合它的定位:智能合约和去中心化应用平台。对系统安全性或准入机制无底层无核心上的支持。而 HyperLedger 在吸收以太坊智能合约特点的同时,提供 MemberShip 及身份验证角色管理等模块,更贴近商业应用场景。
    2. 共识机制不同。由于共识的不一样,所以每秒可处理的交易量也不一样,以太坊是每秒千级别的处理量,而HyperLedger 可以达到十万级别。
    3. 采用的技术实现思路上不一样。以太坊更多的是靠自己实现,自己造轮子,有点开发人员炫技的感觉,如自己提供合约语言 solidity,自己实现 EVM(这个可能是实际需要)。

    表1是笔者曾经的一个私链项目中对两者的比较(私链考虑了 Hydrachain 的可行性)。

    读者可以根据自己实际的 TPS 需求,进行共识的选型。表2是不同共识的一些参考数据。

    表2

    当然,如果考虑自行开发,建议搭建基础比特币网络,做加法,更改共识算法,网络传送协议以及附加合约(可选)。

    其实智能合约在一些场景中不是必选项,对用户来说,可靠方便实时是第一需求,如果针对特定的应用场景,将“合约”固化在区块链里面,也是一种可行的思路。

    针对以上两种联盟链实现,笔者还想强调,并不是所有服务一定得是区块链的,笔者构想了一个通用的保护伞型结构,如比特币的侧链技术,主链提供基础账本服务,侧链提供特定场景服务,侧链上的应用可以是非区块链实现的,只需接口注册即可。

    图1  保护伞结构

    图1 保护伞结构

    交互接口设计

    在交互接口设计上,推荐使用目前业界通用的 Json-RPC 接口,扩展性和友好性兼备。

    一般我们将接口分为两类:开放接口和账户接口。开放接口是指区块链本身的描述信息,是不需要认证的,而账户接口是需要账户认证的。

    基础账本设计

    基础账本设计包含以下两个问题:

    首先是原型区块链是否已经满足需求?如果针对以太坊,基本上不需要改动基础账本,只需构建智能合约即可。如果以比特币体系为基础,则可能有较大的改动。

    不满足需求时如何改动基础账本?这个其实要视账户模型而定,如果使用 UTXO 模式时,改动重点在如何嵌入模板交易体。如果使用 Balance 模式,那么则没有这个问题。

    业务扩展层设计

    业务扩展设计方面的内容比较复杂,篇幅问题这里也只是抛砖引玉提出两个问题:

    1. 扩展层是外接区块链还是内置到区块链?
    2. 如果包含数据输入,是否需要脱敏?脱敏后如何上链?

    先想清楚这两个问题或许能帮你更好地规划业务扩展层的内容。

    开发转变和难点

    开发思维的转变

    与传统网络服务不同的是,区块链开发不再以面向服务为主要关注点,而是面向账本和交易。

    开发者面对的不再是以高可用高并发的应用程序为主要指标,而是切换到了面向用户,关注用户友好性和开发扩展性的终端程序开发。

    所以高并发高性能不再是区块链终端的核心指标,安全性、可扩展性、友好性成了主要指标。

    图2是一个适用于联盟链/私有链项目的工作流程。

    图2  适用于联盟链/私有链项目的工作流程

    图2 适用于联盟链/私有链项目的工作流程

    开发难点

    目前来讲,区块链项目开发的难点有三个:

    • 开发人力资源储备不足

    目前比较成熟的技术体系有比特币及衍生技术体系、以太坊、超级账本 HyperLedger fabric、比特股 Bitshares、瑞波 Ripple 和未来币 NXT。其中前三个是最有影响力的区块链项目。比特币以及衍生技术多以 C++ 语言进行开发;以太坊支持大部分主流语言,官方以 Go 为主,也有其他分支的项目如 Rust 语言的 Parity 钱包;超级账本目前以 Go 为主。

    从目前上海地区的区块链从业人员来看,保守估计在400~500左右。按一半为开发人员计算,也才200多个,面对巨大的市场需求,人才是极度稀缺的。

    由于 C++ 目前仅在金融和游戏领域有部分需求,所以 C++ 工程师不多,尤其是高水平的 C++ 工程师就更少了。Go 作为新兴语言,发展势头很猛,但是 Go 的生态也不如 Java 大。

    如果从 Java 的角度看,如何把其生态利用起来,目前区块链还没有做到那个地步。

    综合来看,区块链在技术方面与其他技术的结合还有待探索。

    • 区块链是交叉学科,需要各方面工程实践的经验。在实践方面,我们希望区块链从业人员同时了解技术和金融业务,这个对人员的素质要求比较高,相应的符合标准的人就更少了。

    • 关于对各个区块链技术体系理解的偏差,区块链技术和概念日新月异,闭门开发可能会走到死胡同,如何保持一部分精力更新知识体系,同时保证开发进度对开发人员是有较大挑战的。

    区块链作为一门新兴的技术,涵盖了去中心化、去信任、共享经济、分布式计算、分布式存储等多方面的内容,考验着技术人员的学习和思考能力。在未来,区块链将同人工智能一起,会影响到普通人生活的方方面面。

    写给 CTO 的主流区块链架构横向剖析

    文/张铮文

    时常听人们谈起区块链,从2009年比特币诞生至今,各式各样的区块链系统或基于区块链的应用不断被开发出来,并被应用到大量的场景中,而区块链技术本身也在不停地变化和改进。

    区块链又被称为分布式账本,与之对应的则是中心化账本,比如银行。与中心化账本不同的是,分布式账本依靠的是将账本数据冗余存储在所有参与节点中来保证账本的安全性。简单地说,区块链会用到三种底层技术:点对点网络、密码学和分布式一致性算法。而通常,区块链系统还会“免费附赠”一种被称为智能合约的功能。智能合约虽然不是区块链系统的必要组成部分,但由于区块链天生所具备的去中心化特点,使它可以很好地为智能合约提供可信的计算环境。

    为了适应不同场景的需求,区块链系统在实际应用的过程中往往会需要进行各种改造,以满足特定业务的要求,比如身份认证、共识机制、密钥管理、吞吐量、响应时间、隐私保护、监管要求等。而实际应用区块链系统的公司往往没有进行这种改造的能力,于是市场上慢慢出现了一些用于定制专用区块链系统的框架,采用这些框架就可以很方便地定制出适用于企业自身业务需求的区块链系统。

    本文将对目前市场上几个典型的区块链框架进行横向对比,看看它们都有哪些特点,以及它们之间到底有什么区别。为了保持对比的客观与公正,本文将只针对开源的区块链框架进行讨论。

    各区块链架构的简单介绍

    比特币

    比特币(Bitcoin)源自中本聪(Satoshi Nakamoto)在2008年发表的一篇论文《比特币:一种点对点的电子现金系统》(Bitcoin:A Peer-to-PeerElectronic Cash System),文中描述了一种被他称为“比特币”的电子货币及其算法。在之后的几年里,比特币不断成长和成熟,而它的底层技术也逐渐被人们认识并抽象出来,这就是区块链技术。比特币作为区块链的鼻祖,在区块链的大家族中具有举足轻重的地位,基于比特币技术开发出的山寨币(Altcoins)的数量有如天上繁星,难以计数。

    中本聪设计比特币的目的,就是希望能够实现一种完全基于点对点网络的电子现金系统,使得在线支付能够直接由一方发起并支付给另外一方,中间不需要通过任何的中介机构。总结来说,他希望比特币能够实现以下这些设计目标:

    1. 不需要中央机构就可以发行货币
    2. 不需要中介机构就可以支付
    3. 保持使用者匿名
    4. 交易无法被撤销

    从电子现金系统的角度来看,以上这些目标在比特币中基本都得到了实现,但是依然有一些技术问题有待解决,比如延展性攻击、区块容量限制、区块分叉、扩展性等。在应用场景方面,目前大量的数字货币项目都是基于比特币架构来设计的,此外还有一些比较实际的应用案例,比如彩色币、tØ 等。

    彩色币(Coloredcoin),通过仔细跟踪一些特定比特币的来龙去脉,可以将它们与其他的比特币区分开来,这些特定的比特币就叫作彩色币。它们具有一些特殊的属性,从而具有与比特币面值无关的价值,利用彩色币的这种特性,开发者可以在比特币网络上创建其他的数字资产。彩色币本身就是比特币,存储和转移不需要第三方,可以利用已经存在的比特币基础网络。

    tØ 是比特币区块链在金融领域的应用,是美国在线零售商 Overstock 推出的基于区块链的私有和公有股权交易平台。

    以太坊

    以太坊(Ethereum)的目标是提供一个带有图灵完备语言的区块链,用这种语言可以创建合约来编写任意状态转换功能。用户只要简单地用几行代码来实现逻辑,就能够创建一个基于区块链的应用程序,并应用于货币以外的场景。以太坊的设计思想是不直接“支持”任何应用,但图灵完备的编程语言意味着理论上任意合约逻辑和任何类型的应用都可以被创建出来。总结来说,以太坊在比特币的功能之外,还有以下几个设计目标:

    1. 图灵完备的合约语言
    2. 内置的持久化状态存储

    目前基于以太坊的合约项目已达到数百个,比较有名的有 Augur、TheDAO、Digix、FirstBlood 等。

    Augur 是一个去中心化的预测市场平台,基于以太坊区块链技术。用户可以用数字货币进行预测和下注,依靠群众的智慧来预判事件的发展结果,可以有效地消除对手方风险和服务器的中心化风险。

    限于篇幅,基于以太坊智能合约平台的项目就不多介绍了。基于以太坊的代码进行改造的区块链项目也有不少,但几乎都是闭源项目,只能依靠一些公开的特性来推断,所以就不在本文展开讨论了。

    Fabric

    Fabric 是由 IBM 和 DAH 主导开发的一个区块链框架,是超级帐本的项目成员之一。它的功能与以太坊类似,也是一个分布式的智能合约平台。但与以太坊和比特币不同的是,它从一开始就是一个框架,而不是一个公有链,也没有内置的代币(Token)。

    超级账本(Hyperledger)是 Linux 基金会于2015年发起的推进区块链技术和标准的开源项目,加入成员包括:荷兰银行(ABN AMRO)、埃森哲(Accenture)等十几个不同利益体,目标是让成员共同合作,共建开放平台,满足来自多个不同行业各种用户案例,并简化业务流程。

    作为一个区块链框架,Fabric 采用了松耦合的设计,将共识机制、身份验证等组件模块化,使之在应用过程中可以方便地根据应用场景来选择相应的模块。除此之外,Fabric 还采用了容器技术,将智能合约代码(Chaincode)放在 Docker 中运行,从而使智能合约可以用几乎任意的高级语言来编写。

    以下是 Fabric 的一些设计目标:

    1. 模块化设计,组件可替换
    2. 运行于 Docker 的智能合约

    目前已经有不少采用 Fabric 架构进行开发的概念验证(POC)项目在实施过程中,其中不乏一些金融机构做出的尝试,不过由于项目刚刚起步,还没有比较成熟的落地应用。

    Onchain DNA

    Onchain DNA(Onchain Distributed Networks Architecture),是由总部位于上海的区块链创业公司“分布科技”开发的区块链架构,可以同时支持公有链、联盟链、私有链等不同应用类型和场景,并快速与业务系统集成。分布科技同样也是超级账本的成员之一。

    与以太坊、Fabric 不同的是,Onchain DNA 在系统底层实现了对多种数字资产的支持,用户可以直接在链上创建自己的资产类型,并用智能合约来控制它的发行和交易逻辑。对于绝大部分的区块链应用场景,数字资产是必不可少的,而为每一种数字资产都开发一套基于智能合约的业务流程非常浪费且低效。因此,由区块链底层提供直接的数字资产功能十分必要。而对于那些完全不需要数字资产的应用场景,同样可以基于 Onchain DNA 提供的智能合约功能来编写任意的自定义逻辑来实现。

    Onchain DNA 的设计目标主要有以下几点:

    1. 多种数字资产的底层支持
    2. 图灵完备的智能合约和持久化状态
    3. 跨链互操作性
    4. 交易的最终性

    目前已有不少金融机构采用 Onchain DNA 架构来进行区块链概念验证产品的开发,如银行、券商、支付、登记结算机构等。除此之外,还有一些已经落地的区块链项目,如小蚁、法链等。

    小蚁(Antshares)是一个定位于资产数字化的公有链,将实体世界的资产和权益进行数字化,通过点对点网络进行登记发行、转让交易、清算交割等金融业务的去中心化网络协议。它采用社区化开发的模式,在架构上与 Onchain DNA 保持一致,从而可以与任何基于 Onchain DNA 的区块链系统发生跨链互操作。

    法链是全球第一个大规模商用的法律存证区块链,一个底层基于 Onchain DNA 区块链技术,并由多个机构参与建立和运营的证据记录和保存系统。该系统没有中心控制点,且数据一旦录入,单个机构或节点无法篡改,从而满足司法存证的要求。

    Corda

    Corda 是由一家总部位于纽约的区块链创业公司 R3CEV 开发的,由其发起的 R3 区块链联盟,至今已吸引了数十家巨头银行的参与,其中包括富国银行、美国银行、纽约梅隆银行、花旗银行、德国商业银行、德意志银行、汇丰银行、三菱 UFJ 金融集团、摩根士丹利、澳大利亚国民银行、加拿大皇家银行、瑞典北欧斯安银行(SEB)、法国兴业银行等。从 R3 成员的组成上也可以看出,Corda 是一款专门用于银行与银行间业务的技术架构。尽管 R3 声称 Corda 不是区块链,但它具备区块链的一些重要特性。

    Corda 由 Java 和 Kotlin 开发,并在其各项功能中充分依赖于 Java,比如智能合约、数据访问接口等。Corda 的设计目标主要是:

    1. 没有全局账本
    2. 由公证人(Notaries)来解决交易的多重支付问题
    3. 只有交易的参与者和公证人才能看到交易

    为此,Corda 的所有交易都不会向全网进行广播,而且所有的节点都是直接通信,没有 P2P 网络。这一点导致了其网络规模会被限制在一个较小的规模内,无法形成大规模的联盟链,适用的业务场景比较狭窄。

    技术对比

    接下来,我们将针对前文中所提到的这些区块链框架进行一系列的技术对比,并从多个维度展开讨论它们的区别与相似之处。

    表1

    数字资产

    区块链的内置代币通常是一种经济激励模型和防止垃圾交易的手段。比特币天生就有且只有一种内置代币,所以在比特币系统中所有的“交易”本质上都是转账行为,除非通过外部的协议层来给比特币增加额外的数字资产。

    以太坊和 Onchain DNA 具有内置代币,它们的作用除了以上提到的经济激励和防止垃圾交易之外,还为系统内置功能提供了一个收费的渠道。比如以太坊的智能合约运行需要消耗 GAS,而 Onchain DNA 的数字资产创建也需要消耗一定的代币(可选)。

    以太坊和 Fabric 没有内置的多种数字资产支持,而是通过智能合约来实现相应的功能。这种方式的好处在于,系统设计可以做到非常简洁,而且资产的行为可以任意指定,自由度极高。然而这样的设计也会带来一系列的负面影响,比如所有的资产创建者不得不自己编写重复的业务逻辑,而用户也没有办法通过统一的方式去操作自己的资产。

    相比之下,Onchain DNA 和 Corda 采用了在底层支持多种数字资产的方式,让资产创建者可以方便地创建自己的资产类型,而用户也可以在同一个客户端中管理所有的资产。对于逻辑更加复杂一点的业务场景来说,他们同样可以利用智能合约来强化资产的功能,或者创建一种与资产无关的业务逻辑。

    账户系统

    UTXO(Unspent Transaction Output)是这样一种机制:每一枚数字货币都会被登记在一个账户的所有权之下,一枚数字货币有两种状态,即要么还没有被花费,要么已经被花费。当需要使用一枚数字货币的时候,就将它的状态标记为已经花费,并创造一枚新的与之等额的数字货币,将它的所有权登记到新的账户之下。在这个过程中,被标记为已花费的数字货币就被称为交易的输入,而创造出来的新的数字货币被称为交易的输出,在一笔交易中,可以包含多个输入和多个输出,但是输入之和与输出之和必须相等。计算一个账户的余额时,只要将所有登记在该账户下的数字货币的面额相加即可。

    表2

    比特币和 Corda 就采用了 UTXO 这样一种账户机制,而以太坊则采用了更加直观的余额机制:每个账户都有一个状态,状态中直接记录了账户当前的余额,转账的逻辑就是从一个账户中减去一部分金额,并在另一个账户中加上相应的金额,减去的部分和加上的部分必须相等。Onchain DNA 在账户机制上同时兼容这两种模式。

    那么 UTXO 模式和余额模式,究竟有什么区别呢?UTXO 最大的好处就是,基于 UTXO 的交易可以并行验证且任意排序,因为所有的 UTXO 之间都是没有关联的,这对区块链未来的扩展性有很大的帮助,而基于余额的设计就没有这个优势了。反过来,余额设计的优点是设计思想非常简洁和直观,便于程序实现,特别是在智能合约中,要处理 UTXO 的状态是非常困难的。这也是为什么以智能合约为主要功能的以太坊选择余额设计的原因,而比特币、OnchainDNA、Corda 这些以数字资产为核心的架构则更倾向于 UTXO 设计。

    关于身份认证,比特币和以太坊基本没有身份认证的设计,原因很简单,因为这两者的设计思想都是强调隐私和匿名,反对监管和中心化,而身份认证就势必要引入一些中心或者弱化的中心机构。

    Fabric、Onchain DNA 和 Corda 不约而同地选择了采用数字证书来对用户身份进行认证,原因在于这三者都有应用于现有金融系统的设计目标,而金融系统必然要考虑合规化并接受监管,此外现有的金融系统已经大范围地采用数字证书方案,这样便可以和区块链系统快速集成。

    共识机制

    共识机制是分布式系统的核心算法,因为分布式系统的数据分散在各个参与节点中,这些分散的数据必须通过一种算法来保持一致性,否则系统将无法正常工作。与传统的分布式系统不同,区块链是一个去中心化的系统,并且可能会承载大量的金融资产,所以它可能会面临大量的拜占庭故障而非一般性故障,而中心化的分布式系统则很少遇到拜占庭故障。因此,区块链的共识机制与传统的分布式系统存在较大的差异。

    表3

    比特币和以太坊采用了工作量证明(Proof-of-Work)机制来保证账本数据的一致性。工作量证明同时也是一种代币分发机制,它通过经济激励的方式来鼓励节点参与区块的构造过程,节点在构造区块的时候需要穷举一个随机数以使得区块符合规定的难度要求,一旦区块链出现分叉,诚实的节点将选择工作量较大的链条,而抛弃工作量较小的。由于假设所有节点都是逐利的,而选择工作量较小的链条就会使自己获得的激励无效,所以最终所有的节点都会是诚实的,从而使每个节点的区块链数据都保持一致。

    为了维护这样一个工作量证明机制的区块链,需要全网具备较大规模的算力支撑来保证网络的安全性,否则账本数据就有可能被篡改。此外,即使维持较大的算力来保护网络,工作量证明也无法从根本上保证交易的最终性,比如比特币就经常产生孤立区块(Orphaned Block),而包含在孤立区块中的交易就有可能被撤销。因此比特币通常要求用户等待6个区块的确认,即1小时左右的时间,才能在一个可接受的概率上认为交易已经最终完成,而这个概率也并非是最终性的——你永远也不知道暗中是否有一个远超过全网的庞大算力正在试图撤销以前的交易。而为了维护庞大算力而支出的电力成本也是相当可观,因此,以太坊已经在设计从工作量证明机制切换到其他共识机制上的方案。

    Fabric 和 Onchain DNA 都设计了基于拜占庭容错(Byzantine Fault Tolerance)模型的共识机制。节点被分为普通节点和记账节点(Validating Peer),只有记账节点才会参与到区块的构造过程,这种角色的分离使得算法的设计者有机会将运行共识算法的节点数量限定在一个可控的规模内。

    拜占庭容错模型对网络中的节点做出了假设和要求:如果共识中有 f 个节点会出现拜占庭故障,那么至少需要 3f+1 个节点参与共识才能避免网络出现分叉。在这个模型下,每个区块的构造过程都需要至少 2f+1 个节点的参与才能够完成,而不像工作量证明机制下每个节点都独立构造区块。一旦区块被构造出来,它就无法被撤销,因为 2f+1 个诚实的记账节点不会在同一高度对两个不同的区块进行签名认证。

    相比较而言,工作量证明机制提供了极高的灵活性和可用性,因为每个节点都独立构造区块而几乎不需要其他节点的参与,节点可以随时加入或者退出网络,即使全网只剩下一个节点,网络还是可以继续工作,但是相应的它也失去了交易的最终性;而拜占庭容错的机制则与之相反,牺牲了一定的灵活性和可用性,记账节点必须在线提供服务而不能退出网络,一旦出现1/3的记账节点停机,那么网络将变得不可用,但它保证了交易的最终性。

    智能合约

    智能合约是1994年由密码学家尼克萨博(Nick Szabo)首次提出的理念,几乎与互联网同龄。智能合约是指能够自动执行合约条款的计算机程序,在比特币出现以前,因为不存在安全可靠的执行环境,智能合约一直不能够应用到现实中。区块链由于其去中心化、公开透明等特性,天生就可以为智能合约提供可信的执行环境。所以,新型的区块链框架几乎都会内置智能合约的功能。

    表4

    比特币内置了一套基于栈的脚本执行引擎,可以运行一种独有的脚本代码,用于对交易进行简单的有效性验证,比如签名验证和多重签名验证等。这套脚本语言被有意设计成非图灵完备的,足够简单却也足以应对货币转账的各种需求。

    以太坊是首个以图灵完备智能合约为主要功能的区块链,用户可以在以太坊的平台上创建自己的合约,而合约的内容可以包含货币转账在内的任意逻辑。合约使用一种名为 Solidity 的语言来编写,它是以太坊团队开发的专门用于编写智能合约的一种高级语言,语法类似 JavaScript,最终被编译成字节码并运行在 EVM(Ethereum Virtual Machine)之中。EVM 提供了堆栈、内存、存储器等虚拟硬件,以及一套专用的指令集,所有的代码都在沙盒中运行。它提供了合约间相互调用的能力,甚至可以在运行时动态加载其它合约的代码来执行。这种能力使得以太坊的合约具有非常高的灵活性,但也可能会使合约的功能具有不确定性。

    与以太坊自己动手开发语言、虚拟机的思路不同,Fabric 选择了使用现有的容器技术来支持智能合约功能。Fabric 的智能合约理论上可以用任何语言来编写,这一点对开发者相当友好,他们将无需学习新的语言,并且可以复用现有的业务代码和丰富的开发库,并使用自己熟悉的开发工具。相对的,采用 Docker 的智能合约架构也有大量的问题:首先,它很难对智能合约的执行流程进行控制,从而无法对其功能进行限制;其次,它无法对合约运行所消耗的计算资源进行精确的评估;此外,运行 Docker 相对而言是极其耗费资源的操作,这就使得难以在移动设备上运行合约;最后,不同节点的硬件配置、合约引用的开发库等,都有可能会使合约的行为具有很强的不确定性。

    Onchain DNA 采用了 AVM(Antshares Virtual Machine)作为其智能合约功能的底层支持。AVM是一个微核心的、平台无关的智能合约执行环境,它提供了一套包含堆栈操作、流程控制、逻辑运算、算数运算、密码学运算、字符串操作、数组操作的指令集,在硬件方面,它只提供了两个计算堆栈。不过,由于它允许区块链的实现者创建自己的虚拟硬件,并以接口的形式开放给智能合约来使用,使得合约可以在运行时取得平台相关的数据、持久化存储以及访问互联网等。虽然这也有可能会使合约的行为具有不确定性,但区块链的实现者可以通过合理编写虚拟硬件来消除这种不确定性。不过,由于目前尚无与 AVM 配套的编译器和开发环境,这使得基于 AVM 进行智能合约开发变得相当困难,开发者不得不使用一种类似汇编的语法来进行合约编写,需要较高的技术能力。

    Corda 的智能合约功能与其自身一样,都是基于 JVM(Java Virtual Machine)的。因此,你可以使用任何与 JVM 兼容的语言来进行开发,比如 Java、Kotlin 等。不过,它对 JVM 进行了一定的改造,使得在其上运行的合约脚本具备确定性。开发的过程大致是这样的:使用 Java 创建一个实现 Contract 接口的类(Class),并提供一个名为 verify 的函数(Function)用于对交易进行验证,该函数接受当前的交易作为参数,如果交易验证失败,则抛出异常(Exception),没有异常就表示验证通过。Corda 使用 JPA(Java Persistence Architecture)来提供持久化功能,支持 SQL 语句和常用的数据库,不过需要安装相应的插件,并且由于数据仅存放在合约执行者的节点,因此无法进行全局的持久化存储。

    扩展性

    区块链的数据结构通常是只能追加记录,而不能修改或删除记录,它真实地记录下完整的历史数据,使得新加入的节点有能力对全网的完整交易历史进行验证,而无需信任其它节点。这种特性带来了去中心化的便利性,但也影响了区块链系统的扩展性,因为区块会无休止地增长,直到塞满整个硬盘。所以有必要提供一种空间回收的机制来应对不断增长的数据。

    表5

    比特币提出了使用默克尔树(Merkle tree)来存放交易散列的方式,当需要回收硬盘空间时,只需将老旧的交易从默克尔树中剔除即可。一个不含交易信息的区块头大小仅有80字节。按照比特币区块生成的速率为每10分钟一个,那么每一年产生的数据约为4.2MB,即使将全部的区块头存储于内存之中都不是问题。

    以太坊、Fabric 和 Onchain DNA 在比特币区块压缩的基础上,又采用了状态快照的方式来节约硬盘空间。具体来说,就是在区块头的结构中不但记录了当前区块所有交易的根散列,还记录了当前区块及过去所有区块中的状态根散列。这些状态包括所有的 UTXO、账户余额、合约存储等,所以节点只需要保留最新的区块和完整的状态信息即可。

    扩展性的另一个重要指标是交易的吞吐量。决定吞吐量的因素有很多种,如网络结构、加密算法、共识机制等,但最重要的还是交易是否可以被并行验证。如果交易可以被并行验证,那么未来就可以通过简单地增加 CPU 数量来提高吞吐量。

    基于 UTXO 系统的比特币可以很容易地对交易进行并行验证,因为 UTXO 之间是没有关联的,对任何一个 UTXO 的状态改变都可以独立进行且与顺序无关;而基于余额的账户系统则不那么容易实现并行,因为可能会同时发生多笔交易对同一个账户进行资产操作,需要进行一些额外的步骤来处理。举个例子,假设账户中的余额为10元,有两笔针对该账户的交易同时发生,第一笔交易在账户中+5元,而第二笔交易在账户中-11元。那么如果先执行第一笔交易,则两笔都能成功,最终余额为4元;如果先执行第二笔交易,那么它会因余额不足而失败,只有第一笔交易会成功,最终余额为15元。

    而对交易的并行验证起到决定性作用的,是智能合约是否具备状态持久化的能力。如果一组合约都是无状态的,那么它们就可以按任意的顺序被执行,不会产生任何副作用;相反,如果合约可以对一组状态产生影响,那么按不同的顺序来执行合约产生的结果也会不同。举个例子,一个计算存款利息的合约,它具有两个子功能:存款和利息结算。假设账户中有100元,利率为10%,现在同时发生了两笔交易,第一笔交易的内容是存入100元,第二笔交易的内容是结算利息。假如第一笔交易先执行,那么最终账户的余额是:(100+100)×110%=220元;如果第二笔交易先执行,那么账户余额将是:100×110%+100=210元。由此可见,具备状态持久化能力的智能合约是顺序相关的,因此难以并发验证,特别是如果合约之间还可以相互调用的话,情况将会更加复杂。

    目前 Fabric 没有提出什么好的办法来解决这个问题;而 Corda 则没有这个问题,因为它的交易本身就不会向全网进行广播,所以只要交易参与者和公证人可以验证即可。以太坊和 Onchain DNA 的方法都是分区,即将各个合约分到不同的逻辑区中,每个区中的合约都顺序执行,而不同的区之间并行执行。以太坊将合约地址的首个字节作为分区依据,由此产生了256个分区,每个合约都在自己的分区中运行,且只能调用与自己相同分区的合约。但这种做法实际上并不能有效地解决问题,因为总有一些通用的底层合约因为被广泛使用,而把大多数的调用者合约聚集在同一个分区中。

    Onchain DNA 将合约分为功能合约(Function code)和应用合约(Applicationcode)。其中功能合约专门用于提供可复用的功能函数,被其它合约调用,且必须被声明为无状态,这一点消除了绝大部分的合约聚集现象;而只有应用合约可以保存自己的状态,所以在执行应用合约时,对其采用动态分区方案:在合约被执行之前,会先计算出它们的调用树,并将调用树有交集的合约放在同一个分区中执行。

    独有特性

    幽灵协议

    幽灵协议是以太坊对现有 POW 算法的改进,它提出的动机是当前快速确认的区块链因为区块的高作废率而受到的低安全性困扰。因为区块需要花一定时间扩散至全网,如果矿工 A 挖出了一个区块然后矿工 B 碰巧在 A 的区块传播至 B 之前挖出了另外一个区块,矿工 B 的区块就会作废并且没有对网络安全作出贡献。如果 A 是一个拥有全网30%算力的矿池而 B 拥有10%的算力,A 将面临70%的时间都在产生作废区块的风险而 B 在90%的时间里都在产生作废区块。通过在计算哪条链“最长”的时候把废区块也包含进来,幽灵协议解决了降低网络安全性的第一个问题;这就是说,不仅一个区块的父区块和更早的祖先块,祖先块的作废的后代区块(以太坊术语中称之为“叔区块”)也被加进来以计算哪一个区块拥有最大的工作量证明。以太坊付给以“叔区块”身份为新块确认作出贡献的废区块87.5%的奖励,把它们纳入计算的“侄子区块”将获得奖励的12.5%。计算表明,带有激励的五层幽灵协议即使在出块时间为 15s 的情况下也实现了95%以上的效率,而拥有25%算力的矿工从中心化得到的益处小于3%。

    国密算法

    国密算法是由中国国家密码管理局制定的一系列商用密码学算法,其中包括了对称加密算法 SM1,椭圆曲线非对称加密算法 SM2,杂凑算法 SM3 等。通常区块链在使用密码学算法时会采用国际标准,如 AES、ECDSA、SHA2 等。而国内的金融机构在选用密码学方案的时候,通常会考虑国密算法。Onchain DNA 提供了可选的密码学模块,针对不同的应用场景可以选择不同密码学标准,解决了安全性和政策性风险。

    跨链互操作

    目前,区块链技术正处于百花齐放、百家争鸣的时代,各种不同的区块链纷纷涌现出来,区块链之间的互操作性成为了一个非常重要而又迫切的需求。企业用户可能需要在不同的链之间进行业务迁移;普通用户可能需要在不同的链之间进行资产交换;央行的数字法币可能会需要在各个区块链上流通等。Onchain DNA 提供了一种跨链互操作协议,通过这种跨链协议,用户可以跨越不同的区块链进行资产交易、合约执行等操作,并保证该操作在各个区块链上的事务一致性。

    无链结构

    正如 Corda 在白皮书中所宣称的那样,它没有链式结构,交易也不向全网进行广播,而只在交易的参与者和公证人之间发送。因此,数据只有“需要访问的人”才能访问,避免了隐私泄露的问题。由于没有全局的链式结构,每个节点只存放和自己有关的交易,而无需存放全网的所有交易,大大的节省了空间。

    总结

    本文从多个维度比较并讨论了当前各个区块链框架的特点和功能,并阐述了它们在各方面的优缺点,以及在应用领域上的适用性和局限性。

    比特币虽然是区块链技术的原型,具有非常重要的地位,但由于其技术架构的局限性,如挖矿、非图灵完备等,很难应用到复杂的业务场景中去,但非常适合用于货币发行。

    以太坊虽然也采用挖矿的形式,但其幽灵协议提高了挖矿效率,新的共识算法也在开发中。以太坊还开发了较多基于密码学的隐私保护方案,比如环签名混币方案,非常适合于创建去中心化自治组织(Decentralized Autonomous Organization)。

    Fabric 和 Onchain DNA 的定位都是企业级区块链解决方案,适合用于定制各种特定业务的联盟链,包括金融领域的应用场景。区别在于 Fabric 以智能合约为导向,而 Onchain DNA 则以数字资产为导向;前者更适合开发复杂的自定义业务流程,而后者则更适合于构建以数字资产为核心的金融业务系统或权益登记流转系统,且具有较强的扩展性。

    Corda 的定位是用于银行间业务的“分布式数据库”,它摒弃了区块和链式结构,更好地把参与者的业务数据区隔开来;但引入了公证人的角色,网络结构较为固定不具灵活性和扩展性,且与现有的银行体系的运作方式差别不大。

    关于区块链,程序员需要了解什么
    区块链现有应用案例分析
    产品定位的“生死劫”
    区块链领域最具人气的平台以太坊
    区块链架构、跨链和演进
    以太坊账户数据存储解读
    区块链在版权保护方面的探索与实践
    区块链技术在零售供应链的商业化应用
    区块链技术实现及在政务网的应用
    将区块链用于京东供应链溯源防伪

    阅读全文: http://gitbook.cn/gitchat/geekbook/5a5eb07bdff55721bc1dcaee

    展开全文
  • 基于PBFT,Antshares实现了他们的dBFT(授权的拜占庭差错容忍)。在dBFT中,一些专业的节点投票来记录交易。  DPOS(授权的权益证明)。PoS和DPOS之间主要的不同是PoS是直接民主的,而DPOS是代议制民主的。利益...
  • 几大主流区块链开源技术的比较

    万次阅读 2019-05-18 08:12:01
    https://github.com/antshares/antshares ,采用改进的拜占庭容错算法-dBFT共识算法,支持智能合约,目前重点领域在数字资产应用,框架核心开发语言C#。 最后,汇总一下几大主流开源技术的比较。   名称 ...
  • 区块链:术语

    千次阅读 2019-05-08 09:54:36
    antshares 小蚁 appcoins 应用币 API 应用程序接口 App Coins 应用币 architecture 架构 assembling 集合 attacks 攻击 attack vectors 攻击...
  • 2017年6月,团队不仅把名字从AntShares改为NEO,而且重新聚焦于市场营销,并取得了巨大的成功。NEO的目标,虽然使用了和ETH一样的技术,但是目标是成为 新智能经济 的平台。 简单说就是,ETH是在为当前的新...
  • [转]区块链主流开源技术体系介绍

    千次阅读 2018-01-15 15:50:54
    区块链技术如今是非常火热,不仅让金融家和创投家趋之若鹜,如今已经在多个领域遍地播种。作为拥有锐利触角的创业家们,是否也想将区块链集成到你们现有的应用中去,而作为IT技术工程师的你,是否也是跃跃欲试,想...
  • 区块链相关术语(中英对照)

    万次阅读 2017-11-14 08:35:07
    antshares 小蚁 appcoins 应用币 API 应用程序接口 App Coins 应用币 architecture 架构 assembling 集合 attacks 攻击 attack vectors 攻击向量 ...
  • 区块链技术综述

    万次阅读 2017-10-31 22:32:38
    一篇区块链的综述文章,将区块链的基本概念讲述清楚。
  • NEO已从原始的“ Antshares”重新命名 NEO标记化资产所有权的证明,而不是资产本身的证明,因此考虑到了股份,股本和资产转让可能伴随的所有法律复杂性和义务。这是一个简单的扩展程序,显示NEO价格和更多信息(要...
  • 小蚁(Antshares)是一个定位于资产数字化的公有链,将实体世界的资产和权益进行数字化,通过点对点网络进行登记发行、转让交易、清算交割等金融业务的去中心化网络协议。它采用社区化开发的模式,在架构上与Onchain...
  • 小蚁(Antshares)是一个定位于资产数字化的公有链,将实体世界的资产和权益进行数字化,通过点对点网络进行登记发行、转让交易、清算交割等金融业务的去中心化网络协议。它采用社区化开发的模式,在架构上与Onchain...
  • 10分钟弄懂当前各主流区块链架构

    万次阅读 多人点赞 2018-07-22 13:28:23
    小蚁(Antshares)是一个定位于资产数字化的公有链,将实体世界的资产和权益进行数字化,通过点对点网络进行登记发行、转让交易、清算交割等金融业务的去中心化网络协议。它采用社区化开发的模式,在架构上与Onchain...
  • 小蚁(Antshares)是一个定位于资产数字化的公有链,将实体世界的资产和权益进行数字化,通过点对点网络进行登记发行、转让交易、清算交割等金融业务的去中心化网络协议。它采用社区化开发的模式,在架构上与Onchain...
  • 小蚁(Antshares)是一个定位于资产数字化的公有链,将实体世界的资产和权益进行数字化,通过点对点网络进行登记发行、转让交易、清算交割等金融业务的去中心化网络协议。它采用社区化开发的模式,在架构上与Onchain...
  • 小蚁区块链,开源地址为https://github.com/antshares/antshares,采用改进的拜占庭容错算法-dBFT共识算法,支持智能合约,目前重点领域在数字资产应用,框架核心开发语言C#。 最后,汇总一下几大主流开源技术的...
  • NEO NEO最初称为Antshares,由2014年的Erik Zhang和Da Hongfei创立。在2017年成为NEO。与以太坊不同,它不仅限于一种语言。 您可以使用不同的编程语言在NEO上构建DApp,包括C#和Java。 经验丰富的用户可以轻松地在...
  • 《区块链:从数字货币到信用社会》长铗、韩锋等 相较于通常意义上的数字货币,区块链与互联网TCP/IP协议更为相似。区块链则为价值互联网提供了理论基础。 在互联网上进行价值交换,需解决三个问题: ...

空空如也

空空如也

1 2 3 4 5 6
收藏数 115
精华内容 46
热门标签
关键字:

AntShares