Zhuang's Diary

言之有物,持之以恒

情商是一种个人能力:这些能力决定我们如何进行自我管理

  1. 自我意识
    • 情感的自我意识:了解个人情感及其影响;用直觉引导决策。
    • 准确的自我评估:了解个人的优缺点。
    • 自信:准确感知个人的价值和能力。
  2. 自我管理
    • 情感的自我控制:控制消极情感和冲动。
    • 透明度:表现出诚实、正直以及可信度。
    • 适应能力:灵活应对不断变化的情况,客服阻碍。
    • 成就感:提升表现以满足卓越性的内在标准的驱动力。
    • 主动性:时刻准备采取行动,抓住机遇。
    • 积极乐观:看到事情积极的一面。
    • 社会能力:这些能力决定我们如何处理人际关系。
  3. 社会意识
    • 同理心:感受他人的情感,了解他人的观点,主动了解他人的关注点。
    • 组织意识:了解组织的现状、决策网以及组织政治。
    • 服务:了解并满足员工、客户或顾客的需求。
  4. 关系管理
    • 鼓舞人心的领导:用一个令人信服的愿景指导并鼓舞员工。
    • 影响:运用各种策略增强说服力。
    • 开发他人能力:通过反馈和指导增强他人的能力。
    • 改变刺激因素:设定新的方向,启发、管理并领导员工。
    • 冲突管理:解决分歧。
    • 团队合作和协作:合作与团队建设。

转自 陈果George 的公众号文章。

IT、咨询、工程设计等等以人员作为主要资源,公司内部为专业/行业/区域等多维度矩阵式组织,面向客户以“项目”为形式开展服务交付的商业模式,我称为“专业服务项目型公司”,运维和产品业务不在此列。

项目型公司的主要运营流程是:

**销售管理:**开展销售活动,管理客户(account)和商机漏斗(pipeline),根据不同的“成单概率”来分别管理商机,驱动销售转化效率

**合同管理:**客户签单,亦即签署项目合同,之前,需要进行合同评审, 包括法务、价格、资源、技术方案、风险等控制环节

**立项管理:**根据客户合同进行项目立项,驱动合同向收入的转化效率和速度,尤其是上市公司,需要达成当期的财务目标

**项目管理:**向客户交付项目,这类公司运营特点是项目有一定的周期,短则几个月,长则几年,公司的利润由项目利润构成,必须加强项目过程控制,方能确保公司利润目标达成,因而项目过程中一方面要确保项目进度,驱动收入达成,另一方面要确保项目质量,控制风险,按月滚动预测未来的资源投入以及到项目结束时的利润。

**资源管理:**项目主要成本是人工资源投入,作为项目型企业组织结构的特点,这些专业人员人事关系上属于专业资源池,根据需要在项目中开展工作,填报项目工时,相应地依据其工时标准成本计入项目成本,“收费工时比率”(Utilization或billability)是公司运营效率的重要指标,从损益表角度看,资源池的总体工时,能被记入项目的部分成为能转化收入的成本,而剩余不能被记入项目的部分,则成为公司管理费用

**费用管理:**其他成本、费用的管理,包括项目相关的分包、差旅,以及公司管理费

**产能管理:**公司的不同服务产品(Offering)需要不同专业能力的资源,前端销售以及项目交付产生的资源需求和资源池里专业合适的资源供给需要滚动匹配,这就是项目型公司的供应链管理,保证产销平衡,跟制造业供应链管理的原理完全一样,组织上,类似于制造业的供应链管理中心,服务公司也要有资源(Resource)和产能(Capacity)管理(R&CM)部门。

**体验管理:**服务业是people business,只有满意敬业的员工,才有满意付钱的客户,才会有公司的利润,因而需要密切监控员工和顾客的满意度。

基于这样的运营体系,公司在周度、月度、季度的经营分析上,通常需要利用这些KPI,来分析、监控公司以及各事业部的运营情况,如上图所示。

需要说明,这些KPI取数的具体口径和时间点,取决于管理需要和会计核算原则,有些按月,有些可以到周,有些为当期数或当期(季/年)累积数,有些为到期末(季/年)预测数:

**1、利润KPI:**公司及各条线事业部的经营毛利

**2、收入KPI:**各条线事业部的营业收入,由项目转化而来;新签单以及在手订单未交付额(backlog)是收入来源

**3、合同前收入KPI:**客户已经确认订单,但是合同尚处于签署流程中,尚未开首付款发票,本着谨慎会计原则,在合同前开工,提前转化收入,这对上市公司增加收入具有重要意义

**4、签单KPI:**实际已签署合同签署金额(signings)

