Zhuang's Diary

言之有物,持之以恒

参考链接==>https://thenextweb.com/podium/2019/05/05/ibms-hyperledger-isnt-a-real-blockchain-heres-why/

选型 Hyperledger Fabric 作为联盟链需要考虑的几个细节问题

1.区块链的智能合约语言如何安全、简单地表达出复杂的业务逻辑?
2.那些目光长远的企业还会考虑到被选择的区块链将来能否可以轻松地与其他公有区块链或私有区块链进行互操作?

3.如何保证公钥签名的有效性?

4.扩展性,升级性如何?

Hyperledger Fabric是如何工作的

区块链的核心是一个去中心化的不可篡改的账本,账本中存储着事件或者交易,而往账本中加入哪些数据完全由共识机制来决定。在比特币和以太坊这样的公有区块链中,这种共识是通过工作量证明或称“挖矿”来实现的。在许可区块链中,参与者提供密码学签名来对共识的内容进行投票,从而达成共识。无论是哪种方式,都不会有中央机构进行干预。

在 Hyperledger Fabric 所提供 API 的帮助下,一笔交易要经过如下步骤:

1)一笔交易预提案被提交后;2)由背书节点( endorsing peer )通过智能合约语言 chaincode 执行它的逻辑,同时它会查询状态数据库并生成要使用到的读写集( RWset );3)之后它还会连同生成的读写集返回交易预提案的回应;4)接下来,系统会将带有读写集的交易预提案提交;5)Ordering服务会把一批次的交易加入到区块中;6/7)所有的节点都会收到订购服务发来的区块信息,但它们需要验证区块中的交易信息来保证区块链中数据的安全性。

结论一:共识过程无容恶、容错能力

在上述的第4步是有Application(SDK)端发出的。而Application相比区块链节点更加不容易被信赖。例如,Application可在一个交易背书成功的情况下,不将交易完成第4步,即不提交给到Orderer;Application也可在一个交易背书成功的情况下,适时(延迟)再行提交给到Orderer;Application也可在一个交易背书成功的情况下,再行将后续背书成功的交易先行提交,前序交易在其后再行提交。凡此等等,都使其无法防止恶意交易、错误交易。

结论二:Channel 设计带来的复杂性远远高于可用性,Private data 设计无容恶和容错能力

Hyperledger Fabric 使用 channel(通道)来保证参与者之间的隐私性。这种隐私性是私有“企业”区块链的一个重要特性,但它必然会带来一些折衷,也会大大增加区块链的复杂性。但从企业区块链需要的可拓展性方面来说,多链解决方案并不是一个好的选择,因为这样做会使得部署过程太过于复杂、节点分布不均匀、智能合约不可靠、还会大大增加潜在的故障点。且,合约无法跨 channel 执行,channel 内的数据形成了新的数据孤岛。

在 2.0 版本中,Private data相关交易在事先配置好的参与方内使用,交易通过达到签名门限数量决定该交易是否通过。门限数设置较高,则无法具备容错能力;门限数设置较低,则无法证实其容恶能力。

结论三:随着网络的扩展,交易延迟加重,网络性能堪忧

从根本上来说 Hyperledger Fabric 的架构根本无法在保持最佳性能的同时进行扩展。在 2.0 版本中,Orderer 集群从 Kafka&Zookeeper 切换至 raft,将改善 Orderer 集群的多中心部署,但交易延迟没有改善。Hyperledger Fabric 区块链在部署之后的性能指标并不尽如人意,随着节点的增加性能还会迅速下降,而且它所宣称的性能是单通道时的性能:如果你想跨过多个通道与整个区块链网络进行交互,这些所谓的性能指标没有任何意义。

对于每个独立的通道,区块链的每秒处理交易量很难突破800这个大关,但即使是拥有16个通道配置的区块链也几乎不能达到1500TPS,若区块链一直维持吞吐量上限运行,其延迟时间可能会达到10到20秒。

最近一些旨在加快 Hyperledger Fabric 运行速度的研究使得其每秒处理交易量能达到惊人的20000,但性能大幅度提升的背后是研究人员对 Hyperledger Fabric 架构的大规模“魔改”,这使得 Hyperledger Fabric 已经成一个近似的区块链变成了一个四不像:背书节点(Endorsers)不再充当验证者而 Kafka 被认定为唯一可行的订购服务。最后,这些仍然只是单通道的性能,这意味着它与区块链作为共享可信来源的整个理念相违背。

结论四:Chaincode与其执行环境的安全性低

