数据专栏

智能大数据搬运工,你想要的我们都有

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

「深度学习福利」大神带你进阶工程师,立即查看>>>
http://www.scs.stanford.edu/~dm/home/papers/kpos.pdf
该作者的主页还有更多有意思的论文,可以看看。 看域名是斯坦福的学生哥。
区块链
2018-04-27 22:39:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
MetaMask是一个开源的以太坊钱包,能帮助用户方便地管理自己的以太坊数字资产, 但在国内由于网络原因,你可能下载不了。本文将介绍如何解决metamask钱包无法下载的问题。
方法1:本地包下载和安装
你可以按照以下操作步骤完成MetaMask钱包的安装:
STEP 1 点击链接: https://github.com/MetaMask/metamask-extension/releases
STEP 2 点击 “Assets” 列表下的 "metamask-chrome-4.4.0.zip" (或你看到的最新版), 下载并解压此压缩包
STEP 3 用谷歌浏览器 (Chrome) 打开链接: chrome://extensions:
选择 "加载已解压的扩展程序” (Load unpacked extension),在跳出菜单中选择刚才解压的文件包
STEP 4 网页将跳转到新的页面,选择 “Get Chrome Extension"
执行上述步骤后,浏览器右上角将出现一个新图标(MetaMask 狐狸插件图标), 成功安装 MetaMask 钱包。
方法2:在线安装
如果你可以直接访问google,也可按照一下步骤快速安装 MetaMask 钱包:
STEP 1 点击链接:
https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn
STEP 2 点击窗口右上角 “ADD TO CHROME”(添加至Chrome浏览器)
STEP 3 点击新窗口中 “Add extension”
STEP 4 执行上述步骤后,浏览器右上角将出现一个新图标(MetaMask 狐狸插件图标)
如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
区块链
2018-04-27 19:20:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
星际文件系统(InterPlanetary File System,缩写IPFS)是一个旨在创建持久且分布式存储和共享文件的网络传输协议。在IPFS星际文件系统网络中的节点将构成一个分布式文件系统。该技术是一种内容可寻址的对等超媒体分发协议。它是一个开放源代码项目,自2014年开始由Protocol Labs在开源社区的帮助下发展。其最初由Juan Benet设计。
IPFS是一个对等的分布式文件系统,它尝试为所有计算设备连接同一个文件系统。在某些方面,IPFS类似于万维网,但它也可以被视作一个独立的BitTorrent群、在同一个Git仓库中交换对象。换种说法,IPFS星际文件系统提供了一个高吞吐量、按内容寻址的块存储模型,及与内容相关超链接。这形成了一个广义的Merkle有向无环图(DAG)。IPFS星际文件系统结合了分布式散列表、鼓励块交换和一个自我认证的命名空间。IPFS没有单点故障,并且节点不需要相互信任。分布式内容传递可以节约带宽,和防止HTTP方案可能遇到的DDoS攻击。
该文件系统可以通过多种方式访问,包括FUSE与HTTP。将本地文件添加到IPFS文件系统可使其面向全世界可用。文件表示基于其哈希,因此有利于缓存。文件的分发采用一个基于BitTorrent的协议。其他查看内容的用户也有助于将内容提供给网络上的其他人。IPFS有一个称为IPNS的名称服务,它是一个基于PKI的全局命名空间,用于构筑信任链,这与其他NS兼容,并可以映射DNS、.onion、.bit等到IPNS。
在2014年,IPFS协议利用比特币区块链协议和网络基础设施的优势来存储不可更改的数据,移除网络上的重复文件,以及获取存储节点的地址信息——用以搜索网络中的文件。
目前的实现采用Go和JavaScript,并有Python的实现正在发展。Go实现被认为是开发正式规范时的“参考实现”。
推荐一个ipfs教程。
用区块链、星际文件系统(IPFS)、Node.js和MongoDB来构建以太坊dapp电商平台:
http://xc.hubwiz.com/course/5abbb7acc02e6b6a59171dd6
区块链
2018-04-27 17:10:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
本文是对以太坊中可升级智能合约领域的各种实现策略的总结 ,目的是汇总迄今为止的相关资源,以帮助我们在设计智能合约时,考虑如何对其进行升级和更新。
100%可升级机制
目前有两种主要策略用来实现可升级的智能合约: 使用代理合约 将逻辑和数据分离成不同的合约。
这两种方法要解决的根本问题是如何更新合同的逻辑,同时仍然保留对合同状态的访问。
代理合约
代理合约使用 delegatecall 操作码将函数调用转发到可更新的目标合约。 由于delegatecall
保留了函数调用的状态,因此可以更新目标合约的逻辑,并且状态将保留在代理合约中以供
更新后的目标合约的逻辑使用。 与delegatecall一样,msg.sender将保持代理合约的调用者身份。
由于最近的拜占庭硬分叉,现在可以获取函数调用的返回大小了,因此与 Nick Johnson
首次提出的方法相比,目前这种方法可以通用。 在 Daonomic 的文章中可以
看到一个通用代理合约的例子,你可以更详细地了解这个机制。
分离逻辑和数据合约
这中方法到将智能合约拆分两个合约: 包含数据(变量,结构,映射等)以及getter/setter的数据合约 包含如何更新这些数据的业务逻辑的逻辑合约
逻辑合约通过setter更新数据,而数据合约只允许逻辑合约调用setter。 这允许在保持数据不变
的同时更换实现逻辑,从而实现完全可升级的系统。
通过引导用户使用新的逻辑合约(通过诸如ENS的解析器)并更新数据合约的权限来允许新的逻辑合约
执行setter,就可以实现合约的更新。
查看 @Thomas Wiesner的视频以更好地了解这一机制。
使用键值对数据模型分离逻辑和数据合约
这种策略的工作原理与上述类似,只是不使用最终期望数据结构(struct,mapping等)来定义合约数据模型,
所有数据都被抽象化并存储在键值对中,然后使用一个标准的命名系统以及sha256散列算法用于查找数据值。
可以查阅 David Rugendyke 的文章以更好地理解这种机制。
部分可升级策略
创建一个完全可升级的合约听起来不错,但需要一个很大的妥协:保证合约的不可变性。 因此在很多情况下
实现部分可升级的合约可能是更合理的选择。
在此策略中,智能合约的核心功能可以保留为不可升级。 其他可能不太完整或更复杂的组件则
采用可升级策略实施。
这方面已经有一些很好的案例: 以太坊名称服务 ENS :ENS核心合约是一个非常简单的合约,不能更改。
域名注册商则可以由管理员升级。 域名注册商是一个合约工厂,如果使用一个新的域管理器,它可以与以前的所有
数据状态重新链接,而不会有太多麻烦。 0xProject :603DEX(去中心化交易所)核心智能合约可以完全升级,而代理合约(每个用户一个)保持不变。
0x“代理”合约(不同于前面介绍的代理策略)包含用户资金和相关设置。 由于这个原因,它不是0x合约系统的可升级部分。
其他挑战 在所有情况下,都需要对是否保持智能合约的不变性进行取舍。 创建可选的可升级智能合约系统对用户来说是可能并且有价值的,但是增加了复杂性。 对Solidity编译器的更改可能会破坏新旧合约之间的兼容性。 制定可升级策略时需要考虑gas开销。
结论
没有一个策略是完美的,选择正确的策略取决于要实施的智能合约。 所有策略都非常复杂,智能合约设计人员应该对
他们所选择的可升级策略非常了解,以避免安全漏洞。 为了创建一个可升级的智能合约,代理机制似乎是最好的全面策略,因为它允许程序员将可升级机制
与合约设计区分开来,这使得一切变得更容易,并且会产生更少的错误,而错误是我们需要升级合约的主要原因。 在最简单的核心逻辑不变的情况下,采用部分升级策略也是保持用户信任的好主意。 首先设计不可升级的智能合约系统,然后制定可升级的策略,这是一种实用且理想的方式。
参考资源
思路与观点 2018-02-01 Zeppelin Solution : Zeppelin与智能合约开发的演变 2016-2017: Stackexchange关于可升级的智能合约的问答 ConsenSys : 以太坊智能合约最佳实践 Evoluchain : Evoluchain
代理合约 2018-02-22 Jorge Izquierdo : ERC DelegateProxy #897 2018-02-15 经济学 : 可升级的以太坊智能合约 , Github项目 2018-01-11 B9lab团队 : upgradable - Github项目 2018-01-10 Manuel Araoz : olidity-proxy - Github项目 2017-06-02 @Ownage : Ether-routher - Github项目 2017-05-24 Nick Johnson : 疯狂的区块链科学:100%可升级的合约 , Gist File 2017-03-15 Jorge Izquierdo : Solidity代码部署高级技术 2017-03-07 Manuel Araoz : Solidity中的代理库 2017-02-13 Jorge Izquierdo : Solidity中库驱动的开发 2017-01-21 Tjaden Hess : 可升级的智能合约 2016-06-16 @Martin Swende : 隐式方法代理技巧
分离逻辑和数据合约 2017-12-09 @Thomas Wiesner : 升级链上智能合约 2017-11-13杰克坦纳: 可升级的智能合约 , Github项目 2017-08-21 Lukas K : 可升级的智能合约 。 我们学习了在区块链上建立保险 2016-08-16 @nikolai : Dapp-a-day 6:可升级的通证合约 @monax : Solidity 1:solidity五种合约模型 @monax : Solidity 7:更新Solidity合约 @Z.com-cloud-blockchain : 合约版本升级解决方案
使用键值对数据模型分离逻辑和数据合约 2018-01-20 Hassan Abdel-Rahman : Solidity可升级合约 2017-11-22 David Rugendyke : 可升级Solidity合约设计 , Github项目 2017-06-29 Chandan Gupta : Solidity可升级合约接口设计 , Github项目 2016-06-08 Elena Dimitrova : 在Solidity中编写可升级合约
英文原文链接 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
转自: http://blog.hubwiz.com/2018/04/27/ethereum-contract-upgrade-strategy/#more
区块链
2018-04-27 15:59:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
拜占庭将军问题 (Byzantine Generals Problem),是由 莱斯利·兰波特 在其同名 论文 中提出的 分布式对等网络通信 容错问题。
在分布式计算中,不同的计算机通过通讯交换信息达成共识而按照同一套协作策略行动。但有时候,系统中的成员计算机可能出错而发送错误的信息,用于传递信息的通讯网络也可能导致信息损坏,使得网络中不同的成员关于全体协作的策略得出不同结论,从而破坏系统一致性。拜占庭将军问题被认为是容错性问题中最难的问题类型之一。

目录 1问题描述 2早期的解决方案 3实用拜占庭容错 4计算机系统 5实务应用