**5、商机KPI:**按预计金额、成单时间和成单概率报告的数字,滚动的签单预测尤为重要,在一个季度内,对于成单概率高(例如90%,75%阶段)的商机,要按周承诺(commit)签单数字,对重点销售项目要明确提出并跟进关单措施,如果出现承诺订单滑掉,要紧抓中概率(例如50%阶段)商机;同时,对本季以后的未来半年到一年的商机要有一定的可视度,保证运营健康

**6、交付质量KPI:**从各个事业部角度,要制定总体项目管理的综合性评价指标,这是一个动态性指标,按月按项目更新并汇总,包括预测项目毛利率,预测成本离计划成本的偏差、流程合规性要求等,同时,对重点项目和重点负面问题项目(严重成本超支)要专项列示,并提出改进措施

**7、资源管理KPI:**如果实现了有效的工时管理制度,资源利用指标可分为收费(billable/chargeable)利用率和有效(productive)利用率,后者包括了前者以及研发、售前支持等有效但不产生收入的活动,资源利用率是公司的生命线指标,如果低于一定的值,说明资源严重闲置,要不是产能管理的问题(签回来的项目没人做,闲的人又不会做新签回来的项目),要不就要限制招人甚至裁员了。

**8、分包KPI:**分包需要占成本一定的比率,适当使用分包有助于提高资源利用率;专业服务公司使用分包的主要目的不是降低成本,而是优化资源利用率。

**9、应收和坏账KPI:**半年以上的应收账、坏账计提、已计提坏账回收等分事业部的指标,以及重大项目列示,对利润有直接影响

**10、需求和能力KPI:**和供应链管理完全一样,需要从需求(demand)和供给(supply)两方面,从专业能力维度(打个比方,例如咨询公司的战略咨询、供应链咨询、财务咨询、人力资源咨询、技术咨询)区分,从时间维度看给出未来一段时间已上项目、计划出项目、被项目预定、资源缺口等数据,并给出培训、外包、招聘、招聘计划到岗等措施

**11、体验KPI:**公司员工在项目中工作,项目中进行周期性员工满意度调研,形成综合的员工满意度指标;客户满意度指标原理类似。

专业服务项目型公司一般基于下图这样的组织架构和责任中心体系来开展运作:矩阵式的客户维度和专业维度的负责人(例如咨询公司的合伙人)开展合作;每个项目的主责,可能属于两个维度中的任何一个;管控上,要做到组织利润中心和项目利润中心的权责匹配。

专业服务公司的核心业务流程是销售管理和项目管理,相应地支持性流程有财务管理、资源管理以及运营监控等。运用IT工具来支撑这些业务流程,有利于加强项目管控、促进协作、控制风险。

传统ERP软件的项目模块(例如SAP ERP的PS模块)解决了项目供应链、项目计划/活动和项目成本等项目相关业务和管理活动的集成,而专业项目管理软件(例如著名的Oracle Primavera)则专长于复杂的项目计划、项目合同、资源和排程优化等。然而,由于“企业项目”的多种特性类型,通用项目型ERP很难具体适用于企业各种类型的项目管理。

在项目型ERP领域里有20多年历史的SAP ERP,直到2014年后才推出了适用于专业服务项目管理的商务项目管理(Commercial Project Management)模块,简称CPM,下图展示了SAP CPM及覆盖的业务流程范围。CPM是一个架在SAP ERP标准的项目模块(SAP ERP-PS)和商务智能(SAP BO)之上的计划和分析工具;不过,在新版S/4 HANA以及S/4 HANA Cloud里,CPM已经成为标准功能。