Hyperledger Fabric 的智能合约(称为链码“Chaincode”)可以用多种编程语言编写,其中包括常见的 Javascript 语言以及 Go 语言。但使用开发人员十分了解的通用编程语言开发是一把双刃剑,它在大大简化开发过程的同时,在安全性方面与专为区块链开发的编程语言相比大大弱化。

在这时如果代码有缺陷或不正确(因为它不是专为区块链设计的)那么可能会造成数百万美元的损失。因此我们认为智能合约语言必须专为区块链设计且为安全性做出了优化。Chaincode 在这几个方面可谓是彻彻底底地失败了,我们发现被誉为开发人员的第一个程序 “Hello World” 在其他语言中仅需几行就可以实现,而在 Chaincode 中居然需要150行之多。代码越多,可能存在的漏洞就越多。这么大数量的代码中可能隐藏着很多能造成数百万美元损失的漏洞。甚至在 Chaincode 的执行环境中可以发送 http request,将合约运行中的运行变量值发送给到任意客户端。

实际上,Hyperledger Fabric 以及 R3 Corda 都因为架构的完全不兼容而与公有区块链切割开来,这里面也有智能合约的责任,因为它们的智能合约语言无法在公有区块链和私有区块链中无缝切换。联盟链更加希望自己的资产可以对公有区块链上的客户使用,部署在公有区块链上的去中心化应用程序也会希望将隐私数据存储在联盟区块链中。

更多参考内容==>http://www.chinaz.com/blockchain/2019/1125/1067365.shtml

与 IBM 的 Hyperledger 不同,Quorum 的区块链要简单得多,但在为保密交易构建架构时,它仍然面临着复杂性问题。现在,Quorum 的几个关键开发人员已经离开团队,去开发新的区块链项目,使用 Quorum 的客户是否会获得强大的支持,这仍有待观察。

也许让 Quorum 面临最大风险的是,这项技术是由一家大银行管理,而不是一家专门的技术公司。对摩根大通来说,Quorum 永远是一种产品,而不是其核心业务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
pragma solidity >=0.6.0 <0.7.0;

contract UserCrud {

// 业务主数据结构
struct UserStruct {
bytes32 userEmail;
uint userAge;
uint index;
}

// 将业务主数据存储在 mapping 中,用户地址是用户数据的索引
// address(key) ---> UserStruct
// 0x1 ---> userEmail:alice@co.com, userAge:22
// 0x2 ---> userEmail:bob@home.com, userAge:44
// 以上为 userStructs 中的存储内容
mapping(address => UserStruct) private userStructs;
// 用户地址被收集进入一个数组 userIndex
address[] private userIndex;
// 反馈新用户
event LogNewUser (address indexed userAddress, uint index, bytes32 userEmail, uint userAge);
// 反馈用户更新
event LogUpdateUser(address indexed userAddress, uint index, bytes32 userEmail, uint userAge);
// 反馈用户删除
event LogDeleteUser(address indexed userAddress, uint index);
// 判断入参的用户是否有与记录中的用户重合,即用户是否已经存在
function isUser(address userAddress)
public
view
returns(bool isIndeed)
{
if(userIndex.length == 0) return false;
return (userIndex[userStructs[userAddress].index] == userAddress);
}
// 插入新的用户主数据
function insertUser(
address userAddress,
bytes32 userEmail,
uint userAge)
public
returns(uint index)
{
if(isUser(userAddress)) {revert("this user already exist.");}
userStructs[userAddress].userEmail = userEmail;
userStructs[userAddress].userAge = userAge;
userIndex.push(userAddress);
userStructs[userAddress].index = userIndex.length-1;
emit LogNewUser(
userAddress,
userStructs[userAddress].index,
userEmail,
userAge);
return userIndex.length-1;
}
// 删除旧的用户主数据
function deleteUser(address userAddress)
public
returns(uint index)
{
if(!isUser(userAddress)) {revert("only other user can deleteUser.");}
uint rowToDelete = userStructs[userAddress].index;
address keyToMove = userIndex[userIndex.length-1];
userIndex[rowToDelete] = keyToMove;
userStructs[keyToMove].index = rowToDelete;
userIndex.pop();
emit LogDeleteUser(
userAddress,
rowToDelete);
emit LogUpdateUser(
keyToMove,
rowToDelete,
userStructs[keyToMove].userEmail,
userStructs[keyToMove].userAge);
return rowToDelete;
}
// 获取用户主数据
function getUser(address userAddress)
public
view
returns(bytes32 userEmail, uint userAge, uint index)
{
if(!isUser(userAddress)) {revert("only exist user can be run by getUser.");}
return(
userStructs[userAddress].userEmail,
userStructs[userAddress].userAge,
userStructs[userAddress].index);
}

function updateUserEmail(address userAddress, bytes32 userEmail)
public
returns(bool success)
{
if(!isUser(userAddress)) {revert("only exist user can updateUserEmail.");}
userStructs[userAddress].userEmail = userEmail;
emit LogUpdateUser(
userAddress,
userStructs[userAddress].index,
userEmail,
userStructs[userAddress].userAge);
return true;
}

function updateUserAge(address userAddress, uint userAge)
public
returns(bool success)
{
if(!isUser(userAddress)) {revert("only exist user can updateUserAge.");}
userStructs[userAddress].userAge = userAge;
emit LogUpdateUser(
userAddress,
userStructs[userAddress].index,
userStructs[userAddress].userEmail,
userAge);
return true;
}

function getUserCount()
public
view
returns(uint count)
{
return userIndex.length;
}

function getUserAtIndex(uint index)
public
view
returns(address userAddress)
{
return userIndex[index];
}

}