问题描述
莱斯利·兰波特在其论文中描述了如下问题: 一组拜占庭将军分别各率领一支军队共同围困一座城市。为了简化问题,将各支军队的行动策略限定为进攻或撤离两种。因为部分军队进攻部分军队撤离可能会造成灾难性后果,因此各位将军必须通过投票来达成一致策略,即所有军队一起进攻或所有军队一起撤离。因为各位将军分处城市不同方向,他们只能通过信使互相联系。在投票过程中每位将军都将自己投票给进攻还是撤退的信息通过信使分别通知其他所有将军,这样一来每位将军根据自己的投票和其他所有将军送来的信息就可以知道共同的投票结果而决定行动策略。
系统的问题在于,将军中可能出现 叛徒 ,他们不仅可能向较为糟糕的策略投票,还可能选择性地发送投票信息。假设有9位将军投票,其中1名叛徒。8名忠诚的将军中出现了4人投进攻,4人投撤离的情况。这时候叛徒可能故意给4名投进攻的将领送信表示投票进攻,而给4名投撤离的将领送信表示投撤离。这样一来在4名投进攻的将领看来,投票结果是5人投进攻,从而发起进攻;而在4名投撤离的将军看来则是5人投撤离。这样各支军队的一致协同就遭到了破坏。
由于将军之间需要通过信使通讯,叛变将军可能通过伪造信件来以其他将军的身份发送假投票。而即使在保证所有将军忠诚的情况下,也不能排除信使被敌人截杀,甚至被敌人间谍替换等情况。因此很难通过保证人员可靠性及通讯可靠性来解决问题。
假始那些忠诚(或是没有出错)的将军仍然能通过多数决定来决定他们的战略,便称达到了拜占庭容错。在此,票都会有一个默认值,若消息(票)没有被收到,则使用此默认值来投票。
上述的故事映射到计算机系统里,将军便成了计算机,而信差就是通信系统。虽然上述的问题涉及了电子化的决策支持与信息安全,却没办法单纯的用 密码学 与 数字签名 来解决。因为不正常的 电压 仍可能影响整个加密过程,这不是密码学与数字签名算法在解决的问题。因此计算机就有可能将错误的结果提交去,亦可能导致错误的决策。
早期的解决方案
在1982年的论文中提过几个解决方案。方案中把问题往下拆解,认为在“拜占庭将军”的问题可以在“军官与士官的问题”里解决,以降低将军问题的发生。而所谓的“军官与士官的问题”,就是探讨军官与他的士官是否能忠实实行命令。 其中一个解决方案认为即使出现了伪造或错误的消息。只要有问题的将军的数量不到三分之一,仍可以达到“拜占庭容错”。原因是把同样的标准下放到“军官与士官的问题”时,在背叛的军士官不足三分之一的情况下,有问题的军士官可以很容易的被纠出来。比如有军官A,士官B与士官C。当A要求B进攻,却要求C撤退时。只要B与C交换所收到的命令,就会立刻发现A有问题。以函数来表示,将军的总数为 n , n 里面背叛者的数量为 t ,则只要 n > 3 t 就可以容错。 另一个解决方案需要有无法消去的签名。在现今许多高度信息安全要求的关键系统里,数字签名就经常被用来实现拜占庭容错,找出有问题的将军。然而,在 生命攸关系统 里,使用 错误侦测码 就可以大幅降低问题的发生。无论系统是否存在拜占庭将军问题。所以需要做密码军算的数字签名也不一定适合这类系统。 假如上述两个解决方案里,将军们无法直接通信时,该论文亦有进一步的解决方案。
此外,1980年代还有其他用来达到拜占庭容错的架构被提出,如:FTMP、MMFCS 与 SIFT。
实用拜占庭容错
1999年,卡斯托(Miguel Castro)与李斯克夫(Barbara Liskov)提出了实用拜占庭容错(PBFT)算法。该算法能提供高性能的运算,使得系统可以每秒处理成千的请求,比起旧式系统快了一些。
而在PBFT之后,许多用于拜占庭容错(BFT)的通信协议也被提出来改善其通信的强健性与效率。比如Q/U、HQ、Zyzzyva与ABsTRACTs ...,用来提升效率。而Aardvark与RBFT是用来加强强健性。另外,Adapt则使用原有的BFT协议做调适,以强化其效率与强健性。BFT协议更可以借由加入可任务的单元,以减少发出副本的次数。比如:A2M-PBFT-EA与MinBFT。
计算机系统
在 分布式对等网络 中需要按照共同一致策略协作的成员计算机即为问题中的将军,而各成员计算机赖以进行通讯的网络链路即为信使。拜占庭将军问题描述的就是某些成员计算机或网络链路出现错误、甚至被蓄意破坏者控制的情况。
实务应用
在点对点式数字货币系统 比特币 里,比特币网络的运作是平行的(parallel)。各结点与终端都运算著散列炼来达成 工作量证明 (PoW)。工作量证明的炼结是解决比特币系统中拜占庭问题的关键,避免有问题的结点(即前文提到的“反叛的将军”)破坏数字货币系统里交易帐的正确性,是对整个系统的运行状态有着重要的意义。
在一些飞行器(如 波音777 )的系统中也有使用拜占庭容错。而且由于是即时系统,容错的功能也要能尽快回复,比如即使系统中有错误发生,容错系统也只能做出一微秒以内的延迟。
一些 航天飞机 的飞行系统甚至将容错功能放到整个系统的设计之中。
拜占庭容错机制是将收到的消息(或是收到的消息的签名)转交到其他的接收者。这类机制都假设它们转交的消息都可能念有拜占庭问题。在高度安全要求的系统中,这些假设甚至要求证明错误能在一个合理的档次下被排除。当然,要证明这点,首先遇到的问题就是如何有效的找出所有可能的、应能被容错的错误。这时候会试着在系统中加入错误插入器。
作者按区块链在解决这个问题上,有一定优势。推荐两个教程: 以太坊 DApp 实战开发入门 去中心化电商 DApp 实战开发
区块链
2018-04-27 14:17:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
NEO DBFT共识算法
dbft改进自算法pbft算法,pbft算法通过多次网络请求确认,最终获得多数共识。其缺点在于随着随着节点的增加,网络开销呈指数级增长,网络通信膨胀,难以快速达成一致。neo的解决方案是通过投票选取出一定数量的节点作为记账人,由此减少网络消耗又可以兼顾交易速度,这也是dbft中d的由来。
代码结构说明 ├── Consensus │   ├── ChangeView.cs //viewchange 消息 │   ├── ConsensusContext.cs //共识上下文 │   ├── ConsensusMessage.cs //共识消息 │   ├── ConsensusMessageType.cs //共识消息类型 ChangeView/PrepareRequest/PrepareResponse │   ├── ConsensusService.cs //共识核心代码 │   ├── ConsensusState.cs //节点共识状态 │   ├── PrepareRequest.cs //请求消息 │   └── PrepareResponse.cs //签名返回消息
共识状态变化流程 1:开启共识的节点分为两大类,非记账人和记账人节点,非记账人的不参与共识,记账人参与共识流程 2:选择议长,Neo议长产生机制是根据当前块高度和记账人数量做MOD运算得到,议长实际上按顺序当选 3:节点初始化,议长为primary节点,议员为backup节点。 4:满足出块条件后议长发送PrepareRequest 5:议员收到请求后,验证通过签名发送PrepareResponse 6:记账节点接收到PrepareResponse后,节点保存对方的签名信息,检查如果超过三分之二则发送 block 7:节点接收到block,PersistCompleted事件触发后整体重新初始化,
共识上下文核心成员 public const uint Version = 0; public ConsensusState State; //节点当前共识状态 public UInt256 PrevHash; public uint BlockIndex; //块高度 public byte ViewNumber; //试图状态 public ECPoint[] Validators; //记账人 public int MyIndex; //当前记账人次序 public uint PrimaryIndex; //当前记账的记账人 public uint Timestamp; public ulong Nonce; public UInt160 NextConsensus; //共识标识 public UInt256[] TransactionHashes; public Dictionary Transactions; public byte[][] Signatures; //记账人签名 public byte[] ExpectedView; //记账人试图 public KeyPair KeyPair; public int M => Validators.Length - (Validators.Length - 1) / 3; //三分之二数量
ExpectedView 维护视图状态中,用于在议长无法正常工作时重新发起新一轮共识。
Signatures 用于维护共识过程中的确认状态。
节点共识状态 [Flags] internal enum ConsensusState : byte { Initial = 0x00, // 0 Primary = 0x01, // 1 Backup = 0x02, // 10 RequestSent = 0x04, // 100 RequestReceived = 0x08, // 1000 SignatureSent = 0x10, // 10000 BlockSent = 0x20, // 100000 ViewChanging = 0x40, //1000000 }
代理节点选择
neo的dbft算法的delegate部分主要体现在一个函数上面,每次产生区块后会重新排序资产,选择前记账人数量的节点出来参与下一轮共识。 /// /// 获取下一个区块的记账人列表 /// /// 返回一组公钥,表示下一个区块的记账人列表 public ECPoint[] GetValidators() { lock (_validators) { if (_validators.Count == 0) { _validators.AddRange(GetValidators(Enumerable.Empty())); } return _validators.ToArray(); } } public virtual IEnumerable GetValidators(IEnumerable others) { DataCache accounts = GetStates(); DataCache validators = GetStates(); MetaDataCache validators_count = GetMetaData(); ///更新账号资产情况 foreach (Transaction tx in others) { foreach (TransactionOutput output in tx.Outputs) { AccountState account = accounts.GetAndChange(output.ScriptHash, () => new AccountState(output.ScriptHash)); if (account.Balances.ContainsKey(output.AssetId)) account.Balances[output.AssetId] += output.Value; else account.Balances[output.AssetId] = output.Value; if (output.AssetId.Equals(GoverningToken.Hash) && account.Votes.Length > 0) { foreach (ECPoint pubkey in account.Votes) validators.GetAndChange(pubkey, () => new ValidatorState(pubkey)).Votes += output.Value; validators_count.GetAndChange().Votes[account.Votes.Length - 1] += output.Value; } } foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash)) { Transaction tx_prev = GetTransaction(group.Key, out int height); foreach (CoinReference input in group) { TransactionOutput out_prev = tx_prev.Outputs[input.PrevIndex]; AccountState account = accounts.GetAndChange(out_prev.ScriptHash); if (out_prev.AssetId.Equals(GoverningToken.Hash)) { if (account.Votes.Length > 0) { foreach (ECPoint pubkey in account.Votes) { ValidatorState validator = validators.GetAndChange(pubkey); validator.Votes -= out_prev.Value; if (!validator.Registered && validator.Votes.Equals(Fixed8.Zero)) validators.Delete(pubkey); } validators_count.GetAndChange().Votes[account.Votes.Length - 1] -= out_prev.Value; } } account.Balances[out_prev.AssetId] -= out_prev.Value; } } switch (tx) { #pragma warning disable CS0612 case EnrollmentTransaction tx_enrollment: validators.GetAndChange(tx_enrollment.PublicKey, () => new ValidatorState(tx_enrollment.PublicKey)).Registered = true; break; #pragma warning restore CS0612 case StateTransaction tx_state: foreach (StateDescriptor descriptor in tx_state.Descriptors) switch (descriptor.Type) { case StateType.Account: ProcessAccountStateDescriptor(descriptor, accounts, validators, validators_count); break; case StateType.Validator: ProcessValidatorStateDescriptor(descriptor, validators); break; } break; } } //排序 int count = (int)validators_count.Get().Votes.Select((p, i) => new { Count = i, Votes = p }).Where(p => p.Votes > Fixed8.Zero).ToArray().WeightedFilter(0.25, 0.75, p => p.Votes.GetData(), (p, w) => new { p.Count, Weight = w }).WeightedAverage(p => p.Count, p => p.Weight); count = Math.Max(count, StandbyValidators.Length); HashSet sv = new HashSet(StandbyValidators); ECPoint[] pubkeys = validators.Find().Select(p => p.Value).Where(p => (p.Registered && p.Votes > Fixed8.Zero) || sv.Contains(p.PublicKey)).OrderByDescending(p => p.Votes).ThenBy(p => p.PublicKey).Select(p => p.PublicKey).Take(count).ToArray(); IEnumerable result; if (pubkeys.Length == count) { result = pubkeys; } else { HashSet hashSet = new HashSet(pubkeys); for (int i = 0; i < StandbyValidators.Length && hashSet.Count < count; i++) hashSet.Add(StandbyValidators[i]); result = hashSet; } return result.OrderBy(p => p); }
议长选择
在初始化共识状态的时候会设置PrimaryIndex,获知当前议长。原理就是简单的MOD运算。 这里有分为两种情况,如果节点正常则直接块高度和记账人数量mod运算即可,如果存在一场情况,则需要根据view_number进行调整。 //file /Consensus/ConsensusService.cs InitializeConsensus方法 if (view_number == 0) context.Reset(wallet); else context.ChangeView(view_number); //file /Consensus/ConsensusContext.cs public void ChangeView(byte view_number) { int p = ((int)BlockIndex - view_number) % Validators.Length; State &= ConsensusState.SignatureSent; ViewNumber = view_number; PrimaryIndex = p >= 0 ? (uint)p : (uint)(p + Validators.Length);//当前记账人 if (State == ConsensusState.Initial) { TransactionHashes = null; Signatures = new byte[Validators.Length][]; } ExpectedView[MyIndex] = view_number; _header = null; } //file /Consensus/ConsensusContext.cs public void Reset(Wallet wallet) { State = ConsensusState.Initial; PrevHash = Blockchain.Default.CurrentBlockHash; BlockIndex = Blockchain.Default.Height + 1; ViewNumber = 0; Validators = Blockchain.Default.GetValidators(); MyIndex = -1; PrimaryIndex = BlockIndex % (uint)Validators.Length; //当前记账人 TransactionHashes = null; Signatures = new byte[Validators.Length][]; ExpectedView = new byte[Validators.Length]; KeyPair = null; for (int i = 0; i < Validators.Length; i++) { WalletAccount account = wallet.GetAccount(Validators[i]); if (account?.HasKey == true) { MyIndex = i; KeyPair = account.GetKey(); break; } } _header = null; }
状态初始化
如果是议长则状态标记为ConsensusState.Primary,同时改变定时器触发事件,再上次出块15s后触发。议员则设置状态为 ConsensusState.Backup,时间调整为30s后触发,如果议长不能正常工作,则这个触发器会开始起作用(具体后边再详细分析)。 //file /Consensus/ConsensusContext.cs private void InitializeConsensus(byte view_number) { lock (context) { if (view_number == 0) context.Reset(wallet); else context.ChangeView(view_number); if (context.MyIndex < 0) return; Log($"initialize: height={context.BlockIndex} view={view_number} index={context.MyIndex} role={(context.MyIndex == context.PrimaryIndex ? ConsensusState.Primary : ConsensusState.Backup)}"); if (context.MyIndex == context.PrimaryIndex) { context.State |= ConsensusState.Primary; if (!context.State.HasFlag(ConsensusState.SignatureSent)) { FillContext(); //生成mine区块 } if (context.TransactionHashes.Length > 1) { //广播自身的交易 InvPayload invPayload = InvPayload.Create(InventoryType.TX, context.TransactionHashes.Skip(1).ToArray()); foreach (RemoteNode node in localNode.GetRemoteNodes()) node.EnqueueMessage("inv", invPayload); } timer_height = context.BlockIndex; timer_view = view_number; TimeSpan span = DateTime.Now - block_received_time; if (span >= Blockchain.TimePerBlock) timer.Change(0, Timeout.Infinite); else timer.Change(Blockchain.TimePerBlock - span, Timeout.InfiniteTimeSpan); } else { context.State = ConsensusState.Backup; timer_height = context.BlockIndex; timer_view = view_number; timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (view_number + 1)), Timeout.InfiniteTimeSpan); } } }
议长发起请求
议长到了该记账的时间后,执行下面方法,发送MakePrepareRequest请求,自身状态转变为RequestSent,也设置了30s后重复触发定时器(同样也是再议长工作异常时起效)。 //file /Consensus/ConsensusContext.cs private void OnTimeout(object state) { lock (context) { if (timer_height != context.BlockIndex || timer_view != context.ViewNumber) return; Log($"timeout: height={timer_height} view={timer_view} state={context.State}"); if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent)) { Log($"send perpare request: height={timer_height} view={timer_view}"); context.State |= ConsensusState.RequestSent; if (!context.State.HasFlag(ConsensusState.SignatureSent)) { context.Timestamp = Math.Max(DateTime.Now.ToTimestamp(), Blockchain.Default.GetHeader(context.PrevHash).Timestamp + 1); context.Signatures[context.MyIndex] = context.MakeHeader().Sign(context.KeyPair); } SignAndRelay(context.MakePrepareRequest()); timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (timer_view + 1)), Timeout.InfiniteTimeSpan); } else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup)) { RequestChangeView(); } } } }
议员广播签名信息
议员接收到PrepareRequest,会对节点信息进行验证,自身不存在的交易会去同步交易。交易同步完成后,验证通过会进行发送PrepareResponse ,包含自己的签名信息,表示自己已经通过了节点验证。状态转变为ConsensusState.SignatureSent。 //file /Consensus/ConsensusContext.cs private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message) { Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived)) return; if (payload.ValidatorIndex != context.PrimaryIndex) return; if (payload.Timestamp <= Blockchain.Default.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp()) { Log($"Timestamp incorrect: {payload.Timestamp}"); return; } context.State |= ConsensusState.RequestReceived; context.Timestamp = payload.Timestamp; context.Nonce = message.Nonce; context.NextConsensus = message.NextConsensus; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); if (!Crypto.Default.VerifySignature(context.MakeHeader().GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false))) return; context.Signatures = new byte[context.Validators.Length][]; context.Signatures[payload.ValidatorIndex] = message.Signature; Dictionary mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash); foreach (UInt256 hash in context.TransactionHashes.Skip(1)) { if (mempool.TryGetValue(hash, out Transaction tx)) if (!AddTransaction(tx, false)) return; } if (!AddTransaction(message.MinerTransaction, true)) return; if (context.Transactions.Count < context.TransactionHashes.Length) { UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); LocalNode.AllowHashes(hashes); InvPayload msg = InvPayload.Create(InventoryType.TX, hashes); foreach (RemoteNode node in localNode.GetRemoteNodes()) node.EnqueueMessage("getdata", msg); } } //file /Consensus/ConsensusContext.cs private bool AddTransaction(Transaction tx, bool verify) { if (Blockchain.Default.ContainsTransaction(tx.Hash) || (verify && !tx.Verify(context.Transactions.Values)) || !CheckPolicy(tx)) { Log($"reject tx: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}"); RequestChangeView(); return false; } context.Transactions[tx.Hash] = tx; if (context.TransactionHashes.Length == context.Transactions.Count) { if (Blockchain.GetConsensusAddress(Blockchain.Default.GetValidators(context.Transactions.Values).ToArray()).Equals(context.NextConsensus)) { Log($"send perpare response"); context.State |= ConsensusState.SignatureSent; context.Signatures[context.MyIndex] = context.MakeHeader().Sign(context.KeyPair); SignAndRelay(context.MakePrepareResponse(context.Signatures[context.MyIndex])); CheckSignatures(); } else { RequestChangeView(); return false; } } return true; }
共识达成后广播区块
其他节点接收到PrepareResponse后,在自己的签名列表中记录对方的签名信息,再检查自己的签名列表是否有超过三分之二的签名了,有则判断共识达成开始广播生成的区块。状态状变为ConsensusState.BlockSent。 private void CheckSignatures() { if (context.Signatures.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p))) { Contract contract = Contract.CreateMultiSigContract(context.M, context.Validators); Block block = context.MakeHeader(); ContractParametersContext sc = new ContractParametersContext(block); for (int i = 0, j = 0; i < context.Validators.Length && j < context.M; i++) if (context.Signatures[i] != null) { sc.AddSignature(contract, context.Validators[i], context.Signatures[i]); j++; } sc.Verifiable.Scripts = sc.GetScripts(); block.Transactions = context.TransactionHashes.Select(p => context.Transactions[p]).ToArray(); Log($"relay block: {block.Hash}"); if (!localNode.Relay(block)) Log($"reject block: {block.Hash}"); context.State |= ConsensusState.BlockSent; } }
Blockchain_PersistCompleted后恢复状态
区块广播后,节点接收到这个信息,会保存区块,保存完成后触发PersistCompleted事件,最终回到初始状态,重新开始新一轮的共识。 private void Blockchain_PersistCompleted(object sender, Block block) { Log($"persist block: {block.Hash}"); block_received_time = DateTime.Now; InitializeConsensus(0); }
错误分析
如果议长无法完成记账任务
这种情况下议长在超出时间之后依然无法达成共识,此时议员会增长自身的ExpectedView值,并且广播出去,如果检查到三分之二的成员viewnumber都加了1,则在这些相同viewnumber的节点之间开始新一轮共识,重新选择议长,发起共识。如果此时原来的议长恢复正常,time到时间后会增长自身的viewnumber,慢慢追上当前的视图状态。
参考
源码 :[ https://github.com/neo-project/neo/tree/master/neo/Consensus )
官方白皮书: http://docs.neo.org/zh-cn/basic/consensus/consensus.html
DBFT : https://www.jianshu.com/p/2383c7841d41
区块链
2018-04-26 23:27:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
在学习以太坊应用开发时,除了学习solidity开发智能合约,一个小白还应该补充 哪些知识?文本将给出相关的学习资源和学习路径。
前端技能学习
智能合约仅仅是以太坊去中心化应用的一个组成部分,要提供用户操作的界面,前端 web开发技能比不可少,这是HTML/CSS/JavaScript的天下: HTML入门与实战 CSS入门与实战 JavaScript入门与实践 jQuery开发手册
如果你希望在前端使用现代框架例例如当红炸子鸡Vue,可以参考以下课程: vue.js 2入门与提高 Vuex 2入门与提高 VueRouter 2入门与提高 vue.js 2工程化实践
后端技能学习
严格的去中心化应用不需要后端,但是很多情况下,基于以太坊的应用需要引入一个后端 才更实际。我们推荐使用nodejs来作为后端的核心开发平台。 nodejs入门 express入门 mongoose入门 mongodb入门
以太坊技能学习 以太坊DApp开发入门 以太坊+IPFS电商DApp实战
区块链
2018-04-26 20:26:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
区块链兄弟社区,区块链技术专业问答先行者,中国区块链技术爱好者聚集地
作者:吴寿鹤
来源: 区块链兄弟
原文链接: http://www.blockchainbrother.com/article/30
著权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
经过长达几年的讨论之后,比特币扩容问题似乎终于要尘埃落定,但不管最终采取何种方案,总是会有一些用户对结果不甚满意。代码优化隔离见证(SegWit)经过优化发展到了如今的Segwit2x提案,而且距离该方案的激活也只剩几步之遥。但另外一组团体称其将于8月1日脱离比特币,创建一种名为Bitcoin Cash的全新加密货币。Bitcoin Cash是什么?又如何与比特币区分开来?又得到了什么样的支持?本文便为你一一解答。
最初支持Segwit2x提案的其他人似乎也对最终扩大区块容量失去了信心,他们现在也正在构建自己版本的比特币想要将命运掌握在自己的手里– 而且要在一个较短的时间期限内实现。
8月1日,准确地说是在UTC时间12:20,该团体称他们将从比特币中脱离出来,创建一种名为Bitcoin Cash的全新加密货币。
Calin Culianu是一名对Bitcoin Cash的实施贡献了代码的开发者,而且他也不喜欢SegWit,并认为其他人也拥有同样的感觉。
Culianu告诉CoinDesk:
“如果Segwit2x协议未能实施2x部分(这是完全合理有可能的),那么最终就只会是基本的SegWit而没有2x,许多矿工很可能会倒戈支持Bitcoin Cash。“
Bitcoin Cash是什么?
那么,它是什么?又如何与比特币区分开来?
有两个值得注意的主要变化:
它将区块链容量增加至8MB。
它去除了SegWit,而SegWit这种代码更改可能将于八月底在比特币区块链上激活。
一些人(包括该项目的一些支持者)称Bitcoin Cash为“山寨币”,而这一术语通常指代软件的分叉,这些分叉创建了一个全新的加密货币并拥有自己的市场。
实际上,该加密货币目前在已经开放的期货市场中的交易价格为461美元,这也就意味着它的价格是比特币当前价格2568美元的18%。
不过与其他山寨币不同,Bitcoin Cash的交易历史与比特币的交易历史是相同的– 至少直到分叉之前是如此因此,如果Bitcoin Cash脱离比特币,那么用户在两条区块链之上都会拥有比特币。
另一个区别就是该项目表示将支持其软件的多种实现,这一点也不奇怪,因为一直都有人指责Bitcoin Core的软件在比特币的网络中太过占优势。
BitcoinABC是第一款实施Bitcoin Cash协议的软件,但其目标仍是期待支持多种软件实现。
Culianu表示Bitcoin Unlimited,Bitcoin Classic以及其他旨在扩大比特币区块链容量的实现,均在努力开发兼容Bitcoin Cash的软件版本。
这些软件可能已经准备好迎接8月1日的分叉,也可能没有。
都有谁参与其中?
到目前为止,大多数比特币公司,矿池,用户以及比特币开发者似乎都对这项工作不感兴趣。不过,还是有一些热心的支持者。
位于北京的挖矿公司ViaBTC拥有近4%的比特币算力,是比特币分叉的首要主导者。
该公司也经营着一家交易所,成为了首家上市该加密货币的交易所,并计划推出专门针对Bitcoin Cash的新矿池。
当被问及是否认为Segwit2x将会实现其路线图时,该公司CEO杨海坡回答说:“我对此表示怀疑。”
此外,Bitcoin Cash已经吸引了一些希望扩大区块容量的用户,以及Bitcoin Classic和Bitcoin Unlimited等其他提案的开发人员的支持。
然而,并未参与进来的才是真正让人感到更加意外的。
即使是曾经的支持者(包括挖矿公司Bitcoin.com与比特大陆)似乎对是否要支持该项目也感到犹豫不决。现在,他们仍然致力于有争议的扩容提案Segwit2x。
挖掘公司比特大陆甚至启发了Bitcoin Cash。然而,该公司表示,他们只计划在某些条件下作出转变。不过,该公司将来可能会既支持Segwit2x,又支持Bitcoin Cash。
在PSA声明中,Bitcoin.com表示,其将允许其矿池中的矿工选择是否要挖掘Bitcoin Cash代币BCC。
尽管如此,目前该矿池仍将在Segwit2x链上进行挖矿,不过其表示如果预计在今后三个月左右的时间进行的SegWit区块链容量扩大最终落空,“其将立即将公司所有资源转移至只支持比特币现金“。
等待,但是为什么?
用户和矿池想要脱离比特币的几个原因:
这些用户想要增加比特币的区块链容量参数,并认为该加密货币的未来就取决于此。
SegWit很有可能很快激活,而一些用户想要避免这一功能。
Segwit2x的区块链容量参数增加有可能最终落空。
观念上与技术上的原因结合也在与用户的对话中展现出来。
当CoinDesk问到BitcoinABC的目标是什么时,Culianu回答道:
“为了挽救比特币。我们想要将比特币扩容,这样比特币就不会消亡。比特币本身已经有些病态并且奄奄一息了。”
有何区别?
过去几年的许多其他努力表明,如果他们从那些运营保护网络的计算机的人那里获得足够的支持,就能够从比特币中分离出来。但到目前为止,还没有任何一个团体实际贯彻这个计划。
Bitcoin Cash或许是独一无二的,因为它明确设定了将比特币一分为二的截止日期,而且距离这一截止日期已经不到一周了。
若矿工与用户确实进行了分叉,这就标志着第一次将会有一个加密货币从比特币中分离出来,而且还带有比特币的交易历史。
与过去的尝试相同,都是想用一种新的比特币来取代如今正在使用的比特币,Bitcoin Cash目标也是如此,不过,它似乎更愿意去等待看看用户是否加入进来。
与其称之为比特币,ViaBTC以及一些中国的比特币公司签署了一项协议将其标记为“竞争币”,而不是“真正的”比特币。
这一举措可能会使分叉更快实现,因为在过去,交易所一直都对如何处理分叉表示十分困惑。
下一步是什么?
如果新的加密货币从比特币主网络中分离出来,就会成为先例。所以,一些用户很好奇想要看看究竟会发生什么。
然而,若没有矿工和用户的大力支持,那么也就可能不会对主网络带来太大的影响。
尽管如此,如果Segwit2x的下半部分落空,或许还是值得一看的。那时,可能就会有更多的支持者。
例如,Culianu就总结得出了一个乐观的观点:
“我直觉觉得比特币现金可能会让所有人都大跌眼镜。几个月之后它成为实际上的比特币也不完全不可能的。更大的8 MB区块链容量是很有吸引力的。“
文章发布只为分享区块链技术内容,版权归原作者所有,观点仅代表作者本人,绝不代表区块链兄弟赞同其观点或证实其描述
区块链
2018-04-26 14:00:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
区块链技术和以太坊开发学习的资料如以太坊白皮书,官方文档;web3.js,Solidity,Truffle,geth中文文档;以太坊,IPFS开发环境搭建,私有链搭建,开发部署等资源汇总整理如下:
1. 适合区块链新手的以太坊DApp开发实战入门
2. 区块链,星际文件系统IPFS,Nodejs和MongoDB构建以太坊DApp电商平台
收集了一些免费区块链、以太坊技术开发相关的文件,有需要的可以下载,文件链接: web3.js API官方文档中文版: https://pan.baidu.com/s/1hOV9hEzi7hFxJCL4LTvC6g 以太坊官方文档中文版     : https://pan.baidu.com/s/1ktODJKLMBmkOsi8MPrpIJA 以太坊白皮书中文版       : https://pan.baidu.com/s/1bzAFnzJ35hlQxJ2J4Oj-Ow Solidity的官方文档中文版 : https://pan.baidu.com/s/18yp9XjEqAHpiFm2ZSCygHw Truffle的官方文档中文版  : https://pan.baidu.com/s/1y6SVd7lSLUHK21YF5FzIUQ C#区块链编程指南         : https://pan.baidu.com/s/1sJPLqp1eQqkG7jmxqwn3EA 区块链技术指南:         : https://pan.baidu.com/s/13cJxAa80I6iMCczA04CZhg 精通比特币中文版:       : https://pan.baidu.com/s/1lz6te3wcQuNJm28rFvBfxg Node.js区块链开发        : https://pan.baidu.com/s/1Ldpn0DvJ5LgLqwix6eWgyg geth使用指南文档中文版   : https://pan.baidu.com/s/1M0WxhmumF_fRqzt_cegnag 以太坊DApp开发环境搭建-Ubuntu   : https://pan.baidu.com/s/10qL4q-uKooMehv9X2R1qSA 以太坊DApp开发环境搭建-windows  : https://pan.baidu.com/s/1cyYkhIJIFuI2oyxM9Ut0eA 以太坊DApp开发私链搭建-Ubuntu   : https://pan.baidu.com/s/1aBOFZT2bCjD2o0EILBWs-g 以太坊DApp开发私链搭建-windows  : https://pan.baidu.com/s/10Y6F1cqUltZNN99aJv9kAA 以太坊ganache CLI命令行参数详解: https://pan.baidu.com/s/1lnknFkwenacaeM4asOcBdg 使用truflle和infura部署以太坊合约: https://pan.baidu.com/s/1PTxSVff2vHSVUihYczRRqw IPFS安装部署与开发环境搭建-windows: https://pan.baidu.com/s/1bnhDvqCoOgAqEBZXMtVbRg
区块链
2018-04-26 10:59:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
IPFS,中文名称翻译为星际文件系统。IPFS安装部署与windows下开发环境搭建的方法如下,由汇智网整理提供:
https://pan.baidu.com/s/1bnhDvqCoOgAqEBZXMtVbRg
区块链
2018-04-26 10:11:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
使用truflle和infura部署以太坊合约是部署以太坊合约的一种方式。infura提供公开的Ethereum主网和测试网路节点。truflle提供以太坊合约开发的框架。如何部署:
https://pan.baidu.com/s/1PTxSVff2vHSVUihYczRRqw
区块链
2018-04-26 10:09:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
以太坊DApp开发环境搭建分为Ubuntu、Windows、mac下的搭建。目的为开发者提供一个以太坊开发、测试的搭建开发环境的指导,减少环境搭建的难度。文档由汇智网整理:
1.以太坊DApp开发环境搭建-Ubuntu : https://pan.baidu.com/s/10qL4q-uKooMehv9X2R1qSA
2.以太坊DApp开发环境搭建-windows : https://pan.baidu.com/s/1cyYkhIJIFuI2oyxM9Ut0eA
区块链
2018-04-26 09:51:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
以太坊Geth私有链环境搭建分为Ubuntu和Windows下的搭建。Geth私有链环境搭建的目的是为开发者提供一个以太坊开发、测试的私有环境。文档由汇智网整理:
1.以太坊DApp开发私链搭建-Ubuntu : https://pan.baidu.com/s/1aBOFZT2bCjD2o0EILBWs-g
2. 以太坊DApp开发私链搭建-windows : https://pan.baidu.com/s/10Y6F1cqUltZNN99aJv9kAA
区块链
2018-04-26 09:45:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
geth使用指南中文版文档,该中文文档原文由网友 趁风卷 创作,最早发布于简书社区。文档中使用go语言编写的命令行客户端 geth 。使用指南的开篇如下:
geth 的命令可以分为 CLI 命令和 JavaScript 控制台交互式命令,约定如下 geth account list:这是 CLI 命令 > eth.accounts:这是 javaScript 控制台的命令,前面有一个 >。进入控制台的方式为 geth console
https://pan.baidu.com/s/1M0WxhmumF_fRqzt_cegnag
区块链
2018-04-26 09:38:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Truffle的官方文档中文版,是学习以太坊开发框架Truffle的基础中文文档。
Truffle是一个世界级的开发环境,测试框架,以太坊的资源管理通道,致力于让以太坊上的开发变得简单,Truffle有以下: 内置的智能合约编译,链接,部署和二进制文件的管理。 快速开发下的自动合约测试。 脚本化的,可扩展的部署与发布框架。 部署到不管多少的公网或私网的网络环境管理功能 使用EthPM&NPM提供的包管理,使用 ERC190 标准。 与合约直接通信的直接交互控制台(写完合约就可以命令行里验证了)。 可配的构建流程,支持紧密集成。 在Truffle环境里支持执行外部的脚本。
原文最早发布于区块链技术博客(http:// tryblockchain.org)
英文地址: http://truffleframework.com/docs/
下载地址: https://pan.baidu.com/s/1y6SVd7lSLUHK21YF5FzIUQ
区块链
2018-04-26 09:34:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Solidity的官方文档中文版,是学习Solidity编程语言的基础,网上流行版本多为极客学院网友共建的wiki。这个官方文档描述了很多Solidity的基本编程知识内容。地址:
https://pan.baidu.com/s/18yp9XjEqAHpiFm2ZSCygHw
区块链
2018-04-26 09:27:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
以太坊白皮书中文版,介绍了以太坊是什么?
开篇这么说:以太坊作为一个全新开放的区块链平台,它允许任何人在平台中建立和使用通过区块链技术运行的去中心化应用。就像比特币一样,以太坊不受任何人控制,也不归任何人所有——它是一个开放源代码项目,由全球范围内的很多人共同创建。和比特币协议有所不同的是,以太坊的设计十分灵活,极具适应性。在以太坊平台上创立新的应用十分简便,随着Homestead的发布,任何人都可以安全地使用该平台上的应用。
https://pan.baidu.com/s/1bzAFnzJ35hlQxJ2J4Oj-Ow
译者未考察到,有侵权请告知。
区块链
2018-04-26 09:22:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
以太坊官网文档中文版,是学习以太坊技术的中文文档中比较经典的文档,现在技术有了很大的更新,但是基础的内容并没有太大变化。原文最早由蓝莲花(汪晓明)于2016年发布于其博客(http://wangxiaoming.com)。地址:
https://pan.baidu.com/s/1ktODJKLMBmkOsi8MPrpIJA
区块链
2018-04-26 09:19:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
#web3.js API 文档# 以太坊DApp开发可以选择使用 web3.js library 提供的web3对象。底层实现上,它是通过 RPC 调用 与本地节点通信。web3.js可以与任何暴露了RPC接口的以太坊节点连接。
web3.js中有eth对象即web3.eth具体来表示与以太坊区块链之间的交互。shh对象表示whisper协议的相关交互。不细说了看文档吧。
web3.js API官方文档中文版: https://pan.baidu.com/s/1hOV9hEzi7hFxJCL4LTvC6g
区块链
2018-04-26 09:05:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
以太坊虚拟机,账户,交易,gas,存储,主存,栈,指令集,消息调用,代码调用,库,日志,创建,自毁这些术语怎么解释?我们来看下,先看以太坊虚拟机。
以太坊虚拟机(EVM)是以太坊中智能合约的运行环境。它不仅被沙箱封装起来,事实上它被完全隔离,也就是说运行在虚拟机EVM内部的代码不能接触到网络、文件系统或者其它进程。甚至智能合约与其它智能合约只有有限的接触。
账户
以太坊中有两类账户,它们共用同一个地址空间。外部账户,该类账户被公钥-私钥对控制(人类)。合约账户,该类账户被存储在账户中的代码控制。
外部账户的地址是由公钥决定的,合约账户的地址是在创建该合约时确定的(这个地址由合约创建者的地址和该地址发出过的交易数量计算得到,地址发出过的交易数量也被称作"nonce")
合约账户存储了代码,外部账户则没有,除了这点以外,这两类账户对于EVM来说是一样的。
每个账户有一个key-value形式的持久化存储。其中key和value的长度都是256比特,名字叫做storage.
另外,每个账户都有一个以太币余额(单位是“Wei"),该账户余额可以通过向它发送带有以太币的交易来改变。
交易
一笔交易是一条消息,从一个账户发送到另一个账户(可能是相同的账户或者零账户,见下文)。交易可以包含二进制数据(payload)和以太币。
如果目标账户包含代码,该代码会执行,payload就是输入数据。
如果目标账户是零账户(账户地址是0),交易将创建一个新合约。正如上文所讲,这个合约地址不是零地址,而是由合约创建者的地址和该地址发出过的交易数量(被称为nonce)计算得到。创建合约交易的payload被当作EVM字节码执行。执行的输出做为合约代码被永久存储。这意味着,为了创建一个合约,你不需要向合约发送真正的合约代码,而是发送能够返回真正代码的代码。
Gas
以太坊上的每笔交易都会被收取一定数量的gas,gas的目的是限制执行交易所需的工作量,同时为执行支付费用。当EVM执行交易时,gas将按照特定规则被逐渐消耗。
gas price(以太币计)是由交易创建者设置的,发送账户需要预付的交易费用 = gas price * gas amount。 如果执行结束还有gas剩余,这些gas将被返还给发送账户。
无论执行到什么位置,一旦gas被耗尽(比如降为负值),将会触发一个out-of-gas异常。当前调用帧所做的所有状态修改都将被回滚。
存储,主存和栈
每个账户有一块持久化内存区域被称为存储。其形式为key-value,key和value的长度均为256比特。在合约里,不能遍历账户的存储。相对于另外两种,存储的读操作相对来说开销较大,修改存储更甚。一个合约只能对它自己的存储进行读写。
第二个内存区被称为主存。合约执行每次消息调用时,都有一块新的,被清除过的主存。主存可以以字节粒度寻址,但是读写粒度为32字节(256比特)。操作主存的开销随着其增长而变大(平方级别)。
EVM不是基于寄存器,而是基于栈的虚拟机。因此所有的计算都在一个被称为栈的区域执行。栈最大有1024个元素,每个元素256比特。对栈的访问只限于其顶端,方式为:允许拷贝最顶端的16个元素中的一个到栈顶,或者是交换栈顶元素和下面16个元素中的一个。所有其他操作都只能取最顶的两个(或一个,或更多,取决于具体的操作)元素,并把结果压在栈顶。当然可以把栈上的元素放到存储或者主存中。但是无法只访问栈上指定深度的那个元素,在那之前必须要把指定深度之上的所有元素都从栈中移除才行。
指令集
EVM的指令集被刻意保持在最小规模,以尽可能避免可能导致共识问题的错误实现。所有的指令都是针对256比特这个基本的数据类型的操作。具备常用的算术,位,逻辑和比较操作。也可以做到条件和无条件跳转。此外,合约可以访问当前区块的相关属性,比如它的编号和时间戳。
消息调用
合约可以通过消息调用的方式来调用其它合约或者发送以太币到非合约账户。消息调用和交易非常类似,它们都有一个源,一个目标,数据负载,以太币,gas和返回数据。事实上每个交易都可以被认为是一个顶层消息调用,这个消息调用会依次产生更多的消息调用。
一个合约可以决定剩余gas的分配。比如内部消息调用时使用多少gas,或者期望保留多少gas。如果在内部消息调用时发生了out-of-gas异常(或者其他异常),合约将会得到通知,一个错误码被压在栈上。这种情况只是内部消息调用的gas耗尽。在solidity中,这种情况下发起调用的合约默认会触发一个人工异常。这个异常会打印出调用栈。就像之前说过的,被调用的合约(发起调用的合约也一样)会拥有崭新的主存并能够访问调用的负载。调用负载被存储在一个单独的被称为calldata的区域。调用执行结束后,返回数据将被存放在调用方预先分配好的一块内存中。
调用层数被限制为1024,因此对于更加复杂的操作,我们应该使用循环而不是递归。
代码调用和库
存在一种特殊类型的消息调用,被称为callcode。它跟消息调用几乎完全一样,只是加载自目标地址的代码将在发起调用的合约上下文中运行。
这意味着一个合约可以在运行时从另外一个地址动态加载代码。存储,当前地址和余额都指向发起调用的合约,只有代码是从被调用地址获取的。
这使得Solidity可以实现”库“。可复用的库代码可以应用在一个合约的存储上,可以用来实现复杂的数据结构。
日志
在区块层面,可以用一种特殊的可索引的数据结构来存储数据。这个特性被称为日志,Solidity用它来实现事件。合约创建之后就无法访问日志数据,但是这些数据可以从区块链外高效的访问。因为部分日志数据被存储在布隆过滤器(Bloom filter) 中,我们可以高效并且安全的搜索日志,所以那些没有下载整个区块链的网络节点(轻客户端)也可以找到这些日志。
创建
合约甚至可以通过一个特殊的指令来创建其他合约(不是简单的向零地址发起调用)。创建合约的调用跟普通的消息调用的区别在于,负载数据执行的结果被当作代码,调用者/创建者在栈上得到新合约的地址。
自毁
只有在某个地址上的合约执行自毁操作时,合约代码才会从区块链上移除。合约地址上剩余的以太币会发送给指定的目标,然后其存储和代码被移除。
注意,即使一个合约的代码不包含自毁指令,依然可以通过代码调用(callcode)来执行这个操作。

内容最早见于网友发起的极客学院WIKI中。

分享两个以太坊开发教程:
1. 以太坊 DApp 实战开发入门
2. 去中心化电商 DApp 实战开发
区块链
2018-04-25 23:25:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
以太坊常用的三种共识机制(算法):PoW(Proof of Work),工作量证明机制;PoS(Proof of Stake):股权证明机制;DPoS(Delegated Proof of Stake),授权股权证明机制。这些共识机制都能在现实生活中找到对应的经济模型,吸引人们参与其中,组成安全网络,并有序运行。但是,长期来看它们各有优缺点,都存在失败的可能。
下面我们看看这些机制的演进过程。
PoW(Proof of Work):工作量证明机制
1.基本原理
这是比特币采用的共识机制,也是最早的。理解起来,很简单,就是“按劳取酬”,你付出多少劳动(工作),就会获得多少报酬(比特币等加密货币)。在网络世界里,这里的劳动就是你为网络提供的计算服务(算力x时长),提供这种服务的过程就是“挖矿”。
那么“报酬”怎么分配呢?假如是真的矿藏,显然在均匀分布的前提下,人们“挖矿”所得的比重与各自提供的算力成正比,通俗一点就是,能力越强获得越多。
2.优点
机制本身当然很复杂,有很多细节,比如:挖矿难度自动调整、区块奖励逐步减半等,这些因素都是基于经济学原理,能吸引和鼓励更多人参与。
理想状态,这种机制,可以吸引很多用户参与其中,特别是越先参与的获得越多,会促使加密货币的初始阶段发展迅速,节点网络迅速扩大。在Cpu挖矿的时代,比特币吸引了很多人参与“挖矿”,就是很好的证明。
通过“挖矿”的方式发行新币,把比特币分散给个人,实现了相对公平(比起那些不用挖矿,直接IPO的币要公平的多)。
3.缺点
一是,算力是计算机硬件(Cpu、Gpu等)提供的,要耗费电力,是对能源的直接消耗,与人类追求节能、清洁、环保的理念相悖。不过,如果非要给“加密货币”找寻“货币价值”的意义,那么这个方面,应该是最有力的证据。
二是,这种机制发展到今天,算力的提供已经不再是单纯的CPU了,而是逐步发展到GPU、FPGA,乃至ASIC矿机。用户也从个人挖矿发展到大的矿池、矿场,算力集中越来越明显。这与去中心化的方向背道而驰,渐行渐远,网络的安全逐渐受到威胁。有证据证明Ghash(一个矿池)就曾经对赌博网站实施了双花攻击(简单的说就是一笔钱花两次)。
三是,比特币区块奖励每4年将减半,当挖矿的成本高于挖矿收益时,人们挖矿的积极性降低,会有大量算力减少,比特币网络的安全性进一步堪忧。
PoS(Proof of Stake):股权证明机制。
1.基本原理
这是点点币(PPC)的创新。没有挖矿过程,在创世区块内写明了股权分配比例,之后通过转让、交易的方式(通常就是IPO),逐渐分散到用户手里,并通过“利息”的方式新增货币,实现对节点的奖励。
简单来说,就是一个根据用户持有货币的多少和时间(币龄),发放利息的一个制度。现实中最典型的例子就是股票,或者是银行存款。如果用户想获得更多的货币,那么就打开客户端,让它保持在线,就能通过获得“利息”获益,同时保证网络的安全。
2.优点
一是节能。不用挖矿,不需要大量耗费电力和能源。
二是更去中心化。首先说,去中心化是相对的。相对于比特币等PoW类型的加密货币,PoS机制的加密货币对计算机硬件基本上没有过高要求,人人可挖矿(获得利息),不用担心算力集中导致中心化的出现(单用户通过购买获得51%的货币量,成本更高),网络更加安全有保障。
三是避免紧缩。PoW机制的加密货币,因为用户丢失等各种原因,可能导致通货紧缩,但是PoS机制的加密货币按一定的年利率新增货币,可以有效避免紧缩出现,保持基本稳定。比特币之后,很多新币采用PoS机制,很多采用工作量证明机制的老币,也纷纷修改协议,“硬分叉”升级为PoS机制。
3.缺点
纯PoS机制的加密货币,只能通过IPO的方式发行,这就导致“少数人”(通常是开发者)获得大量成本极低的加密货币,在利益面前,很难保证他们不会大量抛售。因此,PoS机制的加密货币,信用基础不够牢固。为解决这个问题,很多采用PoW+PoS的双重机制,通过PoW挖矿发行加密货币,使用PoS维护网络稳定。或者采用DPoS机制,通过社区选举的方式,增强信任。
DPoS(Delegated Proof of Stake):授权股权证明机制
1.基本原理
这是比特股(BTS)最先引入的。比特股首次提出了去中心化自治公司(DACs)的理念。比特股的目的就是用于发布DACs。这些无人控制的公司发行股份,产生利润,并将利润分配给股东。实现这一切不需要信任任何人,因为每件事都是被硬编码到软件中的。通俗点讲就是:比特股创造可以盈利的公司(股份制),股东持有这些公司的股份,公司为股东产生回报。无需挖矿。
对于PoS机制的加密货币,每个节点都可以创建区块,并按照个人的持股比例获得“利息”。DPoS是由被社区选举的可信帐户(受托人,得票数排行前101位)来创建区块。为了成为正式受托人,用户要去社区拉票,获得足够多用户的信任。用户根据自己持有的加密货币数量占总量的百分比来投票。DPoS机制类似于股份制公司,普通股民进不了董事会,要投票选举代表(受托人)代他们做决策。
这101个受托人可以理解为101个矿池,而这101个矿池彼此的权利是完全相等的。那些握着加密货币的用户可以随时通过投票更换这些代表(矿池),只要他们提供的算力不稳定,计算机宕机、或者试图利用手中的权力作恶,他们将会立刻被愤怒的选民门踢出整个系统,而后备代表可以随时顶上去。
2.优点
一是,能耗更低。DPoS机制将节点数量进一步减少到101个,在保证网络安全的前提下,整个网络的能耗进一步降低,网络运行成本最低。
二是,更加去中心化。目前,对于比特币而言,个人挖矿已经不现实了,比特币的算力都集中在几个大的矿池手里,每个矿池都是中心化的,就像DPoS的一个受托人,因此DPoS机制的加密货币更加去中心化。PoS机制的加密货币(比如未来币),要求用户开着客户端,事实上用户并不会天天开着电脑,因此真正的网络节点是由几个股东保持的,去中心化程度也不能与DPoS机制的加密货币相比。
三是,更快的确认速度。比如,亿书使用DPoS机制,每个块的时间为10秒,一笔交易(在得到6-10个确认后)大概1分钟,一个完整的101个块的周期大概仅仅需要16分钟。而比特币(PoW机制)产生一个区块需要10分钟,一笔交易完成(6个区块确认后)需要1个小时。点点币(PoS机制)确认一笔交易大概也需要1小时。
3.缺点
前几天,比特股的作者发表了一篇被广泛认为很傻的文章(见参考),预言DAO(去中心化组织)和DAC(去中心化公司)都将失败。文中披露了大量实践经验,基本算是DPoS的问题。概括起来,主要是:
一是投票的积极性并不高。绝大多数持股人(90%+)从未参与投票。这是因为投票需要时间、精力以及技能,而这恰恰是大多数投资者所缺乏的。
二是对于坏节点的处理存在诸多困难。社区选举不能及时有效的阻止一些破坏节点的出现,给网络造成安全隐患。
原文由网友imfly编写,最早发布于技术社区github
分享两个以太坊开发教程:
1. 以太坊 DApp 实战开发入门
2. 去中心化电商 DApp 实战开发
区块链
2018-04-25 23:01:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战入门教程 以太坊去中心化电商应用开发实战
返回匹配指定交易哈希值的交易。
调用: web3.eth.getTransaction(transactionHash [, callback])
参数: transactionHash : String - 交易的哈希值。 callback : Function - 回调函数,用于支持异步的方式执行7。
返回值: Object - 一个交易对象 hash: String - 32字节,交易的哈希值。 nonce: Number - 交易的发起者在之前进行过的交易数量。 blockHash: String - 32字节。交易所在区块的哈希值。当这个区块处于pending将会返回null。 blockNumber: Number - 交易所在区块的块号。当这个区块处于pending将会返回null。 transactionIndex: Number - 整数。交易在区块中的序号。当这个区块处于pending将会返回null。 from: String - 20字节,交易发起者的地址。 to: String - 20字节,交易接收者的地址。当这个区块处于pending将会返回null。 value: BigNumber - 交易附带的货币量,单位为Wei。 gasPrice: BigNumber - 交易发起者配置的gas价格,单位是wei。 gas: Number - 交易发起者提供的gas。. input: String - 交易附带的数据。
示例: var blockNumber = 668; var indexOfTransaction = 0 var transaction = web3.eth.getTransaction(blockNumber, indexOfTransaction); console.log(transaction); /* { "hash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b", "nonce": 2, "blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46", "blockNumber": 3, "transactionIndex": 0, "from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", "value": BigNumber, "gas": 314159, "gasPrice": BigNumber, "input": "0x57cb2fc4" } */
区块链
2018-04-26 23:54:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战入门教程 以太坊去中心化电商应用开发实战
发送一个已经签名的交易。比如可以用下述 签名的例子 。
如果交易是一个合约创建,请使用web3.eth.getTransactionReceipt()在交易完成后获取合约的地址。
调用: web3.eth.sendRawTransaction(signedTransactionData [, callback])
参数: signedTransacionData : String - 16进制格式的签名交易数据。 callback : Function - 回调函数,用于支持异步的方式执行7。
返回值: String - 32字节的16进制格式的交易哈希串。
示例: var Tx = require('ethereumjs-tx'); var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex') var rawTx = { nonce: '0x00', gasPrice: '0x09184e72a000', gasLimit: '0x2710', to: '0x0000000000000000000000000000000000000000', value: '0x00', data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057' } var tx = new Tx(rawTx); tx.sign(privateKey); var serializedTx = tx.serialize(); //console.log(serializedTx.toString('hex')); //0xf889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f web3.eth.sendRawTransaction(serializedTx.toString('hex'), function(err, hash) { if (!err) console.log(hash); // "0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385" });
区块链
2018-04-26 23:54:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战入门教程 以太坊去中心化电商应用开发实战
发送一个交易到网络。如果交易是一个合约创建的,请使用web3.eth.getTransactionReceipt()在交易完成后获取合约的地址。
调用: web3.eth.sendTransaction(transactionObject [, callback])
参数: transactionObject : Object - 要发送的交易对象。 from: String - 指定的发送者的地址。如果不指定,使用web3.eth.defaultAccount。 to: String - (可选)交易消息的目标地址,如果是合约创建,则不填. value: Number|String|BigNumber - (可选)交易携带的货币量,以wei为单位。如果合约创建交易,则为初始的基金。 gas: Number|String|BigNumber - (可选)默认是自动,交易可使用的gas,未使用的gas会退回。 gasPrice: Number|String|BigNumber - (可选)默认是自动确定,交易的gas价格,默认是网络gas价格的平均值 。 data: String - (可选)或者包含相关数据的字节字符串,如果是合约创建,则是初始化要用到的代码。 nonce: Number - (可选)整数,使用此值,可以允许你覆盖你自己的相同nonce的,正在pending中的交易11。 Function - 回调函数,用于支持异步的方式执行7。
返回值: String - 32字节的交易哈希串。用16进制表示。
示例: // compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; web3.eth.sendTransaction({data: code}, function(err, address) { if (!err) console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" });
区块链
2018-04-26 23:53:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
什么是以太坊预言机?智能合约就其性质而言,能够运行各种算法并可以存储和查询数据。预言机可以监控区块链事件并能将监控结果发回智能合约。因为每个节点每次都需要大量计算,所以从Ethereum智能合约开发中进行频繁的网络请求是切不实际的。这样,智能合约就可以与链外的世界进行互动了。
但是这样有一个明显的信任问题。与信任单一外部数据源的分布式智能合约有些矛盾。不过这可以通过让多个独立的预言机来响应相同的查询最终形成共识来缓解这个问题。
有关预言机的更多信息,请查看在分布式应用程序之间提供“可靠连接”的FinTech公司Oraclize。 他们对预言机的解释很不错。
The  Tinypay.co  DNS Oracle
Tinypay的预言机做了三件简单的事情: 从合同中提取'ClientCreated'事件 使用来自事件的数据验证DNS记录 域名确认后,向合约发送'ConfirmClient'交易
我经历了几次迭代,最终实现了,我希望通过它们来引导您了解以太坊的发展。
你也可以直接用RPC,不过似乎不应这么干
我第一次写预言机,我用了Go-Ethereum。我想直接使用RPC API与Ethereum节点进行所有通信。
这很有趣,因为我能够学习很多关于以太坊协议如何进行存储和数据编码等较底层的内容。我必须手动重新在代码中创建ABI(应用程序二进制接口),并使用它来发送和解密消息。 ABI对于定义合约如何交互以及如何从线上的原始字节中提取数据是必需的。
从事件中实际提取数据证明比我想象的要复杂得多。Go-Ethereum的处理事件没完成。我被迫手动轮询RPC端点,并找出如何将来自原始事件的二进制数据解码。Go-Ethereum当然似乎是以太坊团队关注的焦点,他们应该很清楚Go-Ethereum在观看和解码事件方面的问题。我希望他们能很快有所提升,这会使得Go-Ethereum成为编写预言机和其他以太坊客户端应用程序的更好选择。
低级别的RPC API和解码API被证明是非常低效率的,并且他们正在更快地进行迭代,所以...
Web3 则是一个很好的抽象
对于第二次迭代,我切换到node.js并使用web3库与geth节点进行通信。 这给了我内置的抽象了的事件查询,数据提取和格式化,而且明显使开发变得更容易。
我开始使用Alex Beregszaszi非常有用的'tinyoracle'指南,这让我在第二版中获得了不错的成果
下面的代码是经过选择编辑的,完整的代码可以在github存储库中找到(本次迭代的标签为v0.0.2) var Web3 = require('web3'); var web3 = new Web3(); var contracts = require(path.join(__dirname, 'gen_contracts.json')); // First we instruct web3 to use the RPC provider //首先我们指定web3使用RPC接口 web3.setProvider( new web3.providers.HttpProvider( 'http://' + opts.rpc_host + ':' + opts.rpc_port)); // This isn't strictly necessary here, but goes to show the step // required to "unlock" the account before sending transactions. // 这并不是严格需要的,但它显示了在发送交易之前“解锁”帐户所需的步骤。 if (!web3.personal.unlockAccount( web3.eth.coinbase, opts.wallet_password)) { console.error('Could not unlock'); process.exit(); } //Here we register the filter with the ethereum node, //and then begin polling for updates. //在这里,我们用以太坊节点注册过滤器,然后开始轮询更新 function runLoop(o) { var filter = web3.eth.filter({address: o.contract_address}); filter.watch(function (err, results) { if (err) { console.log('WATCH ERROR: ', err); process.exit(); } console.debug(results); }); } // If the contract isn't deployed yet, we deploy it here //如果还没有部署合约,我们在这里部署它。 if (!opts.contract_address) { // This block of code loads the ABI for interpreting contract data. // 该代码块加载ABI来解释合约数据。 var dmC = web3.eth.contract(JSON.parse(contracts.DomainMicropay.abi)); var x = { from: web3.eth.coinbase, data: contracts.DomainMicropay.bin, gas: 1000000 }; // send the transaction for installing the contract. //发送用于部署合约的交易。 dmC.new(x, function (err, resp) { if (err) { console.error('Loading contract', err); process.exit(); } var addr = resp.address; if (!addr) { console.log('Pending tx: ', resp.transactionHash); } else { console.log('Deployed Address: ', addr); opts.contract_address = addr; runLoop(opts); } }); } else { runLoop(opts); // in either case, start the polling event loop. //在任一种情况下,启动轮询事件循环 }
Truffle 应该是你最想用的框架
最后,在第三次迭代中,我放弃了自己搞的这一切。 我们已经在我们的网络前端使用ConsenSys的优秀工具Truffle。 我只是将生成的构件复制到我的node.js项目中,并直接将其包含在内,然后就开始工作。
使用Truffle,我们能够将我们的Solidity合约编译成的一个JavaScript库,它可以确认各种重要的细节,如合同的部署地址,并完全代替低级RPC通信。 查看事件,发送交易和查询数据变成了直接从我们的合同中生成的简单API调用。 // This code extract shows the whole event loop abstracted behind the actual event name: ClientConfirmed and ClientCreated. // 这段代码显示了整个事件循环中的抽象后的实际事件:ClientConfirmed 和 ClientCreated。 startWatcher: function (rpcUrl, unlockPass) { password = unlockPass || password; web3.setProvider(new web3.providers.HttpProvider(rpcUrl)); DomainMicropay.setProvider(web3.currentProvider); contract.ClientConfirmed({}, eventOpts(), function (err, data) { if (err) { console.log('Error ClientConfirmed: ', err); return; } console.log('Event ClientConfirmed: ', data.args.domain); }); contract.ClientCreated({}, eventOpts(), function (err, data) { if (err) { console.log('Error ClientCreated: ', err); return; } console.log('Event ClientCreated: ', data.args.domain); contract.getPaymentContractForDomain .call(data.args.domain) .then(beginDomainVerification(data)) .catch(errFn('Unhandled Error: ')); }); }
正如您所看到的,Truffle为使用智能合约并与之交互提供了一些非常好的抽象。这并不完美,也不能解决合约版本问题等问题。但是我们需要在其他文章中再介绍这些内容。
希望赢得你喜欢,并可以帮助你开发下一个“DApp”。 如果您正在寻求帮助理解或利用区块链技术,请联系 we@mustwin.com 并参考本文。
原文:medium.com/@mustwin/building-an-oracle-for-an-ethereum-contract-6096d3e39551
安利两个实战教程:
1. 适合区块链新手的以太坊DApp开发
2. 用区块链、星际文件系统(IPFS)、Node.js和MongoDB来构建电商平台
区块链
2018-04-25 18:05:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
什么是预言机(oracle)?和以太坊智能合约开发是什么关系?在区块链去中心化的条件下如何实现预言机?面对这些疑惑首先来了解下我们开发以太坊智能合约的需求。
当我们需要获取一些必要的数据时,可能不得不与与第三方进行交流。原因可能有很多种。
例如说在签署比特币多重签名交易时,你可能不相信单一实体。比方说,你希望某些资金在某些条件下被移动。要么自己手动来要么将其其委托给第三方(你可能还不太放心),按照比特币的方式,会通过多重签名交易强制执行你的逻辑,将交易审批流程分发给不同的签署方(预言机)。
利用N-M多重签名交易的方法是确保每个签署者(预言机)只拥有一个私钥,以便他可以在他认为正确的时机放置一个签名,但交易只会有效N次M个签署者(预言机)将就要签署的交易达成共识。这比信任单一的外部实体信息源要强大得多,因为选定的签署者(预言机)是相互竞争的,并且变化不会不大。
其实拥有分布式预言机网络的想法已经存在了很多年,但是在一个跨越不同预言机的通信上找到共识是十分困难的。寻找愿意加入该网络的各方更加困难,因为这需要建立一个良好的激励机制,而关于如何与这个预言机网络进行交互的适当设计也还没有达成一个共识。除此之外,一个主要限制可能是你需要用来获取数据的数据源,其中一些可能在未经过外部各方许可的情况下就已经可以使用了。
但是以太坊智能合约出现后,这个想法就有很大不同,你的交易批准逻辑由网络通过你自己的智能合同代码实施。这意味着一旦某些条件得到验证(智能合约意味着你可以设置验证条件),预言机就不会签名,而是它只向你提供符合你要求的数据,可以直接验证条件并触发你想要的任何事务或状态更改。目前智能合约仍然不能依靠分布式网络来获取外部数据,链上执行的应用程序或者服务,还活在自己的区块链围城里,因此你需要使用预言机才能将外部数据引入进来。
对数据日益增长的需求来说,越来越多的行业寻找越来越复杂的现实世界。然而,大多数关于预言机的误解是由于你可能希望预言机为你获得某些数据而造成的。
例如Augur或Gnosis这样的预测市场的以太坊项目就是为了围绕未来的事实提供一个关于人群不断情绪变化的良好和可靠的指标,例如博彩。预测市场通常被也被称为预言机,但与我们讨论的不同,它的意义更为广泛和完全不同。
还有一点值得讨论,我们可能会想这是我们要调用预言机的价格吗?这只是一个数据源,大多数时候它不会与区块链有任何关联。金融机构通常将“彭博社”或“路透社”也称为预言机,但他们真正的意思是将它们用作信息数据的来源。作为预言机会带来与区块链接口的所有复杂性,这是数据源不可能直接提供的(因为这需要额外的复杂性和成本)。尽管如此,一旦选择了适当的数据源和公式,预言机仍可以访问比如彭博社的数据。把这些也成为是提供“预言机”而不是“数据源”其实是对这个术语的另一种滥用。
为了让这个问题更清楚,我们可以定义3个部分:
1. 数据源
数据源,这是你要查找的信息的来源,这可以取决于你的实际查询,可以是“Augur”(查看未来事件/事实),“Bloomberg”(查找财务数据),“比特币区块链”(查找地址余额,给定交易OP_RETURN的内容或任何其他区块链数据),“WolframAlpha”(查找给定Wolfram Alpha查询的响应)或其他任何来自“网络”的数据。获取网络数据并使用或通过API获取数据既是你想从中获取数据的最简单也是最常用的方式方法。
2. 查询
查询可以选择的数据源,以便确认你想要获取的数据。
3. 预言机 / 预言机网络
预言机/预言机网络负责将你和数据源的一方连接起来。
推荐两个以太坊实战教程: 以太坊 智能合约 ,以太坊开发智能合约与dapp入门实战,适合入门。 以太坊电商教程 ,以太坊通过node.js、mongodb、ipfs、express构建电商平台实战,适合进阶。
区块链
2018-04-25 17:17:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
区块链兄弟社区,区块链技术专业问答先行者,中国区块链技术爱好者聚集地
作者:吴寿鹤
来源: 区块链兄弟
原文链接: http://www.blockchainbrother.com/article/29
著权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

说到分叉,我们首先了解一下在软件开发中的分叉是什么?
软件项目中的分叉
软件开发中的分叉指的是:在开源项目中如果有人Fork了一个项目(一个项目分叉为两个项目),然后开发者沿着这个Fork向另外一个不同的方向独立发展这个项目。例如Litecoin就是bitcoin的一个分叉,litecoin的基础代码就是bitcoin的,不过litecoin后来慢慢的发展成了一个另外一个独立的项目。但是依然和bitcoin有着非常紧密的相关性。但litecoin和bitcoin是两种不同的加密货币。
Bitcoin术语中的软分叉与硬分叉
比特币中的软分叉和硬分叉主要指因比特币协议的突发改变而导致的兼容性的问题。比特币协议发生改变,会有两个不同版本的比特币协议在同时使,他们对其他区块的接受规则不同会导致区块链长期分叉,这两个不同的链都会被不同的网络认为是有效的。链分叉也导致网络分叉。
软分叉是向前兼容的

如上图软分叉的新的规则是以前旧规则的子集,所有被新版本认为是合法的区块也会被以前旧版本认为是合法的。旧版本会接受新版本创建的区块。新版本和旧版本是兼容的。
如果有至少51%的矿工的算力转向的新版本,那么网络自动完成软分叉:一开始旧版本创建的区块在新协议下被认为是不合法的,这时会出现一个短暂的分叉,但最终新版本的分叉会赶超旧版本的分叉成为最长链。因为在旧版本上的算力是小于新版本的。
但是如果小于51%的矿工算力转向新版本,那么软分叉将不会出现,因为旧版本比新版本有更多的算力支持,同时旧版本不兼容新版本。
硬分叉不向前兼容:

旧版本不会接受新版本创建的合法区块,认为新版本的合法区块是不合法的。所以很明显硬分叉是不向前兼容。要实现硬分叉所有的用户(矿工,交易所,普通用户)都要切换的新的协议版本上。
总结:
软分叉向前兼容,旧的版本会接受新版本创建的区块,在软分叉中只需要矿工升级到新版本即可,用户可以继续使用旧版本的协议,他们仍然会接受新版本协议创建的区块。
硬分叉不向前兼容,旧版本不会接受新版本创建的区块。要实现硬分叉所有用户都需要切换到新版本协议上。
为什么硬分叉不需要51%以上的算力,因为即便旧链的长度大于新链也没用,新版本是不会接受旧链上的区块,如果所有用户都更新到新的版本那么客户的钱包会认为旧链上的资产是非法的,旧链上的货币无法使用。
THE DAO 为什么要进行硬分叉而不是软分叉:如果进行软分叉,由于新版本是和旧版本兼容的,所以旧版本上的资产同样也是可以在新版本上消费的,那么就不能达到回滚黑客资产的目的。
文章发布只为分享区块链技术内容,版权归原作者所有,观点仅代表作者本人,绝不代表区块链兄弟赞同其观点或证实其描述
区块链
2018-04-25 13:47:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
infura.io提供了托管的以太坊节点,那么,如何将智能合约部署到infura提供的托管节点?本教程将介绍如何配置truffle来将你的智能合约通过infura发布到以太坊网络上。
如果你还没有看过前序教程,建议先阅读它们: 什么是智能合约 以太坊智能合约开发 以太坊智能合约部署
Infura是一个托管的以太坊节点集群,可以将你开发的以太坊智能合约部署到infura提供的节点上,而无需搭建自己的以太坊节点。
可能你还不了解Infura,但如果你使用过MetaMask,那么就已经接触过Infura了,因为它是MetaMask背后的以太坊供应商。
出于安全原因,Infura不管理你的私钥,这意味着Infura不能代表你签署交易。
但是,Infura可以通过使用 HDWalletProvider 来签署交易。 该服务可以处理事务签名以及与以太坊网络的连接。 点击 这里 了解更多关于HDWalletProvider的信息 。
本教程将向你展示如何使用Infura将现有的dapp迁移到Infura支持的以太坊网络。 在这个特定的例子中,我们将迁移到Ropsten测试网络。 我们假设你已经有了一个dapp, 如果需要一个测试dapp,可以使用Truffle提供的 宠物店 dapp。 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
安装HDWalletProvider
Infura的HDWalletProvider是一个独立的npm软件包,如下安装: npm install truffle-hdwallet-provider 注意 :如果你在Windows上安装并且遇到MSBUILD错误,则可能需要安装Windows构建工具。 在具有管理员权限的控制台中,运行 npm install -g windows-build-tools 然后再次尝试安装。
注册Infura
在使用Infura之前,需要 注册Infura访问令牌 。
填写并提交表格后你就可以收到访问令牌。 相关信息将显示在屏幕上并发送到你提供的电子邮件。 需要记录下来这个访问令牌并确保它不被别人看到!
配置Truffle项目
下一步是编辑你的truffle.js文件来启用HDWalletProvider并为部署到Ropsten进行必要的配置。
STEP 1:首先,在配置文件中定义HDWalletProvider对象。 在truffle.js文件的顶部添加以下代码: var HDWalletProvider = require("truffle-hdwallet-provider");
STEP 2:接下来,提供助记词( mnemonic )来生成你的账户。 var mnemonic = "orange apple banana ... "; 警告 :在此过程中,我们强烈建议将助记符存储在另一个(秘密)文件中,以降低助记符泄漏风险。 如果有人知道你的助记符,他们将拥有你所有的地址和私钥!
STEP 3:添加Ropsten网络定义: module.exports = { networks: { ropsten: { provider: function() { return new HDWalletProvider(mnemonic, "https://ropsten.infura.io/") }, network_id: 3 } } };
注意事项: 虽然该示例仅定义了单个网络,但你可以像往常一样定义多个网络。 ropsten网络定义中的provider将使用实例化的HDWalletProvider 。 HDWalletProvider以助记符和期望的网络为参数。 Infura主页 上提供Infura支持的 网络列表。 确保使用前面拿到的Infura访问令牌替换 。 provider值被封装在一个函数中,这可以确保它在需要之前不会被初始化。 如果连接到多个网络,这一点尤为重要。 关于该主题的更多信息,请参阅Truffle文档的 网络配置 部分。 默认情况下,由助记符产生的第一个账户将负责执行合约迁移任务。 但如果需要的话,你可以传入参数以指定要使用的帐户。 例如,要使用第三个帐户: new HDWalletProvider(mnemonic, "https://ropsten.infura.io/", 2);
账户索引是从零开始的,所以2表示第三个地址。
使用Faucet获取ether
确保你的帐户有足够的账户余额来进行部署。 可以通过称Faucet的服务在Ropsten网络上获取Ether。 虽然在那里有多个Faucet网站,我们推荐的一个服务是在 EthTools 上托管的 。 导航至EthTools的 Ether Faucet 。 输入你的助记符,并选择你想要多少ether(最多5个)。 Faucet将链接到你的第一个帐户。 点击“Request Ether”提交请求。 很快,你的账户将获得请求的ether。 注意 :也可以通过MetaMask申请ether。 在Ropsten上连接你的帐户,然后点击“Buy”按钮,该按钮将提供MetaMask的Ropsten测试Faucet的链接,它的工作方式与上述类似。
我们现在可以开始将合约部署到Ropsten上了!
部署合约
STEP 1: 编译项目: truffle compile
STEP 2:部署到Ropsten网络: truffle migrate --network ropsten
如果一切顺利,应该可以看到类似于以下内容的输出: Using network 'ropsten'. Running migration: 1_initial_migration.js Deploying Migrations... ... 0xd79bc3c5a7d338a7f85db9f86febbee738ebdec9494f49bda8f9f4c90b649db7 Migrations: 0x0c6c4fc8831755595eda4b5724a61ff989e2f8b9 Saving successful migration to network... ... 0xc37320561d0004dc149ea42d839375c3fc53752bae5776e4e7543ad16c1b06f0 Saving artifacts... Running migration: 2_deploy_contracts.js Deploying MyContract... ... 0x7efbb3e4f028aa8834d0078293e0db7ff8aff88e72f33960fc806a618a6ce4d3 MyContract: 0xda05d7bfa5b6af7feab7bd156e812b4e564ef2b1 Saving successful migration to network... ... 0x6257dd237eb8b120c8038b066e257baee03b9c447c3ba43f843d1856de1fe132 Saving artifacts...
需要提醒的是,你的交易ID将与上面的不同。
注意 :如果收到错误 Error: Exceeds block gas limit ,你可能需要为合约手动设置油量上限( gas limit )。 有关详细信息,请参阅 Truffle配置文档 。
STEP 3:如果想验证合约是否已成功部署,可以在Etherscan的Ropsten部分进行检查。 在搜索字段中,输入部署交易ID。 在上面的例子中,交易ID是: 0x7efbb3e4f028aa8834d0078293e0db7ff8aff88e72f33960fc806a618a6ce4d3
你应该可以看到有关交易的详细信息,包括交易受到保护的区块号。
恭喜! 你已经使用Infura和truffle的组合将合约部署到Ropsten上了!
参考: truffle+infura部署以太坊智能合约
区块链
2018-04-25 13:19:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
智能合约是 1990s 年代由尼克萨博提出的理念,几乎与互联网同龄。由于缺少可信的执行环境,智能合约并没有被应用到实际产业中,自比特币诞生后,人们认识到比特币的底层技术区块链天生可以为智能合约提供可信的执行环境,以太坊首先看到了区块链和智能合约的契合,发布了白皮书《以太坊:下一代智能合约和去中心化应用平台》,并一直致力于将以太坊打造成最佳智能合约平台,所以比特币引领区块链,以太坊复活智能合约。
怎样向尚未接触过比特币理念的人介绍以太坊及智能合约在金融合约方面的应用?下面是一种尝试。首先介绍区块链,解释它为什么值得人们的信任,其次介绍智能合约,然后介绍以太坊系统,最后介绍智能合约与金融合约的结合。
比特币的共识机制
比特币的核心技术区块链可以理解成可复制、共享的账本。
比特币的最核心创新:它教会世界如何在不需要信任第三方的情况下远距离转移价值。
人们当然可以面对面地转移实体纸币,但是,在比特币出现以前,我们做不到:在不需要信任中心化第三方机构(邮局、银行等)的情况,远距离向某人转移价值。
就好像银行和支付系统的传统转账模式的基础设施被重构为点对点支付网络。这种转变如下图所示:
比特币打开了点对点的电子价值转移模式的大门,完全不同于现在的银行系统、中央银行和支付系统。 但是,上面的图并没有解释比特币是怎样实现点对点价值转移的。
答案是:比特币系统建立在“可复制、共享的账本”之上。比特币网络中的每个参与者(完全节点)拥有一个完整的交易账本的副本,这一系统的神奇之处在于:它是如何做到使每个人的副本与其他人的副本保持一致的。
所以,正确的示意图应该是下图,每个参与者都能够从相同的可复制、共享的账本中获取信息。
比特币和其它去中心化共识系统的窍门在于:它们怎样保证每个有一个账本的副本,并使每个人确信自己的账本与别人的账本是同步的。
如果每个人拥有的账本的副本是相同的,那么人们就不再需要一个中心化的机构记录谁拥有什么。当你的账本更新,记录一笔新的资产所有权变动时,其他人的账本也会发生相同的变动。
智能合约
智能合约程序不只是一个可以自动执行的计算机程序:它自己就是一个系统参与者。它对接收到的信息进行回应,它可以接收和储存价值,也可以向外发送信息和价值。
这个程序就像一个可以被信任的人,可以临时保管资产,总是按照事先的规则执行操作。
下面这个示意图就是一个智能合约模型:一段代码(智能合约),被部署在分享的、复制的账本上,它可以维持自己的状态,控制自己的资产和对接收到的外界信息或者资产进行回应。

智能合约模型:它是运行在可复制、共享的账本上的计算机程序,可以处理信息,接收、储存和发送价值。
以太坊系统
以太坊项目借鉴了比特币区块链的技术,对它的应用范围进行了扩展。如果说比特币是利用区块链技术的专用计算器,那么以太坊就是利用区块链技术的通用计算机。简单地讲,以太坊 = 区块链 + 智能合约。
与比特币相比,以太坊最大的不同点是:它可以支持更加强大的脚本语言(用技术语言讲就是图灵完备的脚本语言),允许开发者在上面开发任意应用,实现任意智能合约,这也是以太坊的最强大之处。作为平台,以太坊可以类比于苹果的应用商店,任何开发者都可以在上面开发应用,并出售给用户。
以太坊智能合约的金融应用
每一类金融合约都可以程序代码的形式写成智能合约。
差价合约
金融衍生品是“智能合约”的最普遍的应用,也是最易于用代码实现的之一。实现金融合约的主要挑战是它们中的大部分需要参照一个外部的价格发布器;例如,一个需求非常大的应用是一个用来对冲以太币(或其它密码学货币)相对美元价格波动的智能合约,但该合约需要知道以太币相对美元的价格。最简单的方法是 通过由某特定机构(例如纳斯达克)维护的“数据提供“合约进行,该合约的设计使得该机构能够根据需要更新合约,并提供一个接口使得其它合约能够通过发送一 个消息给该合约以获取包含价格信息的回复。
当这些关键要素都齐备,对冲合约看起来会是下面的样子:
等待A输入1000以太币。
等待B 输入1000以太币。
通过查询数据提供合约,将1000以太币的美元价值,例如,x美元,记录至存储器。
30天后,允许A或B“重新激活“合约以发送价值x美元的以太币(重新查询数据提供合约,以获取新价格并计算)给A并将剩余的以太币发送给B。
代币系统(token system)
区块链上代币系统有很多应用,从代表如美元或黄金等资产的子货币到公司股票,单独的代币代表智能资产,安全的不可伪造的优惠券,甚至与传统价值完全没有联系的用来进行积分奖励的代币系统。在以太坊中实施代币系统容易得让人吃惊。关键的一点是理解,所有的货币或者代币系统,从根本上来说是一个带有如下操作的数据库:从A中减去X单位并把X单位加到B上,前提条件是(1)A在交易之前有至少X单位以及(2)交易被A批准。实施一个代币系统就是把这样一个逻辑实施到一个合约中去。
储蓄钱包
假设Alice想确保她的资金安全,但她担心丢失或者被黑客盗走私钥。她把以太币放到和Bob签订的一个合约里,如下所示,这合同是一个银行:
Alice单独每天最多可提取1%的资金。
Bob单独每天最多可提取1%的资金,但Alice可以用她的私钥创建一个交易取消Bob的提现权限。
Alice 和 Bob 一起可以任意提取资金。
一般来讲,每天1%对Alice足够了,如果Alice想提现更多她可以联系Bob寻求帮助。如果Alice的私钥被盗,她可以立即找到Bob把她 的资金转移到一个新合同里。如果她弄丢了她的私钥,Bob可以慢慢地把钱提出。如果Bob表现出了恶意,她可以关掉他的提现权限。
作物保险
一个人可以很容易地以天气情况而不是任何价格指数作为数据输入来创建一个金融衍生品合约。如果一个爱荷华的农民购买了一个基于爱荷华的降雨情况进行反向赔付的金融衍生品,那么如果遇到干旱,该农民将自动地收到赔付资金而如果有足量的降雨他会很开心因为他的作物收成会很好。 多重签名智能契约
多重签名智能合约
比特币允许基于多重签名的交易合约,例如,5把私钥里集齐3把就可以使用资金。以太坊可以做得更细化,例如,5把私钥里集齐4把可以花全部资金,如果只3把则每天最多花10%的资金,只有2把就只能每天花0.5%的资金。

分享两个教程:
1. 适合区块链新手的以太坊DApp开发教程
2. 用区块链、星际文件系统(IPFS)、Node.js和MongoDB来构建以太坊DApp电商平台
区块链
2018-04-25 12:47:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
目前的智能合约基本都是运行在以太坊上。本文将通过一个简单而具体的智能合约实例来帮助大家理解智能合约的编写、部署与调用。这个例子很简单,但通过它你可以了解开发一个以太坊的智能合约的完整过程。 在之后的教程中,我们将结合不同的场景案例,分别举出不同的例子例如投票、众筹、拍卖、ERC20/ERC721代币发行等,并实现相应的solidity示例代码。我们希望你能在实践中逐步理解学习智能合约的开发语言solidity,理解智能合约的运行原理,并掌握必要的以太坊智能合约编程技能。 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
开发语言和开发环境选择
目前智能合约最受欢迎的编程语言为Solidity,但是并不只有Solidity。作为初学者,编写Solidity代码,我们可以使用Remix,它是一个基于浏览器的Soldity IDE,网址为: http://remix.ethereum.org/ 。Remix支持编写、测试和部署智能合约。
编写代码
学一门语言的第一个程序毋庸置疑都是HelloWorld,那么我们就来写一个HelloWorld的智能合约吧。合约代码如下。 pragma solidity ^0.4.21; contract HelloWorld { string hello = "Hello World!!!"; event say(string _value); function sayHello() public { emit say(hello); } }
合约代码第一行指定该合约使用的Solidity版本为0.4.21,不支持高于0.4.21版本的Solidity特性。
在Solidity中,contract关键字包含的代码段即表示一个智能合约,它拥有一些成员变量,表示该合约的数据,如我们的HelloWorld中的hello,我们可以修改操作这些成员。同时它拥有一些function,可以被他人调用。
event是Solidity提供的一种事件和订阅机制,智能合约能够发出一些event,合约调用者能够监听这些事件并作出相应的反应。
这个合约没有做很多事情,它只会在有人调用它的sayHello方法时,发出一个say事件。接下来让我们来部署和执行它。
部署和运行合约
首先我们需要编译这段代码,在Remix的右边有一个Compile的tab,点击Start to compile,编译成功,如果失败会有错误提示,改正即可。
然后我们需要将其部署到区块链上,切换tab到Run。
Remix支持三种环境运行合约。其中如果为JavaScript VM,则合约会在浏览器JavaScript沙箱区块链中被执行,可以理解为Remix使用了浏览器的JS环境虚拟了一个区块链虚拟机。如果为Injected Provider,则Remix将会链接Matamask或者Mist这些区块链钱包,通过它们来间接部署和调用合约。最后为Web3 Provider,Remix会链接Geth等远程区款连节点,来部署和调用合约。
简单起见,我们将使用JavaScript VM,它将为我们初始化出五个区块链账号,使用默认账号即可。将Environment设置为JavaScript VM。
上图除了Environment和Account依次往下,我们将能够看到Gas Limit,这是执行一个Transaction我们能够接受的最大代价。Value表示下一次调用我们将向合约账户转账多少ether。
接下来的HelloWorld表示我们将创建的合约。点击Create既能够创建这个合约。
我们可以点击sayHello调用。可以看到已经调用成功,在logs中打印出了我们发出的event。
结语
在本文中,我们编写了一个最简单的智能合约,并部署和运行了该合约。我们并没有将合约部署到实际的链上,只是在JS 沙箱虚拟机中执行了它。后面的文章中我们将会继续讲解如何将合约部署到链上。
区块链
2018-04-25 00:34:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
学习以太坊智能合约开发最好的方法,莫过于结合具体的应用场景案例,举例如投票、众筹、ERC20或ERC721代币发行等等,通过一个实例的实现,边实践边学习了。在这篇教程中,我们将使用以太坊solidity来实现一个遵循以太坊ERC20代币规范的智能合约,并给出最终实现的solidity全部代码。 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
ERC20规范
ERC20约定了一个代币合约需要实现的接口,规范参见 ERC20 // 接口标准 contract ERC20 { function totalSupply() constant returns (uint totalSupply); // 总发行量 function balanceOf(address _owner) constant returns (uint balance); // 代币分发(注意, 这个只有合约的Creator 可以调用) function transfer(address _to, uint _value) returns (bool success); // 这里是拥有者和拥有者之间的代币转移 function transferFrom(address _from, address _to, uint _value) returns (bool success); function approve(address _spender, uint _value) returns (bool success); function allowance(address _owner, address _spender) constant returns (uint remaining); event Transfer(address indexed _from, address indexed _to, uint _value); event Approval(address indexed _owner, address indexed _spender, uint _value); // Token信息 string public constant name = "4FunCoin"; string public constant symbol = "4FC"; uint8 public constant decimals = 18; // token的精度, 大部分都是18 }
上面的代码是一个标准的ERC20标准的代码, 规范给出了框架, 我们只需要实现相应的函数就好了, 这里给出函数说明。
接口函数说明
函数的形参是局部有效, 所以前面使用下划线, 与其他的变量区别开来. 如 _owner. totalSupply() 函数返回这个Token的总发行量; balanceOf() 查询某个地址的Token数量 , 结合mapping实现 transfer() owner 使用这个进行发送代币 transferFrom () token的所有者用来发送token allowance() 控制代币的交易,如可交易账号及资产, 控制Token的流通 approve() 允许用户可花费的代币数;
事件函数说明
这里两个Event是重点, 事件,可以被前端js代码捕获到并进行相应的处理: event Transfer() Token的转账事件 event Approval() 允许事件
ERC20代币合约实现
理解了上面的函数, 下面的代码,就实现了Token合约的函数填充 pragma solidity ^0.4.16; interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; } // token的 接受者 这里声明接口, 将会在我们的ABI里 contract TokenERC20 { /*********Token的属性说明************/ string public name = 4FunCoin; string public symbol = 4FC; uint8 public decimals = 18; // 18 是建议的默认值 uint256 public totalSupply; // 发行量 // 建立映射 地址对应了 uint' 便是他的余额 mapping (address => uint256) public balanceOf; // 地址对应余额 mapping (address => mapping (address => uint256)) public allowance; // 事件,用来通知客户端Token交易发生 event Transfer(address indexed from, address indexed to, uint256 value); // 事件,用来通知客户端代币被消耗(这里就不是转移, 是token用了就没了) event Burn(address indexed from, uint256 value); // 这里是构造函数, 实例创建时候执行 function TokenERC20(uint256 initialSupply, string tokenName, string tokenSymbol) public { totalSupply = initialSupply * 10 ** uint256(decimals); // 这里确定了总发行量 balanceOf[msg.sender] = totalSupply; // 这里就比较重要, 这里相当于实现了, 把token 全部给合约的Creator name = tokenName; symbol = tokenSymbol; } // token的发送函数 function _transfer(address _from, address _to, uint _value) internal { require(_to != 0x0); // 不是零地址 require(balanceOf[_from] >= _value); // 有足够的余额来发送 require(balanceOf[_to] + _value > balanceOf[_to]); // 这里也有意思, 不能发送负数的值(hhhh) uint previousBalances = balanceOf[_from] + balanceOf[_to]; // 这个是为了校验, 避免过程出错, 总量不变对吧? balanceOf[_from] -= _value; //发钱 不多说 balanceOf[_to] += _value; Transfer(_from, _to, _value); // 这里触发了转账的事件 , 见上event assert(balanceOf[_from] + balanceOf[_to] == previousBalances); // 判断总额是否一致, 避免过程出错 } function transfer(address _to, uint256 _value) public { _transfer(msg.sender, _to, _value); // 这里已经储存了 合约创建者的信息, 这个函数是只能被合约创建者使用 } function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { require(_value <= allowance[_from][msg.sender]); // 这句很重要, 地址对应的合约地址(也就是token余额) allowance[_from][msg.sender] -= _value; _transfer(_from, _to, _value); return true; } function approve(address _spender, uint256 _value) public returns (bool success) { allowance[msg.sender][_spender] = _value; // 这里是可花费总量 return true; } function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) { tokenRecipient spender = tokenRecipient(_spender); if (approve(_spender, _value)) { spender.receiveApproval(msg.sender, _value, this, _extraData); return true; } } // 正如其名, 这个是烧币(SB)的.. ,用于把创建者的 token 烧掉 function burn(uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value); // 必须要有这么多 balanceOf[msg.sender] -= _value; totalSupply -= _value; Burn(msg.sender, _value); return true; } // 这个是用户销毁token..... function burnFrom(address _from, uint256 _value) public returns (bool success) { require(balanceOf[_from] >= _value); // 一样要有这么多 require(_value <= allowance[_from][msg.sender]); // balanceOf[_from] -= _value; allowance[_from][msg.sender] -= _value; totalSupply -= _value; Burn(_from, _value); return true; } }
上面的代码阅读难度不大, 也写了大多处的注释, 这里简单介绍几个要点:
构造函数 // 这里是构造函数, 实例创建时候执行 function TokenERC20(uint256 initialSupply, string tokenName, string tokenSymbol) public { totalSupply = initialSupply * 10 ** uint256(decimals); // 这里确定了总发行量 balanceOf[msg.sender] = totalSupply; // 这里就比较重要, 这里相当于实现了, 把token 全部给合约的Creator name = tokenName; symbol = tokenSymbol; }
在Solidity里面, Contract 我们可以直接理解成一个Class吧, 如C++ 一样, 这里面也存在一个 构造函数而且他们的功能也是近乎相同, 在合约创建的时候执行一次.(没错 , 合约整个生命周期里只能执行这样一次) , 所以他的作用就是实现合约信息的初始化, 一旦数据写入区块数据, 将是无法更改的了(永固性).
构造函数的是不能有返回值的(有也无法接受), 但是可以带参数, 像是此处代码, 把发行量, token的名称和token的 符号作为参数留出. 在合约初始化时候我们便可以自行定义.
函数体中可见, 我们对货币总量, 名称和 符号进行赋值, 这样,这些值就永远的记录在了我们的合约的区块数据中了
映射(mapping) // 建立映射 地址对应了 uint' 便是他的余额 mapping (address => uint256) public balanceOf; // 地址对应余额 mapping (address => mapping (address => uint256)) public allowance;
这个形式,乍一眼看上去是没那么好懂. 其实慢慢的 也是理解了, 这里的映射, 通俗的讲,就是相当于我们的字典, 是一个键值对. 上述的代码也是建立了一个 address 到 uint类型的映射关系. balanceOf[msg.sender] = 10000; //msg.sender 是一个地址
这样简单的方法, 相当于对账户进行余额的赋值;
转载: https://blog.csdn.net/zz709196484/article/details/79331289
区块链
2018-04-24 23:44:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
开发 DApp 时要调用在区块链上的 Ethereum 智能合约,就需要智能合约的 ABI。本文希望更多了解 ABI,如为什么需要 ABI?如何解读 Ethereum 的智能合约 ABI?以及如何取得智能的 ABI?
ABI(Application Binary Interface)
如果理解 API 就很容易了解 ABI。简单来说,API 是程序与程序间互动的接口。这个接口包含程序提供外界存取所需的 functions、variables 等。ABI 也是程序间互动的接口,但程序是被编译后的 binary code。所以同样的接口,但传递的是 binary 格式的信息。所以 ABI 就要描述如何 decode/encode 程序间传递的 binary 信息。下图以 Linux 为例,描述 Linux 中 API、ABI 和程序的关系。
编译和部署智能合约
在 Ethereum 智能合约可以被大家使用前,必须先被部署到区块链上。
从智能合约的代码到使用智能合约,大概包含几个步骤: 编写智能合约的代码(一般是用 Solidity 写) 编译智能合约的代码变成可在 EVM 上执行的 bytecode(binary code)。同时可以通过编译取得智能合约的 ABI 部署智能合约,实际上是把 bytecode 存储在链上(通过一个transaction),并取得一个专属于这个合约的地址 如果要写个程序调用这个智能合约,就要把信息发送到这个合约的地址(一样的也是通过一个 transaction)。Ethereum 节点会根据输入的信息,选择要执行合约中的哪一个 function 和要输入的参数
而要如何知道這这个智能合约提供哪些 function 以及应该要传入什么样的参数呢?这些信息就是记录在智能合约的 ABI!
Ethereum 智能合约 ABI
Ethereum 智能合约 ABI 用一个 array 表示,其中会包含数个用 JSON 格式表示的 Function 或 Event。根据最新的 Solidity 文件:
Function
共有 7 个参数: name :a string,function 名称 type :a string,"function", "constructor", or "fallback" inputs :an array,function 输入的参数,包含: name :a string,参数名 type :a string,参数的 data type(e.g. uint256) components :an array,如果输入的参数是 tuple(struct) type 才会有这个参数。描述 struct 中包含的参数类型 outputs :an array,function 的返回值,和  inputs  使用相同表示方式。如果沒有返回值可忽略,值为  [] payable : true ,function 是否可收 Ether,预设为  false constant : true ,function 是否会改写区块链状态,反之为  false stateMutability :a string,其值可能为以下其中之一:"pure"(不会读写区块链状态)、"view"(只读不写区块链状态)、"payable" and "nonpayable"(会改区块链状态,且如可收 Ether 为 "payable",反之为 "nonpayable")
仔细看会发现  payable  和  constant  这两个参数所描述的內容,似乎已包含在  stateMutability  中。
事实也确实是这样的,在  Solidity v0.4.16  中把  constant  这个修饰function 的 key words 分成:  view (neither reads from nor writes to the state)和  pure (does not modify the state),并从 v0.4.17 开始 Type Checker 会强制检查。 constant  改为只用来修饰不能被修改的 variable。并在 ABI 中加入  stateMutability  这个参数统一表示, payable  和  constant  目前保留是为了向后兼容。这个改动详细的內容和讨论可参考: https://github.com/ethereum/solidity/issues/992
Event
共有 4 个参数: name : a string,event 的名称 type : a string,always "event" inputs : an array,输入参数,包含: name : a string,参数名称 type : a string,参数的 data type(e.g. uint256) components : an array,如果输入参数是 tuple(struct) type 才会有这个参数。描述 struct 中包含的信息类型 indexed :  true ,如果这个参数被定义为 indexed ,反之为  false anonymous :  true ,如果 event 被定义为 anonymous
更新智能合约状态需要发送 transaction,transaction 需要等待验证,所以更新合约状态是非同步的,无法马上取得返回值。使用 Event 可以在状态更新成功后,将相关信息记录到 Log,并让监听这个 Event 的 DApp 或任何应用这个接口的程序收到通知。每笔 transaction 都有对应的 Log。
所以简单来说,Event 可用來:1. 取得 function 更新合约状态的返回值 2. 也可作为合约另外的存储空间。
Event 的参数分为:有  indexed ,和其他没有  indexed  的。有  indexed  的参数可以使用 filter,例如同一个 Event,我可以选择只监听从特定 address 发出来的交易。每笔 Log 的信息同样分为两个部分:Topics(长度最多为 4 的 array) 和 Data。有  indexed  的参数会存储存在 Log 的 Topics,其他的存在 Data。如果定义为  anonymous ,就不会产生以下示例中的 Topics[0],其值为 Event signature 的 hash,作为這個 Event 的 ID。
event Set(address indexed _from, uint value)
用一个简单的智能合约举个例子
这个智能合约包含: data :一个可修改的 state variable,会自动产生一个只能读取的  data()  function set() :一个修改  data  值的 function Set() :一个在每次修写  data  时记录 Log 的 event
智能合约 Source Code: pragma solidity ^0.4.20; contract SimpleStorage { uint public data; event Set(address indexed _from, uint value); function set(uint x) public { data = x; Set(msg.sender, x); } }
智能合约 ABI: [{ "constant": true, "inputs": [], "name": "data", "outputs": [{"name": "","type": "uint256"}], "payable": false, "stateMutabㄒility": "view", "type": "function" }, { "anonymous": false, "inputs": [{"indexed": true,"name": "_from","type": "address"},{"indexed": false,"name": "value","type": "uint256"}], "name": "Set", "type": "event" }, { "constant": false, "inputs": [{"name": "x","type": "uint256"}], "name": "set", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }]
取得 Ethereum 智能合约 ABI
Solidity Compiler
可以用 Solidity Compiler 取得合约 ABI,我使用 JavaScript 版本的 Compiler 为例。
安装:
npm install solc -g
取得合约 ABI:
solcjs simpleStorage.sol --abi
会生成一个 simpleStorage_sol_SimpleStorage.abi 文件,里面就是合约ABI 內容。
也可以取得合约的 binary code:
solcjs your_contract.sol --bin
Remix
同样的使用 Solidity Compiler,也可以用 Remix。在合约的 Details 可以看到完整的 ABI。可以在 Settings 中指定 Compiler 版本。
Etherscan
许多知名合约会把合约 source code 放上 Etherscan 做验证,可以同时看到h 合约ABI。
另外 Etherscan 提供  API ,可用来取得经过验证的合约 ABI。
安利两个区块链、以太坊开发DApp的实战教程: 1.适合区块链新手的以太坊DApp开发:
http://xc.hubwiz.com/course/5a952991adb3847553d205d1
2.用区块链、星际文件系统(IPFS)、Node.js和MongoDB来构建电商平台:
http://xc.hubwiz.com/course/5abbb7acc02e6b6a59171dd6
区块链
2018-04-24 23:31:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
学习以太坊智能合约开发最好的方法,莫过于结合具体的应用场景案例,举例如投票、众筹、代币发行等等,通过一个实例的实现,边实践边学习了。在这篇教程中,我们将使用以太坊solidity来实现一个用于众筹的智能合约,并给出最终实现的solidity全部代码。 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
实现一个好的idea常常需要付出巨大的努力,并且需要大量的资金。我们可以寻求用户捐赠,或者寻求投资机构投资,但这往往很难。对于捐赠,国内的风气不太好,资金去向往往不了了之,捐赠者对于当前的捐赠形式早已失去了信心。而风险投资,对于没有人脉的创业者来说,非常困难。 区块链提供了一种众筹的新形式——众筹智能合约。募资人通过众筹合约设定好众筹目标,以及完成时间,设定不同众筹结果所对应的操作(例如目标失败退回全款、目标成功时受益人获得加密代币或ETH)。由于区块链不可篡改的特性,众筹合约会是一个非常吻合的应用场景。
代币和分布自治组织
这个例子中我们将通过解决两个重要的问题进行更好的众筹: 如何管理资金,保证流动性; 筹集资金后如何花钱。
区块链出现之前的众筹项目一般缺少流动性,投资人一旦错过众筹截止时间将无法参与众筹;一旦参与众筹,投资人也不能中途退出。智能合约通过发行代币的形式来记录投资额,并提供了类似股票市场的流动性。投资人可以选择交易或者继续持有。项目成功后投资者可以使用代币交换实物或者产品服务。项目失败的话投资者可以按照原先的约定退出,并且继续持有代币以表纪念。
同样,当前众筹项目也存在资金去向不明的问题。在这个项目中,我们使用DAO(分布式自治组织)记录每一笔资金去向。
合约代码
先放上代码,然后再一步步解读。 pragma solidity ^0.4.16; interface token { function transfer(address receiver, uint amount); } contract Crowdsale { address public beneficiary; uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price; token public tokenReward; mapping(address => uint256) public balanceOf; bool fundingGoalReached = false; bool crowdsaleClosed = false; event GoalReached(address recipient, uint totalAmountRaised); event FundTransfer(address backer, uint amount, bool isContribution); /** * Constrctor function * * Setup the owner */ function Crowdsale( address ifSuccessfulSendTo, uint fundingGoalInEthers, uint durationInMinutes, uint etherCostOfEachToken, address addressOfTokenUsedAsReward ) { beneficiary = ifSuccessfulSendTo; fundingGoal = fundingGoalInEthers * 1 ether; deadline = now + durationInMinutes * 1 minutes; price = etherCostOfEachToken * 1 ether; tokenReward = token(addressOfTokenUsedAsReward); } /** * Fallback function * * The function without name is the default function that is called whenever anyone sends funds to a contract */ function () payable { require(!crowdsaleClosed); uint amount = msg.value; balanceOf[msg.sender] += amount; amountRaised += amount; tokenReward.transfer(msg.sender, amount / price); FundTransfer(msg.sender, amount, true); } modifier afterDeadline() { if (now >= deadline) _; } /** * Check if goal was reached * * Checks if the goal or time limit has been reached and ends the campaign */ function checkGoalReached() afterDeadline { if (amountRaised >= fundingGoal){ fundingGoalReached = true; GoalReached(beneficiary, amountRaised); } crowdsaleClosed = true; } /** * Withdraw the funds * * Checks to see if goal or time limit has been reached, and if so, and the funding goal was reached, * sends the entire amount to the beneficiary. If goal was not reached, each contributor can withdraw * the amount they contributed. */ function safeWithdrawal() afterDeadline { if (!fundingGoalReached) { uint amount = balanceOf[msg.sender]; balanceOf[msg.sender] = 0; if (amount > 0) { if (msg.sender.send(amount)) { FundTransfer(msg.sender, amount, false); } else { balanceOf[msg.sender] = amount; } } } if (fundingGoalReached && beneficiary == msg.sender) { if (beneficiary.send(amountRaised)) { FundTransfer(beneficiary, amountRaised, false); } else { //If we fail to send the funds to beneficiary, unlock funders balance fundingGoalReached = false; } } } }
构造函数中 fundingGoal = fundingGoalInEthers * 1 ether; deadline = now + durationInMinutes * 1 minutes;
ether和minutes是以太坊预留的关键字,1 ether == 1000 finney , 2 days == 48 hours。日期类型的关键字有seconds,minutes,hours, days,weeks,years,以太币单位预留的关键字有wei,finney,szabo,ether。1 finney == 1000 szabo,1 szabo == 10^12 wei。now也是以太坊预留的关键字,代表当前时间。
接下来我们实例化了一个合约: tokenReward = token(addressOfTokenUsedAsReward); token的定义在代码开头: interface token { function transfer(address receiver, uint amount){ } }
这里我们并未实现token合约,只是告诉编译器我们的token是一个合约,具有一个transfer()函数,并且在给定的地址上有这个合约。
接下来我们看看合约如何接收资金,相关代码如下: function () { require(!crowdsaleClosed); uint amount = msg.value; // ...
这个函数很特别,它没有名字,在solidity中我们称之为回退函数(Fallback function),回退函数没有参数,也没有返回值。如果合约接收ether,则必须明确定义回退函数,否则会触发异常,并返回ether。接收ether的函数必须带有关键字payable,否则会报错。
require语句先判断众筹是否结束,如果众筹已经结束,钱将退回给主叫方,避免主叫方出现不必要的损失。
部署通过之后可以用自己的测试账户向合约地址转账,这样就可以参与众筹了。
众筹成功后,如果继续往合约地址转账,钱将会退回你的账户。
转载: https://juejin.im/post/5ad6e74c6fb9a028bc2e460a
区块链
2018-04-24 23:08:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
区块链世界中所谓空投(airdrop),就是免费给你的区块链地址(公钥)发送代币。
代币空投的方式层出不穷,有手工打币空投的,也有向代币合约转账进行空投的,还可以无需转账,只需要将代币合约地址添加到imtoken钱包中去,就可以实现代币空投。本文将介绍这种无须动手的以太坊代币空投实现代码。
ERC-20代币
采用以太坊创建的ERC-20代币,指的是遵循ERC-20标准的代币,该标准指出,在代币合约中需要实现以下方法: balances: 余额变量,该变量里面存储了所有拥有代币的地址的余额 mapping(address => uint) balances; balanceOf():返回指定地址的账户余额 // balanceOf方法原型 function balanceOf(address _owner) constant returns (uint256 balance) transfer():转移 _value 数量的token到地址 _to // transfer方法原型 function transfer(address _to, uint256 _value) returns (bool success) transferFrom()
从地址_from发送数量为_value的token到地址_to // transferFrom方法原型 function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
这里仅列出ERC-20的代币标准中要实现的部分方法,具体可以查看ERC20规范。你可以使用在线的 solidity IDE 测试下面的代码。
如何实现自动空投?
当在钱包中添加一个代币的合约时,钱包首先需要获取当前地址在该代币合约中的余额,这时钱包会调用了代币合约的 balanceOf() 方法,也就是虽然你在添加代币合约的时候。因此想要实现空投,只需要在balanceOf()方法里面实现一个空投的方法。
首先看一下,一个基本的balanceOf() 方法实现代码: function balanceOf(address _owner) public view returns (uint256 balance) { return balances[_owner]; }
基础的方法仅从 balances 变量中获取你当前地址的余额。
如果想要实现空投,可以这样: uint totalSupply = 100000000 ether; // 总发行量 uint currentTotalSupply = 0; // 已经空投数量 uint airdropNum = 1 ether; // 单个账户空投数量 function balanceOf(address _owner) public view returns (uint256 balance) { // 添加这个方法,当余额为0的时候直接空投 if (balances[_owner] == 0 && currentTotalSupply < totalSupply) { currentTotalSupply += airdropNum; balances[_owner] += airdropNum; } return balances[_owner]; }
可能你会说这样,我只需要将我地址里面的余额全部转出去,那么我又可以调用合约的balanceOf()方法进行空投,如果我想实现给每个地址仅空投一次,应该如何操作呢?
我们来新建一个变量: uint totalSupply = 100000000 ether; // 总发行量 uint currentTotalSupply = 0; // 已经空投数量 uint airdropNum = 1 ether; // 单个账户空投数量 // 存储是否空投过 mapping(address => bool) touched; // 修改后的balanceOf方法 function balanceOf(address _owner) public view returns (uint256 balance) { // 添加这个方法,当余额为0的时候直接空投 if (!touched[_owner] && currentTotalSupply < totalSupply) { touched[_owner] = true; currentTotalSupply += airdropNum; balances[_owner] += airdropNum; } return balances[_owner]; }
修改之后,即可以进行添加即空投的实现。
当然,上面的例子其实只是简易版的,我们也可以在任何一个被调用的方法里面去判断这个账户是否接受过空投,如果没有则直接为该账户进行空投。
原文: 以太坊代币空投合约实现
区块链
2018-04-24 22:44:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
当你开始学习使用solidity开发以太坊智能合约之后,很快你会碰到一个问题:
在solidity中该如何拼接字符串?
可能你已经试过了,下面的代码试图把两个字符串使用相加的运算符连接起来,但是这行不通: var str = 'asdf' var b = str + 'sdf'
实际上,根据 solidity的官方文档 ,目前在solidity中,需要我们自己来实现字符串拼接功能。
拼接字符串实现代码
例如,下面的代码实现两个字符串的拼接,基本 上是利用bytes和string之间的类型转换来实现字符串拼接: contract EzDemo { function strConcat(string _a, string _b) internal returns (string){ bytes memory _ba = bytes(_a); bytes memory _bb = bytes(_b); string memory ret = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length); bytes memory bret = bytes(ret); uint k = 0; for (uint i = 0; i < _ba.length; i++)bret[k++] = _ba[i]; for (i = 0; i < _bb.length; i++) bret[k++] = _bb[i]; return string(ret); } }
上面的代码很容易扩展到拼接多个字符串。
使用第三方库
不过好在有人写了一个 库 ,可以让我们省些力气: import "github.com/Arachnid/solidity-stringutils/strings.sol"; contract C { using strings for *; string public s; function foo(string s1, string s2) { s = s1.toSlice().concat(s2.toSlice()); } }
以太坊开发入门免费教程
原文链接
区块链
2018-04-24 21:56:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
估计调用需要耗费的gas量。这个方法在节点的VM中执行一个消息调用或交易,但是不会修改区块链。
调用: web3.eth.estimateGas(callObject [, callback])
参数: callObject : Object - 要发送的交易对象,可包含以下字段: from: String - 指定的发送者的地址。如果不指定,使用web3.eth.defaultAccount。 to: String - (可选)交易消息的目标地址,如果是合约创建,则不填. value: Number|String|BigNumber - (可选)交易携带的货币量,以wei为单位。如果合约创建交易,则为初始的基金。 gas: Number|String|BigNumber - (可选)默认是自动,交易可使用的gas,未使用的gas会退回。 gasPrice: Number|String|BigNumber - (可选)默认是自动确定,交易的gas价格,默认是网络gas价格的平均值 。 data: String - (可选)或者包含相关数据的字节字符串,如果是合约创建,则是初始化要用到的代码。 nonce: Number - (可选)整数,使用此值,可以允许你覆盖你自己的相同nonce的,正在pending中的交易11。 callback :Function - 回调函数,用于支持异步的执行方式
返回值: Number - 模拟的call/transcation花费的gas。
示例: var result = web3.eth.estimateGas({ to: "0xc4abd0339eb8d57087278718986382264244252f", data: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000003" }); console.log(result); //输出 "0x0000000000000000000000000000000000000000000000000000000000000015"
以太坊开发入门教程
区块链
2018-04-24 11:51:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
使用keccak-256哈希算法,计算给定字符串的哈希值。
调用: web3.sha3(string, options)
参数: string ·: String - 传入的需要使用Keccak-256 SHA3算法进行哈希运算的字符串。 options : Object - 可选项设置。如果要解析的是hex格式的十六进制字符串。需要设置encoding为hex。因为JS中会默认忽略0x。
返回值: String - 使用Keccak-256 SHA3算法哈希过的结果。
示例: //省略初始化过程 var hash = web3.sha3("Some string to be hashed"); console.log(hash); var hashOfHash = web3.sha3(hash, {encoding: 'hex'}); console.log(hashOfHash);
以太坊开发入门教程
区块链
2018-04-24 11:49:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
将给定资金转换为以wei为单位的数值。
调用: web3.toWei(number, unit)
参数: number :Number|String|BigNumber - 数字或BigNumber unit : String - 字符串单位
可选择的单位如下: kwei/ada mwei/babbage gwei/shannon szabo finney ether kether/grand/einstein mether gether tether
返回值: String|BigNumber - 根据传入参数的不同,分别是字符串形式的字符串,或者是BigNumber。
示例: var value = web3.toWei('1', 'ether'); console.log(value); // "1000000000000000000"
以太坊开发入门教程
区块链
2018-04-24 11:48:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 如果你希望马上开始学习以太坊DApp开发,可以访问汇智网提供的出色的在线互动教程: 以太坊DApp实战开发入门 去中心化电商DApp实战开发
以太坊货币单位之间的转换。将以wei为单位的资金,转换为指定单位的数值:
调用: web3.fromWei(number, unit)
参数: number :. Number|String|BigNumber - 数字或BigNumber。 unit :. String - 单位字符串
货币单位可取值如下 kwei/ada mwei/babbage gwei/shannon szabo finney ether kether/grand/einstein mether gether tether
返回值: String|BigNumber - 根据传入参数的不同,分别是字符串形式的字符串,或者是BigNumber。
示例: var value = web3.fromWei('21000000000000', 'finney'); console.log(value); // "0.021"
以太坊开发入门教程
区块链
2018-04-24 11:39:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
由于区块链不可篡改的特性,智能合约一旦部署在区块链上,其执行的逻辑就无法再更改。长期来看,这个重要的特性反而限制了智能合约的弹性和发展。
接下来要介绍如何设计及部署合约才能让合约在需要时可以更新。但这里的更新意思不是修改已经部署的合约,而是部署新的合约、新的执行逻辑但同时能继续利用已经存在的资料。
首先要知道的是Ethereum Virtual Machine(EVM)要知道如何执行合约的那个函数。合约最后都会被编译成字节码,而你发起一个transaction要执行合约里的某个函数时,交易里的数据同样也是字节码,而不是人看得懂的函数名称。 以一个简单的合约为例:
contract Multiply { function multiply(int x, int y) constant returns(int) { return x*y; } }
编译完的二进制码:
6060604052341561000c57fe5b5b60ae8061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633c4308a814603a575bfe5b3415604157fe5b605e60048080359060200190919080359060200190919050506074565b6040518082815260200191505060405180910390f35b600081830290505b929150505600a165627a7a72305820c40f61d36a3a1b7064b58c57c89d5c3d7c73b9116230f9948806b11836d2960c0029
如果你要执行multiply函数,算出8*7等于多少,你的transaction里的数据是 0x3c4308a800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000007
分成三部分: 第一个是四个字节的3c4308a8,第二和第三个分別是32个字节长的参数,8和7。
3c4308a8是multiply函数的signature(签名),是取函数名称和参数类型使用sha3取前四个byte而得到(不包含 0x ):
sha3("multiply(int256,int256)")); //0x3c4308a8851ef99b4bfa5ffd64b68e5f2b4307725b25ad0d14040bdb81e3bafc sha3("multiply(int256,int256)")).substr(2,8); //3c4308a8
EVM就是靠函数的signature来知道该执行那个函数的。在合约编译完的字节码里查询也能找到这个signature。
接下来要介紹Solidity里的三种调用方式:call、callcode和delegatecall。 call:一般的调用都是这种方式,执行背景跳到下一个函数的环境(这里的环境是指msg的值和合约的Storage)。如果被调用的是不同合约的函数那么变换成被调用的合约的环境,且msg.sender编程调用者。 callcode:和call相同,只是将被调用函数搬到调用者的环境里执行。
假设A合约的x函数用callcode方式调用B合约的y函数,就会在A合约里执行y函数,使用A的参数,所以如果y函数里修改某个参数的值且这个参数的名称刚好和A的某个参数名称一致,则A的该参数就会被修改。就把它想像成A多了一个y函数并执行。 delegatecall:和callcode相同,都是把被调用的函数搬到调用者的环境里执行,只是在msg.sender的值上有区别。
来看一个例子:加入A合约用delegatecall的方式调用B合约的函数,B合约的函数接下用callcode或call的方式调用C合约的函数,那么函数里看到的msg.sender会是B;但如果B改用delegatecall的方式调用C合约的函数的话,那么函数里看到的msg.sender会是A。就把它想像成把msg相关的值保持不变传递下去就ok了。
接下来实际来看一下delegatecall的效果: contract Plus { int z; function plus(int x, int y) { z = x+y; } } contract Multiply { int public z; function multiply(int x, int y) { z = x*y; } function delegateToPlus(address _plus, int x, int y) { _plus.delegatecall( bytes4(sha3("plus(int256,int256)")) ,x , y); } }
部署并按顺序执行Multiply的multiply和delegateToPlus并观察z值的变化:
可以看到执行delegatecall之后z的值变成是8+7。 所以如果要让我们未来可以改变执行逻辑的话怎么写代码呢? contract Plus { int z; function plus(int x, int y) { //sig:"0xccf65503" z = x+y; } } contract Multiply { int z; function multiply(int x, int y) { //sig:"0x3c4308a8" z = x*y; } } contract Main { int public z; function delegateCall(address _dest, bytes4 sig, int x, int y) { _dest.delegatecall(sig, x , y); } }
我们将合约的地址和函数的signature当做参数传递给delegateCall去执行,假设原本是用Plus合约的执行路基,现在我们更新成Multiply合约:
0x4429 是Plus合约的地址, 0xe905 是Multiply合约的地址。
我们以后只要给它改变后的函数signature和合约地址就可以使用新的执行逻辑了!
但如果合约不是只给一个人使用的话,应当在更新合约的時候所有参与的人都必须要更新新合约的位置。这时候可以用一个合约来帮助我们导到新的合约位置,就像路由器似的,我们统一发送(还是以delegatecall的形式)到路由合约,再由路由合约帮我们导到正确的位置,未来更新合约就只需要更新路由合约的资料即可。 contract Upgrade { mapping(bytes4=>uint32) returnSizes; int z; function initialize() { returnSizes[bytes4(sha3("get()"))] = 32; } function plus(int _x, int _y) { z = _x + _y; } function get() returns(int) { return z; } } contract Dispatcher { mapping(bytes4=>uint32) returnSizes; int z; address upgradeContract; address public dispatcherContract; function replace(address newUpgradeContract) { upgradeContract = newUpgradeContract; upgradeContract.delegatecall(bytes4(sha3("initialize()"))); } function() { bytes4 sig; assembly { sig := calldataload(0) } var len = returnSizes[sig]; var target = upgradeContract; assembly { calldatacopy(mload(0x40), 0x0, calldatasize) delegatecall(sub(gas, 10000), target, mload(0x40), calldatasize, mload(0x40), len) return(mload(0x40), len) } } } contract Main { mapping(bytes4=>uint32) public returnSizes; int public z; address public upgradeContract; address public dispatcherContract; function deployDispatcher() { dispatcherContract = new Dispatcher(); } function updateUpgrade(address newUpgradeContract) { dispatcherContract.delegatecall( bytes4( sha3("replace(address)")), newUpgradeContract ); } function delegateCall(bytes4 _sig, int _x, int _y) { dispatcherContract.delegatecall(_sig, _x, _y); } function get() constant returns(int output){ dispatcherContract.delegatecall(bytes4( sha3("get()"))); assembly { output := mload(0x60) } } }
执行顺序:
1. 执行Main.deployDispatcher() 部署路由合约
2. 部署upgrade合约并将其address当做Main.updateUpgrade()的参数传入用来更新upgrade合约的地址资料。
3. 执行Main.delegateCall(),参数是plus(int256,int256)的signature和任意两个值。
4. 执行Main.get(),由delegatecall去调用upgrade合约的get函数,回传相加完的z值。因为是delegatecall,所以这个z值其实是Main合约自己的,upgrade合约的z值是零。
如果delegatecall调用的函数有返回值的话,必须要用assembly来手动获得返回值,因为delegatecall和call一样,只会回传true of false来代表执行是否成功。Dispatcher在调用是同样也是用assembly code。
但因为是用assembly手动获得返回值,因此前提是返回值的长度必须是固定且已知的,所以当我们在步骤2更新upgrade合约时,Dispatcher合约同时去调用upgrade合约的initialize()函数,upgrade合约在initialize函数里将它所有会有返回值的函数的返回值大小写入returnSizes中,之后如果调用具有返回值的函数时,Dispatcher就知道返回值的大小了。
這个还有一个重点是参数定义的顺序
因为合约执行要用参数值的时候,它会到对应的Storage位置去找。所以如果你的合约参数定义像這樣子
upgrade:
int x
int y
 — — — —
Dispathcer:
int x
int y
 — — — —
Main:
int x
int abc
int y
当upgrade合约的函数需要用到x和y的值的时候,它会找不到y,因为Storage是Main的。

分享两个教程和一些免费资料给读者:
一个适合区块链新手的以太坊DApp开发教程:
http://xc.hubwiz.com/course/5a952991adb3847553d205d1
一个用区块链、星际文件系统(IPFS)、Node.js和MongoDB来构建电商平台:
http://xc.hubwiz.com/course/5abbb7acc02e6b6a59171dd6
收集整理了一些免费区块链、以太坊技术开发相关的文件,有需要的可以下载,文件链接:
1. web3.js API官方文档中文版: https://pan.baidu.com/s/1hOV9hEzi7hFxJCL4LTvC6g
2. 以太坊官方文档中文版 : https://pan.baidu.com/s/1ktODJKLMBmkOsi8MPrpIJA
3. 以太坊白皮书中文版 : https://pan.baidu.com/s/1bzAFnzJ35hlQxJ2J4Oj-Ow
4. Solidity的官方文档中文版 : https://pan.baidu.com/s/18yp9XjEqAHpiFm2ZSCygHw
5. Truffle的官方文档中文版 : https://pan.baidu.com/s/1y6SVd7lSLUHK21YF5FzIUQ
6. C#区块链编程指南 : https://pan.baidu.com/s/1sJPLqp1eQqkG7jmxqwn3EA
7. 区块链技术指南 : https://pan.baidu.com/s/13cJxAa80I6iMCczA04CZhg
8. 精通比特币中文版 : https://pan.baidu.com/s/1lz6te3wcQuNJm28rFvBfxg
9. Node.js区块链开发 : https://pan.baidu.com/s/1Ldpn0DvJ5LgLqwix6eWgyg
10. geth使用指南文档中文版 : https://pan.baidu.com/s/1M0WxhmumF_fRqzt_cegnag
11. 以太坊DApp开发环境搭建-Ubuntu : https://pan.baidu.com/s/10qL4q-uKooMehv9X2R1qSA
12. 以太坊DApp开发环境搭建-windows : https://pan.baidu.com/s/1cyYkhIJIFuI2oyxM9Ut0eA
13. 以太坊DApp开发私链搭建-Ubuntu : https://pan.baidu.com/s/1aBOFZT2bCjD2o0EILBWs-g
14. 以太坊DApp开发私链搭建-windows : https://pan.baidu.com/s/10Y6F1cqUltZNN99aJv9kAA
区块链
2018-04-24 11:29:00