![](项目型公司的商

来源:SAP网站

业务管理相关的IT系统主要有:

核心业务系统 —— 管理核心业务流程

  • 销售管理CRM系统
  • 项目管理ERP系统
  • 财务系统(和项目管理ERP可以属于一个套件)

辅助系统 —— 辅助业务流程

  • 合同管理系统
  • 资源管理系统
  • 商务智能报表系统

其他相关的应用系统 —— 支持体系,但是和业务系统有一定的相关性,可以建立系统集成关系

  • HR系统
  • 招聘系统
  • 外包采购系统
  • 差旅报销系统
  • 预算管理系统

**其他工具系统,**例如:协作工具、敏捷工具、生产平台(例如DevOps)、文档管理、知识管理、培训系统等等

将总体IT应用架构描绘示意如下:

CRM系统

用CRM系统覆盖上述流程,基于系统的支持,可以为经营管理提供如下重要信息:

  • 客户:维护客户信息,一个客户下可以有多个商机
  • 商机:管理商机相关信息,跟踪围绕商机采取的销售活动,其中商机金额和销售阶段(或者成单概率,例如:100%-已签单, 90%-合同流程中, 75%-已中标, 50%-赢面较大,25%-机会评估中)是开展销售控制的主要指标
  • 销售管道报表:总经理、销售负责人和财务负责人根据公司级或事业部级的汇总销售管道报表,推动销售达成,支持对签单及收入作出准确预测

商务合同系统

由于CRM系统主要处理客户、商机、管道的管理,可能不会覆盖到详细的合同、报价等流程,有些对这些流程的内控处理要求高的公司,会有专门的信息系统来管理这个过程。CRM软件和ERP软件多少都会覆盖到这个部分,企业可以根据实际情况来决定架构规划,其通常功能包括:

**方案评估:**向客户提交方案建议书或投标方案时,进行方案的技术评估、风险评估,按权限审批

**投标和报价流程:**处理投标的商务流程,投标报价按权限审批

**合同审批:**进单过程中,对合同(包括:法务条款TOB和工作内容文本SOW)的各级评审并按权限审批,例如:

  • 法务评审
  • 财务评审
  • 技术方案评审
  • 资源评审
  • 质量标准/风险评审
  • 其他合规性评审(例如数据安全、贸易限制等)

项目ERP系统(项目财务)

项目型ERP是专业服务项目型公司最核心的业务系统,实现了项目管理的财务业务一体化,从项目往上汇总,形成反映公司运营状况的财务信息。我将项目管理的端到端流程梳理如下:

项目型ERP所覆盖的功能主要包括:

  • 项目立项,建立WBS、资源计划、成本预算及项目计划
  • 安排项目资源(即人员)
  • 项目人员每周填报工作,通过方便的time sheet管理,归集项目直接人工成本
  • 其他成本、费用信息可以从财务系统中导入
  • 管理项目变更
  • 月度成本和收入确认
  • 月度进度更新,ETC/EAC成本滚动预测,相应更新项目预算
  • 项目里程碑确认和通知开票
  • 项目状态报表

“项目”是公司最小颗粒度的利润中心,是公司收入和利润的根本来源。从公司管理的角度,项目管理需要围绕下图的“项目财务模型”,在报价、合同以及项目执行的这三个环节,动态地关注项目成本和项目毛利(GP):

专业服务公司的大多数客户项目都是价格固定、按照工作范围(SOW)投入资源来交付,按里程碑开票收款,这类固定价格项目的期间收入确认原则一般采用“完工百分比(POC)”法,而数量相对较少的运维类项目采用“期间均摊法”确认收入,**人天类项目(T&M)**采用“按确认人天开票”确认收入。

POC方法要求项目过程中持续维护项目预算,按月归集并确认成本,从而确认收入。不仅如此,为了准确达成公司经营预算,及时发现并控制经营风险,因而,在项目执行中,项目经理及交付责任人(DO)每月开展滚动的项目财务预测显得尤其重要。

资源管理系统

“资源”是指通过投入时间进项目工作,可以转化为收入的专业人员,例如项目经理、咨询顾问、工程师等。资源管理系统的主要功能是:

  • 技能管理:管理每个资源的技能、技能类型分群等
  • 资源计划:相当于制造业的物料需求计划(MRP),将资源技能和项目需求进行匹配,综合管理:资源预留(根据销售或项目情况,book资源)、资源进项目和出项目的时间点预测、需求平衡等等
  • 资源管理执行:资源上项目、下项目的过程管理

软件公司采用的团队协作工具,例如Jira,也能很好地管理资源,并跟项目ERP和财务管理系统集成:

财务系统

专业服务项目型公司的财务系统和企业标准财务软件并无太大区别,因而本文不再赘述。财务系统和前述的项目ERP系统可以是一个套件,例如SAP、Oracle,也可以分别部署,其覆盖的主要内容有:

  • 成本管理:包括成本中心、成本要素和成本对象的管理,从部门、项目、活动类型等多个维度,进行成本费用的归集和分析
  • 应收账管理:尤其关注半年以上账龄的应收账状态,以及坏账计提和回收
  • 总帐管理

管理分析报表

前述六个模块是运营管理的各个环节,这些运营系统数据统一注入企业数据仓库(EDW),通过商业智能平台,向管理者提供各种分析报表。

参考链接 ==> https://github.com/blockapps/blockapps-sol

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
contract FSM {

struct Transition {
uint state;
uint evt;
uint newState;
}

// expose the transitions to the outside world
Transition[] public transitions;

mapping (uint => uint) stateMachine;

function FSM(){
}

function handleEvent(uint _state, uint _event) returns (uint){
return stateMachine[calculateKey(_state,_event)];
}

function addTransition(uint _state, uint _event, uint _newState) {
stateMachine[calculateKey(_state, _event)] = _newState;
transitions.push(Transition(_state, _event, _newState));
}

function calculateKey(uint _state, uint _event) returns (uint){
return (_state * 1000) + _event;
}
}

参考链接==>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. 智能合约-退款方式