remix 调试如下图:

将上述模型进一步提炼为库文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
pragma solidity 0.5.1; 

/*
UnorderedKeySet v0.93
Library for managing CRUD operations in dynamic key sets.
https://github.com/rob-Hitchens/UnorderedKeySet
*/

library UnorderedKeySetLib {

struct Set {
mapping(bytes32 => uint) keyPointers;
bytes32[] keyList;
}

function insert(Set storage self, bytes32 key) internal {
require(key != 0x0, "UnorderedKeySet(100) - Key cannot be 0x0");
require(!exists(self, key), "UnorderedKeySet(101) - Key already exists in the set.");
self.keyPointers[key] = self.keyList.push(key)-1;
}

function remove(Set storage self, bytes32 key) internal {
require(exists(self, key), "UnorderedKeySet(102) - Key does not exist in the set.");
bytes32 keyToMove = self.keyList[count(self)-1];
uint rowToReplace = self.keyPointers[key];
self.keyPointers[keyToMove] = rowToReplace;
self.keyList[rowToReplace] = keyToMove;
delete self.keyPointers[key];
self.keyList.length--;
}

function count(Set storage self) internal view returns(uint) {
return(self.keyList.length);
}

function exists(Set storage self, bytes32 key) internal view returns(bool) {
if(self.keyList.length == 0) return false;
return self.keyList[self.keyPointers[key]] == key;
}

function keyAtIndex(Set storage self, uint index) internal view returns(bytes32) {
return self.keyList[index];
}

function nukeSet(Set storage self) public {
delete self.keyList;
}
}
// 合约只需要维护keyList即可
contract UnorderedKeySet {

using UnorderedKeySetLib for UnorderedKeySetLib.Set;
UnorderedKeySetLib.Set set;

event LogUpdate(address sender, string action, bytes32 key);

function exists(bytes32 key) public view returns(bool) {
return set.exists(key);
}

function insert(bytes32 key) public {
set.insert(key);
emit LogUpdate(msg.sender, "insert", key);
}

function remove(bytes32 key) public {
set.remove(key);
emit LogUpdate(msg.sender, "remove", key);
}

function count() public view returns(uint) {
return set.count();
}

function keyAtIndex(uint index) public view returns(bytes32) {
return set.keyAtIndex(index);
}

function nukeSet() public {
set.nukeSet();
}
}

另外 rob-Hitchens 使用 solidity 写了一个红黑树,地址如下:

https://github.com/rob-Hitchens/OrderStatisticsTree

有向图:

https://github.com/rob-Hitchens/GraphLib

关联文档:

  1. 智能合约-CURD的详细分析
  2. 智能合约-自毁模式
  3. 智能合约-工厂合约模式
  4. 智能合约-名字登录模式
  5. 智能合约-退款方式

跟别人一起申请专利好吗?

合作申请的情况并不鲜见,很多企业或个人都存在合作申请的情况。从统计信息来看,以下三种情况最常见:

情况一 共同研发

共同研发即共同申请人之间共同为一件专利创新作出了有益贡献,因此,其专利申请人为双方或多方共同申请,这类情况完全符合合作申请的要求,也是最常见的一种情况。

情况二 委托研发

最常见的委托研发,是甲方提出研发需求,乙方为响应研发需求,给出解决方案。这种情况理论上专利申请权可以是乙方,即问题的实际解决方案的提供方。

情况三 母子公司

如国家电网公司和中国石油化工股份有限公司,由于管理制度的设立,使众多专利申请均以共同申请的方式提交到国家知识产权局。如果以子公司享用了母公司的特殊技术资源为理由,也是可以说得过去的。

但是,不管是共同研发、委托开发,还是母子公司,在面对共同的专利申请时,都可以采用法律约定的形式,在双方的合作中约定专利申请的权利及归属。并且,专利权的最终归属以双方约定为准。

不管怎样,既然选择了合作申请,自然有选择合作申请的理由。对申请人来说,合作申请有哪些利弊呢?

优点一:可以共同分担费用

众所周知,专利申请过程中及专利授权后,都有费用,随着专利数量增多,其费用也越来越多,而年费则随着专利年限增加趋势更快。

因此,一些专利申请较多的企业慢慢发现专利年费成为一种负担。

如果选择共同申请,则可以双方约定共同承担专利成本,减轻企业压力。

优点二:有收益后可以共同分享利益

《专利法》规定:合作申请的专利,许可、转化后的收益需要双方共同分配。也就是合作申请后,专利如果有第三方使用,则共同申请人中的任一方都有权分享专利的收益。

优点三:促进合作

很多能申请专利的技术,是技术创新者多方合作的共同成果。在技术分工越来越细化的今天,大家共同合作取得创新成果,是很常见的合作模式。

将创新成果共同申请专利,共同分担费用、共享未来收益,是很多人愿意选择的合作方式。因此,共同申请专利某些程度上可以促进合作。

优点四可双方均享有专利实施权,在专利数量统计中均有效

《专利法》规定:合作申请的专利,其自主实施无需对方同意,也不需要分配利益。因此,双方都可以自由实施专利权记载的创新内容。但是在专利持有量统计时,双方均拥有此专利权。

如国家电网公司和中国石油化工股份有限公司,就是这样的情况,他们的专利申请量第一,与他们合作申请专利的共同申请人虽然分散,但同时也分别拥有多项专利申请。

任何事情有利有弊。

既然合作申请有这么多好处,是否会有问题呢?

弊端一:一些法律手续需要双方共同签署,麻烦

《专利法》规定:合作申请专利的,在专利申请、转让、排他许可、独占许可、复审、无效、放弃、撤销等过程中,均需要各合作方共同决定,共同签字盖章,相对于独立申请,其手续更繁琐。

弊端二:专利权不完整,融资时受限

基于上述弊端可以看出,合作申请的专利,其专利权不完整,不管是在专利申请时,还是在后期专利权实施过程中,都要经过共同申请人同意。投资在投创新技术项目时,面对专利权不完整的情况,往往会选择迟疑的态度。

因为很多专利技术往往会让投资人认为该公司在此技术上设有技术壁垒,给竞争对手增加难度,提高项目的竞争实力。如果专利是共同申请的,则需要做专利权转让或说明。

但是,在很多实际合作项目中,当投资人关注并在意专利权归属时,共同申请人放弃专利权或作出转让的条件会比较苛刻。

有的甚至会因为双方在利益面前难以谈拢而导致融资失败。使专利共同申请变成融资的一个障碍,这种情况对于一些科技创新型的初创公司影响会更大一些,尤其需要在合作前期规划清晰。

因此,基于企业自己的发展规划,如何与外包方合作,专利申请权如何处置,企业创始人在申请时仍需谨慎行事。

参考链接 ==> https://github.com/primasio/daap/blob/master/README-cn.md

  • 安永(EY)之前发布的Nightfall项目,实现了对以太坊上ERC-721类资产私密转账的支持。但是ERC-721的使用使得资产的注册是必须公开的,在资产注册以后转入一个私密合约,之后的转移操作才是对外不可见的。另外,对于文章、图片等类型的数字资产,最重要的流通方式不是所有权的转移,而是使用权的购买。比如文章的转载权购买、图片的购买使用等。对于这类数字资产,使用NFT模型抽象是不够的,也就更加无法实现使用权的私密购买。
  • ZoKrates工具包中,具体的零知识证明算法使用了Groth 16。实现协议时也可以使用Bellman工具包,或者将算法替换为Bulletproofs或者是Sonic算法,以实现更好的性能,以及去除对可信初始化的依赖。
  • AZTEC协议 实现了基于ERC20资产的交易值隐私。易于同态加密和零知识证明算法。目前已经在MakerDAO的 DAI token 中上线使用。同时,在EIP1108中予以完成。

Whisper是Ethereum P2P协议的一部分,可以让消息在同一个区块链内的用户之间传递。

Whisper是独立于区块链之外的协议,智能合约不能够使用。

开启Whisper协议, geth -shh

节点默认不会回复消息。所以必须直连到接收人,否者消息将无法发送。