数据专栏

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

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
区块链相关的应用场景可以参考: http://qkl.zhilitang.vip/dapp/?source=PC-TZ&keyword=qukuailianjiaoyixitongkaifa&e_creative=36051418518&e_keywordid=158453543090#1
目前网络上关于区块链入门、科普的文章不少,本文就不再赘述区块链的基本概念了,如果对区块链不是很了解的话,可以看一下我之前收集的一些入门学习资源: https://blog.51cto.com/zero01/2066321
对区块链技术感到新奇的我们,都想知道区块链在代码上是怎么实现的,所以本文是实战向的,毕竟理论我们都看了不少,但是对于区块链具体的实现还不是很清楚,本文就使用Java语言来实现一个简单的区块链。
但是要完全搞懂区块链并非易事,对于一门较为陌生的技术,我们需要在理论+实践中学习,通过写代码来学习技术会掌握得更牢固,构建一个区块链可以加深对区块链的理解。
准备工作
掌握基本的JavaSE以及JavaWeb开发,能够使用Java开发简单的项目,并且需要了解HTTP协议。
我们知道区块链是由区块的记录构成的不可变、有序的链结构,记录可以是交易、文件或任何你想要的数据,重要的是它们是通过哈希值(hashes)链接起来的。
如果你还不是很了解哈希是什么,可以查看 这篇文章
环境描述 JDK1.8 Tomcat 9.0 Maven 3.5 JSON 20160810 javaee-api 7.0
pom.xml文件配置内容: < dependencies > < dependency > < groupId > javax < artifactId > javaee-api < version > 7.0 < scope > provided < dependency > < groupId > org.json < artifactId > json < version > 20160810
然后还需要一个HTTP客户端,比如Postman,Linux命令行下的curl或其它客户端,我这里使用的是Postman。
Blockchain类
首先创建一个Blockchain类,在构造器中创建了两个主要的集合,一个用于储存区块链,一个用于储存交易列表,本文中所有核心的主要代码都写在这个类里,方便随时查看,在实际开发则不宜这么做,应该把代码拆分仔细降低耦合度。
以下是Blockchain类的框架代码: package org.zero01.core; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class BlockChain { // 存储区块链 private List chain; // 该实例变量用于当前的交易信息列表 private List currentTransactions; public BlockChain () { // 初始化区块链以及当前的交易信息列表 this .chain = new ArrayList(); this .currentTransactions= new ArrayList(); } public List getChain () { return chain; } public void setChain (List chain) { this .chain = chain; } public List getCurrentTransactions () { return currentTransactions; } public void setCurrentTransactions (List currentTransactions) { this .currentTransactions = currentTransactions; } public Object lastBlock () { return null ; } public HashMap newBlock () { return null ; } public int newTransactions () { return 0 ; } public static Object hash (HashMap block) { return null ; } }
Blockchain类用来管理区块链,它能存储交易,加入新块等,下面我们来进一步完善这些方法。
区块的结构
首先需要说明一下区块的结构,每个区块包含属性:索引(index),时间戳(timestamp),交易列表(transactions),工作量证明(稍后解释)以及前一个区块的Hash值。
以下是一个区块的结构: block = { 'index' : 1 , 'timestamp' : 1506057125.900785 , 'transactions' : [ { 'sender' : "8527147fe1f5426f9dd545de4b27ee00" , 'recipient' : "a77f5cdfa2934df3954a5c7c7da5df1f" , 'amount' : 5 , } ], 'proof' : 324984774000 , 'previous_hash' : "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" }
到这里,区块链的概念就清楚了,每个新的区块都包含上一个区块的Hash,这是关键的一点,它保障了区块链不可变性。如果***者破坏了前面的某个区块,那么后面所有区块的Hash都会变得不正确。不理解的话,慢慢消化,可以参考 区块链记账原理 。
由于需要计算区块的hash,所以我们得先编写一个用于计算hash值的工具类: package org.zero01.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class Encrypt { /** * 传入字符串,返回 SHA-256 加密字符串 * * @param strText * @return */ public String getSHA256 ( final String strText) { return SHA(strText, "SHA-256" ); } /** * 传入字符串,返回 SHA-512 加密字符串 * * @param strText * @return */ public String getSHA512 ( final String strText) { return SHA(strText, "SHA-512" ); } /** * 传入字符串,返回 MD5 加密字符串 * * @param strText * @return */ public String getMD5 ( final String strText) { return SHA(strText, "SHA-512" ); } /** * 字符串 SHA 加密 * * @param strSourceText * @return */ private String SHA ( final String strText, final String strType) { // 返回值 String strResult = null ; // 是否是有效字符串 if (strText != null && strText.length() > 0 ) { try { // SHA 加密开始 // 创建加密对象,传入加密类型 MessageDigest messageDigest = MessageDigest.getInstance(strType); // 传入要加密的字符串 messageDigest.update(strText.getBytes()); // 得到 byte 数组 byte byteBuffer[] = messageDigest.digest(); // 將 byte 数组转换 string 类型 StringBuffer strHexString = new StringBuffer(); // 遍历 byte 数组 for ( int i = 0 ; i < byteBuffer.length; i++) { // 转换成16进制并存储在字符串中 String hex = Integer.toHexString( 0xff & byteBuffer[i]); if (hex.length() == 1 ) { strHexString.append( '0' ); } strHexString.append(hex); } // 得到返回結果 strResult = strHexString.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } return strResult; } }
加入交易功能
接下来我们需要实现一个交易\记账功能,所以来完善newTransactions以及lastBlock方法: /** * @return 得到区块链中的最后一个区块 */ public HashMap lastBlock () { return getChain().get(getChain().size() - 1 ); } /** * 生成新交易信息,信息将加入到下一个待挖的区块中 * * @param sender * 发送方的地址 * @param recipient * 接收方的地址 * @param amount * 交易数量 * @return 返回存储该交易事务的块的索引 */ public int newTransactions (String sender, String recipient, long amount) { Map transaction = new HashMap(); transaction.put( "sender" , sender); transaction.put( "recipient" , recipient); transaction.put( "amount" , amount); getCurrentTransactions().add(transaction); return (Integer) lastBlock().get( "index" ) + 1 ; }
newTransactions方法向列表中添加一个交易记录,并返回该记录将被添加到的区块 (下一个待挖掘的区块)的索引,等下在用户提交交易时会有用。
创建新块
当Blockchain实例化后,我们需要构造一个创世区块(没有前区块的第一个区块),并且给它加上一个工作量证明。
每个区块都需要经过工作量证明,俗称挖矿,稍后会继续讲解。
为了构造创世块,我们还需要完善剩下的几个方法,并且把该类设计为单例: package org.zero01.dao; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.json.JSONObject; import org.zero01.util.Encrypt; public class BlockChain { // 存储区块链 private List> chain; // 该实例变量用于当前的交易信息列表 private List> currentTransactions; private static BlockChain blockChain = null ; private BlockChain () { // 初始化区块链以及当前的交易信息列表 chain = new ArrayList>(); currentTransactions = new ArrayList>(); // 创建创世区块 newBlock( 100 , "0" ); } // 创建单例对象 public static BlockChain getInstance () { if (blockChain == null ) { synchronized (BlockChain.class) { if (blockChain == null ) { blockChain = new BlockChain(); } } } return blockChain; } public List> getChain() { return chain; } public void setChain (List> chain) { this .chain = chain; } public List> getCurrentTransactions() { return currentTransactions; } public void setCurrentTransactions (List> currentTransactions) { this .currentTransactions = currentTransactions; } /** * @return 得到区块链中的最后一个区块 */ public Map lastBlock () { return getChain().get(getChain().size() - 1 ); } /** * 在区块链上新建一个区块 * * @param proof * 新区块的工作量证明 * @param previous_hash * 上一个区块的hash值 * @return 返回新建的区块 */ public Map newBlock ( long proof, String previous_hash) { Map block = new HashMap(); block.put( "index" , getChain().size() + 1 ); block.put( "timestamp" , System.currentTimeMillis()); block.put( "transactions" , getCurrentTransactions()); block.put( "proof" , proof); // 如果没有传递上一个区块的hash就计算出区块链中最后一个区块的hash block.put( "previous_hash" , previous_hash != null ? previous_hash : hash(getChain().get(getChain().size() - 1 ))); // 重置当前的交易信息列表 setCurrentTransactions( new ArrayList>()); getChain().add(block); return block; } /** * 生成新交易信息,信息将加入到下一个待挖的区块中 * * @param sender * 发送方的地址 * @param recipient * 接收方的地址 * @param amount * 交易数量 * @return 返回该交易事务的块的索引 */ public int newTransactions (String sender, String recipient, long amount) { Map transaction = new HashMap(); transaction.put( "sender" , sender); transaction.put( "recipient" , recipient); transaction.put( "amount" , amount); getCurrentTransactions().add(transaction); return (Integer) lastBlock().get( "index" ) + 1 ; } /** * 生成区块的 SHA-256格式的 hash值 * * @param block * 区块 * @return 返回该区块的hash */ public static Object hash (Map block) { return new Encrypt().getSHA256( new JSONObject(block).toString()); } }
通过上面的代码和注释可以对区块链有直观的了解,接下来我们来编写一些简单的测试代码来测试一下这些代码能否正常工作: package org.zero01.test; import java.util.HashMap; import java.util.Map; import org.json.JSONObject; import org.zero01.dao.BlockChain; public class Test { public static void main (String[] args) throws Exception { BlockChain blockChain = BlockChain.getInstance(); // 一个区块中可以不包含任何交易记录 Map block = blockChain.newBlock( 300 , null ); System.out.println( new JSONObject(block)); // 一个区块中可以包含一笔交易记录 blockChain.newTransactions( "123" , "222" , 33 ); Map block1 = blockChain.newBlock( 500 , null ); System.out.println( new JSONObject(block1)); // 一个区块中可以包含多笔交易记录 blockChain.newTransactions( "321" , "555" , 133 ); blockChain.newTransactions( "000" , "111" , 10 ); blockChain.newTransactions( "789" , "369" , 65 ); Map block2 = blockChain.newBlock( 600 , null ); System.out.println( new JSONObject(block2)); // 查看整个区块链 Map chain = new HashMap(); chain.put( "chain" , blockChain.getChain()); chain.put( "length" , blockChain.getChain().size()); System.out.println( new JSONObject(chain)); } }
运行结果: // 挖出来的新区块 { "index" : 2 , "transactions" : [], "proof" : 300 , "timestamp" : 1519478559703 , "previous_hash" : "185b62ca1fc31285bce8878acfc970983cb561f19c63b65120d2c95148cf151f" } // 包含一笔交易的区块 { "index" : 3 , "transactions" : [ { "amount" : 33 , "sender" : "123" , "recipient" : "222" } ], "proof" : 500 , "timestamp" : 1519478559728 , "previous_hash" : "bce15693c0a028b1fc6d7d1c1d30494f97ef37b8b3384865559ceed9b5ff798b" } // 包含多笔交易的区块 { "index" : 4 , "transactions" : [ { "amount" : 133 , "sender" : "321" , "recipient" : "555" }, { "amount" : 10 , "sender" : "000" , "recipient" : "111" }, { "amount" : 65 , "sender" : "789" , "recipient" : "369" } ], "proof" : 600 , "timestamp" : 1519478656178 , "previous_hash" : "b0edde645f76fc3a6cb45b7c91b07b686e8e214cfc1dea4823bf38bda37c909c" } // 整个区块链,第一个是创始区块 { "chain" : [ { "index" : 1 , "transactions" : [], "proof" : 100 , "timestamp" : 1519478656153 , "previous_hash" : "0" }, { "index" : 2 , "transactions" : [], "proof" : 300 , "timestamp" : 1519478656154 , "previous_hash" : "7925a01fa8cb67b51ea89b9cfcfa16c5febee008bb559f94c5758418e7acc670" }, { "index" : 3 , "transactions" : [ { "amount" : 33 , "sender" : "123" , "recipient" : "222" } ], "proof" : 500 , "timestamp" : 1519478656178 , "previous_hash" : "40ccc2f4ad97f75cb611ed69a4ecc7438eefd31afca17ca00c2ed7b5163d0831" }, { "index" : 4 , "transactions" : [ { "amount" : 133 , "sender" : "321" , "recipient" : "555" }, { "amount" : 10 , "sender" : "000" , "recipient" : "111" }, { "amount" : 65 , "sender" : "789" , "recipient" : "369" } ], "proof" : 600 , "timestamp" : 1519478656178 , "previous_hash" : "b0edde645f76fc3a6cb45b7c91b07b686e8e214cfc1dea4823bf38bda37c909c" } ], "length" : 4 }
通过以上的测试,可以很直观的看到区块链的数据,但是现在只是完成了初步的代码编写,还有几件事情还没做,接下来我们看看区块是怎么挖出来的。
理解工作量证明
新的区块依赖工作量证明算法(PoW)来构造。PoW的目标是找出一个符合特定条件的数字,这个数字很难计算出来,但容易验证。这就是工作量证明的核心思想。
为了方便理解,举个例子:
假设一个整数 x 乘以另一个整数 y 的积的 Hash 值必须以 0 结尾,即 hash(x * y) = ac23dc…0。设变量 x = 5,求 y 的值?
用Java实现如下: package org.zero01.test; import org.zero01.util.Encrypt; public class TestProof { public static void main (String[] args) { int x = 5 ; int y = 0 ; while (! new Encrypt().getSHA256((x * y) + "" ).endsWith( "0" )) { y++; } System.out.println( "y=" + y); } }
结果是 y=21 ,因为: hash (5 * 21) = 1253e9373e...5e3600155e860
在比特币中,使用称为Hashcash的工作量证明算法,它和上面的问题很类似。矿工们为了争夺创建区块的权利而争相计算结果。通常,计算难度与目标字符串需要满足的特定字符的数量成正比,矿工算出结果后,会获得比特币奖励。
当然,在网络上非常容易验证这个结果。
实现工作量证明
让我们来实现一个相似PoW算法,规则是:寻找一个数 p,使得它与前一个区块的 proof 拼接成的字符串的 Hash 值以 4 个零开头: ... /** * 简单的工作量证明: * - 查找一个 p' 使得 hash(pp') 以4个0开头 * - p 是上一个块的证明, p' 是当前的证明 * * @param last_proof * 上一个块的证明 * @return */ public long proofOfWork ( long last_proof) { long proof = 0 ; while (!validProof(last_proof, proof)) { proof += 1 ; } return proof; } /** * 验证证明: 是否hash(last_proof, proof)以4个0开头? * * @param last_proof * 上一个块的证明 * @param proof * 当前的证明 * @return 以4个0开头返回true,否则返回false */ public boolean validProof ( long last_proof, long proof) { String guess = last_proof + "" + proof; String guess_hash = new Encrypt().getSHA256(guess); return guess_hash.startsWith( "0000" ); }
衡量算法复杂度的办法是修改零开头的个数。使用4个来用于演示,你会发现多一个零都会大大增加计算出结果所需的时间。
现在Blockchain类基本已经完成了,接下来使用Servlet接收HTTP请求来进行交互。
Blockchain作为API接口
我们将使用Java Web中的Servlet来接收用户的HTTP请求,通过Servlet我们可以方便的将网络请求的数据映射到相应的方法上进行处理,现在我们来让Blockchain运行在基于Java Web上。
我们将创建三个接口: /transactions/new 创建一个交易并添加到区块 /mine 告诉服务器去挖掘新的区块 /chain 返回整个区块链
注册节点ID
我们的“Tomcat服务器”将扮演区块链网络中的一个节点,而每个节点都需要有一个唯一的标识符,也就是id。在这里我们使用UUID来作为节点ID,我们需要在服务器启动时,将UUID设置到ServletContext属性中,这样我们的服务器就拥有了唯一标识,这一步我们可以配置监听类来完成,首先配置web.xml文件内容如下: < web-app version = "3.0" xmlns = "http://java.sun.com/xml/ns/javaee" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" > < listener > < listener-class > org.zero01.servlet.InitialID
然后编写一个类实现ServletContextListener接口,在初始化方法中把uuid设置到ServletContext的属性中: package org.zero01.servlet; import java.util.UUID; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class InitialID implements ServletContextListener { public void contextInitialized (ServletContextEvent sce) { ServletContext servletContext = sce.getServletContext(); String uuid = UUID.randomUUID().toString().replace( "-" , "" ); servletContext.setAttribute( "uuid" , uuid); } public void contextDestroyed (ServletContextEvent sce) { } }
创建Servlet类
我们这里没有使用任何框架,所以我们需要通过最基本的Servlet来接收并处理用户的HTTP请求: package org.zero01.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; // 该Servlet用于运行工作算法的证明来获得下一个证明,也就是所谓的挖矿 @WebServlet ( "/mine" ) public class Mine extends HttpServlet { protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } } package org.zero01.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; // 该Servlet用于接收并处理新的交易信息 @WebServlet ( "/transactions/new" ) public class NewTransaction extends HttpServlet { protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } } package org.zero01.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; // 该Servlet用于输出整个区块链的数据 @WebServlet ( "/chain" ) public class FullChain extends HttpServlet { protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }
我们先来完成最简单的FullChain的代码,这个Servlet用于向客户端输出整个区块链的数据(JSON格式): package org.zero01.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.json.JSONObject; import org.zero01.core.BlockChain; // 该Servlet用于输出整个区块链的数据 @WebServlet ( "/chain" ) public class FullChain extends HttpServlet { protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { BlockChain blockChain = BlockChain.getInstance(); Map response = new HashMap(); response.put( "chain" , blockChain.getChain()); response.put( "length" , blockChain.getChain().size()); JSONObject jsonResponse = new JSONObject(response); resp.setContentType( "application/json" ); PrintWriter printWriter = resp.getWriter(); printWriter.println(jsonResponse); printWriter.close(); } }
发送交易
然后是记录交易数据的功能,每一个区块都可以记录交易数据,发送到节点的交易数据结构如下: { "sender" : "my address" , "recipient" : "someone else's address" , "amount" : 5 }
实现代码如下: package org.zero01.servlet; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.json.JSONObject; import org.zero01.core.BlockChain; // 该Servlet用于接收并处理新的交易信息 @WebServlet ( "/transactions/new" ) public class NewTransaction extends HttpServlet { protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding( "utf-8" ); // 读取客户端传递过来的数据并转换成JSON格式 BufferedReader reader = req.getReader(); String input = null ; StringBuffer requestBody = new StringBuffer(); while ((input = reader.readLine()) != null ) { requestBody.append(input); } JSONObject jsonValues = new JSONObject(requestBody.toString()); // 检查所需要的字段是否位于POST的data中 String[] required = { "sender" , "recipient" , "amount" }; for (String string : required) { if (!jsonValues.has(string)) { // 如果没有需要的字段就返回错误信息 resp.sendError( 400 , "Missing values" ); } } // 新建交易信息 BlockChain blockChain = BlockChain.getInstance(); int index = blockChain.newTransactions(jsonValues.getString( "sender" ), jsonValues.getString( "recipient" ), jsonValues.getLong( "amount" )); // 返回json格式的数据给客户端 resp.setContentType( "application/json" ); PrintWriter printWriter = resp.getWriter(); printWriter.println( new JSONObject().append( "message" , "Transaction will be added to Block " + index)); printWriter.close(); } }
挖矿
挖矿正是神奇所在,它很简单,只做了以下三件事: 计算工作量证明PoW 通过新增一个交易授予矿工(自己)一个币 构造新区块并将其添加到链中
代码实现如下: package org.zero01.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.json.JSONObject; import org.zero01.core.BlockChain; //该Servlet用于运行工作算法的证明来获得下一个证明,也就是所谓的挖矿 @WebServlet ( "/mine" ) public class Mine extends HttpServlet { protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { BlockChain blockChain = BlockChain.getInstance(); Map lastBlock = blockChain.lastBlock(); long lastProof = Long.parseLong(lastBlock.get( "proof" ) + "" ); long proof = blockChain.proofOfWork(lastProof); // 给工作量证明的节点提供奖励,发送者为 "0" 表明是新挖出的币 String uuid = (String) this .getServletContext().getAttribute( "uuid" ); blockChain.newTransactions( "0" , uuid, 1 ); // 构建新的区块 Map newBlock = blockChain.newBlock(proof, null ); Map response = new HashMap(); response.put( "message" , "New Block Forged" ); response.put( "index" , newBlock.get( "index" )); response.put( "transactions" , newBlock.get( "transactions" )); response.put( "proof" , newBlock.get( "proof" )); response.put( "previous_hash" , newBlock.get( "previous_hash" )); // 返回新区块的数据给客户端 resp.setContentType( "application/json" ); PrintWriter printWriter = resp.getWriter(); printWriter.println( new JSONObject(response)); printWriter.close(); } }
注意交易的接收者是我们自己的服务器节点,我们做的大部分工作都只是围绕Blockchain类的方法进行交互。到此,我们的区块链就算完成了,我们来实际运行下。
运行区块链
由于我们这里也没有写前端的web页面,只写了后端的API,所以只能使用 Postman 之类的软件去和API进行交互。首先启动Tomcat服务器,然后通过post请求 http://localhost:8089/BlockChain_Java/transactions/new 来添加新的交易信息(注意我这里没有使用默认的8080端口,默认的情况下是8080端口):
但是这时候还没有新的区块可以写入这个交易信息,所以我们还需要请求 http://localhost:8089/BlockChain_Java/mine 来进行挖矿,挖出一个新的区块来存储这笔交易:
在挖了两次矿之后,就有3个块了,通过请求 http://localhost:8089/BlockChain_Java/chain 可以得到所有的区块块的信息: { "chain" : [ { "index" : 1 , "proof" : 100 , "transactions" : [], "timestamp" : 1520928588165 , "previous_hash" : "0" }, { "index" : 2 , "proof" : 35293 , "transactions" : [ { "amount" : 6 , "sender" : "d4ee26eee15148ee92c6cd394edd974e" , "recipient" : "someone-other-address" }, { "amount" : 1 , "sender" : "0" , "recipient" : "050bbfe4ad644d008545ff490387a889" } ], "timestamp" : 1520928734580 , "previous_hash" : "e5cf7ba38f7f0c3a93fcca5d57b624c8fd255093af4abe3c6999be61bdb81040" }, { "index" : 3 , "proof" : 35089 , "transactions" : [ { "amount" : 1 , "sender" : "0" , "recipient" : "050bbfe4ad644d008545ff490387a889" } ], "timestamp" : 1520928870963 , "previous_hash" : "aa64ab003d15d50a43bd59deb88c939ea43349d00d0b653abd83b42e8fa4417c" } ], "length" : 3 }
一致性(共识)
我们已经有了一个基本的区块链可以接受交易和挖矿。但是区块链系统应该是分布式的。既然是分布式的,那么我们究竟拿什么保证所有节点有同样的链呢?这就是一致性问题,我们要想在网络上有多个节点,就必须实现一个一致性的算法。
注册节点
在实现一致性算法之前,我们需要找到一种方式让一个节点知道它相邻的节点。每个节点都需要保存一份包含网络中其它节点的记录。因此让我们新增几个接口: /nodes/register 接收URL形式的新节点列表 /nodes/resolve执行一致性算法,解决任何冲突,确保节点拥有正确的链
我们需要修改下BlockChain的构造函数并提供一个注册节点方法: package org.zero01.core; ... import java.net.URL; ... private Set nodes; private BlockChain () { ... // 用于存储网络中其他节点的集合 nodes = new HashSet(); ... } public Set getNodes () { return nodes; } /** * 注册节点 * * @param address * 节点地址 * @throws MalformedURLException */ public void registerNode (String address) throws MalformedURLException { URL url = new URL(address); String node = url.getHost() + ":" + (url.getPort() == - 1 ? url.getDefaultPort() : url.getPort()); nodes.add(node); } ...
我们用 HashSet 集合来储存节点,这是一种避免出现重复添加节点的简单方法。
实现共识算法
前面提到,冲突是指不同的节点拥有不同的链,为了解决这个问题,规定最长的、有效的链才是最终的链,换句话说,网络中有效最长链才是实际的链。
我们使用以下算法,来达到网络中的共识: ... import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; ... public class BlockChain { ... /** * 检查是否是有效链,遍历每个区块验证hash和proof,来确定一个给定的区块链是否有效 * * @param chain * @return */ public boolean validChain (List> chain) { Map lastBlock = chain.get( 0 ); int currentIndex = 1 ; while (currentIndex < chain.size()) { Map block = chain.get(currentIndex); System.out.println(lastBlock.toString()); System.out.println(block.toString()); System.out.println( "\n-------------------------\n" ); // 检查block的hash是否正确 if (!block.get( "previous_hash" ).equals(hash(lastBlock))) { return false ; } lastBlock = block; currentIndex++; } return true ; } /** * 共识算法解决冲突,使用网络中最长的链. 遍历所有的邻居节点,并用上一个方法检查链的有效性, 如果发现有效更长链,就替换掉自己的链 * * @return 如果链被取代返回true, 否则返回false * @throws IOException */ public boolean resolveConflicts () throws IOException { Set neighbours = this .nodes; List> newChain = null ; // 寻找最长的区块链 long maxLength = this .chain.size(); // 获取并验证网络中的所有节点的区块链 for (String node : neighbours) { URL url = new URL( "http://" + node + "/BlockChain_Java/chain" ); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.connect(); if (connection.getResponseCode() == 200 ) { BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(connection.getInputStream(), "utf-8" )); StringBuffer responseData = new StringBuffer(); String response = null ; while ((response = bufferedReader.readLine()) != null ) { responseData.append(response); } bufferedReader.close(); JSONObject jsonData = new JSONObject(bufferedReader.toString()); long length = jsonData.getLong( "length" ); List> chain = (List) jsonData.getJSONArray( "chain" ).toList(); // 检查长度是否长,链是否有效 if (length > maxLength && validChain(chain)) { maxLength = length; newChain = chain; } } } // 如果发现一个新的有效链比我们的长,就替换当前的链 if (newChain != null ) { this .chain = newChain; return true ; } return false ; } ...
第一个方法 validChain() 用来检查是否是有效链,遍历每个块验证hash和proof.
第2个方法 resolveConflicts() 用来解决冲突,遍历所有的邻居节点,并用上一个方法检查链的有效性, 如果发现有效更长链,就替换掉自己的链
让我们添加两个Servlet,一个用来注册节点,一个用来解决冲突:
注册节点: package org.zero01.servlet; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.json.JSONObject; import org.zero01.core.BlockChain; // 用于注册节点的Servlet @WebServlet( "/nodes/register" ) public class NodesRegister extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding( "utf-8" ); // 读取客户端传递过来的数据并转换成JSON格式 BufferedReader reader = req.getReader(); String input = null ; StringBuffer requestBody = new StringBuffer(); while ((input = reader.readLine()) != null ) { requestBody.append(input); } JSONObject jsonValues = new JSONObject(requestBody.toString()); // 获得节点集合数据,并进行判空 List< String > nodes = (List) jsonValues.getJSONArray( "nodes" ).toList(); if (nodes == null ) { resp.sendError( 400 , "Error: Please supply a valid list of nodes" ); } // 注册节点 BlockChain blockChain = BlockChain.getInstance(); for ( String address : nodes) { blockChain.registerNode(address); } // 向客户端返回处理结果 Map < String , Object > response = new HashMap< String , Object >(); response.put( "message" , "New nodes have been added" ); response.put( "total_nodes" , blockChain.getNodes().toArray()); resp.setContentType( "application/json" ); PrintWriter printWriter = resp.getWriter(); printWriter.println( new JSONObject(response)); printWriter.close(); } }
解决冲突: package org.zero01.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.json.JSONObject; import org.zero01.core.BlockChain; // 用于解决冲突 @WebServlet ( "/nodes/resolve" ) public class NodesResolve extends HttpServlet { protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { BlockChain blockChain = BlockChain.getInstance(); boolean replaced = blockChain.resolveConflicts(); Map response = new HashMap(); if (replaced) { response.put( "message" , "Our chain was replaced" ); response.put( "new_chain" , blockChain.getChain()); } else { response.put( "message" , "Our chain is authoritative" ); response.put( "chain" , blockChain.getChain()); } resp.setContentType( "application/json" ); PrintWriter printWriter = resp.getWriter(); printWriter.println( new JSONObject(response)); printWriter.close(); } }
我们可以在不同的机器运行节点,或在一台机机开启不同的网络端口来模拟多节点的网络,这里在同一台机器开启不同的端口演示,配置两个不同端口的服务器即可,我这里启动了两个节点: http://localhost:8089 和 http://localhost:8066 。
两个节点互相进行注册:

然后在8066节点上挖两个块,确保是更长的链:
接着在8089节点上访问接口/nodes/resolve ,这时8089节点的链会通过共识算法被8066节点的链取代:
通过共识算法保持一致性后,两个节点的区块链数据就都是一致的了:

到此为止我们就完成了一个区块链的开发,虽然这只是一个最基本的区块链,而且在开发的过程中也没有考虑太多的程序设计方面的问题,而是以最基本、原始的方式进行开发的。但是我们不妨以这个简单的区块链为基础,发挥自己的能力动手去重构、扩展、完善这个区块链程序,直至成为自己的一个小项目。
本文项目代码地址如下: https://github.com/Binary-ZeroOne/blockchain-java-demo
区块链
2020-02-05 20:24:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文介绍一个利用以太坊区块链管理物联网IoT设备的身份识别、验证和声誉的IoT设备管理系统。该系统使用Web界面在以太坊智能合约中注册物联网设备,并通过密码学签名消息验证Iot设备对平台的 使用权。 以太坊教程链接: Dapp入门 | 电商Dapp实战 | ERC721实战 | Php对接 | Java对接 | Python对接 | C#对接 | Dart对接
1、区块链物联网设备管理系统的基本概念
物联网/IoT设备的标识 :通过默克尔树(Merkle Tree)的利用,无需暴露设备的私有属性即可完成IoT设备的注册。使用公钥(或其衍生表示)作为IoT设备的标识ID。
物联网/IoT设备的消息签名与验证 :系统中的每个消息都需要由发送端的IoT设备签名,并在接收端的IoT设备处进行验证。
发送端IoT设备的消息签名生成:
接收端IoT设备的消息签名验证:
物联网/IoT设备的固件指纹 :通过保存IoT设备的固件哈希,可以验证设备所运行的固件是否被非法篡改。
物联网/IoT设备的信誉机制 :基于Web的信任原理,设备可以形成一个信任网络。一个IoT设备从其他 有信誉的设备得到越多的签名,该设备就越可信。
2、区块链物联网设备管理系统的整体说明
系统主要组成部分包括:实体、设备和IoT平台:
系统开发基于以下技术栈: Ethereum Solidity Truffle Framework Web3.js React
项目主要目录内容说明如下: contracts - Solidity智能合约 frontend - Web前端,基于React开发 simulations - IoT设备和平台仿真
系统中IoT设备的配置文件示例如下: { "identifier": "0xf34d4c8f79657f1086f55b817837439c303dff19", "metadataHash": "43af4ba721cd8c9ba432ed6aca9adb96d16f82c25ba76...", "firmwareHash": "b01d2af9ea9dd59dd9c8af3f1639da03c79b7ed28adaa...", "metadata": [ "Olive grove", "45.0270,14.61685", "Espressif Systems", "00:0a:95:9d:68:16" ], "firmware": "333f14cdb0a8520199257479ba126a10bca96b229b7924085...", "address": "0xf34d4c8f79657f1086f55b817837439c303dff19", "publicKey": "d627bbb0a7c150f814a1960ebe69f0d8b4494e1033d9e72...", "privateKey": "48a2e48b2d178e7d1f1508f2964a89079f1f8a301ebb85a...", "curve": "secp256k1", "deviceId": 0 }
3、区块链物联网设备管理系统的主要用户界面
网络状态界面:
实体历史记录界面:
IoT设备ID管理界面:
元数据管理界面:
IoT设备固件信息维护界面:
IoT设备维护确认界面:
配置下载界面:
IoT设备列表界面:
IoT设备ID维护界面:
IoT设备历史数据查看界面:
论文链接: Using blockchain for registration and control of IoT devices 源码下载: iot-device-management
原文链接: 基于以太坊区块链的物联网/IoT设备管理 — 汇智网
区块链
2020-02-05 08:38:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
开源java区块链平台,可做联盟链、私链使用,不适用于公链。各节点已知IP,维持长连接。共识机制采用PBFT。无虚拟货币,可用于存储各种类型的数据,无需挖矿。不仅仅可以用来做账本,还可以做各种定制化的存储需求。理念来自于腾讯的trustsql。加密、公钥私钥、网络模块、存储模块等。
有研究微服务网关权限的,在网关zuul中对所有下游服务权限做控制,覆盖到所有接口,权限控制到角色、菜单、按钮、方法。基于zuul纯内存的方式,校验时性能无损耗。参考我另一个项目 https://gitee.com/tianyalei/zuulauth
有对多线程并发调度框架感兴趣的,参考我另一个项目 https://gitee.com/tianyalei/asyncTool 该并发框架支持任意的多线程并行、串行、阻塞、依赖、回调,可以任意组合各线程的执行顺序,还带全链路回调。
md_blockchain
Java区块链平台,基于Springboot开发的区块链平台。区块链qq交流群737858576,一起学习区块链平台开发,当然也交流Springboot、springcloud、机器学习等知识。
起因
公司要开发区块链,原本是想着使用以太坊开发个合约或者是使用个第三方平台来做,后来发现都不符合业务需求。原因很简单,以太坊、超级账本等平台都是做共享账本的,有代币和挖矿等模块。而我们需要的就是数家公司组个联盟,来共同见证、记录一些不可篡改的交互信息,如A公司给B公司发了一个xxx请求,B公司响应了什么什么。其实要的就是一个分布式数据库,而且性能要好,不能像比特币那种10分钟才生成一个区块。我们要的更多的是数据库的性能,和区块链的一些特性。
经过
项目于18年3月初开始研发,历时一月发布了第一版。主要做了存储模块、加密模块、网络通信、PBFT共识算法、公钥私钥、区块内容解析落地入库等。已经初步具备了区块链的基本特征,但在merkle tree、智能合约以及其他的一些细节上,尚不到位。
希望高手不吝赐教,集思广益,提出见解或方案,来做一个区块链平台项目,适合更多的区块链场景,而不仅仅是账本和各种忽悠人的代币。
理想中的区块链平台:
项目说明
主要有存储模块、网络模块、PBFT共识算法、加密模块、区块解析入库等。
该项目属于"链",非"币"。不涉及虚拟币和挖矿。
存储模块
Block内存储的是类Sql语句。联盟间预先设定好符合业务场景需要的数据库表结构,然后设定好各个节点对表的操作权限(ADD,UPDATE,DELETE),将来各个节点就可以按照自己被允许的权限,进行Sql语句的编写,并打包至Block中,再全网广播,等待全网校验签名、权限等信息的合法性。如果Block合法,则进入PBFT共识算法机制,各节点开始按照PrePrepare、Prepare、Commit等状态依次执行,直到2f+1个commit后,开始进行本地生成新区块。新区块生成后,各节点进行区块内容解析,并落地入库的操作。
场景就比较广泛了,可以设定不同的表结构,或者多个表,进而能完成各自类型信息的存储。譬如商品溯源,从生产商、运输、经销商、消费者等,每个环节都可以对某个商品进行ADD信息的操作。
存储采用的是key-value数据库rocksDB,了解比特币的知道,比特币用的是levelDB,都是类似的东西。可以通过修改yml中db.levelDB为true,db.RocksDB为false来动态切换使用哪个数据库。
结构类似于sql的语句,如ADD(增删改) tableName(表名)ID(主键) JSON(该记录的json)。这里设置了回滚的逻辑,也就是当你做了一个ADD操作时,会同时存储一条Delete语句,以用于将来可能的回滚操作。
网络模块
网络层,采用的是各节点互相长连接、断线重连,然后维持心跳包。网络框架使用的是t-io,也是oschina的知名开源项目。t-io采用了AIO的方式,在大量长连接情况下性能优异,资源占用也很少,并且具备group功能,特别适合于做多个联盟链的SaaS平台。并且包含了心跳包、断线重连、retry等优秀功能。
在项目中,每个节点即是server,又是client,作为server则被其他的N-1个节点连接,作为client则去连接其他N-1个节点的server。同一个联盟,设定一个Group,每次发消息,直接调用sendGroup方法即可。
但仍需要注意的是,由于项目采用了pbft共识算法,在达到共识的过程中,会产生N的3次方数量的网络通信,当节点数量较多,如已达到100时,每次共识将会给网络带来沉重的负担。这是算法本身的限制。
共识模块PBFT
分布式共识算法是分布式系统的核心,常见的有Paxos、pbft、bft、raft、pow等。区块链中常见的是POW、POS、DPOS、pbft等。
比特币采用了POW工作量证明,需要耗费大量的资源进行hash运算(挖矿),由矿工来完成生成Block的权利。其他多是采用选举投票的方式来决定谁来生成Block。共同的特点就是只能特定的节点来生成区块,然后广播给其他人。
区块链分如下三类:
私有链:这是指在企业内部部署的区块链应用,所有节点都是可以信任的,不存在恶意节点;
联盟链:半封闭生态的交易网络,存在不对等信任的节点,可能存在恶意节点;
公有链:开放生态的交易网络,为联盟链和私有链等提供全球交易网络。
由于私有链是封闭生态的存储系统,因此采用Paxos类共识算法(过半同意)可以达到最优的性能;联盟链有半公开半开放特性,因此拜占庭容错是适合选择之一,例如IBM超级账本项目;对于公有链来说,这种共识算法的要求已经超出了普通分布式系统构建的范畴,再加上交易的特性,因此需要引入更多的安全考虑。所以比特币的POW是个非常好的选择。
我们这里可选的是raft和pbft,分别做私链和联盟链,项目中我使用了修改过的pbft共识算法。
先来简单了解pbft:
(1)从全网节点选举出一个主节点(Leader),新区块由主节点负责生成。
(2)每个节点把客户端发来的交易向全网广播,主节点将从网络收集到需放在新区块内的多个交易排序后存入列表,并将该列表向全网广播。
(3)每个节点接收到交易列表后,根据排序模拟执行这些交易。所有交易执行完后,基于交易结果计算新区块的哈希摘要,并向全网广播。
(4)如果一个节点收到的2f(f为可容忍的拜占庭节点数)个其它节点发来的摘要都和自己相等,就向全网广播一条commit消息。
(5)如果一个节点收到2f+1条(包括自己)commit消息,即可提交新区块到本地的区块链和状态数据库。
(6)客户端收到f + 1个成功(即便有f个失败、再f个恶意返回的错误信息,f + 1个正确的也是多数派)的返回,即可认为该次写入请求是成功的。
可以看到,传统的pbft是需要先选举出leader的,然后由leader来搜集交易,并打包,然后广播出去。然后各个节点开始对新Block进行校验、投票、累积commit数量,最后落地。
而我这里对pbft做了修改,这是一个联盟,各个节点是平等的,而且性能要高。所以我不想让每个节点都生成一个指令后,发给其他节点,再大家选举出一个节点来搜集网络上的指令组合再生成Block,太复杂了,而且又存在了leader节点的故障隐患。
我对pbft的修改是,不需要选择leader,任何节点都可以构建Block,然后全网广播。其他节点收到该Block请求时即进入Pre-Prepare状态,校验格式、hash、签名、和table的权限,校验通过后,进入Prepare状态,并全网广播状态。待自己累积的各节点Prepare的数量大于2f+1时,进入commit状态,并全网广播该状态。待自己累积的各节点Commit的数量大于2f+1时,认为已达成共识,将Block加入区块链中,然后执行Block中sql语句。
很明显,和有leader时相比,缺少了顺序的概念。有leader时能保证Block的顺序,当有并发生成Block的需求时,leader能按照顺序进行广播。譬如大家都已经到number=5的区块了,然后需要再生成2个,有leader时,则会按照6、7的顺序来生成。而没有leader时,则可能发生多节点同时生成6的情况。为了避免分叉,我做了一些处理,具体的可以在代码里看实现逻辑。
区块信息查询
各节点通过执行相同的sql来实现一个同步的sqlite数据库(或mysql等其他关系型数据库),将来对数据的查询都是直接查询sqlite,性能高于传统的区块链项目。
由于各个节点都能生成Block,在高并发下会出现区块不一致的情况。如果因为某些原因导致链分叉了,也提供了回滚机制,sql可以回滚。原理也很简单,你ADD一个数据时,我会在区块里同时记录两个指令,一个是ADD,一个是回滚用的DELETE。同理,UPDATE时也会保存原来的旧数据。区块里的sql落地,譬如顺序执行1-10个指令,回滚时就是从10-1执行回滚指令。
每个节点都会记录自己已经同步了的区块的值,以便随时进行sql落地入库。
对区块链信息的查询,那就简单了,直接做数据库查询即可。相比于比特币需要检索整个区块链的索引树,速度和方便性就大不同了。
简单使用说明
使用方法:先下载 md_blockchain_manager项目 ,然后导入工程里的sql数据库文件,修改application.yml数据库配置,最后启动manager项目。
然后修改md_blockchain中application.yml里的name、appid和manager项目数据库里的某个值对应,作为一个节点。如果有多个节点,则某个节点都和数据库里对应,填写各节点的ip。managerUrl就是manager项目的url,让该项目能访问到manager项目。
在md_blockchian项目启动时,在ClientStarter类中可见,启动时会从manager项目拉取所有节点的数据,并进行连接。如果自己的ip和appId等不在manager数据库中,则无法启动。
可以通过访问localhost:8080/block?content=1来生成一个区块。正常使用时至少要启动4个节点才行,否则无法达成共识,PBFT要求2f+1个节点同意才能生成Block。为了方便测试,可以直接修改pbftSize的返回值为0,这样就能自己一个节点玩起来了。如果有多个节点,在生成Block后就会发现别的节点也会自动同步自己新生成的Block。目前代码里默认设置了一张表message,里面也只有一个字段content,相当于一个简单的区块链记事本。当有4个节点时,可以通过并发访问其中的几个来同时生成Block进行测试,看是否会分叉。还可以关停其中的一个,看其他的三个是否能达成共识(拜占庭最多容许f个节点故障,4个节点允许1个故障),恢复故障的那个,看是否能够同步其他正常节点的Block。可以进行各种测试,欢迎提bug。
可以通过localhost:8080/block/sqlite来查看sqlite里存的数据,就是根据Block里的sql语句执行后的结果。
我把项目部署到docker里了,共启动4个节点,如图:
manager就是md_blockchain_manager项目,主要功能就是提供联盟链内各节点ip和各节点的权限信息
四个节点ip都写死了,都启动后,它们会相互全部连接起来,并维持住长连接和心跳包,相互交换最新的Block信息。
我调用一下block项目的生成区块接口, http://ip:port/block?content=1,可以看到各节点投票及pbft的各状态
别的节点会是这样,收到block项目请求生成区块的请求、并开始校验,然后进入pbft的投票状态
如果某节点断线了、或者是新加入的节点,从别的正常节点拉取新区块
此外还有高并发情况下,各节点同时生成Block,系统处理共识、保证区块链不分叉的一些测试。
这个生成区块的接口是写好用来测试的,正常走的流程是调用instuction接口,先生产符合自己需求的指令,然后组合多个指令,调用BlockController里的生成区块接口。
区块链
2020-02-03 20:32:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
如何使用web3j为Java应用或Android App增加以太坊区块链支持,教程内容即涉及以太坊中的核心概念,例如账户管理包括账户的创建、钱包创建、交易转账,交易与状态、智能合约开发与交互、过滤器和事件等,同时也详细说明如何使用web3j提供的API开发接口与以太坊进行交互,是java工程师学习以太坊应用开发的不二选择。
以太坊概述
以太坊是备受关注的区块链,它基于密码学技术和P2P通信技术 构建了一个去中心化的平台,所有的交易同步保存在每个节点中, 通过将区块单向级联成链,以太坊有效的保证了交易的不可篡改:
智能合约平台
以太坊是第一个实现了虚拟机的区块链,因此为智能合约 - Smart Contract - 的运行提供了良好的支持环境。也正因为这个原因,以太坊被称为区块链 2.0,以区别于比特币代表的以数字加密货币为核心特征的区块链1.0。
可以将智能合约理解为机器之间的合同约定,在满足一定条件时自动 执行约定好的逻辑,例如在保险理赔流程中,如果理赔条件满足就自动 将赔偿金释放给出险人,这个流程就可以使用智能合约来实现。
有多种语言可以开发以太坊智能合约,但目前最常用的是类似于JavaScript的 Solidity语言。本课程中将采用Solidity讲解智能合约的开发。
JSON RPC与web3j
如果我们希望构造一个去中心化应用(DApp),除了智能合约的开发, 通常还需要使用其他开发语言为用户提供操作智能合约的用户接口,例如 开发一个网页、一个手机App或者一个桌面应用。这些代码都需要与以太坊进行交互。
以太坊规定了每个节点需要实现的JSON RPC API 应用开发接口,该接口是传输无关的,应用程序可以通过HTTP、websocket或IPC等多种 通信机制来使用该接口协议操作以太坊节点:
理论上你可以使用任何语言基于JSON RPC接口开发出以太坊之上的 去中心化应用,不过为了提高开发效率,更好的办法是 使用特定语言的JSON RPC封装库,这些库封装了JSON RPC的协议细节, 有助于开发人员聚焦在业务逻辑的实现上。
web3j 是一个轻量级的用于集成以太坊功能的Java开发库,它是Java版本的以太坊JSON RPC 接口协议封装实现,如果需要将你的Java应用或Android应用接入以太坊,用web3j就对了。
web3j体系概述
web3j的功能组织在不同的包中,下图展示了 org.web3j 主要包之间的依赖关系:
core :JSON RPC协议的封装主要由包 org.web3j.core 实现,它依赖于 org.web3j.crypto 包提供的密钥与签名相关的功能,以及 org.web3j.abi 包提供的java/solidity类型映射支持。
console : org.web3j.console 包实现了一个可以单独运行的命令行程序web3j,我们将使用它来 生成solidity合约的Java封装类,其中, org.web3j.codegen 包实现了从abi到java封装类的代码生成。
节点相关 : org.web3j.infura 包封装了对Infura公共节点旳http访问服务接口, org.web3j.geth 和 org.web3j.parity 则分别封装了这两种常用以太坊节点软件旳管理接口。
本课程 的目的是帮助java工程师快速掌握使用web3j开发以太坊应用的技能,因此 主要以web3j的开发接口为主线来展开课程内容,同时穿插讲解以太坊的一些基本 概念,例如:账户、交易和智能合约的开发等。
课程内容概述 hello,web3j
将通过一个简单的java应用的开发来讲解使用web3j进行以太坊应用开发的最简流程,通过这一部分的学习,你就可以在自己的java应用中引入以太坊支持了。 账户管理
将详细介绍web3j提供的账户管理接口。如果你对开发钱包应用(中心化/去中心化)感兴趣,这部分内容会有很大的帮助。web3j创建账户,创建钱包,转账特别是代币转账等丰富的进行交易的功能。 状态与交易
主要讲解web3j提供的交易操作接口,同时也介绍一些重要的概念,例如状态、裸交易、gas等。这部分内容将帮助你理清java应用与以太坊交互的大多数问题。 智能合约
将通过一个投票合约的开发、编译、代码生成、部署与交互的完整流程,讲解使用web3j操作solitiy智能合约的方法。 过滤器与事件
主要讲解以太坊的通知机制和web3j的响应式封装接口。
该 web3j教程 为每个知识点都提供了相应的预置代码,你可以在在线实验环境的 ~/repo 目录下查看。
区块链
2020-02-03 20:29:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
区块链开发用什么语言?通过本文你将使用 Go 语言开发自己的区块链(或者说用go语言搭建区块链)、理解哈希函数是如何保持区块链的完整性、掌握如何用Go语言编程创造并添加新的块、实现多个节点通过竞争生成块、通过浏览器来查看整个链、了解所有其他关于区块链的基础知识。
但是,文章中将不会涉及工作量证明算法(PoW)以及权益证明算法(PoS)这类的共识算法,同时为了让你更清楚得查看区块链以及块的添加,我们将网络交互的过程简化了,关于 P2P 网络比如“全网广播”这个过程等内容将在后续文章中补上。
开发环境
我们假设你已经具备一点 Go 语言的开发经验。在安装和配置 Go 开发环境后之后,我们还要获取以下一些依赖: ~$ go get github.com/davecgh/ go -spew/spew
spew 可以帮助我们在终端中中直接查看 struct 和 slice 这两种数据结构。 ~$ go get github.com/gorilla/mux
Gorilla 的 mux 包非常流行, 我们用它来写 web handler。 ~$ go get github.com/joho/godotenv
godotenv 可以帮助我们读取项目根目录中的 .env 配置文件,这样就不用将 http端口之类的配置硬编码进代码中了。比如像这样: ADDR = 8080
接下来,我们创建一个 main.go 文件。之后的大部分工作都围绕这个文件,开始写代码吧!
导入依赖包
我们将所有的依赖包以声明的方式导入进去: package main import ( "crypto/sha256" "encoding/hex" "encoding/json" "io" "log" "net/http" "os" "time" "github.com/davecgh/go-spew/spew" "github.com/gorilla/mux" "github.com/joho/godotenv" )
数据模型
接着我们来定义一个结构体,它代表组成区块链的每一个块的数据模型: type Block struct { Index int Timestamp string BPM int Hash string PrevHash string } Index 是这个块在整个链中的位置 Timestamp 显而易见就是块生成时的时间戳 Hash 是这个块通过 SHA256 算法生成的散列值 PrevHash 代表前一个块的 SHA256 散列值 BPM 每分钟心跳数,也就是心率
接着,我们再定义一个结构表示整个链,最简单的表示形式就是一个 Block 的 slice: var Blockchain [] Block
我们使用散列算法(SHA256)来确定和维护链中块和块正确的顺序,确保每一个块的 PrevHash 值等于前一个块中的 Hash 值,这样就以正确的块顺序构建出链:
散列和生成新块
我们为什么需要散列?主要是两个原因: 在节省空间的前提下去唯一标识数据。散列是用整个块的数据计算得出,在我们的例子中,将整个块的数据通过 SHA256 计算成一个定长不可伪造的字符串。 维持链的完整性。通过存储前一个块的散列值,我们就能够确保每个块在链中的正确顺序。任何对数据的篡改都将改变散列值,同时也就破坏了链。以我们从事的医疗健康领域为例,比如有一个恶意的第三方为了调整“人寿险”的价格,而修改了一个或若干个块中的代表不健康的 BPM 值,那么整个链都变得不可信了。
我们接着写一个函数,用来计算给定的数据的 SHA256 散列值: func calculateHash ( block Block ) string { record := string (block.Index) + block.Timestamp + string (block.BPM) + block.PrevHash h := sha256. New () h. Write ([]byte(record)) hashed := h. Sum (nil) return hex. EncodeToString (hashed) }
这个 calculateHash 函数接受一个块,通过块中的 Index,Timestamp,BPM,以及 PrevHash 值来计算出 SHA256 散列值。接下来我们就能编写一个生成块的函数: func generateBlock (oldBlock Block, BPM int ) (Block, error) { var newBlock Block t := time.Now() newBlock.Index = oldBlock.Index + 1 newBlock.Timestamp = t.String() newBlock.BPM = BPM newBlock.PrevHash = oldBlock.Hash newBlock.Hash = calculateHash(newBlock) return newBlock, nil }
其中,Index 是从给定的前一块的 Index 递增得出,时间戳是直接通过 time.Now() 函数来获得的,Hash 值通过前面的 calculateHash 函数计算得出,PrevHash 则是给定的前一个块的 Hash 值。
校验块
搞定了块的生成,接下来我们需要有函数帮我们判断一个块是否有被篡改。检查 Index 来看这个块是否正确得递增,检查 PrevHash 与前一个块的 Hash 是否一致,再来通过 calculateHash 检查当前块的 Hash 值是否正确。通过这几步我们就能写出一个校验函数: func isBlockValid (newBlock, oldBlock Block) bool { if oldBlock.Index+ 1 != newBlock.Index { return false } if oldBlock.Hash != newBlock.PrevHash { return false } if calculateHash(newBlock) != newBlock.Hash { return false } return true }
除了校验块以外,我们还会遇到一个问题:两个节点都生成块并添加到各自的链上,那我们应该以谁为准?这里的细节我们留到下一篇文章,
这里先让我们记住一个原则:始终选择最长的链:
通常来说,更长的链表示它的数据(状态)是更新的,所以我们需要一个函数能帮我们将本地的过期的链切换成最新的链: func replaceChain (newBlocks []Block) { if len (newBlocks) > len (Blockchain) { Blockchain = newBlocks } }
到这一步,我们基本就把所有重要的函数完成了。接下来,我们需要一个方便直观的方式来查看我们的链,包括数据及状态。通过浏览器查看 web 页面可能是最合适的方式!
Web 服务
我猜你一定对传统的 web 服务及开发非常熟悉,所以这部分你肯定一看就会。
借助 Gorilla/mux 包,我们先写一个函数来初始化我们的 web 服务: func run () error { mux := makeMuxRouter() httpAddr := os.Getenv( "ADDR" ) log.Println( "Listening on " , os.Getenv( "ADDR" )) s := &http.Server{ Addr: ":" + httpAddr, Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20 , } if err := s.ListenAndServe(); err != nil { return err } return nil }
其中的端口号是通过前面提到的 .env 来获得,再添加一些基本的配置参数,这个 web 服务就已经可以 listen and serve 了!
接下来我们再来定义不同 endpoint 以及对应的 handler。例如,对“/”的 GET 请求我们可以查看整个链,“/”的 POST 请求可以创建块。 func makeMuxRouter() http.Handler { muxRouter := mux.NewRouter() muxRouter.HandleFunc( "/" , handleGetBlockchain).Methods( " GET " ) muxRouter.HandleFunc( "/" , handleWriteBlock).Methods( " POST " ) return muxRouter }
GET 请求的 handler: func handleGetBlockchain (w http.ResponseWriter, r *http.Request) { bytes, err := json.MarshalIndent(Blockchain, "" , " " ) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } io.WriteString(w, string (bytes)) }
为了简化,我们直接以 JSON 格式返回整个链,你可以在浏览器中访问 localhost:8080 或者 127.0.0.1:8080 来查看(这里的8080就是你在 .env 中定义的端口号 ADDR)。
POST 请求的 handler 稍微有些复杂,我们先来定义一下 POST 请求的 payload: type Message struct { BPM int }
再看看 handler 的实现: func handleWriteBlock (w http.ResponseWriter, r *http.Request) { var m Message decoder := json.NewDecoder(r.Body) if err := decoder.Decode(&m); err != nil { respondWithJSON(w, r, http.StatusBadRequest, r.Body) return } defer r.Body.Close() newBlock, err := generateBlock(Blockchain[ len (Blockchain) -1 ], m.BPM) if err != nil { respondWithJSON(w, r, http.StatusInternalServerError, m) return } if isBlockValid(newBlock, Blockchain[ len (Blockchain) -1 ]) { newBlockchain := append (Blockchain, newBlock) replaceChain(newBlockchain) spew.Dump(Blockchain) } respondWithJSON(w, r, http.StatusCreated, newBlock) }
我们的 POST 请求体中可以使用上面定义的 payload,比如: { "BPM" : 75 }
还记得前面我们写的 generateBlock 这个函数吗?它接受一个“前一个块”参数,和一个 BPM 值。POST handler 接受请求后就能获得请求体中的 BPM 值,接着借助生成块的函数以及校验块的函数就能生成一个新的块了!
除此之外,你也可以: 使用spew.Dump 这个函数可以以非常美观和方便阅读的方式将 struct、slice 等数据打印在控制台里,方便我们调试。 测试 POST 请求时,可以使用 POSTMAN 这个 chrome 插件,相比 curl它更直观和方便。
POST 请求处理完之后,无论创建块成功与否,我们需要返回客户端一个响应: func respondWithJSON (w http.ResponseWriter, r *http.Request, code int , payload interface {}) { response, err := json.MarshalIndent(payload, "" , " " ) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([] byte ( "HTTP 500: Internal Server Error" )) return } w.WriteHeader(code) w.Write(response) }
快要大功告成了。
接下来,我们把这些关于区块链的函数,web 服务的函数“组装”起来: func main () { err := godotenv.Load() if err != nil { log.Fatal(err) } go func () { t := time.Now() genesisBlock := Block{ 0 , t.String(), 0 , "" , "" } spew.Dump(genesisBlock) Blockchain = append (Blockchain, genesisBlock) }() log.Fatal(run()) }
这里的 genesisBlock (创世块)是 main 函数中最重要的部分,通过它来初始化区块链,毕竟第一个块的 PrevHash 是空的。
哦耶!完成了
可以从这里获得完整的代码: Github repo
让我们来启动它: ~$ go run main. go
在终端中,我们可以看到 web 服务器启动的日志信息,并且打印出了创世块的信息:
接着我们打开浏览器,访问 localhost:8080 这个地址,我们可以看到页面中展示了当前整个区块链的信息(当然,目前只有一个创世块):
接着,我们再通过 POSTMAN 来发送一些 POST 请求:
刷新刚才的页面,现在的链中多了一些块,正是我们刚才生成的,同时你们可以看到,块的顺序和散列值都正确。
总结
刚刚我们完成了一个自己的区块链,虽然很简单(陋),但它具备块生成、散列计算、块校验等基本能力。接下来你就可以继续深入的学习
区块链的其他重要知识,比如工作量证明、权益证明这样的共识算法,或者是智能合约、Dapp、侧链等等。
目前这个实现中不包括任何 P2P 网络的内容,我们会在下一篇文章中补充这部分内容,当然,我们鼓励你在这个基础上自己实践一遍!
另外安利两个教程:1. 以太坊DApp开发入门实战 2. 以太坊区块链电商DApp实战
区块链
2020-02-03 20:19:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
用JavaScript开发实现一个简单区块链。通过这一开发过程,你将理解区块链技术是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的记录。
然而,在通常情况下,当我们谈到区块链的时候也会谈起使用区块链来解决的问题,这两者很容易混淆。像流行的比特币和以太坊这样基于区块链的项目就是这样。“区块链”这个术语通常和像交易、智能合约、加密货币这样的概念紧紧联系在一起。
这就令理解区块链变得不必要得复杂起来,特别是当你想理解源码的时候。下面我将通过 200 行 JS 实现的超级简单的区块链来帮助大家理解它,我给这段代码起名为 NaiveChain。你可以在 Github
查看更多的技术细节。
块结构
第一个逻辑步骤是决定块结构。为了保证事情尽可能的简单,我们只选择最必要的部分:index(下标)、timestamp(时间戳)、data(数据)、hash(哈希值)和 previous hash(前置哈希值)。
这个块中必须能找到前一个块的哈希值,以此来保证整条链的完整性。 class Block { constructor (index, previousHash, timestamp, data, hash) { this .index = index; this .previousHash = previousHash.toString(); this .timestamp = timestamp; this .data = data; this .hash = hash.toString(); } }
块哈希
为了保存完整的数据,必须哈希区块。SHA-256会对块的内容进行加密,记录这个值应该和“挖矿”毫无关系,因为这里不需要解决工作量证明的问题。 var calculateHash = (index, previousHash, timestamp, data ) => { return CryptoJS . SHA256 ( index + previousHash + timestamp + data ). toString (); };
块的生成
要生成一个块,必须知道前一个块的哈希值,然后创造其余所需的内容(= index, hash, data and timestamp)。块的data部分是由终端用户所提供的。 var generateNextBlock = ( blockData ) => { var previousBlock = getLatestBlock(); var nextIndex = previousBlock.index + 1 ; var nextTimestamp = new Date ().getTime() / 1000 ; var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData); return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash); };
块的存储
内存中的Javascript数组被用于存储区块链。区块链的第一个块通常被称为“起源块”,是硬编码的。 var getGenesisBlock = () => { return new Block( 0 , "0" , 1465154705 , "my genesis block!!" , "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7" ); }; var blockchain = [getGenesisBlock()];
确认块的完整性
在任何时候都必须能确认一个区块或者一整条链的区块是否完整。在我们从其他节点接收到新的区块,并需要决定接受或拒绝它们时,这一点尤为重要。 var isValidNewBlock = ( newBlock, previousBlock ) => { if (previousBlock.index + 1 !== newBlock.index) { console .log( 'invalid index' ); return false ; } else if (previousBlock.hash !== newBlock.previousHash) { console .log( 'invalid previoushash' ); return false ; } else if (calculateHashForBlock(newBlock) !== newBlock.hash) { console .log( 'invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash); return false ; } return true ; };
选择最长的链
任何时候在链中都应该只有一组明确的块。万一冲突了(例如:两个结点都生成了72号块时),会选择有最大数目的块的链。
var replaceChain = ( newBlocks ) => { if (isValidChain(newBlocks) && newBlocks.length > blockchain.length) { console .log( 'Received blockchain is valid. Replacing current blockchain with received blockchain' ); blockchain = newBlocks; broadcast(responseLatestMsg()); } else { console .log( 'Received blockchain invalid' ); } };
与其他结点的通信
结点的本质是和其他结点共享和同步区块链,下面的规则能保证网络同步。 当一个结点生成一个新块时,它会在网络上散布这个块。 当一个节点连接新peer时,它会查询最新的block。 当一个结点遇到一个块,其index大于当前所有块的index时,它会添加这个块到它当前的链中,
或者到整个区块链中查询这个块。
我没有采用自动发现peer的工具。peers的位置(URL)必须是手动添加的。
节点控制
在某种程度上用户必须能够控制节点。这一点通过搭建一个HTTP服务器可以实现。 var initHttpServer = () => { var app = express(); app.use(bodyParser.json()); app.get( '/blocks' , (req, res) => res.send(JSON.stringify(blockchain))); app.post( '/mineBlock' , (req, res) => { var newBlock = generateNextBlock(req.body.data); addBlock(newBlock); broadcast(responseLatestMsg()); console .log( 'block added: ' + JSON.stringify(newBlock)); res.send(); }); app.get( '/peers' , (req, res) => { res.send(sockets.map(s => s._socket.remoteAddress + ':' + s._socket.remotePort)); }); app.post( '/addPeer' , (req, res) => { connectToPeers([req.body.peer]); res.send(); }); app.listen(http_port, () => console .log( 'Listening http on port: ' + http_port)); };
用户可以用下面的方法和节点互动: 列出所有的块 用用户提供的内容创建一个新的块 列出或者新增peers
下面这个Curl的例子就是最直接的控制节点的方法: #get all blocks from the node curl http : //localhost:3001/blocks
系统架构
需要指出的是,节点实际上展现了两个web服务器:一个(HTTP服务器)是让用户控制节点,另一个(Websocket HTTP服务器)。
总结
创造 NaiveChain 的目的是为了示范和学习,因为它并没有“挖矿”算法(PoS或PoW),
不能被用于公用网络,但是它实现了区块链运作的基本特性。
另外安利两个教程:1. 以太坊DApp开发入门实战 2. 以太坊区块链电商DApp实战
区块链
2020-02-03 20:17:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
Hyperledger Fabric是最流行的区块链开发框架之一,它有独特的定位和一些鲜明的特点,例如许可制架构、可插拔组件、支持私密交易的通道、模块化以及可扩展性,因此适合企业联盟链应用的开发。在这篇文章中,我们将介绍如何使用链码加密/解密保存在Hyperledger Fabric区块链上的敏感数据。 Hyperledger Fabric区块链开发教程: Node.js | Java | Golang
1、Hyperledger Fabric链码加密/解密的应用背景
在企业环境中,有时我们需要处理一些敏感的数据,例如保存信用卡数据、银行信息、生物识别数据、健康信息等等,这些敏感数据是我们基于分布式账本的业务应用的一部分,最终用户通常希望即使在数据被渗透的情况下也能保证这些私密信息的安全性。
在一些传统的应用中,我们会将数据库中的数据加密,这样即使有人偷偷进入数据库,也无法理解数据的真实含义。同样,加密区块链数据库中的用户数据也是保护隐私的有效手段。现在让我们看看如何使用NodeJS链码来加密要写入区块链数据库的数据。
在我们开始后续的实现之前,需要先指出一点:由于引入了额外的加密和解密环节,这会导致生产环境中的应用处理速度变慢,要进行加密/解密处理的数据量越大,对应用性能的影响就越大。
2、Hyperledger Fabric链码加密/解密的处理流程
在我们开始加密处理之前,先解释一下要用到的链码的逻辑。示例链码就是一个简单的用户注册和登录实现。用户需要先提供用户名和密码进行注册,这些身份信息将以明文形式保存在数据库中,当用户登录时,将使用保存在数据库中的身份信息进行身份验证。因此我们将为这些身份信息添加 加密/解密层。
在这个示例中,我将尽力保持代码的简单,使用nodejs内置的crypto库。根据应用的不同,你也可以使用定制的加密实现。
加密方法实现如下: function encrypt(data,password){ const cipher = crypto.createCipher('aes256', password); let encrypted = cipher.update(data, 'utf8', 'hex'); encrypted += cipher.final('hex'); return encrypted; }
encrypt() 方法使用aes256算法加密指定的数据,它有两个参数: data:要加密的数据 password:加密口令
解密方法实现如下: function decrypt(cipherData,password) { const decipher = crypto.createDecipher('aes256', password); let decrypted = decipher.update(cipherData, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted.toString();}
decrypt() 方法使用aes256算法和传入的加密口令,解密传入的加密数据。
3、Hyperledger Fabric链码加密/解密的实现代码
我们之前介绍了用户注册/登录链码的逻辑。当用户注册时提交其用户名和登录密码,因此我们需要在将用户的身份数据存入Hyperledger Fabric区块链之前先进行加密操作。 async signUp(stub, args) { if (args.length != 3) { return Buffer.from('Incorrect number of arguments. Expecting 3'); }else{ console.info('**Storing Credentials on Blockchain**'); const credentials = {userName:args[0],password:args[1]}; let data = JSON.stringify(credentials); let cipher = encrypt(data,args[2]); await stub.putState(args[0], Buffer.from(JSON.stringify(cipher))); console.info('*Signup Successfull..Your Username is '+args[0]); return Buffer.from('Signup Successfull..Your Username is '+args[0]); } }
同样,当登录时,链码需要验证用户名是否在Hyperledger Fabric的链上数据库中存在并检查密码是否正确。因此在检查身份信息之前,需要首先解密Hyperledger Fabric的链上数据: async login(stub, args) { if (args.length != 3) { return Buffer.from('Incorrect number of arguments. Expecting 3'); } let userName=args[0]; let password=args[1]; let credentialsAsBytes = await stub.getState(args[0]); if (!credentialsAsBytes || credentialsAsBytes.toString().length <= 0) { return Buffer.from('Incorrect Username..!'); } else{ let data= JSON.parse(credentialsAsBytes); let decryptData= decrypt(data,args[2]); let credentials= JSON.parse(decryptData); if (password!=credentials.password) { return Buffer.from('Incorrect Password..!'); } //Functions go here after signin console.log('Login Successfull..✓'); return Buffer.from('Login Successfull..'); } } }
最后我们实现用户注册/登录链码的路由分发: async Invoke(stub) { let ret = stub.getFunctionAndParameters(); console.info(ret); let method = this[ret.fcn]; if (!method) { console.error('no function of name:' + ret.fcn + ' found'); throw new Error('Received unknown function ' + ret.fcn + ' invocation'); } try { let payload = await method(stub, ret.params); return shim.success(payload); } catch (err) { console.log(err); return shim.error(err); } }
完整的Hyperledger Fabric代码可以在 这里 下载。
原文链接: Hyperledger Fabric最佳实践 - 用链码加密/解密链上数据 -汇智网
区块链
2020-02-02 18:51:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
区块链现在是热门的技术,每个人都在寻求用区块链解决各种各样的问题。自2017年我开始从事智能合约的安全审计以来,已经看到了太多错误的区块链用例。有些错误的区块链用例看起来符合逻辑并且也有益处,但是实际上其中存在着问题。本文将介绍存在8种典型的基于区块链的错误的解决方案,以期帮助开发者/投资者/客户更深刻地理解区块链技术的边界。 相关教程推荐: Hyperledger Fabric | Ethereum | Tendermint | Bitcoin | EOS
1、基于区块链的供应链管理
假设你订购了一批货物,承运人承诺了运输条件,例如保持你的货物处于冷藏状态。一种区块链应用解决方案是在货车上安装可以监视冷柜温度的传感器并定期将温度数据写入区块链,这样你就可以确信承运人所承诺的运输条件在整个过程中都得到满足。
这个区块链应用案例的问题不在区块链,而在于传感器。作为现实世界的一部分,传感器很容易被愚弄。例如,一个恶意的承运人可能只会启动货车中的一个小冷柜然后把传感器放进这个小冷柜,而把你的货物放在货车的没有冷藏环境的空间以节省成本。
我将这种问题定义为: 区块链不是物联网 。
在文本中我们将多次重温这一定义。虽然区块链不允许修改数据,但是它并不能保证数据是正确的。唯一的例外是链上交易,当系统不需要与现实世界交互时,才能保证基于区块链的系统能够验证数据,例如一个地址是否有足够的资金来处理交易。
从区块链外部向区块链提交信息的应用被称为预言机/Oracles。在预言机的解决方案完善之前,任何基于区块链的供应链管理,就像上面这样的冷鲜物流跟踪区块链应用,都是毫无意义的,就像没有可靠的引擎就去设计飞机一样徒劳。
我从这篇文章 你是否需要区块链? 借用了物流冷柜的区块链应用案例,也推荐你阅读该文并对下图深入思考区块链应用的合理性:
2、基于区块链的真品验证
虽然这个区块链应用案例类似于上面的供应链用例,但是我还是想单独列出来,因为它以一种不同的形式出现。
假设我们生的是产昂贵并且独一无二的商品,例如高级手表、葡萄酒或汽车。我们希望客户确信他们买到的东西确实是我们造的,因此我们将葡萄酒瓶关联到一个基于区块链的通证,并在瓶上印一个二维码。现在从我们的工厂到消费者的每一个环节(工厂、物流商、商店、消费者)都通过一个单独的区块链交易进行确认,因此消费者可以在线查看一瓶葡萄酒的历史轨迹。
然而,这个听起来相当不错的区块链应用案例却无法抵御非常简单的攻击:一个不良商人可以复制一个带通证的正品的酒瓶,然后用劣质葡萄酒罐装,或者换掉你的高级葡萄酒,卖给不关心是不是有通证验证的人。为什么会这么简单就被破解?是的,就是因为: 区块链不是物联网 。
酒瓶是现实世界中的物理对象,因此酒瓶可以被伪造,这一点和数字签名是不同的。
3、基于区块链的声明验证
让我们以大学毕业证书的验证为例来介绍这个区块链应用案例的背景。在这种区块链应用案例中,我们需要验证一个声明的真实性,例如:彼得是大学毕业生,而不是要验证一个物理对象的真实性。要确保文凭合规并且签发日期正确,我们需要检查数字签名和时间戳。
数字签名很好,有些人甚至将数字签名的基础 —— 非对称密码学 —— 称为20世纪最伟大的发明。但是我们不要将其与区块链混淆。实际上,数字签名在区块链之前很早就已经得以广泛应用了。要注意的是,现在数字签名常常与区块链捆绑在一起作为卖点。可能你需要的只是数字签名,一个区块链应用并不符合你的需求。
时间戳和区块链更接近一些。实际上,区块链本身就是最可靠的打时间戳的方法。你不需要发明任何新东西,只需要将数据的哈希写入比特币区块链。
将学生的毕业文凭数字化,然后由几个教授签名,最后将哈希写入比特币区块链,这是一个好的区块链应用案例吗?是的。不过,重要的是不要用中心化的验证手段,例如网站或手机app,因为那将会是这个区块链应用的一个致命故障点。
4、基于区块链的投票
投票也是一个流行的区块链应用案例。当谈到利用区块链投票时,我们需要首先清楚地了解这个区块链应用要解决的问题是什么。
投票作弊/投票人验证
要解决这个问题,我们需要的是数字签名而不是区块链。这里主要的问题与私钥有关:从哪里得到私钥以及如何存储私钥。相信不用我解释为什么不能由用户在自己设备生成私钥的系统是错误的,然而除此之外,代码开源以及正确地审计密钥生成软件、第三方硬件也同样重要,以确保用户可以正确处理私钥问题。
虽然一个区块链应用系统的开发者可以解决前两个问题,第三个则要难的多。比特币可以帮助我们学习如何使用密钥。实际上,丢失你的社交媒体账号的密码是一回事,但是丢失你的资产的私钥则要严重的多了。
再一次,是预言机/oracle将公钥与特定的个人关联起来,如果我们需要利用它投票的话。
公开计票
基本可以说以太坊智能合约可以很好地解决这个问题,因为它可以让每个人都看到某个候选人得到多少投票。不过在这个区块链应用案例中,开放程度有点过了,因为我们可以看到每个人地投票,因此可以影响他们。虽然系统可以设计成每个人只能看到自己的投票,但是这又有另一个更复杂的问题:只要投票人了解别人可以知道他的投票情况,投票人就会有压力。
这里还要重申,在这个区块链应用中,我们需要预言机来检查是否存在虚假的投票人的投票。
5、基于区块链的著作权验证
假设艺术家A希望利用区块链来注册他的一个作品。该艺术家拍摄了画作的照片,然后将照片哈希上传到区块链,然后他可以将照片贴到自己的博客里现在,如果艺术家B宣称这副作品是他创作的,艺术家A可以利用区块链上的哈希轻松地证明其著作权。
这个听起来蛮不错的区块链应用案例中存在两个潜在的问题: 首先,艺术家B可以说他不了解区块链,因此没有用区块链来登记其著作权。因此,只有当区块链著作权普及后这一流程才有益。 其次,艺术家B可以闯入艺术家A的工作室,拍摄作品的照片,然后在艺术家B 之前先将 照片的哈希传上区块链
原因在于: 区块链不是物联网
是的,总的来说,这个区块链应用案例是有价值的,然而,除了比特币区块链也不需要别的什么东西了。
注意,我说的只是著作权的证明,在我的理解中知识产权没有意义。
6、基于区块链的土地所有权登记
另一个常见的区块链应用案例是将基于区块链的通证与土地所有权关联,这里面至少有两个问题:
权威机构修改
虽然一个酒瓶/手表/汽车可以在个人之间转让,土地所有权和转让必须由监管机构登记,这通常需要实地走访你的土地。如果监管机构坚持你已经转让了土地,那么区块链记录会怎么样?第一个选项是:区块链记录依然表明你是土地的所有人,虽然这已经不符合实际情况了。第二个选项:权威机构生成自己的记录,因此覆盖了你之前的记录,这意味着区块链也没有起作用。这是一个非常重要的问题,因为区块链被宣称的一大优点就是保护你免于这种修改行为。
中心化的开发与支持
谁负责开发这样一个系统并提供支持?如果是监管机构自己或其合作伙伴负责,那么这样一个系统不是去中心化的。一个去中心化的协议再加上中心化的开发等同于中心化的协议。
此外,每次当有人向你推销区块链应用案例时,问问自己: 是不是用分布式数据库就够了?
如果答案是 YES ,那么为什么还要用区块链呢?实际上,区块链要慢的多,而且会消耗更多的资源。另外数据库开发和集成方面的专家成本要低的多,也更容易找到。
考虑到所有这些问题,我相信对于土地登记而言,一个分布式数据库是更好的选择,即使该系统的确需要更加可靠和开放。
实际上,看起来这个区块链应用案例已经成为了现实。Bitfury最近宣布其基于Exonum框架开发的区块链土地登记系统已经上线,并计划拓展到乌克兰和摩尔多瓦。非常奇怪的是,我没有找到该项目的任何技术资料,这表明出于某种原因Bitfury并不急于鼓吹这一项目。
7、基于区块链的银行间转账
根据之前的一些研究,这个应该算是一个好的区块链应用案例。银行间转账涉及到一组彼此并不信任的机构,利用区块链可以无需第三方可信机构的介入。虽然在这里可以使用比特币,银行也不会将其相互之间的支付活动公开化。因此我们需要一个私有的区块链,只有参与跨行转账的银行可以输入数据、运行节点并验证交易。
在功能方面,这样一个系统和具有访问控制的分布式数据库有区别吗?是的,的确有一些区别,但是只有当机构之前有分歧时才能看到区别之处。这里的问题在于:银行是认同系统提供的共识,还是更愿意诉诸法庭?如果银行可以选择第二个选项,那么这个系统就没有什么意义。
另外,如果立法机构禁止或限制这样的系统,或者要求法院不承认该系统的数据,那么这整个区块链应用案例也没有什么意义了。
8、为了代币而代币
是的,我要说的就是2019年的ICO。为了证明这种行为还在继续,提醒你别忘了在2019年1月28号,BitTorrent成功ICO。
我的意思是,有些创业公司通过发行代币给你分红权这种行为。问题还是在于: 区块链不是物联网
和风险投资或监管机构不同,区块链并不为投资者负责。代币形式的承诺并不能强制企业的创始人做任何事情。在这方面,ICO更像是众筹而非IPO。
虽然喜欢去中心化机构这个概念,我必须承认在这一领域几乎不存在这样的系统,这意味着你要么选择现有的工具,要么信任公司的创始人。
原文链接: 错误的区块链应用案例 — 汇智网
区块链
2020-01-29 08:26:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
每周生活 1、每周至少运动一次(正常情况) 2、每周至少一次外面聚餐 3、有好看的电影,周末一起看 4、每周至少学习一项新知识(包括看书)
每月生活 1、每月至少保养一次 2、不定期购买生活用品(包括吃的、用的) 3、每季度买一次衣服(按需购买) 4、每月算账
区块链
2020-01-21 16:57:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
目前,互联网应用越来越深入人们的生活,足不出户就可以接收到很多资源信息,但是你是否注意过个人信息安全?浏览网站的时候是否查看过网站有没有部署SSL证书?现在大家都开始关注网站安全,SSL证书的作用也愈发明显。而网站为什么要选择安全级别高的SSL证书呢?
目前,安全级别最高的SSL证书就是EV SSL证书,也被成为扩展验证型SSL证书,作为安全程度最高的SSL证书,一直受到大型企业网站的重视,比如说需要高强度保密技术的银行金融等机构,都会选择EV SSL证书。
网站如果部署了EV SSL证书,会在浏览器地址栏显示绿色的公司名称和安全锁,当用户登录部署了EV SSL证书的互联网网页页面开展预览,能够帮助大家辨认出网址真伪,减少进入仿冒网站的风险,并且提高了网站的可靠品牌形象,此类SSL证书特别适合经常进行网站交易的网站。
随着互联网技术的发展,安全级别高的SSL证书,其安全性数据加密级别也在不断提升。为了确保顾客每一次登录网站均可得到达到几百位的强制性数据加密维护,许多知名品牌常有在业界发布强制性加密算法,很大程度上降低隐私保护信息内容泄露。
选择安全级别高的SSL证书,申请办理时,必须进行公司身份认证,其服务提供商根据对公司资质及网站域名使用权等层面的查询,确保批准出来的每一张SSL证书均能够证实公司真实性及合法性,都是提高部署SSL证书网站可靠的合理方式。
以上就是网站为什么要选择安全级别高的SSL证书,如有需求,可以去安信SSL证书看看。
区块链
2020-01-21 11:13:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
1. Solo共识介绍
Solo共识模式是指Order节点为单节点通信模式,由Peer节点发送过来的消息由一个Order节点进行排序和产生区块。
由于排序服务只有一个Order为所有节点(Peer)服务,没有高可用性和可扩展性,不适合用于生产环境,可以用于开发和测试环境。
Solo is not intended for production. It is not, and will never be, fault tolerant.——Fabric官方文档
2. Solo共识设计
Solo共识工作时序如下图所示。图中所描述的范围是在SDK发起交易到交易落地这整个过程。
在Order节点容器启动时,启动Solo排序服务,开启监SDK发送过来的消息,收到消息后调用Solo服务进行数据区块处理。其中,Solo模式调用过程说明:
(1)SDK通过gRPC连接Peer,发送交易信息Tx;
(2)Peer调用合约后,将返回结果再回复给SDK;
(3)SDK通过gRPC连接Order,将(2)的sdkPeerReply发送给Order,执行Solo共识服务:
A.接收消息
B.消息入列
C.消息排序
D.消息切块(根据时间或交易数量分切)
E.生成区块
F.写入区块文件
G.通知Peers
3. Solo共识模式网络部署
首先order设置共识机制为“solo”,多机多节点部署需要至少两台服务器,一台 Order 排序服务节点,一台 peer 节点,每新加一台额外的服务器都可作为新的 peer 节点来加盟。
区块链
2020-01-20 17:09:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
说区块链其实是一串数据所组成的,但是大家有没有想过这个问题,就是如果区块链是由数据构成的话,那么这个具体的数据是存放在哪呢?
正常情况下,我们用 lnmp 环境,用户的数据大都放在 mysql , postgresql 数据库中,那像 bitcoin , openbaazar,alexadria library(decentralized) 这类区块链的网站和应用,用户的交易记录和商品的图片,用户的视频,文字都放在哪里?不用数据库软件吗?如果想要备份怎么办?不用买服务器和防火墙了? 假设,如果有 2 亿人用 openbazaar 去卖东西,打开并运行这个应用,这 2 亿人形成的区块链是个什么样的状态?其中有 5 千万在不同的地点,不同的时间,上传了不同的商品,这些商品的匿名属性又是如何保证的?如果有 10 亿人把文字,原创图片,音乐,视频上传到了 alexadria decentralized website.并且全球 10 亿人全部同时在线,是不是说这些文字和图片分布并存储在了用户不同的计算机硬盘上了?如果其中一部分用户关闭这个应用,相当于节点消失,那数据存储的状态会发生任何变化吗?
使用区块链技术在网络上执行的智能合同拥有不可更改、自动化和智能化等特点。商业机构使用区块链技术有很多优势,例如降低成本,提高业务执行速度,降低合同履约风险等。区块链使用了协议规定的密码机制进行了认证,保证不会被篡改和伪造,因此任何交易双方之间的价值交换活动都是可以被追踪和查询到的。
如果想要在区块链中修改“账本记录”,需要把整个链条上的加密数据进行破解和修改,其难度相当大,这是区块链的结构所决定的。如真实的区块链技术应用场景——蜜链城市,MT5实际操作http://www.gendan5.com/mt5.html每个城市居民创造的数据资产者会被全网节点进行分布式记录,并加密存储,任何人无法篡改。此外,任何人想要获取您的数据资产,都需要居民本人授权。
区块链技术的不可篡改性降低了监管机构的管理费用,提高了审计的透明度。
使用区块链技术在网络上执行的智能合同拥有不可更改、自动化和智能化等特点。商业机构使用区块链技术有很多优势,例如降低成本,提高业务执行速度,降低合同履约风险等。
区块链使用了协议规定的密码机制进行了认证,保证不会被篡改和伪造,因此任何交易双方之间的价值交换活动都是可以被追踪和查询到的。
如果想要在区块链中修改“账本记录”,需要把整个链条上的加密数据进行破解和修改,其难度相当大,这是区块链的结构所决定的。
区块链很安全的原因就是采用了分布式存储的方式。就算是黑客破解和修改了随意一个节点的信息,也会没有什么作用的,但是篡改者如果把大半数的系统节点数据都篡改的话,这样才能真正的去篡改数据!
区块链很安全的原因就是采用了分布式存储的方式。就算是黑客破解和修改了随意一个节点的信息,也会没有什么作用的,但是篡改者如果把大半数的系统节点数据都篡改的话,这样才能真正的去篡改数据!
区块链
2020-01-20 16:32:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
在以太坊区块链上,Gas被用来补偿矿工为智能合约的存储与执行所提供的算力。目前以太坊的利用在逐渐增长,而交易手续费成本也水涨传告 —— 现在每天的gas成本已经高达数百万美元。随着以太坊生态系统的扩大,Solidity智能合约开发者也需要关注gas利用的优化问题了。本文将介绍在使用Solidity开发以太坊智能合约时常用的一些Gas优化模式。 以太坊教程链接: Dapp入门 | 电商Dapp实战 | Token实战 | Php对接 | Java对接 | Python对接 | C#对接 | Dart对接
1、使用短路模式排序Solidity操作
短路(short-circuiting)是一种使用或/与逻辑来排序不同成本操作的solidity合约开发模式,它将低gas成本的操作放在前面,高gas成本的操作放在后面,这样如果前面的低成本操作可行,就可以跳过(短路)后面的高成本以太坊虚拟机操作了。 // f(x) 是低gas成本的操作 // g(y) 是高gas成本的操作 // 按如下排序不同gas成本的操作 f(x) || g(y) f(x) && g(y)
2、删减不必要的Solidity库
在开发Solidity智能合约时,我们引入的库通常只需要用到其中的部分功能,这意味着其中可能会包含大量对于你的智能合约而言其实是冗余的solidity代码。如果可以在你自己的合约里安全有效地实现所依赖的库功能,那么就能够达到优化solidity合约的gas利用的目的。
例如,在下面的solidity代码中,我们的以太坊合约只是用到了SafeMath库的 add 方法: import './SafeMath.sol' as SafeMath; contract SafeAddition { function safeAdd(uint a, uint b) public pure returns(uint) { return SafeMath.add(a, b); } }
通过参考SafeMath的这部分代码的实现,可以把对这个solidity库的依赖剔除掉: contract SafeAddition { function safeAdd(uint a, uint b) public pure returns(uint) { uint c = a + b; require(c >= a, "Addition overflow"); return c; } }
3、显式声明Solidity合约函数的可见性
在Solidity合约开发种,显式声明函数的可见性不仅可以提高智能合约的安全性,同时也有利于优化合约执行的gas成本。例如,通过显式地标记函数为外部函数(External),可以强制将函数参数的存储位置设置为 calldata ,这会节约每次函数执行时所需的以太坊gas成本。
4、使用正确的Solidity数据类型
在Solidity中,有些数据类型要比另外一些数据类型的gas成本高。有必要了解可用数据类型的gas利用情况,以便根据你的需求选择效率最高的那种。下面是关于solidity数据类型gas消耗情况的一些规则: 在任何可以使用 uint 类型的情况下,不要使用 string 类型 存储uint256要比存储uint8的gas成本低,为什么?点击这里查看 原文 当可以使用 bytes 类型时,不要在solidity合约种使用 byte[] 类型 如果 bytes 的长度有可以预计的上限,那么尽可能改用bytes1~bytes32这些具有固定长度的solidity类型 bytes32所需的gas成本要低于string类型
5、避免Solidity智能合约中的死代码
死代码(Dead code)是指那些永远也不会执行的Solidity代码,例如那些执行条件永远也不可能满足的代码,就像下面的两个自相矛盾的条件判断里的Solidity代码块,消耗了以太坊gas资源但没有任何作用: function deadCode(uint x) public pure { if(x < 1) { if(x > 2) { return x; } } }
6、避免使用不必要的条件判断
有些条件断言的结果不需要Solidity代码的执行就可以了解,那么这样的条件判断就可以精简掉。例如下面的Solidity合约代码中的两级判断条件,最外层的判断是在浪费宝贵的以太坊gas资源: function opaquePredicate(uint x) public pure { if(x < 1) { if(x < 0) { return x; } } }
7、避免在循环中执行gas成本高的操作
由于 SLOAD 和 SSTORE 操作码的成本高昂,因此管理storage变量的gas成本要远远高于内存变量,所以要避免在循环中操作storage变量。例如下面的solidity代码中, num 变量是一个storage变量,那么未知循环次数的若干次操作,很可能会造成solidity开发者意料之外的以太坊gas消耗黑洞: uint num = 0; function expensiveLoop(uint x) public { for(uint i = 0; i < x; i++) { num += 1; } }
解决上述反模式以太坊合约代码的方法,是创建一个solidity临时变量来代替上述全局变量参与循环,然后在循环结束后重新将临时变量的值赋给全局变量: uint num = 0; function lessExpensiveLoop(uint x) public { uint temp = num; for(uint i = 0; i < x; i++) { temp += 1; } num = temp; }
8、避免为可预测的结果使用Solidity循环
如果一个循环计算的结果是无需编译执行Solidity代码就可以预测的,那么就不要使用循环,这可以可观地节省gas。例如下面的以太坊合约代码就可以直接设置num变量的值: function constantOutcome() public pure returns(uint) { uint num = 0; for(uint i = 0; i < 100; i++) { num += 1; } return num; }
9、循环合并模式
有时候在Solidity智能合约中,你会发现两个循环的判断条件一致,那么在这种情况下就没有理由不合并它们。例如下面的以太坊合约代码: function loopFusion(uint x, uint y) public pure returns(uint) { for(uint i = 0; i < 100; i++) { x += 1; } for(uint i = 0; i < 100; i++) { y += 1; } return x + y; }
10、避免循环中的重复计算
如果循环中的某个Solidity表达式在每次迭代都产生同样的结果,那么就可以将其移出循环先行计算,从而节省掉循环中额外的gas成本。如果表达式中使用的变量是storage变量,这就更重要了。例如下面的智能合约代码中表达式 a*b 的值,并不需要每次迭代重新计算: uint a = 4; uint b = 5; function repeatedComputations(uint x) public returns(uint) { uint sum = 0; for(uint i = 0; i <= x; i++) { sum = sum + a * b; } }
原文链接: Solidity Gas优化的10个代码模式 — 汇智网
区块链
2020-01-20 09:01:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文翻译自 中本聪 ( Satoshi Nakamoto) 提供的资料
区块链:点对点电子金融服务系统。(Bitcoin: A Peer-to-Peer Electronic Cash System )
允许在线从甲方向乙方支付,而无需提供格外
的证据。这样可以避免维护信息安全而支付额外的成本。
The network timestamps transactions by hashing them into an ongoing
chain of hash-based proof-of-work, forming a record that cannot be
changed without redoing the proof-of-work.
The longest chain not only serves as proof of the sequence of
events witnessed, but proof that it came from the largest pool of
CPU power. As long as a majority of CPU power is controlled by nodes
that are not cooperating to attack the network, they'll generate the
longest chain and outpace attackers. The network itself requires
minimal structure. Messages are broadcast on a best effort basis,
and nodes can leave and rejoin the network at will, accepting the
longest proof-of-work chain as proof of what happened while they
were gone.
通过对互联网时间戳交易哈希处理,进入一个持续增长的基于哈希的工作量证明,
构成一条除非重做否则不相同的记录。最长的区块链不仅提供所有事件顺序的见证
,而且这个见证来自最大的CPU处理计算池。只要大部分的CPU处理器没有被控制攻
击网络,那么区块链的长度会不断增长并超过攻击者。基于互联网络最小的结构,
区块链信息在最可靠的基础上进行广播,节点可以自由的离开和重新加入网络,接
收当前最新的最长的区块链信息。
Introduction:
虽然传统的线上金融方式足够好,但是却继承了传统的信用模型结构的缺点。那就
是线上的支付方式不是完全不可逆的,所以无法避免的会产生纠纷。这种调解成本
花费限制了最小的实际交易规模,并减少了小额临时交易的可能性。但是丧失不可
逆服务的不可逆付款能力的代价更大,商家必须警惕他们的客户,让他们提供比原
来更多的信息。而且一定比例的欺诈行为是不可避免的,除非是使用物理货币避免
这些成本和付款的不确定性,但是存在不需要信用机构的支付方式。

比特币如何运作
与传统的银行和支付系统不同,比特币系统是基于分散的信任。在比特币中,代替
中央信任机构的是信任,它是通过比特币系统中不同参与者的交互而形成的紧急属
性。在本章中,我们将通过跟踪通过比特币系统进行的单个交易从更高层次上检查
比特币,并观察它成为“信任”并被分布式共识的比特币机制接受,并最终记录在
区块链中,即分布式账本。
比特币系统由以下用户组成:包含密钥的用户钱包,在网络上传播的交易以及矿工
(通过竞争性计算)生成共识区块链,该共识区块链是所有交易的权威分类帐。
在跟踪通过比特币网络到区块链的交易时,我们将使用“区块链浏览器”站点来可
视化每个步骤。区块链浏览器是一个网络应用程序,可充当比特币搜索引擎,因为
它允许您搜索地址,交易和区块,并查看它们之间的关系和流程。
流行的区块链浏览器有:
BlockCypher Explorer
blockchain.info
BitPay Insight
Blockstream Explorer
这些功能均具有搜索功能,可以获取比特币地址,交易哈希,区块编号或区块哈希
,并从比特币网络中搜索相应的信息。
注意:比特币网络可以按分数值进行交易,例如,从毫比特币(比特币的1/1000)
到比特币的1/100,000,000(即所谓的聪,最小的比特币单位)
比特币交易:
简而言之,交易告诉网络某个比特币价值的所有者已授权将该价值转让给另一所有
者。现在,新所有者可以通过创建另一笔交易来授权比特币所有权中的其他交易,
从而花费比特币,依此类推。
比特币交易就像一行两次记录的薄记分类账。每次交易包含一个或多个“输入”,
每个输入就像执行减法操作,减去消费用户比特币账户的支出数据。同样,每次交
易包含一个或多个“输出”操作,每个输出就像执行加法操作,增加商家用户比特
币账户的收入数据。而且输入和输出(支出和收入)总计并不一定相等。相反,商
家收入总计小于消费者支出总计,这个差额代表隐含交易费,即把一小部分手续费
支付给发现这个挖掘出这个比特币的矿工(最初记录在区块链分类账上的交易的人
)。比特币交易就像一个记录两次薄记分类账的交易。
The transaction also contains proof of ownership for each amount of
bitcoin (inputs) whose value is being spent, in the form of a
digital signature from the owner, which can be independently
validated by anyone. In bitcoin terms, "spending" is signing a
transaction that transfers value from a previous transaction over to
a new owner identified by a bitcoin address.
比特币交易通过消费者的数字签名的形式包含了作为“输入”花费的比特币所有权
证明的信息。通过这个数字签名每一个人可以独立的验证这个交易。用比特币的术
语来说,“支出”是指将一笔交易从先前的交易转移到由比特币地址标识的新所有
者的交易。
Transaction as Double-Entry Bookkeeping
Input Value **** Output Value
Input1 0.10BTC **** Output1 0.10BTC
Input2 0.20BTC **** Output2 0.20BTC
Input3 0.10BTC **** Output3 0.20BTC
Input4 0.15BTC
Total Inputs:0.55BTC
Total Outputs:0.50BTC
Inputs 0.55BTC
Outputs 0.50BTC
------- -------
Difference 0.05BTC(implied transaction fee)
Ps:交易作为两次记账
Transaction Chains(交易链)
Inputs From Outputs To
Joe 0.1000BTC 0.1000 BTC (spent)
Transaction Fees: 0.0000 BTC
Inputs From Outputs To
密钥 Bob's Address 0.0150 BTC (spent)
Alice 0.1000BTC Alice's Address 0.0845 BTC (unspent)
Transaction Fees: 0.0005 BTC
Inputs From Outputs To
密钥 Gopesh's Address 0.0100 BTC (unspent)
Bob 0.0150 BTC Alice's Address 0.0045 BTC (unspent)
Transaction Fees: 0.0005 BTC
Ps:交易链,其中一个交易的输出是下一个交易的输入。
Making Change(找零)
Many bitcoin transactions will include outputs that reference both
an address of the new owner and an address of the current owner,
called the change address.
许多比特币交易都将包含同时引用新所有者地址和当前所有者地址的输出,称为更
改地址。
举例:如果您购买的商品成本为5比特币,但只能使用20比特币输入,则您将向商
店所有者发送一份5比特币的输出,并将其中的15比特币的输出发送给自己作为零
钱(减去一定的交易费用)。而且,更改地址不必与输入的地址相同,出于隐私原
因,更改地址通常是所有者钱包中的新地址。
Different wallets may use different strategies when aggregating
inputs to make a payment requested by the user. They might aggregate
many small inputs, or use one that is equal to or larger than the
desired payment. Unless the wallet can aggregate inputs in such a
way to exactly match the desired payment plus transaction fees, the
wallet will need to generate some change.
不同的钱包可能使用不同的策略,当汇总输入(支出)进行用户要求的付款。它们
可能汇总许多小的输入(支出),或者使用一个等于或大于所需的付款。除非钱包
可以用一种方法准确汇总输入(支出)与付款金额和手续费的合计相等,但这个功
能可能需要“比特币钱包”迭代多个版本之后实现。
相似的行为在人们使用零钱中经常出现,优先使用与付款接近的零钱比一直使用大
面额的钱币来说可以减少很多零钱。人类可以在潜意识中找到了这两种极端之间的
平衡,但比特币钱包开发人员则在努力实现这一平衡。
In summary, transactions move value from transaction inputs to
transaction outputs. An input is a reference to a previous
transaction’s output, showing where the value is coming from. A
transaction output directs a specific value to a new owner’s
bitcoin address and can include a change output back to the original
owner. Outputs from one transaction can be used as inputs in a new
transaction, thus creating a chain of ownership as the value is
moved from owner to owner
总之,交易将价值从交易输入转移到交易输出。输入是对先前交易的输出的引用,
显示了价值的来源。交易输出将特定值定向到新所有者的比特币地址,并且可以将
更改输出包括回原始所有者。一笔交易的输出可以用作新交易的输入,从而在值从
所有者转移到所有者时创建所有权链
Common Transaction Forms(基础的交易形式)
最常见的交易形式是从一个地址到另一个地址的简单付款,其中通常包括退还给原
始所有者的一些“更改”。这种类型的事务具有一个输入和两个输出。
Common Transaction
Input0 "From Alice,signed by Alice"
Output0 "To Bob"
Output1 "To Alice"(change)
另一种常见的交易形式是将多个输入汇总为一个输出的交易(请参阅“ 交易汇总
资金”)。这表示在现实世界中相当于将一堆硬币和纸币兑换为一个较大的纸币。
此类交易有时是由钱包应用程序生成的,以清理许多较小的金额,这些金额是作为
“找零”而收到的。
Aggregation Transaction
Input1
Input2
Input3 Output0
.
.
InputN
Ps:交易汇总资金
最后,在比特币分类账上经常看到的另一种交易形式是一种将一个输入分配到代表
多个接收者的多个输出的交易(请参阅交易分配资金)。商业实体有时会使用这种
类型的交易来分配资金,例如在处理多名员工的工资支付时。
Distributing Transaction
Output1
Output2
Input0 Output3
.
.
OutputN
Ps:交易分配资金
Constructing a Transaction(构建交易)
比特币的钱包应用程序包含用于选择适当的输入和输出以构建符合用户规格的交易
的所有逻辑。用户只需要指定目的地和金额,其余的发生在钱包应用程序中而无需
用户执行实现的逻辑。重要的是,即使钱包应用程序完全脱机,它也可以构造交易
。就像在家里写一张支票然后再用信封将其发送到银行一样,在连接到比特币网络
时也无需构建交易和签名。
Getting the Right Inputs(获取正确的输入)
钱包应用程序首先会去寻找可以满足输出的输入费用。大多数钱包会持续追踪属于
该钱包中地址的所有可用输出。因此,钱包应用程序将记录用户第一个注册在区块
链网络的可用的交易输出地址副本。。作为全节点客户端运行的比特币钱包应用程
序实际上包含了区块链中每笔交易未使用的输出的副本。这允许钱包构造交易输入
,并快速验证传入交易是否具有正确的输入。但是,由于全节点客户端占用大量磁
盘空间,因此大多数用户钱包运行“轻量级”客户端,这些客户端仅跟踪用户自己
未使用的输出。
如果钱包应用程序不维护未用交易输出的副本,则可以使用不同提供商提供的各种
API或通过使用应用程序编程接口(API)调用来请求全节点,来查询比特币网络以
检索此信息。
https://blockchain.info/unspent?
active=1Cdid9KFAaatwczBwBttQcwXYCpvK8h7FK
该请求被构造为针对特定URL的HTTP GET命令。该URL将返回一个地址的所有未花
费的交易输出,为任何应用程序提供构造交易输入所需的信息。我们使用简单的命
令行HTTP客户端curl来检索响应。
{
"unspent_outputs":[
{

"tx_hash":"186f9f998a5...2836dd734d2804fe65fa35779",
"tx_index":104810202,
"tx_output_n": 0,

"script":"76a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac",
"value": 10000000,
"value_hex": "00989680",
"confirmations":0
}
]
}
该响应表示在用户地址“1Cdid9KFAaatwczBwBttQcwXYCpvK8h7FK”的所有权下。
这个响应包含未使用的输出的交易的引用及其在“satoshis”的价值(1亿=1比特
币)。有了这些信息,钱包应用程序可以构造一个交易,以将该价值转移到新的所
有者地址。
如果钱包应用程序在未使用的输出中没有包含足够的比特币来支付消费费用,则钱
包应用程序可能必须通过大量未使用的较小输出来“翻找”,例如从钱包里捡硬币
,直到找到足够的钱来支付咖啡。在这两种情况下,当钱包应用程序创建交易输出
(付款)时,可能都需要找回零钱。
Creating the Outputs(创建输出)
A transaction output is created in the form of a script that creates
an encumbrance on the value and can only be redeemed by the
introduction of a solution to the script. In simpler terms, Alice’s
transaction output will contain a script that says something like,
"This output is payable to whoever can present a signature from the
key corresponding to Bob’s public address." Because only Bob has
the wallet with the keys corresponding to that address, only Bob’s
wallet can present such a signature to redeem this output. Alice
will therefore "encumber" the output value with a demand for a
signature from Bob.
Ps:Alice 代表消费用户,Bob 代表商家用户。
交易的输出是创建一种在价值上“加密”的脚本形式,而且能且仅能被“解密”的
脚本来兑现。简而言之,用户的交易输出将包含一个监听脚本的形式:“这个输出
可以支付给任何能提供商家用户的钱包地址的密钥的数字签名的人”。因为只有商
家用户有这个地址的密钥,所以只有商家用户的钱包账户能够兑现这部分的输出。
This transaction will also include a second output, because Alice’s
funds are in the form of a 0.10 BTC output, too much money for the
0.015 BTC cup of coffee. Alice will need 0.085 BTC in change. Alice
’s change payment is created by Alice’s wallet as an output in the
very same transaction as the payment to Bob. Essentially, Alice’s
wallet breaks her funds into two payments: one to Bob and one back
to herself. She can then use (spend) the change output in a
subsequent transaction.
当交易包含“找零”操作时,将包含第二个输出。在消费用户的比特币钱包会产生
一个“与支付的交易完全相同”的找零输出。事实上,比特币钱包将用户的资金分
为两笔款项:一笔给商户,另一笔还给用户自己。然后,用户可以在后续事务中使
用(花费)更改输出。
最后,为了使交易及时由网络处理,用户的比特币钱包应用程序将收取少量费用。
这在交易中并不明确;它由输入和输出之间的差异暗示。如果用户获得了0.085的
找零,而仅创建0.0845作为第二个输出,则将丢失0.0005 BTC(半毫比特币)。
输入花费的0.10 BTC没有完全用在两个比特币钱包应用程序收取的输出上,因为它
们的总和少于0.10。所产生的差额是矿工收取的交易费用,作为验证费用并将交易
记录在区块链上的区块中的费用。
Adding the Transaction to the Ledger(将交易添加到分类帐)
用户的钱包应用程序创建的交易长258字节,包含确认资金所有权和分配新所有者
所需的一切。然后,交易必须被传输到比特币网络,它将成为区块链的一部分。
Transmitting the transaction(传输交易)
Because the transaction contains all the information necessary to
process, it does not matter how or where it is transmitted to the
bitcoin network. The bitcoin network is a peer-to-peer network, with
each bitcoin client participating by connecting to several other
bitcoin clients. The purpose of the bitcoin network is to propagate
transactions and blocks to all participants.
由于交易包含处理所需的所有信息,因此如何或在何处将其传输到比特币网络都无
关紧要。比特币网络是一个点对点网络,每个比特币客户端都通过连接到其他几个
比特币客户端来参与。比特币网络的目的是将交易和区块传播给所有参与者。
How it propagates(它如何传播)
通过比特币协议来参与比特币网络的任何系统,例如服务器,桌面应用程序或钱包
,都称为比特币节点。用户的钱包应用程序可以将新交易发送到通过任何类型的连
接所连接的任何比特币节点:有线,WiFi,移动等。用户的比特币钱包不必直接连
接到商户的比特币钱包,并且用户不必使用特定的互联网连接,尽管这两种选择也
是可能的。接收到之前从未见过的有效交易的任何比特币节点都将立即将其转发到
与其连接的所有其他节点,这种传播技术称为泛洪。因此,事务在对等网络中迅速
传播出去,在几秒钟之内到达大部分节点。
商户的视角:
如果商家的钱包应用直接连到用户的钱包应用程序,则商户的钱包应用可能是接收
交易的第一个节点。但是,即使用户的钱包通过其他节点发送了交易,它也将在几
秒内到达商户的钱包应用程序。并且,商家的钱包应用程序会立即将用户的交易标
识为收款,因为它包含可通过商家的密钥赎回的输出。商家的钱包应用程序还可以
独立验证交易是否格式正确,使用先前未使用的输出以及包含足够的交易费用以包
含在下一个区块中。此时,商家可以冒着很小的风险假定该交易不久将被包含在区
块中并得到确认。
Tip
A common misconception about bitcoin transactions is that they must
be "confirmed" by waiting 10 minutes for a new block, or up to 60
minutes for a full six confirmations. Although confirmations ensure
the transaction has been accepted by the whole network, such a delay
is unnecessary for small-value items such as a cup of coffee. A
merchant may accept a valid small-value transaction with no
confirmations, with no more risk than a credit card payment made
without an ID or a signature, as merchants routinely accept today.
关于比特币交易的一个普遍误解是必须等待10分钟等待一个新区块,或者等待60分
钟等待一个完整的六次确认,以“确认”这些交易。尽管通过确认可以确保整个网
络都接受了该交易,但是对于小额商品(例如一杯咖啡)而言,这种延迟是不必要
的。就像今天的商人通常接受的那样,商人可以接受没有确认的有效小额交易,其
风险不比没有ID或签名的信用卡付款多。
Bitcoin Mining(比特币采矿)
The transaction is now propagated on the bitcoin network. It does
not become part of the blockchain until it is verified and included
in a block by a process called mining
交易现在在比特币网络上传播。直到被称为采矿的过程验证并包含在区块中,它才
成为区块链的一部分。
The bitcoin system of trust is based on computation. Transactions
are bundled into blocks, which require an enormous amount of
computation to prove, but only a small amount of computation to
verify as proven. The mining process serves two purposes in bitcoin:
比特币系统的信任是基于计算的。通过大量的计算证明,确定将交易事务绑定到多
个块中,并仅需少量的计算就可以证明是经过证明的。挖矿过程在比特币中有两个
用途:
1、Mining nodes validate all transactions by reference to bitcoin’s
consensus rules. Therefore, mining provides security for bitcoin
transactions by rejecting invalid or malformed transactions.
2、Mining creates new bitcoin in each block, almost like a central
bank printing new money. The amount of bitcoin created per block is
limited and diminishes with time, following a fixed issuance
schedule.
1、挖矿节点通过参考比特币的共识规则来验证所有交易。因此,挖矿通过拒绝无
效或格式错误的交易为比特币交易提供安全性。
2、采矿在每个区块中都会创建新的比特币,就像中央银行在印刷新钱一样。按照
固定的发行时间表,每个区块创建的比特币数量是有限的,并且会随着时间而减少

Mining achieves a fine balance between cost and reward. Mining uses
electricity to solve a mathematical problem. A successful miner will
collect a reward in the form of new bitcoin and transaction fees.
However, the reward will only be collected if the miner has
correctly validated all the transactions, to the satisfaction of the
rules of consensus. This delicate balance provides security for
bitcoin without a central authority.
采矿在成本和报酬之间达成了良好的平衡。采矿使用电力来解决数学问题。成功的
矿工将以新的比特币和交易费的形式收集奖励。但是,只有在矿工正确地验证了所
有交易并达到共识规则的情况下,才会收集奖励。这种微妙的平衡在没有中央授权
的情况下为比特币提供了安全性。
A good way to describe mining is like a giant competitive game of
sudoku that resets every time someone finds a solution and whose
difficulty automatically adjusts so that it takes approximately 10
minutes to find a solution. Imagine a giant sudoku puzzle, several
thousand rows and columns in size. If I show you a completed puzzle
you can verify it quite quickly. However, if the puzzle has a few
squares filled and the rest are empty, it takes a lot of work to
solve! The difficulty of the sudoku can be adjusted by changing its
size (more or fewer rows and columns), but it can still be verified
quite easily even if it is very large. The "puzzle" used in bitcoin
is based on a cryptographic hash and exhibits similar
characteristics: it is asymmetrically hard to solve but easy to
verify, and its difficulty can be adjusted.
描述挖矿的好方法就像一个巨大的数独游戏,每当有人找到解决方案时,数独都会
重置,难度会自动调整,因此大约需要10分钟才能找到解决方案。想象一个巨大的
数独难题,大小为数千行和数千列。如果我向您展示完整的拼图,您可以很快地对
其进行验证。但是,如果拼图上有几个正方形,而其余的都是空的,则需要大量的
工作才能解决!数独的难度可以通过更改其大小(增加或减少行和列)来进行调整
,但是即使数独很大,仍然可以很容易地对其进行验证。比特币中使用的“拼图”
基于加密哈希,并具有相似的特征:它不对称地难以解决,但易于验证,并且可以
调整其难度。
Mining Transactions in Blocks(区块交易)
New transactions are constantly flowing into the network from user
wallets and other applications. As these are seen by the bitcoin
network nodes, they get added to a temporary pool of unverified
transactions maintained by each node. As miners construct a new
block, they add unverified transactions from this pool to the new
block and then attempt to prove the validity of that new block, with
the mining algorithm (Proof-of-Work).
新交易不断从用户钱包和其他应用程序流入网络。正如比特币网络节点所看到的那
样,它们被添加到每个节点维护的未验证交易的临时池中。当矿工构造一个新区块
时,他们将未验证的交易从该池中添加到新区块,然后尝试使用挖掘算法(工作量
证明)证明该新区块的有效性。挖掘的过程在[mining]中有详细说明。
Transactions are added to the new block, prioritized by the
highest-fee transactions first and a few other criteria. Each miner
starts the process of mining a new block of transactions as soon as
he receives the previous block from the network, knowing he has lost
that previous round of competition. He immediately creates a new
block, fills it with transactions and the fingerprint of the
previous block, and starts calculating the Proof-of-Work for the new
block. Each miner includes a special transaction in his block, one
that pays his own bitcoin address the block reward (currently 12.5
newly created bitcoin) plus the sum of transaction fees from all the
transactions included in the block. If he finds a solution that
makes that block valid, he "wins" this reward because his successful
block is added to the global blockchain and the reward transaction
he included becomes spendable. Jing, who participates in a mining
pool, has set up his software to create new blocks that assign the
reward to a pool address. From there, a share of the reward is
distributed to Jing and other miners in proportion to the amount of
work they contributed in the last round.
交易被添加到新的区块中,首先按费用最高的交易和其他一些条件确定优先级。每
个矿工都知道自己已经失去了前一轮的竞争,因此一旦从网络接收到前一个交易块
,便开始挖掘新的交易块。他立即创建一个新块,并用交易记录和上一个块的指纹
填充它,然后开始计算新块的工作量证明。每个矿工在自己的区块中包括一项特殊
交易,该交易向区块地址支付他自己的比特币地址(目前为12.5个新创建的比特币
)加上区块中包含的所有交易的交易费用总和。如果他找到使该区块有效的解决方
案,则他“获胜” 此奖励是因为他成功的区块已添加到全球区块链,并且他包含
的奖励交易变得可花费
Alice’s transaction was picked up by the network and included in
the pool of unverified transactions. Once validated by the mining
software it was included in a new block, called a candidate block,
generated by Jing’s mining pool. All the miners participating in
that mining pool immediately start computing Proof-of-Work for the
candidate block. Approximately five minutes after the transaction
was first transmitted by Alice’s wallet, one of Jing’s ASIC miners
found a solution for the candidate block and announced it to the
network. Once other miners validated the winning block they started
the race to generate the next block.
网络收集了新的交易,并将其包含在未验证的交易池中。经采矿软件验证后,它就
包含在某群矿工的采矿池生成的新区块(称为候选区块)中。参与该采矿池的所有
矿工都立即开始为候选区块计算工作量证明。在交易首次通过用户的钱包程序传输
后大约五分钟,Jing的ASIC矿工之一找到了针对该候选区块的解决方案,并将其发
布给网络。一旦其他矿工验证了获胜区块,他们便开始比赛以生成下一个区块。
Approximately 19 minutes later, a new block, #277317, is mined by
another miner. Because this new block is built on top of block
#277316 that contained Alice’s transaction, it added even more
computation to the blockchain, thereby strengthening the trust in
those transactions. Each block mined on top of the one containing
the transaction counts as an additional confirmation for Alice’s
transaction. As the blocks pile on top of each other, it becomes
exponentially harder to reverse the transaction, thereby making it
more and more trusted by the network.
大约19分钟后,另一个矿工开采了一个新的区块#277317。由于此新块是在包含爱
丽丝交易的块#277316之上构建的,因此它向区块链添加了更多计算,从而增强了
对那些交易的信任。在包含交易的区块之上挖掘的每个区块都将作为对Alice交易
的额外确认。随着这些块彼此重叠,逆转交易变得越来越困难,从而使它越来越受
到网络的信任。
In the diagram in Alice’s transaction included in block #277316, we
can see block #277316, which contains Alice’s transaction. Below it
are 277,316 blocks (including block #0), linked to each other in a
chain of blocks (blockchain) all the way back to block #0, known as
the genesis block. Over time, as the "height" in blocks increases,
so does the computation difficulty for each block and the chain as a
whole. The blocks mined after the one that contains Alice’s
transaction act as further assurance, as they pile on more
computation in a longer and longer chain. By convention, any block
with more than six confirmations is considered irrevocable, because
it would require an immense amount of computation to invalidate and
recalculate six blocks. We will examine the process of mining and
the way it builds trust in more detail in [mining].
在该图包括在块#277316爱丽丝的交易,我们可以看到块#277316,其中包含
Alice的交易。在它的下方是277,316个区块(包括区块#0),它们以区块链(区
块链)的方式相互链接,一直返回到区块#0,称为创世区块。随着时间的流逝,
随着块中“高度”的增加,每个块以及整个链的计算难度也随之增加。在包含
Alice事务的块之后挖掘的块可作为进一步的保证,因为它们在越来越长的链中堆
积了更多的计算量。按照惯例,具有超过六个确认的任何块都被认为是不可撤消的
,因为它将需要大量的计算才能使六个块无效并重新计算。我们将在[mining]中更
详细地研究挖掘的过程及其建立信任的方式。
Block 277318 Transactions
Block Depth Block 277317 Transactions
Block Height Block 277316 Alice's Transactions
Block 277315 Transactions
Block 277314 Transactions
Spending the Transaction(交易支出)
Now that Alice’s transaction has been embedded in the blockchain as
part of a block, it is part of the distributed ledger of bitcoin and
visible to all bitcoin applications. Each bitcoin client can
independently verify the transaction as valid and spendable. Full-
node clients can track the source of the funds from the moment the
bitcoin were first generated in a block, incrementally from
transaction to transaction, until they reach Bob’s address.
Lightweight clients can do what is called a simplified payment
verification (see [spv_nodes]) by confirming that the transaction is
in the blockchain and has several blocks mined after it, thus
providing assurance that the miners accepted it as valid.
现在,爱丽丝的交易已作为一个块的一部分嵌入到区块链中,它是比特币分布式分
类帐的一部分,并且对所有比特币应用程序都是可见的。每个比特币客户都可以独
立验证交易的有效性和可支配性。从节点首次生成比特币之时起,全节点客户就可
以跟踪资金的来源,从交易到交易逐个递增,直到到达Bob的地址为止。轻量级客
户可以通过确认交易位于区块链中并在其后开采了几个区块来进行所谓的简化支付
验证(请参阅[spv_nodes]),从而确保矿工将其视为有效。
区块链
2020-01-18 11:44:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
快速发展时期。尽管如此,但仍需要关注区块链安全风险突出、核心技术亟需突破、区块链技术有待与实体经济深度融合发展、区块链人才缺口较大等问题,从而更好推动区块链技术与产业健康有序发展。
一、对形势的基本判断
(一)区块链技术创新不断涌现
当前,区块链技术尚不成熟,仍处于发展早期。对于区块链性能、隐私安全、可扩展等方面的技术创新正在不断涌现。针对区块链性能问题,出现如下几类创新解决方案。
一是并行的方式。例如以太坊分片技术、墨客MOAC子链技术、Fabric多通道技术。
二是DAG(有向无环图)方式。例如区块链与物联网创新项目IOTA采用DAG技术使得区块链系统的可扩展性不再受到区块大小限制,仅取决于网络带宽、CPU处理速度和存储容量等限制。
三是优化共识算法的方式。例如PoS共识算法通过保持多中心情况下减少参与共识的节点的方式以获取性能的提升。
区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式,是一种全新的分布式基础架构。 人们可以利用区块链式数据结构来验证与存储数据,利用分布式节点共识算法来生成和更新数据,利用密码学的方式保证数据传输和访问的安全,利用由自动化脚本代码组成的智能合约来编程和操作数据。
区块链安全性分析
一般认为,区块链较为安全。一方面,比特币的加密算法SHA256保证了私钥的难攻破性;另一方面区块链中拥有更多的节点,保证了即便单一节点被攻破,仍然有其他节点保护整个数据库的安全性与完整性。
但这两种特点并不能代表区块链安全的全部内容,区块链作为一个庞大的生态,用户作为市场的参与者与投资者,需要对数字货币的买卖与使用。这涉及到从钱包、交易所、比特币http://www.gendan5.com/digitalcurrency/btc.html私钥保存到共识机制、协议及整个系统的安全性,在这些方面区块链安全问题依然没能得到很好的解决。
目前,区块链安全事故主要集中在三大板块,即区块链自身机制、区块链生态安全、区块链使用安全。
区块链技术及其安全问题
区块链技术以其所具有的去中心化、分布式账本、防篡改、时序性等特征,在众多领域创新改革与发展中得到广泛应用。随着区块链技术应用范围的不断扩大,区块链技术应用安全问题愈发凸显。基于此,本文从区块链定义、特征与应用等层面入手,就区块链技术及其安
在技术不断积累深入时,国内部分城市已开始鼓励区块链产业入驻,创建出初步的区块链创业扶持政策。与此同时,国外相对成熟的资本市场也正在完善区块链衍生品加密数字货币的相关法规。
技术层面上,区块链技术目前生活化的场景落地以蚂蚁金服、腾讯、百度、京东等巨头企业为主力,区块链创业公司在底层技术上取得较大成果,成为传统企业连接区块链技术的桥梁。
但不可忽视的是,区块链领域的安全问题屡见不鲜,合约机制中的天然弊端和发展过程中产生的漏洞成为不法分子的攻击点。
区块链
2020-01-17 17:01:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
Besu是Hyperledger中的企业以太坊产品,其最大优势在于兼容以太坊主网。本教程介绍如何使用Hyperledger Besu快速启动一个企业以太坊网络并利用JSON RPC进行数据查询和交易提交,以及如何使用Truffle开发企业以太坊DApp并使用内置的工具进行数据调试和运维监控。
1、启动企业以太坊网络 以太坊教程推荐: Dapp入门 | 电商Dapp实战 | Token实战 | Php对接 | Java对接 | Python对接 | C#对接 | Dart对接
首先克隆Besu的quickstart仓库的源代码: git clone https://github.com/PegaSysEng/besu-quickstart.git
然后进入besu-quickstart目录,执行如下命令构建besu的docker镜像: ./run.sh
上面的命令会构建docker镜像并启动4个容器来模拟一个包含6个besu节点的企业以太坊网络。当脚本执行完成后,你可以看到如下输出信息: ************************************* Besu Quickstart ************************************* List endpoints and services ---------------------------------- Name Command State Ports --------------------------------------------------------------------------------------------------------- besu-quickstart_bootnode_1 /opt/besu/bootnode_sta ... Up 30303/tcp, 8545/tcp, 8546/tcp besu-quickstart_explorer_1 nginx -g daemon off; Up 0.0.0.0:32768->80/tcp besu-quickstart_grafana_1 /run.sh Up 3000/tcp besu-quickstart_minernode_1 /opt/besu/node_start.s ... Up 30303/tcp, 8545/tcp, 8546/tcp besu-quickstart_node_1 /opt/besu/node_start.s ... Up 30303/tcp, 8545/tcp, 8546/tcp besu-quickstart_node_2 /opt/besu/node_start.s ... Up 30303/tcp, 8545/tcp, 8546/tcp besu-quickstart_node_3 /opt/besu/node_start.s ... Up 30303/tcp, 8545/tcp, 8546/tcp besu-quickstart_node_4 /opt/besu/node_start.s ... Up 30303/tcp, 8545/tcp, 8546/tcp besu-quickstart_prometheus_1 /bin/prometheus --config.f ... Up 9090/tcp besu-quickstart_rpcnode_1 /opt/besu/node_start.s ... Up 30303/tcp, 8545/tcp, 8546/tcp
以及访问端结点列表: **************************************************************** JSON-RPC HTTP service endpoint : http://localhost:32768/jsonrpc JSON-RPC WebSocket service endpoint : ws://localhost:32768/jsonws GraphQL HTTP service endpoint : http://localhost:32768/graphql Web block explorer address : http://localhost:32768 Prometheus address : http://localhost:32768/prometheus/graph Grafana address : http://localhost:32768/grafana-dashboard **************************************************************** JSON-RPC HTTP服务用于DApp或Metamask钱包的访问 JSON-RPC WebSocket服务用于DApp通过websocket访问节点 GraphQL HTTP服务用于DApp或Metamask钱包的访问节点的GraphQL服务 Web区块浏览服务用于浏览区块,在你的浏览器中输入该地址即可 Prometheus服务用于为Prometheus仪表盘提供指标数据 Grafana服务用于为Grafana仪表盘提供数据
要再次显示访问端结点,可以使用如下命令: ./list.sh
2、使用企业以太坊区块浏览器
在本教程中我们使用Alethio轻量级以太坊浏览器,你也可以使用 EthScan 。
在你的浏览器中打开前面提到的web block explorer endpoint列出的地址,就可以查看企业以太坊网络中的区块数据了。
可以在区块浏览器中看到有6个besu节点:4个普通节点、1个出块节点和一个引导节点。
点击 Best Block 右侧的区块号就可以显示该区块的详细数据:
点击左上角的放大镜,就可以搜索区块、交易哈希、或以太坊地址:
3、监视Besu节点的运行状况
可以使用Prometheus和Grafana这些运维监视工具来可视化节点的健康状态和运行情况。参考前面给出的访问端结点,可以在你的浏览器中直接访问这些工具。例如使用Grafana:
4、使用JSON-RPC访问Besu节点
Besu支持标准的以太坊JSON-RPC API接口。例如使用curl调用 web3_clientVersion 命令来查看节点的版本: curl -X POST --data '{ "jsonrpc":"2.0", "method":"web3_clientVersion", "params":[], "id":1 }'
其中 表示前面列出的访问端结点的地址,你需要根据自己的实际情况替换,例如 http://localhost:32768/jsonrpc 。上面命令的返回结果类似如下: { "jsonrpc" : "2.0", "id" : 1, "result" : "besu/" }
或者使用 net_peerCount 命令查看节点已连接的Peer数量: curl -X POST --data '{ "jsonrpc":"2.0", "method":"net_peerCount", "params":[], "id":1 }'
结果如下: { "jsonrpc" : "2.0", "id" : 1, "result" : "0x6" }
或者使用 eth_blockNumber 查看最新的区块号: curl -X POST --data '{ "jsonrpc":"2.0", "method":"eth_blockNumber", "params":[], "id":1 }'
结果如下: { "jsonrpc" : "2.0", "id" : 1, "result" : "0x8b8" }
5、使用MetaMask创建企业以太坊交易
在发送企业以太坊交易之前,我们需要先创建一个账号,或者使用这个私有网络的创世配置中已经声明的几个账号:
账号1 :同时也是币基地址 Address: 0xfe3b557e8fb62b89f4916b721be55ceb828dbd73 Private key : 0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63 Initial balance : 0xad78ebc5ac6200000 (200000000000000000000 in decimal)
账号2: Address: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57 Private key : 0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3 Initial balance : 0x90000000000000000000000 (2785365088392105618523029504 in decimal)
账号3: Address: 0xf17f52151EbEF6C7334FAD080c5704D77216b732 Private key : 0xae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f Initial balance : 0x90000000000000000000000 (2785365088392105618523029504 in decimal
在登录进MetaMask之后,链接到我们建立的Besu网络的某个节点,然后你就可以创建交易了。
6、基于Besu网络的Truffle宠物商店演示
要运行Truffle的Pet Shop演示,首先我们需要安装truffle及pet-shop模板,然后还需要针对Besu的企业以太坊网络进行一些简单的调整。
首先安装truffle: npm install -g truffle
然后创建pet-shop-tutorial目录并进入该目录: mkdir pet-shop-tutorial cd pet-shop-tutorial
然后解压Truffle的pet-shop box: truffle unbox pet-shop
安装truffle-wallet: npm install --save @truffle/hdwallet-provider
接下来修改pet-shop-tutorial目录中的truffle-config.js文件,以便添加我们的钱包提供器。请参考以下内容进行修改: const PrivateKeyProvider = require("truffle-hdwallet-provider"); const privateKey = "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63"; module.exports = { // See // for more about customizing your Truffle configuration! networks: { development: { host: "127.0.0.1", port: 7545, network_id: "*" // Match any network id }, quickstartWallet: { provider: () => new PrivateKeyProvider(privateKey, ""), network_id: "*" }, } };
替换为你的 HTTP RPC 访问端结点,例如 http://localhost:32770/jsonrpc 。
将 privateKey 替换为前面的账户1,即币基地址,其中有以太币。
由于我们使用企业以太坊网络而不是Ganache仿真器,因此在执行合约部署时,需要指定网络: truffle migrate --network quickstartWallet
输出结果类似如下: sing network 'quickstartWallet'. Running migration: 1_initial_migration.js Deploying Migrations... ... 0xfc1dbc1eaa14fa283c2c4415364579da0d195b3f2f2fefd7e0edb600a6235bdb Migrations: 0x9a3dbca554e9f6b9257aaa24010da8377c57c17e Saving successful migration to network... ... 0x77cc6e9966b886fb74268f118b3ff44cf973d32b616ed4f050b3eabf0a31a30e Saving artifacts... Running migration: 2_deploy_contracts.js Deploying Adoption... ... 0x5035fe3ea7dab1d81482acc1259450b8bf8fefecfbe1749212aca86dc765660a Adoption: 0x2e1f232a9439c3d459fceca0beef13acc8259dd8 Saving successful migration to network... ... 0xa7b5a36e0ebc9c25445ce29ff1339a19082d0dda516e5b72c06ee6b99a901ec0 Saving artifacts...
你可以在区块浏览器中查看上述输出中的合约地址。
同样,在执行测试时也要指定使用我们的企业以太坊网络: truffle test --network quickstartWallet
输出结果如下: Using network 'quickstartWallet'. Compiling ./contracts/Adoption.sol... Compiling ./test/TestAdoption.sol... Compiling truffle/Assert.sol... Compiling truffle/DeployedAddresses.sol... TestAdoption ✓ testUserCanAdoptPet (2071ms) ✓ testGetAdopterAddressByPetId (6070ms) ✓ testGetAdopterAddressByPetIdInArray (6077ms) 3 passing (37s)
7、企业以太坊网络的停止/重启/清理
使用如下脚本停止Besu构成的企业以太坊网络,但不删除dockers容器: ./stop.sh
使用如下命令重新启动企业以太坊网络: ./resume.sh
如果要停止网络并删除相应的docker容器,使用如下命令: ./remove.sh
原文链接: Hyperledger Besu企业以太坊快速教程 — 汇智网
区块链
2020-01-17 10:15:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
转载提醒
写在之前,我第一时间公开后,发现有人转载了本篇内容,但是没注明转载地址,这样是不友好的,以下内容是我个人在个人环境下搭建的,且被模糊转载(不加转载地址)后,找不到源头,有疑问的小伙伴都没地方去提问,这就没什么意义了。因此,转载请注明转载来源。
1. 环境搭建
1.1. Ubuntu环境搭建
使用的物料: Orcle VM VirtualBox-6.1.0-135406-Win.exe ubuntu-18.04.2-desktop-amd64.iso
1.2. Ubuntu网络设置
https://www.cnblogs.com/weschen/p/7096642.html
1.3. Ubuntu全屏设置 方法一: https://my.oschina.net/u/2454816/blog/1788356 方法二: https://blog.csdn.net/fmyzc/article/details/79486111 在终端输入xrandr,并回车。注意要是小写英文状态下输入。 输入我们需要设置的分辨率,xrandr -s 1920x1440,然后回车。1920后面的是字母x。
1.4. 在Ubuntu设置中文输入法
https://blog.csdn.net/nanhuaibeian/article/details/85851335
1.5. Ubuntu安装git apt-get update -y apt install git
查看版本:git --version git config --global user.name "venus" git config --global user.email ["c**123@163.com"](mailto:\)
1.6. Ubuntu使用命令行安装jdk1.8 sudo apt install openjdk-8-jre-headless sudo apt install openjdk-8-jdk-headless
等待安装好后,输入:java、javac,检验是否安装成功。
https://blog.csdn.net/hunt_er/article/details/82850509
1.7. 安装idea sudo wget [https://download.jetbrains.8686c.com/ideaIU-2019.1.3.tar.gz](https://download.jetbrains.8686c.com/ideaIU-2019.1.3.tar.gz)
设置桌面快捷方式: [Desktop Entry] Name=IntelliJ IDEA Comment=IntelliJ IDEA Exec=/home/venus/ideaIU/idea-IU-191.7479.19/bin/idea.sh Icon=/home/venus/ideaIU/idea-IU-191.7479.19/bin/idea.png Terminal=false Type=Application Categories=Developer;
修改文件权限给普通用户:chown -R venus idea.desktop
https://www.cnblogs.com/zaid/p/11141348.html
2. 克隆代码与环境编译
2.1.No PACKAGE libcrypto found sudo apt install libssl-dev
2.2. set BOOT_ROOT sudo apt-get install libboost-all-dev
2.3. 重装GMP:GMP_LIBRARY_NOTFOUND sudo apt-get install libgmp3-dev
2.4. CMake错误No CMAKE_CXX_COMPILER could be found sudo apt-get update sudo apt-get install -y build-essential
https://blog.csdn.net/dddxxxx/article/details/88709549
2.5. 手动复制依赖包到路径JsnarkCircuitBuilder cp /usr/share/java/junit4.jar /home/venus/jsnark/JsnarkCircuitBuilder cp /home/venus/bcprov-jdk15on-159.jar /home/venus/jsnark/JsnarkCircuitBuilder
区块链
2020-01-16 20:40:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
1. 分布式数字身份
分布式身份不止是人,包括组织,甚至未来也包括物品。这些人或者组织、物品不简单依靠于原先中心化权威机构,无法被拿走或者删除,而且是终身携带的身份。
1.1. 数字身份标识
国际电子技术委员会将“身份”定义为“一组与实体关联的属性”。数字身份通常由身份标识符及与之关联的属性声明来表示,分布式数字身份包括:分布式数字身份标识符和数字身份凭证(声明集合)两部分。
分布式数字身份标识符(DID)是由字符串组成的标识符,用来代表一个数字身份,不需要中央注册机构就可以实现全球唯一性。通常,一个实体可以拥有多个身份,每个身份被分配唯一的DID值,以及与之关联的非对称密钥。不同的身份之间没有关联信息,从而有效地避免了所有者身份信息的归集。
分布式身份标识(Decentralized Identifiers, DID)是一种去中心化的可验证的数字标识符,具有分布式、自主可控、跨链复用等特点。实体可自主完成DID的注册、解析、更新或者撤销操作。DID具体解析为DID Document,DID Document包括DID的唯一标识码,公钥列表和公钥的详细信息(持有者、加密算法、密钥状态等),以及DID持有者的其他属性描述。
并且,一个实体可对应多个DID。
“声明(claims)”是指与身份关联的属性信息,这个术语起源于基于声明的数字身份,一种断言(assert)数字身份的方式,独立于任何需要依赖它的特定系统。声明信息通常包括:诸如姓名,电子邮件地址、年龄、职业等。
声明可以是一个身份所有者(如个人或组织)自己发出的,也可以是由其他声明发行人发出的,当声明由发行人签出时被称为可验证声明。用户将声明提交给相关的应用,应用程序对其进行检查,应用服务商可以像信任发行人般信任其签署的可验证声明。多项声明的集合称为凭证(credentials)。
DID和一个DID文档(DID Document)关联。DID文档上记录的数据是由用户自己决定的,不必要的信息可以完全不记录在DID文档上。在DID系统中,有身份颁布者,身份持有人和验证者三类角色。持有人向颁布者申请身份,验证者在需要时验证持有人的身份。DID数据存放在区块链上,链上不存储隐私数据。而他们三者直接的相互交互使用非对称加密算法、零知识证明等密码算法。
1.2. 可验证声明
可验证声明(Verifiable Credential)提供了一种规范来描述实体所具有的某些属性,实现基于证据的信任。DID持有者,可以通过可验证声明,向其他实体(个人、组织、具体事物等)证明自己的某些属性是可信的。同时,结合数字签名和零知识证明等密码学技术,可以使得声明更加安全可信,并进一步保障用户隐私不被侵犯。
2. 可解决的问题
数字分布式标识可提供全局唯一的分布式实体身份标识、可信数据交换协议,促进跨部门、跨地域的身份认证和数据合作。摆脱对传统模式下单一中心ID注册的依赖。实体的现实身份和可验证数字凭证的内容可链下存储。支持实体将信息最小化或者选择性披露给其他机构,同时防止任何第三方反向推测出实体在现实世界或其他场景语义中的身份。
3. 使用场景
https://weidentity.readthedocs.io/zh_CN/latest/docs/use-cases.html
3.1. 数据共享 背景
当前,不同机构间存在着大量用户数据流通的需求。然而,由于各个机构之间通常难以组建有效的信任合作机制,因此,各机构间难以将各自保管的用户数据安全可信地授权共享给其他机构。通过分布式数字身份DID解决方案,可帮助机构间进行可信数据授权及共享,使得各机构可基于全面的数据为用户提供更高质量的服务。 参与方
用户、数据持有机构、数据使用机构、身份证明机构 解决方案及流程
1、在身份证明机构、数据持有机构、数据使用机构间搭建区块链网络,机构作为节点接入并注册DID
2、由身份证明机构为用户生成DID
3、用户授权数据使用机构使用自己的数据
4、数据使用机构生成授权凭证(Credential),标明授权对象、数据属主、有效期、授权内容等属性,并使用机构私钥进行签名;数据使用机构可选择将授权凭证生成摘要并写入区块链,达到增信目的
5、数据使用机构出示授权凭证给数据持有机构
6、数据持有机构通过凭证验证(Verify)接口,验证授权凭证
7、验证通过,数据持有机构将数据发送给数据使用机构
4. 如何实现与使用
4.1. W3C与DID标准
分散标识符(DID)是一种新型的标识符,它是全局惟一的、可解析的、高可用性的,并且可以通过密码验证。DID通常与加密材料(如公钥和服务端点)相关联,用于建立安全的通信通道。DID对于任何有利于自我管理、加密可验证标识符(如个人标识符、组织标识符和物联网场景中的标识符)的应用程序都非常有用。例如,目前W3C可验证凭据的商业部署大量使用分散的标识符来标识人员、组织和事物,并实现许多安全和隐私保护保证。
W3C的DID标准下的DID系统主要包括以下层次要素:
l基础层:DID规范,包括DID标识符(Identifier)和DID文档(Document)
l应用层:可验证声明或凭证(Verifiable Claims 或 Verifiable Credentials, VC)
有关w3c的DID标准官方地址:
A Primer for Decentralized Identifiers: https://w3c-ccg.github.io/did-primer/
Decentralized Identifiers (DIDs) 2019 v1.0: https://www.w3.org/TR/did-core
Decentralized Identifiers (DIDs) 2020 v1.0: https://w3c.github.io/did-core/
Verifiable Credentials Data Model 1.0: https://www.w3.org/TR/vc-data-model
4.2. DID与传统标识体系的区别
常见的有两种:UUID(全局唯一标识符)和URN(统一资源名称)。对于UUID,不用集中式注册机构即可提供全局唯一性,但不能全局解析。而URN,一次分配给实体并且永远不需要更改,需要集中的注册机构。此外,二者都没有加密验证标识符所有权的能力。
对于全新的DID,可提供不依赖任何集中授权的终生便携式数字身份,且满足:持久性,全局可解析性,密码可验证性和分散性。
4.3. DID格式
lDID示例一(W3C Credentials Community Group):did:example:123456789abcdefg
DID标识符不容易记忆。根据Zooko三角形理论,没有任何标识符能够同时实现易记忆、安全、去中心化。在这里,W3C的DID取了后两者。
lDID示例二(微众银行DID):did:weid:1:0x0086eb1f712ebc6f1c276e12ec21
Did **:** weid : chain-id : bs-specific-string
Did:遵循DID规范,固定前缀did
Weid:WeIdentity DID规范的method name字段,固定为weid
Chain-id:网络id,用于路由到不同的网络
bs-specific-string:基于底层区块链平台生成,代表Entity在链上的地址,保证全网唯一
关于更多合法地址: https://w3c-ccg.github.io/did-method-registry/
4.4.DID文档(DID Document)
DID基础设施可以被认为是全局键值数据库,其中该数据库是所有DID兼容的区块链,分布式分类帐或分散式网络。在此虚拟数据库中,键是DID,值是DID document。DID文档的目的是描述公钥、身份验证协议和服务端点,它们是引导与标识实体的密码可验证交互所必需的。
一个DID对应一个Document。DID文档是一个JSON-LD Object,包括以下几个部分:
DID文档内容 描述 DID主题 DID标识符本身,也就是DID文档所描述的该DID。由于DID的全局唯一特性,因此在DID文档中只能有一个DID。
公钥 公钥用于数字签名及其他加密操作,这些操作是实现身份验证以及与服务端点建立安全通信等目的的基础。如果 DID 文档中不存在公钥,则必须假定密钥已被撤销或无效,同时必须包含或引用密钥的撤销信息(例如,撤销列表)。
身份验证 身份验证的过程是 DID 主题通过加密方式来证明它们与 DID 相关联的过程。
授权 授权意味着他人代表 DID 主题执行操作,例如当密钥丢失的时候,可以授权他人更新 DID 文档来协助恢复密钥。
服务端点
时间戳
除了发布身份验证和授权机制之外,DID 文档的另一个主要目的是为主题发现服务端点。服务端点可以表示主题希望公告的任何类型的服务,包括用于进一步发现、身份验证、授权或交互的去中心化身份管理服务。
文档创建时间和更新时间
文档内容示例: {   "@context": "https://w3id.org/did/v1",   "id": "did:example:123456789abcdefghi",   "authentication": [{     // used to authenticate as did:...fghi     "id": "did:example:123456789abcdefghi#keys-1",     "type": "RsaVerificationKey2018",     "controller": "did:example:123456789abcdefghi",     "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\\r\\n"   }],   "service": [{     // used to retrieve Verifiable Credentials associated with the DID     "id":"did:example:123456789abcdefghi#vcs",     "type": "VerifiableCredentialService",     "serviceEndpoint": "https://example.com/vc/"   }] }
需要注意的是,DID文档中没有任何和个人真实信息相关的内容,比如你的真实姓名、地址、手机号等。因此光靠DID规范是无法验证一个人的身份的,必须要靠DID应用层中的可验证声明VC。
有关JSON-LD详解,可参见: https://json-ld.org/spec/latest/json-ld/
有关DID文档详细规范,可参见“6. DID Documents”: https://w3c.github.io/did-core/#did-documents
4.5. DID相关操作 Create:创建一个新的DID
DID方法规范必须指定客户端如何在DID注册表上创建DID及其相关的DID文档,包括建立控制证明所需的所有加密操作。 Read/Verify:解析验证DID文档
DID方法规范必须指定客户端如何使用DID从DID注册中心请求DID文档,包括客户端如何验证响应的真实性。 Update:DID文档升级
DID方法规范必须指定客户端如何更新DID注册表上的DID文档,包括建立控制证明所需的所有加密操作,或者声明不可能进行更新。 Deactive:停用DID
DID方法规范必须指定客户端如何在DID注册表上停用DID,包括建立停用证明所需的所有密码操作,或者声明不可能停用。
有关DID方法和操作规范,可参见“8. DID Methodds”: https://w3c.github.io/did-core/#did-method-schemes
4.6. DIDs与隐私设计
隐私是任何身份管理解决方案的重要组成部分,对于使用不可变的全球身份系统来说,这一点尤为重要。 成对匿名的DID
尽管DID可以用作众所周知的公共标识符,但它们也可以用作基于每个关系发布的私有标识符。因此,一个自然人A可以拥有成千上万的成对唯一的DID,而不是一个单独的DID(例如手机号码或国家ID号码),而无需A的同意就可以将其关联起来,可以像通讯录一样轻松地进行管理。 链下私有数据
链下存储所有的私有数据,仅通过对等连接进行加密交换。 选择性披露
DID使得分散式PKI(DPKI)成为可能,这使个人可以通过两种方式更好地控制其个人数据。首先,它可以使用加密的数字凭据进行共享。其次,这些凭证可以使用 零知识证明密码术 来 最小化数据 透露,例如,可以透露自己已经超过一定年龄,而无需透露确切的生日。
有关DPKI解释: http://www.elecfans.com/blockchain/996128.html
4.7.DIDs与可验证凭证(Verifiable Credentials, VC)
至此,以上都是DID规范基础,可验证声明才是建立DID整个体系的价值所在。因为在这一层中,DID既可以用来标识个体的身份,也可以用来标识组织的身份,甚至是物品。
4.7.1. 可验证凭证系统架构
在VC系统中,有一下几种参与者: 发行者Issuer
拥有用户数据并能开具VC的实体,如政府、银行、大学等机构和组织。 持有者Holder
持有者即用户。用户向Issuer请求、收到、持有VC的实体,向验证者出示VC。开具的VC可以自我保存,方便以后再次使用,例如保存在钱包里。 验证者Verifier
接受VC并进行验证,由此可以提供给出示VC者某种类型的服务。 标识符注册机构Verifiable Data Registry
维护DIDs的数据库,如某条区块链、分布式账本(可理解为前面提到的DID里的example字段)。
之所以需有Verifiable Data Registry,是因为验证者要验证VC,也要验证用户。验证VC用VC和发VC的Issuer,验证用户用DID和存DID的数据库。
关于“可验证凭证系统”解释,可参考: https://www.w3.org/TR/vc-data-model
VC的格式也是JSON-LD,示例如下: { // set the context, which establishes the special terms we will be using // such as 'issuer' and 'alumniOf'. "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], // specify the identifier for the credential "id": "http://example.edu/credentials/1872", // the credential types, which declare what data to expect in the credential "type": ["VerifiableCredential", "AlumniCredential"], // the entity that issued the credential "issuer": "https://example.edu/issuers/565049", // when the credential was issued "issuanceDate": "2010-01-01T19:73:24Z", // claims about the subjects of the credential "credentialSubject": { // identifier for the only subject of the credential "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", // assertion about the only subject of the credential "alumniOf": { "id": "did:example:c276e12ec21ebfeb1f712ebc6f1", "name": [{ "value": "Example University", "lang": "en" }, { "value": "Exemple d'Université", "lang": "fr" }] } }, // digital proof that makes the credential tamper-evident // see the NOTE at end of this section for more detail "proof": { // the cryptographic signature suite that was used to generate the signature "type": "RsaSignature2018", // the date the signature was created "created": "2017-06-18T21:19:10Z", // purpose of this proof "proofPurpose": "assertionMethod", // the identifier of the public key that can verify the signature "verificationMethod": "https://example.edu/issuers/keys/1", // the digital signature value "jws": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5X sITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUc X16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtj PAYuNzVBAh4vGHSrQyHUdBBPM" } }
4.7.2. 验证者验证VC
因为VC中是没有Issuer的公钥的(也不应该有,因为就算有了,验证者还需要亲自验证公钥是否是真的)。这里VC的id是一个URI,而VC中的Issuer字段也是一个URI。而Issuer也可能是使用DID来作为其身份的。因此,通过VC中的Issuer字段——URI地址得到其DID,然后从DID对应的DID文档里可以得到其公钥。用公钥验证对VC的签名就能验证VC是否Issuer发的。
4.7.3. 验证者验证用户
用Holder(即用户)的DID对应的DID文档里的公钥来验证其数字签名的合法性。
5. 可验证凭证保护策略
5.1. 使用JSON网络签名确保 JSON  Web Token(JSON 网络令牌 )的安全
https://tools.ietf.org/html/rfc7519
https://tools.ietf.org/html/rfc7515
5.2. 链接数据签名
https://w3c-dvcg.github.io/ld-signatures/
5.3. Camenisch-Lysyanskaya 零知识证明
http://groups.csail.mit.edu/cis/pubs/lysyanskaya/cl02b.pdf
6. 微众银行的WeIdentity规范
https://weidentity.readthedocs.io/zh_CN/latest/docs/weidentity-spec.html
7. 微软的DID
https://www.microsoft.com/zh-cn/security/technology/own-your-identity
区块链
2020-01-16 20:35:01
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
Web3E,即Web3 for Embedded,是一个面向Arduino嵌入设备的全功能Web3开发框架,开发语言为C/C++。Web3E可以帮助嵌入设备开发者快速实现能够接入以太坊区块链的物联网/IoT设备,为物联网开发者打开了一扇新的大门。
1、Web3E简介
Web3E主要在ESP32上进行测试,ESP8266也可以正常工作。Web3E还包含了一个快速开发DApp注入器,可以很方便地将你的嵌入设备转换为以太坊DApp。
Web3E的开发始于一个简单的需求:开发一个能够在ESP32上运行的门禁DApp。这期间经历了相当多的挫折,我们意识到需要一个方法来简化物联网嵌入设备的DApp的开发,这就是开发Web3E的最初动机。
Web3E的主要特性包括: 支持TokenScript接口 开箱即用的以太坊DApp注入器,可以立刻将物联网嵌入设备转化为支持ECDSA密码学技术 的以太坊DApp 经过优化精简的密码学算法实现 交易系统已经充分优化,以太坊ERC20和ERC875合约都有实际使用
2、Web3E安装
建议使用Platformio安装Web3E,因为Web3E目前已经是Platformio开发库的一份子了,所以不需要克隆原始的Web3E代码库。
使用Web3E很简单,只需要在Platformio中创建一个新项目,然后参考如下内容修改platformio.ini: [env:esp32dev] platform = espressif32 board = esp32dev framework = arduino ; Serial Monitor options monitor_speed = 115200 lib_deps = # Using a library name Web3E
3、Web3E的示例及使用方法
在Web3E中预置了4个物联网+以太坊的示例应用: Simple DApp:展示如何创建可以运行在嵌入设备上的DApp。板载密码学引擎 可以与用户输入充分交互,在ESP32上的公钥恢复和签名验证可以毫秒级完成 查询钱包余额:展示在嵌入设备上如何查询ERC20代币余额以及非同质化通证(NFT)余额 交易广播:展示在嵌入设备上如何实现ERC20和ERC875代币的转账交易 以太币转账:展示如何在嵌入设备上实现以太币转账
例如,下面的代码展示了如何使用Web3E让物联网嵌入设备支持以太币转账: // Setup Web3 and Contract with Private Key ... Contract contract(&web3, ""); contract.SetPrivateKey(PRIVATE_KEY); uint32_t nonceVal = (uint32_t)web3.EthGetTransactionCount(&address); //obtain the next nonce uint256_t weiValue = Util::ConvertToWei(0.25, 18); //send 0.25 eth unsigned long long gasPriceVal = 1000000000ULL; uint32_t gasLimitVal = 90000; string emptyString = ""; string toAddress = "0xC067A53c91258ba513059919E03B81CF93f57Ac7"; string result = contract.SendTransaction( nonceVal, gasPriceVal, gasLimitVal, &toAddress, &weiValue, &emptyString);
下面的代码使用Web3E在物联网嵌入设备上查询指定的以太坊地址的以太币余额: //obtain balance in Wei uint256_t balance = web3.EthGetBalance(&address); //get string balance as Eth (18 decimals) string balanceStr = Util::ConvertWeiToEthString(&balance, 18);
使用Web3E让嵌入设备支持ERC20代币的发送要复杂一点,但考虑到这是在用C/C++,也还能够接受: string contractAddr = "0x20fe562d797a42dcb3399062ae9546cd06f63280"; Contract contract(&web3, contractAddr.c_str()); contract.SetPrivateKey(); //Get contract name string param = contract.SetupContractData("name()", &addr); string result = contract.ViewCall(¶m); string interpreted = Util::InterpretStringResult(web3.getString(&result).c_str()); Serial.println(interpreted.c_str()); //Get Contract decimals param = contract.SetupContractData("decimals()", &addr); result = contract.ViewCall(¶m); int decimals = web3.getInt(&result); Serial.println(decimals); unsigned long long gasPriceVal = 22000000000ULL; uint32_t gasLimitVal = 4300000; //amount of erc20 token to send, note we use decimal value obtained earlier uint256_t weiValue = Util::ConvertToWei(0.1, decimals); //get nonce uint32_t nonceVal = (uint32_t)web3.EthGetTransactionCount(&addr); string toAddress = "0x007bee82bdd9e866b2bd114780a47f2261c684e3"; string valueStr = "0x00"; //Setup contract function call string p = contract.SetupContractData("transfer(address,uint256)", &toAddress, &weiValue); //push transaction to ethereum result = contract.SendTransaction(nonceVal, gasPriceVal, gasLimitVal, &contractAddr, &valueStr, &p); string transactionHash = web3.getString(&result);
4、总结
让嵌入设备接入以太坊,是发挥智能合约能力的重要环节,因为机器天生容易按规矩办事。Web3E提供了一个相对完整的解决方案,虽然目前仅适用于部分Arduino设备,但这对于物联网嵌入设备开发者而言绝对是一个好工具。如果希望系统的学习以太坊开发知识,可以参考如下教程: 以太坊DApp开发入门 | 去中心化电商DApp实战
原文链接: Web3E物联网嵌入设备的以太坊DApp开发框架 — 汇智网
区块链
2020-01-16 09:55:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
从2017年底曝出天价数字猫的全球第一款区块链游戏《CryptoKitties》从而让区块链游戏一炮而红,区块链宠物游戏从本质上说,区块链游戏应用只是一类电子宠物养成游戏,区块链游戏app玩家需要用以太币交易购买虚拟宠物,而区块链宠物游戏中的宠物其实是由不同的“代码”写成的,各类虚拟宠物也因此被赋予了不同的DNA,价值也就各不相同。
区块链领域除了货币和金融之外,游戏也一直备受瞩目,从加密猫开始,它点燃了人们对区块链游戏的热情。不过,由于用户体验和扩展斗玩网首发原创性等问题,区块链游戏一直处于较小规模的状态,那么,当前的区块链游戏进展到什么程度?它的未来会有希望吗?不管如何,有一个事转载自站长之家实不可否认,相比较于两年前,当前投入到区块链游戏的研发和资金已经极大增加,其用户数也比之前增长了不少。
随着更多好玩的区块转载自站长之家链游戏入场外汇交易术语http://www.gendan5.com/terminology.html它会让玩家逐步认识到区块链游戏跟传统游戏的不同,慢慢地它会开拓出自己的疆土,区块链游戏无法取代传统游戏,但因站长之家,斗玩网为它的独特属性,如道具所有权、跨游戏的资产交易等,终有一天,它会成长起来
什么是区块链游戏游戏归游戏,玩家归玩家,道具归道具,场地归场地,组织归组织。过去20多年发展出来的网络游戏,基本都是基于HTTP协议下的。这使得去中心化从技术上不可能实现。而区块链技术的出现和不断成熟,将使得虚拟资产去中心化储存、游戏规则去中心化制定从技术层面变得可行。相比现有的网络游戏,区块链游戏在去中心化技术的支持下,玩家将拥有虚拟资产的完全产权,开发者也无法随意更改游戏的规则。游戏开发者和玩家的关系会发生根本的改变。
这同时也意味着,数字资产将更接近实物资产,可以被玩家/用户所拥有。而玩家在数字资产上的投入,也将像在现实中种地、制作手工艺品、画画一样,产生价值并可以交易。而这些变动,将使得网络游戏可以更像打篮球、踢足球这些现实中的游戏。篮球的游戏制定者仅仅制定了篮球游戏的规则。最初的篮球、球场、球鞋这些游戏道具可能是由篮球发明人所创造,但是后续的开发完全由玩家/社区完成。
玩家如果觉得篮球好玩,就可以遵守他的规则,自行购买游戏道具进行游戏。而游戏道具随时可以出售,玩家也可以随时离开游戏并且不会有任何损失。而区块链游戏的开发者也将仅仅制定游戏的规则。最初的游戏道具可以由开发者制作,但是后续的开发可能将大部分交由玩家和社区完成。区块链游戏的玩家如果不想玩这个游戏了,随时可以选择退出这个游戏。游戏的账号和游戏中的道具可以随意出售。玩家同样不会有任何损失。在17年底堵塞以太坊网络的CryptoKitties就是类似这样的一款游戏。
现有区块链游戏进行了分类:
菠菜游戏
金融/数字游戏
游戏+通证
游戏+区块链
这四类游戏并没有明显的界限,有的还会互相包含。
区块链游戏表面上与现有的游戏玩法并无二致,但是有了区块链的加持,玩家能够拥有独一无二的真正属于自己的数字资产,并且更加安全。
现阶段大体可以将区块链游戏分为四大类:以太坊游戏、链克游戏、公有链游戏和私有链游戏。根据玩法和功能特性又可分为 10 种游戏类型,以下就是这 10 种类型的区块链游戏分类及代表游戏:
区块链
2019-12-25 17:15:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一、前言
自从2009年第一枚比特币诞生,九年多时间里,区块链技术正在被应用在人们生活的各方各面,从1.0时代的数字货币,到2.0时代的智能合约,再到当下3.0时代的全面应用,区块链每一次时代跃迁都必然具有划时代意义。
今天主要聊一聊区块链2.0时代的智能合约。相信币圈大多数投资者们都或多或少了解智能合约,但是可能也存在不少所谓的“投机者”只关心炒币,懒得去关心这些底层技术;可是从长远来看,不论你是投机还是投资都应该了解并学习它。
二、智能合约
智能合约(smart contract)是由尼克•萨博(Nick Szabo)提出来的。他的定义是“一个智能合约是一套以数字形式定义的承诺(promises) ,包括合约参与方可以在上面执行这些承诺的协议。”
简单来说,智能合约是一个事务处理模块和状态机构成的系统,它的存在是为了让复杂、带有触发条件的数字化承诺能够按参与者意愿正确执行
三、智能合约的实现方法
实现智能合约就需要“图灵完备”的计算机编程语言。“图灵完备”这个词大家似乎了解的不多,可以简单地理解为能把世间一切可以计算解决的问题都计算出来的,这样的一种虚拟机或者编程语言就叫图灵完备。
举一个不太精确但是很容易理解的例子说明一下:比如两口做饭的锅,一口锅可以实现一切的烹饪方法煎、炒、蒸、炖、炸、汆、涮、卤等,而另外的一口锅则只能实现蒸和炖,其他的都不能实现,那么前者就是图灵完备的,后者则不是。
智能合约之所以可以在以太坊上完美应用,就是因为以太坊在其区块链上提供了一种近乎图灵完备的计算环境。只要是编程语言能够实现的计算,其都能支持,这也为智能合约在更加广泛的环境中得以应用坚实了基础。
四、智能合约的作用
没有提供外汇返佣http://www.fx61.com/功能之前,区块链技术的应用范围还仅限于电子现金领域,有了智能合约区块链技术广泛应用成为可能,因为区块链上的智能合约一旦写入就不能被篡改,而且任何人都无法干预它自动执行,所以如果用智能合约来替代人的履约行为,可想而知信任成本会大幅下降,交易行为达成效率会大为改善,这对现实生活的改变将会是广泛的、全面的,毕竟我们生活的世界全靠信任工具维系。
举个例子:将一个农作物收成保险业务写成智能合约,合同约定当连续60天不下雨情况发生时,保险公司支付理赔款。保险公司在区块链上建立这样一个智能合约,代码设定自动从天气信息网站搜索天气信息,当数据达到指标,代码自动执行资金转账,执行理赔,整个过程不需要人参与,没有保险理赔申请、没有现场勘查、没有审批流程、不需要投保人跑来跑去和耐心等待。可能你觉得传统的技术也能做到,但是你是否意识到如果可以这样,那保险公司的作用是不是被削弱了,如果我们想不用保险公司来做个事,而是用户自发组织来做,那就会面临缺少信任工具的问题,只有运行在区块链上的智能合约才能解决这个问题,这个作物保险智能合约就是区块链制造的信任工具。理论上任何人都可以开发类似的智能合约,只要满足保险产品的风控逻辑即可达成。
区块链
2019-12-25 14:49:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
Raft是Hyperledger Fabric 1.4.1中新增的排序服务模块,这个教程将介绍如何部署一个基于Raft排序服务的多机Fabric网络。
相关教程推荐: Hyperledger Fabric Java开发详解 Hyperledger Fabric Node.JS开发详解
1、用Raft排序服务启动byfn示例
BYFN是学习Hyperledger Fabric的一个很好的例子:它包含了Fabric网络的所有元素,并且在byfn.sh中完整表现出来。当我们不加任何参数运行这个脚本时,它将启动一个包含2个机构、4个peer和1个orderer(使用solo排序)的Fabric网络。byfn.sh的参数 -o 用来指定排序服务的类型: ./byfn.sh up -o
最新的BYFN网络设计中包含了5个orderer的密码学资料。如果使用Solo或Kafka排序服务,将值运行第一个Orderer(参见docker-compose-cli.yaml中的定义)。
当我们指定raft作为排序服务时的一个区别之处在于,使用configtxgen生成创世区块我们需要指定configtx.yaml中的SampleMultiNodeEtcdRaft配置端。其他的操作都保持不变。
最后,我们还需要启动其他4个orderer,这些内容在docker-compose-etcdraft2.yaml中定义。
下面时基于raft排序的BYFN网络启动后的情况,你可以看到有5个orderer在运行:
下面是基于Raft排序服务的BYFN网络的拓扑示意图:
在下面的内容中,我们将不再使用BYFN脚本,而是从零开始来学习如何构建多主机的Raft排序的Fabric网络。
2、Hyperledger Fabric多机部署的不同方案
由于Hyperledger Fabric的组件以容器形式部署,当这些容器都在本机时会很顺利的工作。但是当这些容器需要运行在不同的主机上时,我们需要找出让它们彼此通信的办法。
虽然Hyperledger Fabric官方没有给出正式的推荐方案,目前大致有三种方案:
使用静态IP :通过指定容器运行的主机IP,容器之间就可以彼此通信。可以在docker-compose文件中使用extra_hosts方法来指定主机IP,当容器运行后,就可以在/etc/hosts文件中看到这些项。这一方案容易理解,我们也不需要依赖于外部组件,缺点在于所有的东西都是静态配置的,不利于需要动态修改配置的应用场景。
使用docker swarm :Docker Swarm是Docker环境中的原生容器编排服务。简而言之,Docker Swarm为跨主机的容器提供了一个叠加网络层,使容器彼此之间能够通信,就像在一台主机上一样。这一方案的好处在于原始的配置只需要简单修改就可以使用,也不需要在配置中硬编码像IP地址这样的静态信息。缺点在于需要依赖外部组件Docker Swarm。在这个教程中我们将使用这一方案。
使用Kubernetes :k8s使目前最流行的容器编排工具,其机制类似于Docker Swarm。我们已经注意到有一些教程尝试利用k8s来进行fabric的多机部署,但是使用k8s的难度要明显高于前两种方案。
3、Fabrc Raft多机演示环境搭建
我们需要将容器分发到4个主机,本教程使用AWS上的4个EC2实例,但是并不使用AWS提供的特别功能,仅仅是用它来运行Ubuntu以及必要的软件,采用公共IP进行通信。当然你可以可以选择其他的云服务提供商。
在Fabric网络启动运行后,我们将使用Fabcar链码进行测试。总体流程如下: 启动AWS EC2实例,安装必要的镜像和工具。 构建一个叠加网络,将4个主机都加入该网络 在主机1上准备所有资料,包括密码学资料、通道配置交易、每个节点的docker-compose 文件等。然后拷贝到其他主机。 使用docker-compose启动所有组件 创建通道mychannel并将所有peer加入该通道 安装并实例化Fabcar链码 调用查询链码方法
4、Fabric Raft多机演示
4.1 启动主机
本教程使用AWS EC2 t2.small实例,使用fabric 1.4.4。注意在演示中我们使用了简化的全开放安全组,在生产环境中你应当根据自己的需求来决定开放哪些端口:
4.2 使用Docker Swarm构建叠加网络
现在我们可以打开4个终端,分别对应每个主机: ssh -i ubuntu@
从Host 1执行如下命令: docker swarm init --advertise-addr docker swarm join-token manager
运行结果如下:
使用最后的输出,将其他节点以管理者身份加入swarm。
从host 2/3/4执行如下命令: --advertise-addr
运行结果如下:
最后,我们添加一个叠加网络,该网络将用于下面的演示,这一步的操作只需要在一个节点上执行。如果Docker Swarm正常工作,所有的节点都会加入这个叠加网络。
从host 1创建叠加网络first-network: docker network create --attachable --driver overlay first-networkdocker network ls
运行结果如下:
在其他主机上,我们可以看到这个网络:
现在已经构建好了叠加网络,这些信息将在稍后用于docker-compose文件。
4.3 在host 1上准备资料
一个关键的环节时确保所有的Farbic成员使用相同的密码学资料。我们将使用host 1来创建这些密码学资料,然后拷贝到其他主机。
理论上,我们只需要确保个体身份(证书和签名私钥)遵循所要求的规范。一个机构的证书应当由同一个CA签发 —— 例如org1的证书应当由ca.org1签发。出于简化目的,在本教程中,我们在host 1上创建所有的密码学资料,然后将整个目录拷贝到其他主机。
首先进入fabric-samples目录,然后创建一个raft-4node-swarm目录。
在host 1上执行如下命令: cd fabric-samples mkdir raft-4node-swarm cd raft-4node-swarm
直接从first-network拷贝crypto-config.yaml和configtx.yaml文件: cp ../first-network/crypto-config.yaml . cp ../first-network/configtx.yaml .
然后生成必要的密码学资料: ../bin/cryptogen generate --config=./crypto-config.yaml export FABRIC_CFG_PATH=$PWD mkdir channel-artifacts ../bin/configtxgen -profile SampleMultiNodeEtcdRaft -outputBlock ./channel-artifacts/genesis.block ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
现在我们为所有主机准备docker-compose文件,主要基于BYFN中的文件,需要创建6个docker-compose文件以及一个env文件: base/peer-base.yaml base/docker-compose-peer.yaml host1.yaml host2.yaml host3.yaml host4.yaml .env
4.3.1 base/peer-base.yaml # Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # version: '2' services: peer-base: image: hyperledger/fabric-peer:$IMAGE_TAG environment: - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock # the following setting starts chaincode containers on the same # bridge network as the peers # https://docs.docker.com/compose/networking/ - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=first-network - FABRIC_LOGGING_SPEC=INFO #- FABRIC_LOGGING_SPEC=DEBUG - CORE_PEER_TLS_ENABLED=true - CORE_PEER_GOSSIP_USELEADERELECTION=true - CORE_PEER_GOSSIP_ORGLEADER=false - CORE_PEER_PROFILE_ENABLED=true - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: peer node start orderer-base: image: hyperledger/fabric-orderer:$IMAGE_TAG environment: - FABRIC_LOGGING_SPEC=INFO - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 - ORDERER_GENERAL_GENESISMETHOD=file - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block - ORDERER_GENERAL_LOCALMSPID=OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp # enabled TLS - ORDERER_GENERAL_TLS_ENABLED=true - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] - ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1 - ORDERER_KAFKA_VERBOSE=true - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key - ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] working_dir: /opt/gopath/src/github.com/hyperledger/fabric command: orderer
4.3.2 base/docker-compose-base.yaml # Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # version: '2' services: orderer.example.com: container_name: orderer.example.com extends: file: peer-base.yaml service: orderer-base volumes: - ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block - ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp - ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls - orderer.example.com:/var/hyperledger/production/orderer ports: - 7050:7050 peer0.org1.example.com: container_name: peer0.org1.example.com extends: file: peer-base.yaml service: peer-base environment: - CORE_PEER_ID=peer0.org1.example.com - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP volumes: - /var/run/:/host/var/run/ - ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp - ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls - peer0.org1.example.com:/var/hyperledger/production ports: - 7051:7051 peer1.org1.example.com: container_name: peer1.org1.example.com extends: file: peer-base.yaml service: peer-base environment: - CORE_PEER_ID=peer1.org1.example.com - CORE_PEER_ADDRESS=peer1.org1.example.com:7051 - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS=peer1.org1.example.com:7052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7051 - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP volumes: - /var/run/:/host/var/run/ - ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp - ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls - peer1.org1.example.com:/var/hyperledger/production ports: - 7051:7051 peer0.org2.example.com: container_name: peer0.org2.example.com extends: file: peer-base.yaml service: peer-base environment: - CORE_PEER_ID=peer0.org2.example.com - CORE_PEER_ADDRESS=peer0.org2.example.com:7051 - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:7052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:7051 - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:7051 - CORE_PEER_LOCALMSPID=Org2MSP volumes: - /var/run/:/host/var/run/ - ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp - ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls - peer0.org2.example.com:/var/hyperledger/production ports: - 7051:7051 peer1.org2.example.com: container_name: peer1.org2.example.com extends: file: peer-base.yaml service: peer-base environment: - CORE_PEER_ID=peer1.org2.example.com - CORE_PEER_ADDRESS=peer1.org2.example.com:7051 - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS=peer1.org2.example.com:7052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:7051 - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:7051 - CORE_PEER_LOCALMSPID=Org2MSP volumes: - /var/run/:/host/var/run/ - ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp:/etc/hyperledger/fabric/msp - ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls:/etc/hyperledger/fabric/tls - peer1.org2.example.com:/var/hyperledger/production ports: - 7051:7051
4.3.3 host1.yaml # Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # version: '2' volumes: orderer.example.com: orderer5.example.com: peer0.org1.example.com: networks: byfn: external: name: first-network services: orderer.example.com: extends: file: base/docker-compose-base.yaml service: orderer.example.com container_name: orderer.example.com networks: - byfn orderer5.example.com: extends: file: base/peer-base.yaml service: orderer-base container_name: orderer5.example.com networks: - byfn volumes: - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block - ./crypto-config/ordererOrganizations/example.com/orderers/orderer5.example.com/msp:/var/hyperledger/orderer/msp - ./crypto-config/ordererOrganizations/example.com/orderers/orderer5.example.com/tls/:/var/hyperledger/orderer/tls - orderer5.example.com:/var/hyperledger/production/orderer ports: - 8050:7050 peer0.org1.example.com: container_name: peer0.org1.example.com extends: file: base/docker-compose-base.yaml service: peer0.org1.example.com networks: - byfn cli: container_name: cli image: hyperledger/fabric-tools:$IMAGE_TAG tty: true stdin_open: true environment: - SYS_CHANNEL=$SYS_CHANNEL - GOPATH=/opt/gopath - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock #- FABRIC_LOGGING_SPEC=DEBUG - FABRIC_LOGGING_SPEC=INFO - CORE_PEER_ID=cli - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP - CORE_PEER_TLS_ENABLED=true - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: /bin/bash volumes: - /var/run/:/host/var/run/ - ./../chaincode/:/opt/gopath/src/github.com/chaincode - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts depends_on: - orderer.example.com - peer0.org1.example.com networks: - byfn
4.3.4 host2.yaml # Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # version: '2' volumes: orderer2.example.com: peer1.org1.example.com: networks: byfn: external: name: first-network services: orderer2.example.com: extends: file: base/peer-base.yaml service: orderer-base container_name: orderer2.example.com networks: - byfn volumes: - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block - ./crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/msp:/var/hyperledger/orderer/msp - ./crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/:/var/hyperledger/orderer/tls - orderer2.example.com:/var/hyperledger/production/orderer ports: - 7050:7050 peer1.org1.example.com: container_name: peer1.org1.example.com extends: file: base/docker-compose-base.yaml service: peer1.org1.example.com networks: - byfn
4.3.5 host3.yaml # Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # version: '2' volumes: orderer3.example.com: peer0.org2.example.com: networks: byfn: external: name: first-network services: orderer3.example.com: extends: file: base/peer-base.yaml service: orderer-base container_name: orderer3.example.com networks: - byfn volumes: - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block - ./crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/msp:/var/hyperledger/orderer/msp - ./crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/:/var/hyperledger/orderer/tls - orderer3.example.com:/var/hyperledger/production/orderer ports: - 7050:7050 peer0.org2.example.com: container_name: peer0.org2.example.com extends: file: base/docker-compose-base.yaml service: peer0.org2.example.com networks: - byfn
4.3.6 host4.yaml # Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # version: '2' volumes: orderer4.example.com: peer1.org2.example.com: networks: byfn: external: name: first-network services: orderer4.example.com: extends: file: base/peer-base.yaml service: orderer-base container_name: orderer4.example.com networks: - byfn volumes: - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block - ./crypto-config/ordererOrganizations/example.com/orderers/orderer4.example.com/msp:/var/hyperledger/orderer/msp - ./crypto-config/ordererOrganizations/example.com/orderers/orderer4.example.com/tls/:/var/hyperledger/orderer/tls - orderer4.example.com:/var/hyperledger/production/orderer ports: - 7050:7050 peer1.org2.example.com: container_name: peer1.org2.example.com extends: file: base/docker-compose-base.yaml service: peer1.org2.example.com networks: - byfn
4.3.7 .env COMPOSE_PROJECT_NAME=net IMAGE_TAG=latest SYS_CHANNEL=byfn-sys-channel
下面是目录中的内容:
下面是针对BYFN中的文件所作的修改: base/peer-base.yaml 中,CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE修改为 我们之前创建的叠加网络first-network base/docker-compose-base.yaml 中,由于所有的peers都在不同的主机上,我们 将端口映射改回7051:7051。在每个peer的环境变量中也进行了相应的修改。 在所有的 hostn.yaml 文件中,我们添加叠加网络first-network
现在我们在host 1上准备好了所有资料,将该目录拷贝到其他主机。由于不能跨EC2实例拷贝文件,我们使用本地机器进行桥接操作: # on Host 1 cd .. tar cf raft-4node-swarm.tar raft-4node-swarm/# on my localhost scp -i ubuntu@:/home/ubuntu/fabric-samples/raft-4node-swarm.tar . scp -i raft-4node-swarm.tar ubuntu@:/home/ubuntu/fabric-samples/# on Host 2, 3 and 4 cd fabric-samples tar xf raft-4node-swarm cd raft-4node-swarm
现在所有的节点都有了同样的密码学资料和docker-compose文件,我们可以启动容器了。
4.4 分别启动各主机上的容器
我们使用docker-compose启动全部主机: # on Host 1, 2, 3 and 4, bring up corresponding yaml file docker-compose -f hostn.yaml up -d
运行结果如下:
4.5 创建通道并加入peer
由于我们仅在host 1上由命令行CLI,因此从host 1的终端执行所有的命令。
为mychannel通道创建创世区块: docker exec cli peer channel create -o orderer.example.com:7050 -c mychannel \ -f ./channel-artifacts/channel.tx --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
将peer0.org1加入mychannel: docker exec cli peer channel join -b mychannel.block
将peer1.org1加入mychannel: docker exec -e CORE_PEER_ADDRESS=peer1.org1.example.com:7051 \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt \ cli peer channel join -b mychannel.block
将peer0.org2加入mychannel: docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer channel join -b mychannel.block
将peer1.org2 加入mychannel: docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer1.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt \ cli peer channel join -b mychannel.block
4.6 安装并实例化Fabcar链码
从host 1的终端将Fabcar链码安装到所有peer节点: # to peer0.org1 docker exec cli peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/fabcar/go/ # to peer1.org1 docker exec -e CORE_PEER_ADDRESS=peer1.org1.example.com:7051 \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt \ cli peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/fabcar/go/ # to peer0.org2 docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/fabcar/go/ # to peer1.org2 docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer1.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt \ cli peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/fabcar/go/
在通道mychannle实例化Fabcar链码: docker exec cli peer chaincode instantiate -o orderer.example.com:7050 --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ -C mychannel -n mycc -v 1.0 -c '{"Args":[]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"
4.7 链码调用与查询
首先调用 initLedger 方法将10个车辆记录载入账本。
在peer0.org1上执行: docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls true \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ -c '{"Args":["initLedger"]}'
现在可以从4个不同的peer节点查询车辆记录: # from peer0.org1 docker exec cli peer chaincode query -n mycc -C mychannel -c '{"Args":["queryCar","CAR0"]}' # from peer1.org1 docker exec -e CORE_PEER_ADDRESS=peer1.org1.example.com:7051 \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt \ cli peer chaincode query -n mycc -C mychannel -c '{"Args":["queryCar","CAR0"]}' # from peer0.org2 docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer chaincode query -n mycc -C mychannel -c '{"Args":["queryCar","CAR0"]}' # from peer1.org2 docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer1.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt \ cli peer chaincode query -n mycc -C mychannel -c '{"Args":["queryCar","CAR0"]}'
运行结果如下:
现在我们使用orderer3.example.com来调用 changeCarOwner,并在执行 后进行查询: docker exec cli peer chaincode invoke -o orderer3.example.com:7050 --tls true \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ -c '{"Args":["changeCarOwner","CAR0","KC"]}' # from peer0.org1 docker exec cli peer chaincode query -n mycc -C mychannel -c '{"Args":["queryCar","CAR0"]}' # from peer1.org2 docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer1.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt \ cli peer chaincode query -n mycc -C mychannel -c '{"Args":["queryCar","CAR0"]}'
运行结果如下:
你可以使用其他的orderer进行链码调用。由于这些排序节点构成了raft集群,你 应该得到同样的结果,这表示排序节点集群工作正常。
4.8 清理环境
要清理运行环境,使用docker-compose将容器停掉并移除即可: # each host docker-compose -f noden.yaml down -v
5、总结
在本教程中,我们基于BYFN示例进行修改,构建了一个基于Raft排序集群的 Hyperledger Fabric网络,使用Docker Swarm来实现多主机容器的通信。
原文链接: Hyperledger Fabric Raft排序多机部署 - 汇智网
区块链
2019-12-24 18:49:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
随着区块链技术越来越受到关注,区块链在安全方面也面临更大的挑战,因此需要从技术体制上保证链上数据和链上交易的安全。本文将简要介绍加密通信、数字签名以及匿名通信等几个与区块链紧密相关的安全技术。
区块链是一种去中心化的分布式电子记账系统,http://www.gendan5.com/mt5.html它实现的基础是一种受信任且绝对安全的模型。在加密算法的配合下,交易信息会按照发生的时间顺序公开记录在区块链系统中,并且会附带相应的时间戳。关键之处在于,这些数字“区块”只能通过所有参与交易的人一致同意才可以更新,因此攻击者无法通过数据拦截、修改和删除来进行非法操作。
因此,区块链就有成为安全社区一个重要解决方案的潜力,对于金融、能源和制造业来说亦是如此。就目前来说,验证比特币交易是它的一个主要用途,但这种技术也可以扩展到智能电网系统以及内容交付网络等应用场景之中。
如何将区块链应用到网络安全之中?
无论是保护数据完整性,还是利用数字化识别技术来防止物联网设备免受DDoS攻击,区块链技术都可以发挥关键作用,至少现在它已经显示出了这种能力。
爱丁堡龙比亚大学计算机学院的教授Bill Buchanan表示:“区块链可以弥补我们在安全实践方面的信任缺失度,在2018年,我们对任何数据都要进行加密,这是必须的。但是目前来说,我们没办法判断你的电子邮件有没有被其他人看过或者修改过,我们甚至还无法验证邮件是否真的是你朋友发过来的。
但是在区块链技术的帮助下,我们可以记录并验证我们的(交易)行为。虽然现在大家一提到区块链,可能首先想到的就是各种加密货币,但区块链技术其实还可以为我们的数字服务构造更加值得信任的基础设施。
虽然银行、金融和房地产市场时区块链技术最常应用的领域,但与互联网相关的教育,社交媒体和安全方面也受到了区块链技术的影响。尤其是区块链技术与网络安全有着本质性的联系,也有评论称区块链技术是加密和安全领域数十年研究的最高成果,它提供了一种完全不同的方法来存储信息、进行交易、执行功能和建立信任,这使得它特别适合在具有高安全性需求和相互未知的环境中应用。
因此,尽管类似于比特币的加密数字资产有时会出现价格波动,但以区块链为基础的底层技术已经成功经受住了8年多的网络攻击。这就是为什么像洛克希德马丁等行业巨头企业,决定将区块链用于网络安全的原因。其他一些初创企业也在探索区块链技术在网络安全方面的应用。
但对企业而言,目前在应用中的挑战在于,企业已成功实施很多区块链技术的概念验证,却苦于无法建立有效的业务案例。对于现有技术解决方案,区块链技术带来的额外好处很难量化。区块链项目是一项新兴技术,其优势尚待证实,再加上所需的彻底性变革、对多方外部力量的依赖、所带来的传统系统沉没成本和转换成本,都增加了该项目的风险。
使用区块链在网络安全中的缺点
1. 不可逆性
如果用户忘记或者是丢失用于解密密钥的所需的密钥,则可能会使得无法修复加密数据。
2.存储方面的限制
每块尽可以包含不超过1兆的数据,但是,区块链每秒只能处理7个任务
3.网络攻击仍有风险
尽管区块链技术将大大的降低恶意攻击的风险,但仍不是万能的。
4.适应性挑战
尽管区块链技术可以应用到几乎任何方面的业务,但公司如果遇到困难,区块链应用还是需要完全替换现有的系统,因此,公司在实施区块链技术之前,应该先考虑到这一点。
5.高运营成本
区块链的运行,需要大量的计算能力,与现有的技术系统相比,需要更多更高的成本、
6.区块链识字
就目前的技术而言,还没有足够的开发者拥有在区块链技术方面的丰富的有关密码学的知识。
总结
区块链在网络安全的分散管理方式,是当前行业要面
区块链
2019-12-24 17:10:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
区块链作为一种崭新的、颠覆性的技术,是国内外活跃的研究领域和毕业设计选题方向。本文列出最新的一组区块链方面的论文,希望可以对选择区块链毕业设计的同学们有所帮助,这是 汇智网 编辑整理的区块链毕业设计论文系列中的第四篇。
1、比特币网络实体活动分析与可视化
本论文提出了一个可视化分析工具Bitcoinduite,用于探索分析 比特币 网络中的金融活动。
比特币是世界范围内最大的数字加密货币,它也对当下的传统金融系统形成了挑战 - 比特币用户可以绕过传统的银行系统以(伪)匿名的方式进行转账。虽然比特币交易都记录在可以公开访问的账本上,但是对于交易参与者(我们称之为:实体)是如何使用比特币的,我们了解的并不多。Bitconduite提供了一个以实体为中心的交易视图,通过向导工作流来帮助非技术专家探索比特币实体的行为模式,同时还包括相似性聚类分析、多尺度交易数据探索等等。论文中包含的两个用例展示了系统的工作流以及其分析能力。在论文的最后,给出了领域专家的使用反馈意见,并探讨了后续的潜在研究方向。
论文PDF下载: Visualizing and Analyzing Entity Activity on the Bitcoin Network
2、基于区块链的个人隐私信息管理系统
区块链是一个关于历史交易的分布式共识所建立的分布式账本,它是比特币等数字加密货币的底层技术,不过区块链在金融领域之外也有很多应用。由于其置的安全性以及不需要第三方信任的机制,区块链已经开始开始出现在其他的应用中。在本论文中,我们提出了一个基于许可制区块链的第三方审批管理系统,其策略可以由治理机构决定。
我们已经使用 Hyperledger Fabric 完成了概念验证(PoC)实现,为终端用户提供了控制和审批其隐私信息使用的服务。我们详细该解决方案可以满足欧盟的数据保护法案(DGPR)。虽然目前的性能和可用性评估还比较有限,但我们的设计和实现可以满足隐私保护的7个基本原则。
论文PDF下载: Design and Implementation of a Blockchain-based Consent Management System
3、ChainifyDB - 区块链化现有数据管理系统
目前的许可制区块链系统是单独形式提供的,要求用户在已经很复杂的数据管理体系中再增加一个新的交易处理系统。这看起来很七块,因为区块链和传统数据库在很多方面是有共性的。因此本论文提出了一种区块链化现有数据系统的思路,而不是全盘替代。不过不幸的是,这一任务要远比听起来更有挑战性:由于我们希望在异构的交易处理系统之上进行区块链化,就不得不放弃一些假设并引入更强大的处理模型。
我们提出的WLC模型可以创建一个高度灵活的许可制区块链层,我们称之为ChainifyDB,它有以下特性:(a)基于久经考验的数据库技术(b)比现有的许可制区块链更强的保障(c)提供复杂的恢复机制(d)六倍于Hyperledger Fabric的交易吞吐量(e)易于和已有的异构数据库集成。
论文PDF下载: ChainifyDB: How to Blockchainify any Data Management System
4、区块链游戏 - 拜占庭系统合成与纳什均衡
本论文从两个正交的视角——分布式容错系统和游戏理论 —— 提出了区块链合成观点。
我们在区块链上下文中定义了新的游戏理论问题并给出了该问题的纳什均衡推导。
论文PDF下载: The Blockchain Game: Synthesis of Byzantine Systems and Nash Equilibria
5、BDoS - 区块链拒绝服务攻击
采用PoW共识的区块链例如比特币有大量的资金沉淀,但目前针对区块链的拒绝服务攻击还不多见,这主要是攻击的成本问题:已知的攻击要么针对个体,要么需要控制大部分的系统资源。
在本论文中,我们提出了一种基于激励机制的攻击:BDoS,它的成本要低得多,据我们所知 这是第一个基于激励机制的DoS攻击。
论文PDF下载: BDoS: Blockchain Denial of Service
本文整理了最新的可用于区块链毕业设计的参考论文,如果需要访问区块链毕业设计必读 论文系列的最新文章,可以持续关注我们的 博客 ,或加入QQ群:532241998。
原文链接: 区块链毕业设计必读论文4 - 汇智网
区块链
2019-12-24 13:31:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
BnbTool 开发包适用于为PHP应用快速增加对 币安链 / Binance Chain 数字资产的支持能力, 即支持使用自有部署区块链节点的应用场景,也支持基于第三方节点开放API服务的轻量级部署场景。 官方下载地址: http://sc.hubwiz.com/codebag/bnbtool/ 。
1、开发包概述
BnbTool开发包是一个完整的币安链PHP开发包,可以极大地提升区块链钱包、交易平台或区块链应用开发过程中与币安链的对接实现效率。BnbTool主要包含以下特性: 完善的币安链节点RPC API与Rest API封装 完善的Tendermint Amino编解码器PHP实现 离线管理私钥,离线签名交易,离线序列化/反序列化交易 透明支持自有节点或第三方节点访问币安链,例如查询数据或广播交易
BnbTool软件包运行在**Php 7.1+**环境下,当前版本1.0.0,主要实现类/接口及相互之间的关系如下图所示:
BnbTool的主要代码文件清单见官网: http://sc.hubwiz.com/codebag/bnbtool/
2、使用演示代码
下载开发包并解压后,进入demo目录运行演示代码。
2.1 CryotoDemo
CryptoDemo.php演示了如何使用BnbTool的Crypto封装类实现币安链账户的创建与恢复,签名的生成与验证。
在终端执行如下命令启动CryptoDemo: ~$ php CryptoDemo.php
运行结果类似下图:
2.2 RpcClientDemo
RpcClientDemo.php演示了如何使用BnbTool的RpcClient调用币安链节点的RPC API。
在终端执行如下命令启动RpcClientDemo: ~$ php RpcClientDemo.php
运行结果类似下图:
2.3 RestClientDemo
RestClientDemo.php演示了如何使用BnbTool的RestClient调用 币安链的Rest API。
在终端执行如下命令启动RestClientDemo: ~$ php RestClientDemo.php
运行结果类似下图:
2.4 ToolKitDemo
ToolKitDemo.php演示了如何使用BnbTool的ToolKit入口类实现币安链账户的创建、转账、余额查询与历史交易查询。
在终端执行如下命令启动ToolKitDemo: ~$ php ToolKitDemo.php
运行结果类似下图:
3、ToolKit类使用说明
ToolKit是BnbTool的入口类,利用它可以快速完成币安链账户的创建、转账、DEX挂单等操作。ToolKit的主要属性与方法如下: 属性 keyStore:密钥库实例 restClient:币安链Rest API客户端实例 方法 newAddress():创建新账户并返回生成的地址,新的私钥/地址自动加入密钥库 importKey():导入指定的私钥并返回对应的地址,该私钥/地址自动加入密钥库 transfer():执行代币转账交易 placeOrder():在DEX委托挂单 cancleOrder():取消DEX上的委托单 freezeToken():冻结指定数量的代币 unfreezeToken():解冻指定数量的代币 dexList():在DEX上市交易对
3.1 ToolKit的实例化
实例化ToolKit需要传入两个参数:币安链节点Rest API服务地址,以及该节点接入的网络。例如,使用本机的Rest API服务器接入Binance Chain的测试网: use BnbTool\ToolKit; $kit = new ToolKit( 'http://localhost:8080', //Rest API访问基地址 'testnet' //测试链,可选:mainnet | testnet );
ToolKit也提供了两个静态方法用来快速创建接入主网或测试网的实例: $kit = ToolKit::mainnet(); //使用 https://dex.binance.org接入主网 $kit = ToolKit::testnet(); //使用 https://testnet-dex.binance.org接入测试网
容易理解, ToolKit::mainnet() 等价于如下的代码: new ToolKit('https://dex.binance.org','mainnet');
3.2 账户创建与恢复
使用ToolKit的 newAddress() 方法创建新账户,该方法将生成随机私钥并返回该私钥对应的地址,同时将私钥信息存入ToolKit的密钥库。例如下面的代码创建一个新的币安链账户并显示该账户的地址: $address = $kit->newAddress(); //创建新账户并返回地址 echo "new address: $address" . PHP_EOL; //显示新账户的地址
也可以使用 importKey() 方法导入已有的私钥,该方法将返回所导入私钥对应的地址。例如下面代码导入指定的私钥并显示该账户的地址: $prv = '49bd38a8...5af84709670fd'; //要导入ToolKit的私钥 $address = $kit->importKey($prv); //导入私钥并返回地址 echo "restored: $address" . PHP_EOL; //显示恢复的地址
3.3 使用密钥库
ToolKit使用密钥库来保存账户信息,密钥库遵从IKeyStore接口的4个方法: add():添加账户信息 getAll():返回所有账户的列表 getByKey():查询指定私钥的账户 getByAddress():查询指定地址的账户
使用ToolKit的 keyStore 属性就可以访问当前使用的密钥库对象。例如,下面的代码列表显示当前密钥库中的所有账户: $items = $kit->keyStore->getAll(); //返回密钥库全部账户 foreach($items as $item){ //逐行显示账户私钥和地址 echo "key:{$item->key}, address: {$item->address}" . PHP_EOL; }
可以使用密钥的 getByKey() 方法查询指定密钥的账户地址,例如: $prv = '49bd38a8...5af84709670fd'; //要查询的私钥 $item = $kit->keyStore->getByKey($prv); //返回该私钥对应的账户记录 if(!is_null($item)) //如果找到的话 echo "address => {$item->address}\n"; //显示账户地址
3.4 转账交易
使用ToolKit的 tranfer() 方法执行代币转账交易。例如下面的代码在两个指定账号间转账1.234个BNB代币,并附备注信息: $kit->importKey('....'); //导入转账发起账号的私钥 $ret = $kit->transfer( 'tbnb1hfw...x3kh9d7p5ryya', //转账发起账号 'tbnb1l5f...xcyt0ec40avsp', //转账接收账号 'BNB', //代币符号 1.234, //代币数量 'rent' //备注信息 ) echo "tx hash => {$ret[0]->hash}\n"; //显示交易哈希
注意,由于交易需要发起账号签名,因此在调用 transfer() 方法之前,务必保证ToolKit的密钥库中已有该发起账号的私钥。
3.5 查询账户余额
由于币安链的Rest API更容易使用,ToolKit使用RestClient而不是RpcClient来与币安链交互,可以通过ToolKit的 restClient 属性来访问预创建的RestClient实例。
例如,下面的代码使用RestClient的 getAccount() 方法来查询 指定账户的所有种类代币的余额并逐行显示: $ret = $kit->restClient->getAccount('tbnb1hfw...x3kh9d7p5ryya'); //查询账户信息 foreach($ret->balances as $b){ //遍历全部币种 echo "symbol: {$b->symbol}, free: {$b->free}\n"; //显示币种符号与可用余额 }
3.6 查询账户的历史交易
类似的,使用RestClient的 getTransactions() 方法,可以查询指定账户的历史交易。例如下面的代码: $ret = $kit->restClient->getTransactions('tbnb1hfw...x37p5ryya'); //查询历史交易 foreach($ret->tx as $tx){ //遍历全部交易 echo json_encode($tx) . PHP_EOL; //显示交易内容 }
getTransactions() 方法支持分页处理,例如,下面的代码使用 offset 和 limit 选项声明需要返回从100#开始的20个交易: $ret = $kit->restClient->getTransactions( 'tbnb1hfw...x3kh9d7p5ryya', //要查询的账户地址 [ 'offset'=>100, //记录起始位置 'limit'=>20 //返回记录数量 ] );
getTransactions() 对应于Rest API中的 /v1/api/transactions ,可以参考该文档了解更多可用的查询过滤参数。
区块链
2019-12-23 19:50:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
很多新手都在纠结怎么去选择一家靠谱的交易所,做为一个较为有经验的投资人,给大家做个简单的分析:
那么作为一个币圈小白该如何选择交易所呢?其实很简单的教大家一个工具:非小号,上线查查交易所排名。
1、首选主流交易所,排名前30的,基本靠谱。如果要选择注册,找个前五的吧。一般老韭菜都在好几个交易所有账号。因为不同的币种上线的交易所不一样。
2、根据使用习惯,比如PC端啊,有无手机APP,有无苹果系统app,再看看交易所的手续费、分红、推荐返佣金、交易挖矿的具体规定和费率。
最后,大家还比较关心最近新上线的交易所,没被非小号收录,而最近作得又比较火的。对这些新上线的交易所,我们从这几方面来做个判断:
1、网站技术,页面打开的流畅速度,注册的流程,交易承载量,交易的安全措施,api接口的安全性;
2、团队背景,技术、运营的团队背景,通过百度可以查询到一些信息,看是否有比较牛X的技术团队,比较有实力的投资机构,比较专业的运营管理团队;
3、看交易所的模式,最近发现很多朋友圈在推传销交易所,完全是做拆分盘、互助盘、传销币的原班人马搞的。这样的就没必要去碰了,非要拉个人头,排个左区右区,这不是传销是啥?新模式交易即挖矿,参与交易分红,然后也得看分红的周期,是日结,周结,月结还是每单交易完就结。最后再看看交易所上币的投票规则,研究一下常用币种的转出费率。
几乎所有区块链领域的人都认为,去中心化交易所是加密货币交易的未来。这是因为,在当今的行业,数字资产交易既不安全也不简单。
要开始交易,你必须首先通过OTC网站购买法币,该服务通常收取一定费用,外汇分析师www.gendan5.com/experts.html并提供糟糕的汇率。购买完成后,你就不能再完全控制自己的资金了,但是交易所可以。
该制度迫使中心化交易所负责持有和保护所有用户的资金。因此,交易所必须管理一些控制巨额资金的中心化钱包。
火币网(Huobi)
火币全球专业站,是火币集团旗下服务于全球专业交易用户的创新数字资产交易平台,致力于发现优质的创新数字资产投资机会,目前提供四十多种数字资产品类的交易及投资服务,总部位于新加坡,由火币全球专业站团队负责运营。火币集团是一家具有全球竞争力与影响力的数字资产综合服务商,为超过130个国家百万级用户提供优质服务。在新加坡、香港、韩国、日本等多个国家和地区均有独立的交易业务和运营中心。在技术平台、产品支线、安全风控体系、运营及客户服务体系等方面,火币集团在全球均处于领先地位。
币安网(Binance)
binance是全球领先的区块链资产交易平台,为全球区块链爱好者提供多币种、多语言的币币兑换服务,目前包含 binance 区块链资产交易平台、binance info,binance labs,binance launchpad 等业务。binance 的团队核心成员来自 bloomberg、blockchain.info、摩根史丹利、野村证券等世界知名企业,他们是全球区块链社区、金融和科技领域的顶级精英团队。
Bitfinex
bitfinex是全世界最大、最高级的比特币交易平台之一,支持以太坊、比特币、莱特币、以太经典等虚拟币的交易,每天的成交量达30多亿人民币。提供币币交易,美元与币的交易。注册非常简单。2016年,bitfinex大概有12万枚比特币通过社交媒体被盗。受此事件影响,当时比特币价格跌了20%。
K网(Kraken)
总部位于旧金山的kraken成立于2011年,是欧元交易量最大的比特币交易所,也可用加拿大元、美元、英镑和日元交易。kraken一直被独立新闻媒体评为最佳和最安全的比特币交易所。kraken是第一个在彭博终端上显示交易价格和交易量的比特币交易所,第一个通过了加密验证的外汇储备审计,是第一家加密货币银行的合伙人。
Bithumb
占有韩国比特币市场份额75.7%的bithumb是世界五大比特币交易所之一,每天交易量超过13,000比特币,约占全球比特币交易量的10%。该交易所也是世界上最大的以太坊市场。尽管韩元目前是比特币的第四大货币市场,落后于美元、人民币和日圆,但韩元市场是以太坊最大的市场。bithumb在韩国的以太坊交易中占比44%左右。
ZT
ZT(www.zt.com)是全球性数字资产交易平台之一,主要面向全球用户提供比特币、莱特币、以太币等数字资产的币币和衍生品交易服务。目前,公司已完成对新加坡、美国、日本、韩国、柬埔寨、香港等多个国家及地区的布局。
特点是拥有100余项安全与风控措施,每秒10万笔的撮合效率,方便快捷的C2C服务,秒冲秒提,体验感和安全性能都非常不错,目前在非小号上排名前十位,对于初入币市的新人来说是一个不错的选择。
区块链交易所排名头部的无疑是币安、火币、ok等不过由于大对项目方的严格审核制度和高昂的上币费,而XT.com交易所针对这种情况,制定了一套专门为项目方服务的政策
我建议你在巴比特或者bittalk泡一段时间,了解了比特币以及区块链的基本知识之后再选择交易所。
同时要弄明白你为什么要投资币圈,这是一个新型的投资项目,价格波动范围很大,风险高同时可能收益也高。并且现在正是区块链的寒冬期,这些是否都是你已经考虑过了的。
如果这些都是你已经了解和思考过的,那么再来谈谈我所接触过的交易所的一些特点。
怎样判断交易所,主要看上线的币种,交易所成立的时间,以及安全保障。
像最早接触的火币/币安等交易所,这些交易所的优势就是平台已经较为成熟,上线币种多,资产安全也同样会有保障,但于此同时,成立时间久,套路也会更多一些,所以也适合一些初入币圈的人去交易。
而相对小一些的交易所,像Dcoin/kucoin这样相对小一些的交易所,因为平台时间不久,相对来说福利活动会多一些,并且套路也相对简单一些,针对一些想赚点小钱的用户,也是不错的选择。
区块链
2019-12-23 16:56:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一、前言
区块链根据不同的应用场景分为应用于公众的公有链,需要授权使用的私有链和联盟链,还有在原有区块链基础上进行扩展的侧链、跨链等,随着区块链的发展,相信还会有其他形式的应用出现。在开始之前我们需要先了解什么是哈希(Hash),哈希又称哈希函数或散列算法,简单的说,哈希函数是用于将任意大小(输入)的数据映射到固定大小输出的任何函数。散列算法应用于数据输入,并且得到的固定长度输出称为散列。
盖一间房子,它的基本单元结构是每一块砖;而组成区块链的基本单元结构,就叫做区块。每个区块由区块头和区块主体组成。
二、区块头
区块头交易数据的公开、可溯源、不可篡改是让区块链与中心化系统相比的最大优势。
区块链由一个个区块组成,每个区块相当于一个小账本。要保障这些小账本的安全,需按照严格顺序排列,并保存到成千上万台电脑上。如何保障这些小账本的顺序,就需要在区块中设置一些参数。这些参数放在一起就组成了小账本的扉页,这就是区块头。
区块头存储结构化的数据,大小是80字节;而区块主体利用一种神奇的树状结构,记录区块挖出的这段时间里所有交易信息,所需空间比较大。平均来讲,假设一个区块内有400笔交易信息,区块主体可能比区区块头中的参数信息规定每一个小账本在一条链的具体位置,让一个个没有关系的小账本组成了一个先后顺序严格确定、不可篡改、不断生长的区块链。
默克尔树的根哈希存储方式,既让区块链可以快速发现信息被篡改,又可以快速定位到具体的交易信息。
区块链的众多功能都在区块头的参数里得意体现。要想透彻了解一条区块链,就需要仔细研究分析它的区块头中的信息。
虽然区块头比区块主体小,但区块头总归是脑袋,大部分功能其实都由区块头实现。
三、区块体
对于矿池,它有两种模式,一种模式是老板个人投资,还有就是他投资了一部分矿机,然后负责托管其它矿机,或者进行算力出租等。目前,没有看到有学者去研究,我觉得这个其实很有意思。
比如我买了一些矿机,向社会融资,融了资以后,你的那笔钱可能就变成了几个矿机放在那里,根据它对应算力的比例,分配给你挖出来的币。其实这就涉及到一个民间融资相关法律的规范问题。
对于公有链,Axitrader返佣http://www.fx61.com/brokerlist/axitrader.html以及监管机构似乎还没有认真去思考法律上以及监管上的应对方式。其实这涉及两个阶段, 在公链脱离项目方之前,或者项目方能够长期控制公链运行的时候,从责任承担的主体来看是清晰的,看他有没有故意设置一些恶意的代码啊。如果没有的话,可能承担较少的责任。如果这个公链的项目方是完全匿名,甚至无法追查(比如中本聪),那么实质上也很难确定责任。
当公链正式运行脱离项目方掌控之后,就像比特币区块链网络系统一样,这时候它已经没有一个特定的主体为它的运行来承担责任负责。现在法律上和监管上可能都没有合适的应对方式。
区块链
2019-12-23 15:29:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>

如今,从理发师到在股市工作的朋友,人人都在谈论比特币。别担心,这篇文章不是那种讨论如何从比特币中赚钱的文章,我将努力帮助你理解比特币的基层技术,以及区块链在未来几十年里如何发挥作用。
历史回顾
2008年10月31日,一个名为Satoshi Nakamoto的匿名人士(或组织)发表了一份白皮书,介绍了一种不涉及任何金融中介机构、直接从发送方到接收方汇款的新方法。
文中给这个概念起了个名字——比特币。由于比特币使用了密码学的一些基本概念,这种新的货币交换方式被归类为加密货币。比特币的唯一用途是用于金融交易,但研究人员意识到,可以利用它的基础技术构建其他安全可靠的应用程序,从而彻底改变当前系统的工作方式。
“区块链”就是这个基础技术的名字。你觉得有很多专业词汇?没关系,让我们来简化一下!
什么是区块链?——类比真实世界
想象你住在一个城市,这个城市有一个可以同时停放200辆车的大停车位(假设只有一层)。这个停车位有一个大门,大门是锁着的,只有当有车辆进出时才会打开。现在让我们从不同的角度来分析这个单层的停车场建筑: 价格 :由于一些私人企业建造了这个专用停车位,所有的维护费用将由业主公司承担,所以出租一个停车位将会有很高的租金。 安全 :如果小偷进入大门,他们可以很容易地进入你的车(取走车轮燃料,或损坏刹车等任何东西!) 限制 :如果你所在城市的汽车数量从200辆增加到300辆会怎样?停车位将没有足够的空间容纳所有的汽车,一些其他的私人机构将不得不建造一个新的停车位。 信任 :你信任停车位公司,他们有责任确保车子的安全性和可靠性。 集中式 :因为所有的车都在一栋楼里,我们可以把它当成一个集中式停车场。
现在,让我们修改当前的场景。想象一下,你的城市里有200个住户,所有人都有两个车库。简单来说,我们假设每个住户只有一辆车(所有的车都填满了上面描述的大停车位)。所以,每户都有一个空车库。现在,假设这个城市的人们决定把多余的车库出租给任何需要停车的人。这种提供停车位的模式将解决200辆或更多汽车停车问题,而不需要为整个城市建造任何更大的中央停车位。与前面的场景类似,我们来分析一下这个场景: 价格 :由于第二个车库不是专门出租的,而且维修费用也比较低,所以相对于中央大停车位来说,多出的空间租金也比较低。 安全性 :每辆车都锁在不同的车库里,因此小偷必须打开所有车库里的门才能进入汽车,从而提供更多的安全性。(区块链中的安全性略有不同,但是为了简单起见,我们现在就这样考虑吧!) 限制 :随着房屋数量的增长,假设每个新房子都有额外的车库空间,那么容纳更多汽车的空间将持续增加,从而也增加了承租人和出租人间的联络网。 信任缺失 :由于没有中央机构控制这些分散的停车位,我们假设所有的车库业主在出租他们的车位时会制定一定的规则。 去中心化 :如前所述,这些停车位分布在整个城市,我们可以认为它是一个去中心化的停车场。
上面的类比为理解区块链的实际技术基础架构提供了基础。
停车模式到技术模式
这个停车模型用现实世界语言展示了区块链的基本概况。现在,让我们尝试将停车示例的组件与实际的技术模型匹配起来:
这个大型中央停车场是一个像AWS、Google Cloud等的集中系统(这些云平台也在一定程度上是分布式,但为了简单起见,我们将它们假设为一个单一的实体)。
汽车是数据和应用。
分布式停车场是一个分散的系统——区块链。
等等!我们似乎错过了一些东西。
不是所有的分散系统都是区块链!!是的,区块链是一种特殊类型的分散系统,具有独特的特性。哪种特性?我们来讨论一下。
“块”组成了区块链
让我们重新审视一下我们的分布式停车示例,并做一些小小的更改。我们假设一个特定车库的锁是当一辆车停在里面的时候产生的(假设同一辆车每天去同一个停车场)。另外,假设所有的分布式车库已经按顺序编号。50号车库的锁钥匙对是基于49号车库的锁钥匙对,也是基于50号车库内停放的汽车的特征(如颜色、重量、发动机编号等),这个过程从1号车库开始,一直持续到200号车库甚至更多。
每个车库的锁钥匙对取决于车库内汽车的功能和前一个车库的锁钥匙对。
因此,如果一个小偷试图进入49号车库并修改车子的特征时,说出它的颜色或注册号,停在49号车库的车的特点将会改变,这也意味着一个新的49号车库的锁钥匙对将会生成。因为50号车库的锁钥匙对取决于49号车库的锁钥匙对,50号车库的锁钥匙对也将改变,其他的车库也一样。
现在,让我们做一个最后的假设。假设计算一个锁钥匙对需要大量的计算资源,这意味着如果任何一个小偷修改了任何汽车的任何特征,我们必须重新计算这些对,这将是几乎不可能的。
如果一个锁钥匙对改变了,会发生什么?
希望你还记得我们说过的所有的车库主人都要遵守一些规则?
这些规则之一就是检查一个有效的车库。如果你可以验证一个车库的锁钥匙对,那么这个车库就是有效的。如果任何一个锁钥匙对被更改,那么之后的所有车库的锁钥匙对都是无效的,因为每一个锁钥匙对都依赖于前一对。(与生成锁钥匙对相比,验证特定车库的锁钥匙对的过程非常快)。
这种一个对取决于前一个对的形式组成了一个车库链,在技术世界中,这些车库是“块”,因此得名区块链(一串积木链)。
区块链中的块通过hashes连接到下一个块,就像我们的示例中的锁钥匙对一样。与车库示例类似,如果修改了一个块中的hashes,那么需要重新计算下面所有块的hashes,因为计算hashes是一个非常耗费资源的操作,所以实际上不可能做到这一点,因此网络会排除无效的块。hash的计算过程被称为挖掘,我们将在本系列的下篇中详细讨论它。
如何从修改中恢复块?
在区块链网络上的所有计算机,都会保留一个完整的区块链副本,因此,如果一个特定计算机或多台计算机上的一个块或一个完整的链被修改,整个网络会试图与自己的完整副本链进行比较。
如果网络上的大多数节点(或计算机)发现修改后的链是无效的,则将修改后的链替换为来自其他节点的有效链,这使得区块链中51%的节点可能受攻击。简单地说,如果网络上超过50%的节点是恶意的(或者有一个修改过的链),那么整个网络都可能受到攻击。
结论
唷!!有很多信息需要消化。这是完整的初学者指南的第一部分,提供了基本的区块链基础。我希望这篇文章能为你和你的朋友讨论区块链时提供帮助。请查看本系列的下一篇,其中我们将讨论Ethereum、智能契约和挖掘。
原文链接: https://medium.com/@_sidharth_m_/beginners-guide-to-blockchain-explaining-it-to-a-5-years-old-772caac6ae97
欢迎点击“ 京东云 ”了解更多精彩内容
以上信息来源于网络,由“京东云开发者社区”公众号编辑整理,不代表京东云立场。
区块链
2019-12-23 14:50:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>> 本文主要介绍PBFT算法的垃圾回收、视图变更机制及状态机不确定性问题的解决等。
1. 垃圾回收
本部分介绍PBFT算法的垃圾回收机制。
1.1 概述
本节介绍从本地日志中删除历史消息的机制。
对算法来说,为了保证安全性,每个副本节点需要保证如下两点:
对于每个请求来说,在被至少f+1个正常节点执行之前,所有相关的消息都必须记录在消息日志中;
同时,如果一条请求被执行,节点能够在视图变更中向其他节点证明这一点。
此外,如果某个副本节点缺失的一些消息正好已经被所有正常节点删除,则需要通过传输部分或全部的服务状态来使节点状态更新到最新。因此,节点需要某种方式来证明状态的正确性。
如果每执行一次操作,都生成一个状态证明,代价将会很大。因此可以每执行一定数量的请求后生成一次状态证明,例如:只要节点序号是某个值比如100的整数倍时,就生成一次,此时称这个状态为检查点。如果一个检查点带有相应的证明,我们则称其为稳定的检查点。
1.2 稳定检查点的生成
如上所述,一个带有证明的检查点被称为稳定的检查点,这种证明的生成过程如下:
1、副本节点i生成一个检查点之后,会组装检查点消息,并全网广播给其他所有副本节点,检查点消息格式如下:
,
这里n指的是生成目前最新状态的最后一条执行请求的序号,d是当前服务状态的摘要。
2、每个副本节点等待并收集 2f+1 个来自其它副本节点的检查点消息(有可能包括自己的),这些消息有相同的序号 n 和摘要 d。这 2f+1 个检查点消息就是该检查点的正确性证明。
一旦一个检查点成为稳定检查点后,节点将从本地消息日志中删除所有序号小于或等于n的请求所对应的预准备、准备和确认消息。同时,会删除所有更早的检查点和对应的检查点消息。
检查点的生成协议可以用来移动低水线 h 和高水线 H:
h的值就是最新稳定检查点所对应的稳定消息序号;
高水线 H = h+k,这里k要设置足够大,至少要大于检查点的生成周期,比如说:假如每隔100条请求生成检查点,k就可以取200。
2. 视图变更
PBFT算法运行过程中,如果主节点失效了,为了保持系统的活性(liveness),就需要用到视图变更协议。
2.1 视图变更的触发
由于主节点失效时,客户端最终会将请求发送到所有其他副本节点。每个节点收到客户端请求后,如果该请求没有执行过,副本节点判断自己是否为主节点,不是的话就会把请求转发给主节点,同时启动一个定时器(假如之前没有启动过的话)。
如果请求在定时器时间间隔内执行完,则节点会停止定时器(不过如果此时节点恰好在等待执行另外一个请求,则会重启定时器);否则,节点会尝试触发视图的变更,具体过程如下节所示。
2.2 视图变更协议
对于副本节点i来说,假设其当前所处的视图编号为 v ,经由视图变更协议,从视图 v 变更到 v+1。
视图变更过程中,节点将不再接受其他任何类型的消息,只接受 checkpoint, view-change, 和 new-view 消息。
视图变更过程如下:
1. 节点组装 VIEW-CHANGE 消息并广播给全网其他所有副本节点。
VIEW-CHANGE消息的格式如下:

消息中的各字段含义如下:
v+1: 要变更到的目标视图编号;
n: 对应于节点已知的、最新的检查点 s 的请求序号;
C:包含 2f+1 个检查点消息的集合。这些检查点消息用于证明检查点 s 的正确性;
P:是一个集合,现在来解释一下其包含的信息。
对于任何一条客户端请求 m ,如果 m 在当前副本节点 i 上已经准备好, 即 prepared(m, v, n', i) 为 true, 并且 n' > n,那么根据定义,节点上已经存储了对应的预准备消息和 2f 个与之匹配的、有效的发自不同的节点的准备消息。这里,匹配的含义是:拥有相同的视图,消息序号以及 m 的摘要。我们把这些预准备
消息和准备消息组成的集合记为 。
P 就是所有 组成的集合。因此,P 包含了所有在副本节点上准备好的、序号大于 n 的请求的预准备和准备消息。在视图变更中,其提供的信息便于在新的视图中重新分配每条请求的消息序号。
2. 每个节点相继广播各自组装的 view-change 消息。同时,新视图中对应的新的主节点将收集来自其他副本节点的 view-change 消息。当其收集到 2f 个有效的 对应新视图 v+1 的 view-change 消息后,将组装并广播 new-view 消息,格式如下:

其中,V是一个消息集合,包含所有有效的、对应于新视图 v+1 的 2f+1 个 view-change 消息(包括主节点自己组装的)。而 O 则是主节点为各 view-change 消息中包含的、符合要求的请求组装的预准备消息的集合。 O中的消息按如下方式组装:
首先,根据 V 中各条view-change 消息中包含的预准备和准备消息,主节点先找到最新的稳定检查点,将其对应的消息序号赋值给 min-s;然后从所有准备消息中找到最大的那个消息序号,将其赋值给 max-s;
然后,对于min-s 和 max-s 之间的每一个消息序号 n, 主节点为其组装位于视图 v+1 上的预准备消息,这分为两种情况:
a) 在 V 中存在某个或多个 view-change 消息, 它们的 P 集合中的某个集合元素包含的准备消息中包含有对应于序号 n 的消息。
此时,主节点组装的预准备消息如下:

其中,d 是V中特定请求消息的摘要,并且该请求在 V 中的一个最新视图上的预准备消息中被分配了序号 n 。
b) 另外一种情况,是 V 中不存在和 n 对应的准备消息。此时,主节点只是模拟为一个特殊的空请求(null request)组装一个预准备消息:

其中,D(null) 为空请求的摘要。空请求和其他请求一样进行三阶段协议,但是其执行就是一个空操作(noop)。
3. 主节点广播 new-view 消息后,也会把 O 中的消息写入本地消息日志中。同时,如果主节点本地的最新稳定检查点的消息序号落后于 min-s 的话,则会将 min-s 对应的检查点的证明,也就是相应的检查点消息写入消息日志,并按之前介绍的垃圾回收机制删除所有的历史消息。
4. 此时,主节点正式变更到新视图 v+1, 开始接收消息。
5. 每个副本节点收到针对 v+1 视图的 new-view 消息后,会进行校验,是否满足以下条件:
签名正确;
其中包含的 view-change 消息是针对 v+1 视图,并且有效;
集合 O 中的信息正确、有效。节点判断有效与否的方法是进行类似于主节点生成 O 那样的计算。
如果校验通过,副本节点会将相关信息写入到本地日志中。 同时,针对 O 中的每一条预准备消息,组装并广播对应的准备消息,并且把准备消息写入到本地消息日志中。
此时,副本节点也如同主节点那样,进入到新视图 v+1 中。
之后,在新的视图中,针对所有序号位于 min-s 和 max-s 之间的请求,系统会重新运行三阶段协议。只不过对于每一个副本节点来说,如果当前确认的请求之前已经执行过的话,节点就不再执行该请求。每条被执行的请求,其相关信息会被存储在本地。节点根据这些信息确定请求的执行情况。
以上完成了对视图变更的介绍。
2.3 视图变更中节点的信息同步
视图变更时,由于 new-view 消息中并不包含原始的客户端请求,因此副本节点可能缺失某条客户端请求 m ,或者某个稳定的检查点。
此时节点可以从其他副本节点同步缺失的信息。例如,假如节点 i 缺失某个稳定检查点 s ,这个检查点在 V 中可以找到相应的证明,也就是 对应的 checkpoint 消息。由于总共有 2f+1个这样的消息,而错误节点最多 f个,因此至少有 f+1 个正常节点发送过这样的消息。因此,可以从这些正常节点获取到对应的检查点状态。
对于副本复制服务的状态来说,可以通过生成不同的检查点来划分状态。当节点需要同步状态时,只需按检查点来获取即可。这可以避免一次发送整个服务状态。
3. 关于状态机的不确定性
PBFT算法基于状态机副本复制服务,状态机要求每个节点的状态必须是确定性的。而大多数服务有时会有某种形式的不确定性。例如,对于网络文件系统而言,如果不基于状态机副本复制的话,文件的最后修改时间这个属性可以设置为服务器的本地时间。但如果是每个副本节点独自设置这个时间的话,就会导致各节点状态的不一致。
因此,需要相应机制来确保各节点使用相同的值。一般情况下,这个值不应该由客户端来决定,因为客户端拥有的信息并不完全。例如,多个客户端并发发送请求时,它们并不知晓其请求如何被排序。
可以由主节点来选取这个值,具体有两种方法:
1. 第一种方法适用于大多数服务,由主节点独立选取非确定的值。
主节点将该值和客户端请求拼接在一起,然后运行三阶段协议,确保所有正常节点就请求和该值的序号达成一致。这可以防止出现下列情况:
失效的主节点故意向不同的副本节点发送不同的值,从而使各个节点上的状态出现不一致。
对于这种方法来说,虽然所有正常节点使用相同的值,但这个由主节点发送的值可能是错误的。这种情况下,要求每个副本节点必须能够基于其状态来明确地判断该值的正确性,以及如何处理可能的错误值。
2. 第二种方法是该值的选取由各副本节点一起参与。这种方法要求在三阶段协议基础上额外增加一个阶段:主节点收集各副本节点发过来的、可验证来源的、共计 2f+1 个值,并把这些值和客户端请求拼接在一起,然后运行三阶段协议。 之后,每个副本节点基于这些值和各自的状态进行确定的计算,从而得到
所需选取的值。这种计算可以是类似于求中位数等。

相关阅读: PBFT算法流程

本文结束,下篇文章将分享PBFT算法流程补充(二),关注我们,第一时间获取分享!
区块链
2019-12-19 19:08:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
 从定义上看,两者似乎没有直接的联系,但是贝宝金融beibaojinrong以为,区块链作为一种资源存在,具有按需供给的性质,也是云计算的组成部分之一,两者之间的技术是可以相互融合的,达到效用最大化的。
  其一,云计算可以利用自身已经成熟的基础架构或根据实际需求做出相应的反应,从而加速开发应用流程,来满足未来区块链技术的在各个领域的深入发展。其二,“信任度、可靠度、可控制度”是云计算发展需要跨越的三大障碍,利用这些优势和传统云计算技术相结合,将实现基于区块链的分布式计算领域的一些突破。
  云计算内的存储和区块链内的存储都是由普通存储介质组成。而区块链里的存储是作为链里各节点的存储空间,区块链里存储的价值不在于存储本身,而在于相互链接的不可更改的块,是一种特殊的存储服务。云计算里确实也需要这样的存储服务。比如结合城市服务,将数据放在这种类型的存储里,利用不可修改性,让视频、语音、文件等作为公认有效的法律依据。
  云计算里的安全主要是确保应用能够安全、稳定、可靠的运行。这种性质的安全是在传统安全领域范畴,而区块链内的安全是确保每个数据块不被篡改,数据块的记录内容不被没有私钥的用户读取。从贝宝beibao,Swift Code,银行代码,Swift代码www.gendan5.com/swiftcode.html,中国顶级加密货币金融服务提供商角度出发,如果云计算和基于区块链的安全存储产品结合,就能设计出加密存储设备,个人信息的保密性也将得到提高。
云计算内的存储和区块链内的存储都是由普通存储介质组成。只是相应管理物理介质的“文件系统”有所差异。最大的区别是区块链的文件系统可以写和读数据,但数据一旦写入就不能修改和删除。同时还会采用海量的独立副本来确保数据的不可修改性和数据的完整性。区块链存储的重点不在是”块“,而是在于“链”。通过链来确保记录内容的不可修改性,是一种特殊的存储服务。云计算里确实也需要这样的存储服务。如果一定让我来写关于区块链应用的白皮书,我觉得这才是真正的应用点。比如结合”平安城市“,将数据放在这种类型的存储里,利用不可修改性,让视频、语音、文件等作为公认有效的法律依据。
云计算里的区块链的存储服务实现有2种实现方法,第一种是将数据块直接记录在区块链里,第二种是将记录的数据块进行哈希,将哈希值记录在 云计算里的安全主要是确保应用能够安全、稳定、可靠的运行。这种安全属于传统安全领域范畴。而区块链内的安全是确保每个数据块不被篡改,数据块的记录内容不被没有私钥的用户读取。利用这一点,如果和上面介绍的基于区块链的安全存储产品结合,就能设计出的加密存储设备。
管理和协同
区块链技术如何应用于云计算?
数据隐私保护。用户将自己数据上传到云端,首先面对的就是个人信息的安全问题,同时也存在用户数据被泄露的风险,而区块链技术中应用到的密码学技术,将用户上的隐私传数据加密。当个人隐私数据需要读取时,要经过用户的身份认证才可以正确获得解密数据,并且数据各种的操作记录都会被记录到区块链上,可以随时查看。
目前区块链方面的云计算服务,是提供的一些基础的计算、存储、分布式 CDN 等服务。大部分集中在 IaaS 层,其中也有一部分是 PaaS 和 SaaS 层。比如迅雷推出的私人云盘产品;以及用户通过贡献带宽和存储,获得最直接的回报——“链客”等。
但不得不说的是,由于区块链技术带来的“币圈”成为了众多区块链大佬“割韭菜”的镰刀,因此区块链技术也饱受质疑,但是技术本无罪,能够为生活带来更多的便捷,为用户提供安全、稳定服务的技术就是值得在国家监管的框架内推广的。
区块链
2019-12-19 16:38:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>> //bitbay.net/en/exchange-rate/bitcoin-price-usd
币安(binance)API接口
//api.binance.com
pandas join,merge, concat 函数
区块链
2019-12-19 11:37:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一、安全加密
通俗将比特币的匿名性是因为它不需要你证明你是你,只要密码没错就可以完全控制此账号。而开通新账号(比特币地址)也不需要拿一堆资料做实名认证等,你可开通上万账号而不用任何证明,保管好密码(密钥)就行。所以比特币监管难,很难知晓这个账号属于谁,更无法限制此账号的交易。净给党找麻烦 新手入门了解比特币跪荐这个牛逼的答案:比特币是什么。后续我将发布新的答案让大家了解比特币,先给赞,才有动力哈:)。题主说“我现在想购买1个比特币,那我支付的时候应该要用到微信、支付宝或网银吧”,这个也没错,怎么才能拥有第一个比特币呢?题主想到的是怎么我得用钱去买呀,既然有交易记录就能追踪。实际上你是没法拿钱直接购买比特币的!有几种方式购买比特币:找好基友,一手交钱一手交货,他给你的比特币账号上转载1个比特币,你看到你的比特币多了1个币后,你再从微信或者什么的给他发红包。到比特币交易所上注册账号(如同炒股),你往你交易所账上打人民币,再请求交易所买入比特币一枚,交易所便可收下你的人民币,等其他卖家卖出比特币后,卖家收到人民币减少比特币,而者一个比特币便流向你的比特币账号。如果你是大明星,告诉你的百万粉丝们,我的比特币账号是0x0234.... ,那么你的死忠粉便会积极的将他比特币转账给你。拿到别人的比特币账号的密码,你就可任意践踏TA的账号了,转账/买东西等等。综上,题主首先想到的买比特币的途径是一种很自然的那钱买卖商品的逻辑,当然还你许多其他方式。如何保证匿名性,是可以做到的,但一般人很难做到。如,今年7月份爆发的比特币勒索病毒,FBI是可以监控这个比特币地址的所有交易信息的,一但有与现实相关的交易,边可顺藤木瓜。所以这个勒索者都不敢轻易动比特币。外汇经纪商对比http://www.fx61.com/brokerlist对于我们大众来说,这个匿名性会比现有的所有交易形式都高,对于个人来说足够。通常比特币被认为是一个匿名的支付网络。但事实上,比特币可能是世界上最透明的支付网络。同时,如果使用得当,比特币可以提供可接受的隐私性。永远记住养成良好的习惯来保护你的隐私是你自己的责任。而比特币的最大特性不是匿名性而是用最快的传递速度来形成平等财富的转移进而去消除世界上各式各样的意识形态。(等我以后的回答,整理中)
二、数字签名
从根本上来说,数字签名是一种确保电子文档(电子邮件、电子表格、文本文件等)真实可靠的方法。“真实可靠”的含义是:您知道文档是谁创建的,并且知道在作者创建该文档之后,没有人对其进行过任何形式的修改。
在数字签名中,私钥由我掌握,是消息所有者的标志,公钥公开给其他人,用于大家验证发送者身份以及消息是否被篡改。完整的数字签名由签名和验证两个组成部分组成,签名过程消息发送方需要同事提供方数字证书的私钥及公钥将消息加密型成功签名发送给消息接收方,验证过程则由消息接收者通过公钥对消息发送者及信息真伪进行辨别。
在数字签名中客户的公钥是其身份的标志,当使用私钥签名时,如果接收方或验证方用其公钥进行验证并获通过,那么可以肯定,签名人就是拥有私钥的那个人,因为私钥只有签名人知道。
区块链
2019-12-18 16:05:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一看懂这张图你就基本看懂了南非金矿
注册直接扫码


区块链
2019-12-18 13:07:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一、前言
自从比特币大火之后,挖矿就非常流行,由许多人都购买矿机挖坑。许多人说采矿很难,可是采矿不就是用计算机算出哈希吗,这正是计算机的强项啊,怎么会变得很难,迟迟算不出来呢?
二、区块链难度系数
区块链的难度系数:是设计区块链挖矿难易的关键因子,难度系数越低,挖矿越容易。难度系数越高,相应越难。例如比特币的难度系数是18。
难度系数一般是hash值的前置0的个数。
java 区块链中设计合理的难度系数
例如难度系数定为6,也就是区块的有效hash,必须前面有6个0
例如难度系数为6的有效hash为:
00000048bfdc5e67aa448686438f1350a6cc7f4477feb5562b0368a808fdef57
具体代码实现也很简单:
/**
*
* 类名:BlockService.java
* 描述:区块服务
* 时间:2018年3月12日 下午7:05:06
*
* @author cn.wenwuyi
* @version 1.0
* @param hash 区块hash
* @return boolean
*/
private boolean isValidHashDifficulty(String hash) { //定义难度系数
int dificutty = 6; //定义标志符0(当然也可以定义其他,一般是0)
外汇保证金http://www.fx61.com/definitions/muniu/466.htmlchar zero = '0'; int i; for (i = 0; i < hash.length(); i++) { //获得hash字符串的i位置的字符
char ichar = hash.charAt(i); //如果i处的值不为0则跳出
if (ichar != zero) { break;
}
} //判断i是否大于等于难度系数,返回即可
return i >= dificutty;
}
Hash 的有效性跟目标值密切相关,只有小于目标值的 Hash 才是有效的,否则 Hash 无效,必须重算。由于目标值非常小,Hash 小于该值的机会极其渺茫,可能计算10亿次,才算中一次。这就是采矿如此之慢的根本原因。
区块头里面还有一个 Nonce 值,记录了 Hash 重算的次数。第 100000 个区块的 Nonce 值是274148111,即计算了 2.74 亿次,才得到了一个有效的 Hash,该区块才能加入区块链。
三、难度系数的动态调节
比特币选择10分钟来产生区块,也就是1/600 BPS (Blocks/Sec),这个是根据具体设计而制定的, 也是人为的选择。而比特币的交易处理速度最高为:7 TPS (Transactions/Sec), 这个是整个交易验证机制、共识机制,和P2P通讯机制,以及代码实现后所达到的一个技术上限。相比而言,以太坊目前是1/20 BPS和20 TPS,维基链是1/10 BPS和1000+TPS。对于POW共识机制的公链来说,BPS是通过变更挖矿的难度系数来动态调节的。然而对于DPOS机制的公链,BPS是恒定的。
矿具有随机性,没法保证正好十分钟产出一个区块,有时一分钟就算出来了,有时几个小时可能也没结果。总体来看,随着硬件设备的提升,以及矿机的数量增长,计算速度一定会越来越快。
为了将产出速率恒定在十分钟,中本聪还设计了难度系数的动态调节机制。他规定,难度系数每两周(2016个区块)调整一次。如果这两周里面,区块的平均生成速度是9分钟,就意味着比法定速度快了10%,因此接下来的难度系数就要调高10%;如果平均生成速度是11分钟,就意味着比法定速度慢了10%,因此接下来的难度系数就要调低10%。难度系数越调越高(目标值越来越小),导致了采矿越来越难。
区块链
2019-12-17 17:02:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一、区块链简介
什么是区块链?
举个例子来说:区块链就好比是一个特殊的谷歌电子表格,它被世界上每台计算机共享,并连接到因特网上。每次发生事务时,它都会被记录到这张电子表格的一行中。
区块链到底是啥?区块链为何这么重要?区块链技术的未来如何?
任何拥有移动设备或计算机的人都可以通过互联网连接并访问这张电子表格。任何人都可以查看并将事务添加到此电子表格中,但不允许任何人编辑已经存在电子表格里的信息。
就像这个电子表格有“行”一样,区块链有“块”。
块是数据的集合。通过按时间顺序一个接一个地连接数据块,每一块数据都被添加到区块链中,这与电子表格的一行接一行非常相似。
这一系列的连接块一个接一个,使它成为一个块链(即一个区块链)。
这里要强调的一个概要:区块链是一个全球在线数据库,任何人在任何地方都可以使用它。因为它存在于互联网上,所以它是“去中心化的”,这意味着区块链分类账在全世界所有的计算机之间共享,而不是在一个中心位置。
二、区块链共识机制
区块链常被大家称为传递信任的工具,而这信任背后所依赖的就是共识机制。可以将区块链看作是一个全民参与的分布式账本,那么就需要制定一套大家认可接受的规则来解决“怎么记账有效”、“选谁来记账”的问题,而这套规则就是区块链的共识机制。
为了方便理解,我们来举个例子。一个寝室六人准备去聚餐,通过商议,选择吃火锅,那么吃火锅就是大家形成的共识。而商议的方式,少数服从多数就是大家确定就餐地方的共识机制。
在区块链的世界里,因其本身去中心化的特性,导致并没有一个像银行一样的中心记账机构来保证链上所有的记账内容保持一致,因此如何让全网达成共识就显得至关重要。共识机制就是用来解决这一难题的,可以说共识机制是分布式系统的核心。
而在共识机制中,PoW、PoS、DPoS,分别代表区块链网络的三种主要记账规则,它们的作用非常大,直接关系到记账权和相关收益的分配。下面为大家逐一介绍这三种主要的共识机制。
三、工作量证明机制(POW)
POW共识机制由算力决定记账权,按照持有的算力占总算力的百分比来决定获得该次记账权的概率。节点需要不断消耗算力工作,进行哈希计算,以找到期望的随机数。验证节点被称为“矿工”,随机数查找过程称为“挖矿”。“挖矿”有三个重要功能:发行新的货币、维护系统的支付功能、通过算力保障系统安全。
工作量证明机制被认为极其消耗能源,而且是将电能无谓地转化为热能白白消耗掉。因此另一种POS机制的加密货币逐渐风靡。天空币、Byteball、IOTA等非链区块链也为解决比特币耗能而应运而生。
工作量证明机制即对于工作量的证明,是生成要加入到区块链中的一笔新的交易信息(即新区块)时必须满足的要求。在基于工作量证明机制构建的区块链网络中,节点通过计算随机哈希散列的数值解争夺记账权,求得正确的数值解以生成区块的能力是节点算力的具体表现。
工作量证明机制具有完全去中心化的优点,在以工作量证明机制为共识的区块链中,节点可以自由进出。大家所熟知的比特币网络就应用工作量证明机制来生产新的货币。然而,由于工作量证明机制在比特币网络中的应用已经吸引了全球计算机大部分的算力,其他想尝试使用该机制的区块链应用很难获得同样规模的算力来维持自身的安全。同时,基于工作量证明机制的挖矿行为还造成了大量的资源浪费,达成共识所需要的周期也较长,因此该机制并不适合商业应用。
四、权益证明(POS)
POS共识机制由持币数以及持有的时间来决定记账权。持有币数及持有的时间占系统总量的百分比,决定获得该次记账权的概率。
权益证明使用伪随机选举来选择作为下一个区块验证者的节点,基于包括币龄,随机化和节点资产等多种因素。
值得注意的是,在权益证明系统中,区块被称为“锻造”而非挖掘出来。使用权益证明的加密货币通常首先销售一些预先开采的硬币,或是在启动时先使用工作量证明算法,然后切换到权益证明。
在基于工作量证明的系统中,矿工的奖励是越来越多的(被挖出的)加密货币,而权益证明的系统中奖励通常是交易手续费。
想要参与到锻造过程的用户需要先将一定数量的币在网络中锁定作为他们的股权。一个节点股权的多少决定了它被选为下一个区块验证者的机会 - 股权越多,机会越大。为了防止在这个过程中网络不会偏向最富有的节点,选择过程中有一些特殊的步骤。两种最常用的方法是“随机区块选择”和“币龄选择”。
在随机区块选择中,通常通过查找同时有最低的散列值和最多的股权的节点作为验证者,由于股权的数量是公开的,因此下一个锻造者可以被其他节点预测。
币龄选择根据股份的时间长短选择节点。币龄的计算方法是作为股权的币的数量乘以作为股权的天数。一旦一个节点锻造了一个区块,它的币龄就会重置为零,并且还需要等待一定时间后才能锻造下一个区块 - 这样防止股权多的节点垄断区块链。
每一个使用权益证明算法的加密货币都有自己的一套它们认为对自己和用户最好的规则和方法
当一个节点被选为锻造下一个区块时,它首先将检查块中的事务是否有效,然后对块进行签名并将其添加到区块链中。作为奖励,节点获得了这个区块中事务的手续费。
如果一个节点想停止锻造者的身份,那么它的股权和所得的奖励将在一段时间后被释放,从而使网络有时间验证该节点是否向区块链中添加了假区块。
它必须代表的是一种权利,一种固有和内在的价值,第二是加密,也就是说通证的真实性、防篡改性、保护隐私等能力,由密码学予以保障。每一个通证,就是由密码学保护的权利。这种保护,比任何法律、权威和枪炮提供的保护都更坚固、更可靠.第三是可流通,也就是说通证必须能够在一个网络中流动,从而随时随地可以验证。所以明白了通证经济的三要素,就应该知道该不该整治这些点赞乱象股份授权证明.
五、DPOS共识机制
DPOS共识机制是一种基于投票选举的共识算法,类似于代议制民主。在POS的基础上,DPOS先选举若干代理人,由代理人验证和记账,代理人之间轮流出块。DPOS相比POS能大幅度提升选举效率,在牺牲一部分去中心化特性的情况下得到性能提升。
第一,目前已经有成功运行数年,发展相对成熟的DPoS项目。比如,比特股和Steem。
第二,越来越多的币种开始采用DPoS作为共识机制。EOS、Nano(XRB)、LISK、ARK、Aelf、阿希、闪电比特币……大势所趋,挡也挡不住。
第三,完全的去中心化真的有必要吗?如果你读过《人类简史》,应该知道,让人类或者说智人逐渐融合的,有三股最大的力量,即经济上的货币秩序、政治上的帝国秩序、宗教上的全球性宗教。由此可见,经济、政治、宗教(或者说人的心灵)从来都是一个整体,不可孤立看待。
去中心化,一个多么诱人的字眼。在看到的一瞬间,就会联想到民主、平等这些美好的字眼,而中心化则对应着独裁、专制等不好的含义。
但很多人并不清楚,“民主”二字,在历史上相当长的一段时间内,都不是一个褒义词。因为民主,往往意味着“多数人的暴政”。曾几何时,雅典人实施了比今天更为去中心化、更为激进的雅典式民主,万人公民大会,500人民众法庭……哲学之父苏格拉底,就是死于这样的审判 。
或许你不愿相信,但目前美国的政治制度,相对比较先进。即代议制民主,民众投票选举议员,议员组成国会,为国家掌舵。
六、混合证明机制
采用工作量证明机制POW发行新币,采用权益证明机制POS维护网络安全。较典型的就是以太坊采用POW+POS混合共识机制。
如何在公链中建立高效的互信的共识机制,成为世界性的难题. 混合算法于是应运而生,即把两种甚至多种共识机制运用在同一区块链公链的底层机构中,其中,初链的解决方案别出心裁,它结合了一种改进版的PBFT(实用拜占庭)和POW(工作量证明)共识。PoW:(Proof of Work)即工作量证明,根据矿工的工作量对数字货币进行分配,矿机的性能越高,数量越多,工作量越大,得到的数字货币就会越多。Pow共识确保了激励和委员会的选举,而实用拜占庭容错系统降低了拜占庭协议的运行复杂度,天然气代码http://www.kaifx.cn/mt4/kaifx/1788.html从指数级别降低到多项式级别,使拜占庭协议在分布式系统中应用成为可能,是一种状态机副本复制算法,即服务作为状态机进行建模,状态机在分布式系统的不同节点进行副本复制,每个状态机的副本都保存了服务的状态,同时也实现了服务的操作。它承担一种具有瞬时处理高吞吐量事务、交易验证、公平交易委员会的成员轮值公牛的高效共识机制,以及作为一种补偿基础设施去处理不同的基础设施。保留PBFT记录账本的机制不动,将超级节点的选取开放给公链,利用POW协议作为准系统支持超级节点的动态选取和协议达成,将超级节点社区的组建由私有链与联盟链性质转换为公有链性质。
七、区块链发展意义
1.可信存证和查询:区块链提供了链上数据不可篡改、共享可查的链上记录等能力,百度云在数字版权、信息共享平台等区块链应用领域拥有场景实践。
2.可信的积分激励型应用:百度云结合度宇宙、绿洲等Dapp实践,拥有合规框架下的通证激励解决方案。
3.数字资产发行和唯一性保障:莱茨狗是典型的高性能数字资产游戏应用,百度云提供了云端构建数字资产应用的全套方案。
4.多方协作,信任达成,附加金融:区块链提供了多方信任和数据共享机制,百度云在资产证券化、供应链金融、信用卡催收等方向拥有落地实践。
5.清算、结算和支付:百度在区块链平台技术的性能和安全性上持续发力,结合百度自研的超级链技术,在跨境支付和金融清算结算上拥有前瞻布局,拥有全面的区块链支付解决方案。
区块链
2019-12-16 17:47:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>

一比特币
比特币是2008年出现的第一个电子货币,是由中本聪发明的,目前尚不清楚中本聪是一个人还是一群人,不过它们解决了现代金融系统的根本问题:
1.让用户负责金融业务并拥有资金
2.消除交易中间商
3.减少费用
4.使交易透明化,能够防止腐败和削减开支
二、比特币客户端下载
Bitcoin Core 首次同步需要花费很长时间和下载很多数据。您应该确保有足够的带宽以及存储整个块链大小的磁盘空间(超过20GB)。如果你有一个良好的互联网连接,你可以保持您的电脑运行 Bitcoin Core 并且开放 8333 端口以帮助加强网络。 阅读完整的节点指南了解细节。比特币客户端间信息同步所依赖的底层技术原理实际就是P2P。一般第一次启动客户端时,会有一个预置的稳定运行节点(比特币模型下或许可以认为是一些大型矿机?)列表,启动时首先去连接这些稳定运行节点获取信息,运行过程中可以向自己的相邻节点请求相邻节点的相邻节点。总结起来就是初始启动有一个预置列表,之后的每次运行可以根据客户端策略保留特定量历史连接节点去连接。
Bitcoin Core客户端是一个由社区驱动的自由软件项目,基于MIT协议授权发布。
三、注册挖矿网站
你需要到挖矿网站注册(Register)一个帐号(Account),以便保存你的工作成果和收款地址。目前运作的比较好的有
BMP(按积分分配,服务器不稳定会影响收益份额)
注册好帐号后,可能需要点开电子邮件中地址或输入邮件中的确认码,以确认邮箱地址。在网站payment address中填入你的收款地址,将minimum payment(最小自动付款额)设置成0.01,以便尽快收到第一笔付款。
然后注册新的worker帐号(挖矿工人进程),因为每个人可能有多个计算机或多个计算进程可以使用外汇返佣http://www.fx61.com/,所以每个帐号下可注册多个worker。Worker通常有独立的用户名和密码,worker用户名一般是你的帐号名+自定义后缀,密码简单好记就好,worker的密码被别人知道也没有什么安全问题。注意不要和账户或邮箱密码相同即可。
四、比特币客户端操作技巧
以Windows 比特币官方PC客户端为例,打开下载好的安装程序,点击 NEXT。
点击Browse选择比特币钱包的安装地址。然后点击下一步继续操作。注:此地址并非钱包数据的更新地址。
安装会以进度条的形式显示安装进度,等待文件复制完成。
完成安装过程,点击Finish完成安装。勾选Run Bitcoin则立即运行。
找到 快捷方式 或者 开始菜单中的程序,点击运行钱包,会出现启动画面。这时候会自动为您产生一个账号,并开始尝试同步帐户信息,将会花很长时间。
找到存放钱包的目标目录,数据都存放在这个位置,因此可以去下载比较新的离线数据放到这里,然后在离线数据的基础上进行 增量更新,减少更新时间。
注意事项:注意备份自己的帐户,证书等丢失,比特币也会丢失。
区块链
2019-12-16 17:41:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
近两年来,区块链技术的研究与应用呈现出爆发式增长态势,被认为是继大型机、个人电脑、互联网、移动/社交网络之后又一次颠覆式创新。区块链技术是下一代云计算的雏形,有望像互联网一样彻底重塑人类社会活动形态,并实现从目前的信息互联网向价值互联网的转变。相对比国际其他国家的行业发展,我国区块链行业起步稍晚,基础相对欧美稍弱,但从发展势头和潜力来看,我国区块链行业非常有可能实现像互联网及移动支付领域一样的超车。区块链应用有的可以在实体上体现出来,还有一些需要通过互联网平台体现出来,目前处于智能时代,从行业分布来看,金融及企业服务是主力军。
一、金融行业
二、人力资源行业
三、保险行业
四、房地产行业
五、医药行业
前段时间发生了疫苗造假事件,其问题根源在于,在封闭的药监体系内,制药企业可以随意更改工艺参数、产品记录等,作为药品使用者的普通人却没法介入监管,这导致造假屡次发生,而且难以找出是哪个环节出了问题。区块链技术是一种"历史记录不可篡改的数据库技术",它则为药品溯源提供了新的工具。
六、互联网行业
互联网时代,流量、数据为王,互联网大公司靠着这两样东西获利无数,但数据、流量的产生者——广大用户却没能得到分毫收益。而且时至今日,市场逐渐饱和,互联网产品的获客成本也越来越高,即使公司砸下大笔推广费,结果依旧收效甚微,而区块链与加密货币组合的出现则改变了这个困局。
七、汽车行业
其实在汽车行业所存在问题还是很多的,股票代码查询http://www.gendan5.com/topic/lcSearch.html尤其是在整合方面透露出的问题一直困扰着大家。若是将区块链和汽车行业结合在一起其实在汽车行业所存在问题还是很多的,尤其是在整合方面透露出的问题一直困扰着大家。若是将区块链和汽车行业结合在一起,就可以解决很多的问题。比如在制造汽车时候就可以将各个零件的安装情况都记录下来,这样车主既可以全面了解到整个汽车的具体零件,这样在维修、保养时候也更加方便。同时汽车的制造商还可以运用区块链记录这个注册车辆,跟踪车辆的所有权,这样可以更好的保护车主的权益。
八、共享交通
区块链可以用于创建分散式的点对点共享交通应用。让车主和使用者在没有第三方提供的情况下,以安全的方式制定条款明细。
九、慈善
关于慈善方面的抱怨包括效率低下和腐败,这都将妨碍善款到达受捐者的手中。使用区块链技术追踪捐款能让你确认善款的流向。
基于比特币的BitGive基金会等慈善组织使用区块链,从而保证分布式账簿透明 让捐赠者看到受捐者能收到善款。
十、公共福利
公共福利系统是另一个受到低效和官僚主义影响的行业。区块链技术可以以更加精简和安全的方式,帮助评估、核实和分配福利或失业救济。
以上这些只是先简单介绍,区块链在未来的功效及运行范围随着发展情况会更加广泛,也将会对社会的发展产生更多的影响。
区块链
2019-12-16 17:24:04
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>> 摘要:在上一篇文章《 IPSE跨链:BABE共识算法工作原理简析 》中已经介绍了Babe算法,本文将阐述与之协同工作的GRANDPA算法的工作原理。
IPSE“星际搜索”是一个面向IPFS网络的搜索引擎,帮助用户快速搜索分布式网络上的文件,并快速访问。在IPSE的挖矿模型中,用户完成分发、存储等任务,为哈希内容添加语义标签,数据安全存储到IPFS网络,获得挖矿奖励。其token发行和转账依赖于EOS网络。由于区块链网络之间的互操作已经不可避免,数字资产的转换需要一个跨链通道,IPSE开启了2.0计划。
在现有基础上,IPSE将打造应用链,经过跨链系统,实现与其它区块链网络的互通,之后会完成资产映射,使效率提升。IPSE 2.0网络将基于现有的Substrate进行开发设计,连通Polkadot等网络。Polkadot是一个异构的多链架构,其本身也使用Substrate,而在底层,Polkadot使用到了IPFS协议栈的Libp2p协议。
IPFS(星际文件系统)作为一种分布式的超媒体传输协议,目的是构建一个去中心化结构的互联网,这和Substrate/Polkadot的愿景一致。
Polkadot愿景是为互操作性、安全性、可扩展性和创新提供最强大的平台。Polkadot的目标是在2019年底之前发布一条中继链和几条平行链以启动创世块。此后,网络将增加到大约100条平行链。IPSE将会使用到平行链技术,进行2.0网络的设计。为保证IPSE平行链和Polkadot系统的中继链的状态一致性,利用了混合共识机制,分别是BABE和GRANDPA。
GRANDPA:一个值得信赖的共识算法
比特币的工作量证明或其它协议有一个问题,即它们不提供异步安全性,这意味着足够大的攻击可能导致全网混乱。Polkadot为了实现异步安全,将区块的生成和确认进行分开。
Polkadot使用其原始的GRANDPA(基于GHOST的Recursive Ancestor Deriving Prefix Agreement)共识来建立一个更安全,更有弹性的网络。
在良好的网络条件下,GRANDPA几乎可以瞬间完成分块。在糟糕的网络条件下,比如网络分区,GRANDPA可以在分区解析时一次性完成大量的块(理论上是数百万个)。
GRANDPA背后的关键是将区块链的结构纳入共识算法。当考虑一个区块是否有效时,依赖于要考虑该区块的父块的有效性。此区块有效即父块有效,依此类推。另外,参与者不对单个区块进行投票,而是让参与者对他们认为有效的最高区块进行投票,并且GRANDPA算法将利用表决的方式将投票应用到之前所有的区块。之后GRANDPA算法将确定投票数量大于2/3的最佳区块,并生成最终证明(proof-of-finality)。最终证明是通过获得多数票并将它们捆绑在一起成为一条消息来构造的。
换句话说,只要有超过2/3的验证人证明链种包含了某个特定区块,所有和该区块的相联的区块也就获得最终确认。
那么拥有投票权的验证人会作弊吗?首先,验证人运行的时全节点,负责验证和增加区块到 中继链中,2/3保障只有符合全网大多数节点的利益的事物才会被确认。其次,在网络中还有提名人和校对人(钓鱼人)角色,验证人作弊将受到校对人的制约,并将失去提名人的信任。
总体上,BABE算法负责出块,GRANDPA算法负责确认,在2/3递归确定原则的进行下,区块整体效率就获得质的提升。中继链是Polkadot网络的核心,它确保平行链和平行链之间传递信息。信息可以是 交易或任何类型数据。IPSE 2.0平行链构建之后,在BABE+GRANDPA混合共识算法的作用下,将获得高的消息传递效率,并同时能共享共识安全。
区块链
2019-11-21 17:33:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
最近整个区块链行业都比较激动,其他非区块链行业的企业也被这波热潮炒的蠢蠢欲动。其实,越是这个时候,越能沉下心做事的项目才有更大突破的可能。
不要以为一些事情的发生就是意为着全面支持,或许这意为着对违规、不合法的“区块链”项目会进行更加强力的整顿。 区块链项目不等同于虚拟币,通证只是区块链项目对应的激励机制,不是完全等于的关系。不要想靠着区块链这个名头去赚一波快钱。真正研究区块链技术和发展区块链生态的团队和社区才明白其中的痛苦和艰难,只能感受到利益的团队,或许只为了快速地获取短期利益……
区块链
2019-11-21 14:59:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
/ Windows服务 / -- 启动MySQL net start mysql -- 创建Windows服务 sc create mysql binPath= mysqld_bin_path(注意:等号与值之间有空格)
/ 连接与断开服务器 / mysql -h 地址 -P 端口 -u 用户名 -p 密码 SHOW PROCESSLIST -- 显示哪些线程正在运行 SHOW VARIABLES -- 显示系统变量信息
/ 数据库操作 / ------------------ -- 查看当前数据库 SELECT DATABASE(); -- 显示当前时间、用户名、数据库版本 SELECT now(), user(), version(); -- 创建库 CREATE DATABASE[ IF NOT EXISTS] 数据库名 数据库选项 数据库选项: CHARACTER SET charset_name COLLATE collation_name -- 查看已有库 SHOW DATABASES[ LIKE 'PATTERN'] -- 查看当前库信息 SHOW CREATE DATABASE 数据库名 -- 修改库的选项信息 ALTER DATABASE 库名 选项信息 -- 删除库 DROP DATABASE[ IF EXISTS] 数据库名 同时删除该数据库相关的目录及其目录内容
/ 表的操作 / ------------------ -- 创建表 CREATE [TEMPORARY] TABLE[ IF NOT EXISTS] [库名.]表名 ( 表的结构定义 )[ 表选项] 每个字段必须有数据类型 最后一个字段后不能有逗号 TEMPORARY 临时表,会话结束时表自动消失 对于字段的定义: 字段名 数据类型 [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] -- 表选项 -- 字符集 CHARSET = charset_name 如果表没有设定,则使用数据库字符集 -- 存储引擎 ENGINE = engine_name 表在管理数据时采用的不同的数据结构,结构不同会导致处理方式、提供的特性操作等不同 常见的引擎:InnoDB MyISAM Memory/Heap BDB Merge Example CSV MaxDB Archive 不同的引擎在保存表的结构和数据时采用不同的方式 MyISAM表文件含义:.frm表定义,.MYD表数据,.MYI表索引 InnoDB表文件含义:.frm表定义,表空间数据和日志文件 SHOW ENGINES -- 显示存储引擎的状态信息 SHOW ENGINE 引擎名 {LOGS|STATUS} -- 显示存储引擎的日志或状态信息 -- 自增起始数 AUTO_INCREMENT = 行数 -- 数据文件目录 DATA DIRECTORY = '目录' -- 索引文件目录 INDEX DIRECTORY = '目录' -- 表注释 COMMENT = 'string' -- 分区选项 PARTITION BY ... (详细见手册) -- 查看所有表 SHOW TABLES[ LIKE 'pattern'] SHOW TABLES FROM 表名 -- 查看表机构 SHOW CREATE TABLE 表名 (信息更详细) DESC 表名 / DESCRIBE 表名 / EXPLAIN 表名 / SHOW COLUMNS FROM 表名 [LIKE 'PATTERN'] SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern'] -- 修改表 -- 修改表本身的选项 ALTER TABLE 表名 表的选项 eg: ALTER TABLE 表名 ENGINE=MYISAM; -- 对表进行重命名 RENAME TABLE 原表名 TO 新表名 RENAME TABLE 原表名 TO 库名.表名 (可将表移动到另一个数据库) -- RENAME可以交换两个表名 -- 修改表的字段机构(13.1.2. ALTER TABLE语法) ALTER TABLE 表名 操作名 -- 操作名 ADD[ COLUMN] 字段定义 -- 增加字段 AFTER 字段名 -- 表示增加在该字段名后面 FIRST -- 表示增加在第一个 ADD PRIMARY KEY(字段名) -- 创建主键 ADD UNIQUE [索引名](字段名)-- 创建唯一索引 ADD INDEX [索引名](字段名) -- 创建普通索引 DROP[ COLUMN] 字段名 -- 删除字段 MODIFY[ COLUMN] 字段名 字段属性 -- 支持对字段属性进行修改,不能修改字段名(所有原有属性也需写上) CHANGE[ COLUMN] 原字段名 新字段名 字段属性 -- 支持对字段名修改 DROP PRIMARY KEY -- 删除主键(删除主键前需删除其AUTO_INCREMENT属性) DROP INDEX 索引名 -- 删除索引 DROP FOREIGN KEY 外键 -- 删除外键 -- 删除表 DROP TABLE[ IF EXISTS] 表名 ... -- 清空表数据 TRUNCATE [TABLE] 表名 -- 复制表结构 CREATE TABLE 表名 LIKE 要复制的表名 -- 复制表结构和数据 CREATE TABLE 表名 [AS] SELECT * FROM 要复制的表名 -- 检查表是否有错误 CHECK TABLE tbl_name [, tbl_name] ... [option] ... -- 优化表 OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... -- 修复表 REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM] -- 分析表 ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
/ 数据操作 / ------------------ -- 增 INSERT [INTO] 表名 [(字段列表)] VALUES (值列表)[, (值列表), ...] -- 如果要插入的值列表包含所有字段并且顺序一致,则可以省略字段列表。 -- 可同时插入多条数据记录! REPLACE 与 INSERT 完全一样,可互换。 INSERT [INTO] 表名 SET 字段名=值[, 字段名=值, ...] -- 查 SELECT 字段列表 FROM 表名[ 其他子句] -- 可来自多个表的多个字段 -- 其他子句可以不使用 -- 字段列表可以用*代替,表示所有字段 -- 删 DELETE FROM 表名[ 删除条件子句] 没有条件子句,则会删除全部 -- 改 UPDATE 表名 SET 字段名=新值[, 字段名=新值] [更新条件]
/ 字符集编码 / ------------------ -- MySQL、数据库、表、字段均可设置编码 -- 数据编码与客户端编码不需一致 SHOW VARIABLES LIKE 'character_set_%' -- 查看所有字符集编码项 character_set_client 客户端向服务器发送数据时使用的编码 character_set_results 服务器端将结果返回给客户端所使用的编码 character_set_connection 连接层编码 SET 变量名 = 变量值 SET character_set_client = gbk; SET character_set_results = gbk; SET character_set_connection = gbk; SET NAMES GBK; -- 相当于完成以上三个设置 -- 校对集 校对集用以排序 SHOW CHARACTER SET [LIKE 'pattern']/SHOW CHARSET [LIKE 'pattern'] 查看所有字符集 SHOW COLLATION [LIKE 'pattern'] 查看所有校对集 CHARSET 字符集编码 设置字符集编码 COLLATE 校对集编码 设置校对集编码
/ 数据类型(列类型) / ------------------ 1. 数值类型 -- a. 整型 ---------- 类型 字节 范围(有符号位) tinyint 1字节 -128 ~ 127 无符号位:0 ~ 255 smallint 2字节 -32768 ~ 32767 mediumint 3字节 -8388608 ~ 8388607 int 4字节 bigint 8字节 int(M) M表示总位数 - 默认存在符号位,unsigned 属性修改 - 显示宽度,如果某个数不够定义字段时设置的位数,则前面以0补填,zerofill 属性修改 例:int(5) 插入一个数'123',补填后为'00123' - 在满足要求的情况下,越小越好。 - 1表示bool值真,0表示bool值假。MySQL没有布尔类型,通过整型0和1表示。常用tinyint(1)表示布尔型。 -- b. 浮点型 ---------- 类型 字节 范围 float(单精度) 4字节 double(双精度) 8字节 浮点型既支持符号位 unsigned 属性,也支持显示宽度 zerofill 属性。 不同于整型,前后均会补填0. 定义浮点型时,需指定总位数和小数位数。 float(M, D) double(M, D) M表示总位数,D表示小数位数。 M和D的大小会决定浮点数的范围。不同于整型的固定范围。 M既表示总位数(不包括小数点和正负号),也表示显示宽度(所有显示符号均包括)。 支持科学计数法表示。 浮点数表示近似值。 -- c. 定点数 ---------- decimal -- 可变长度 decimal(M, D) M也表示总位数,D表示小数位数。 保存一个精确的数值,不会发生数据的改变,不同于浮点数的四舍五入。 将浮点数转换为字符串来保存,每9位数字保存为4个字节。 2. 字符串类型 -- a. char, varchar ---------- char 定长字符串,速度快,但浪费空间 varchar 变长字符串,速度慢,但节省空间 M表示能存储的最大长度,此长度是字符数,非字节数。 不同的编码,所占用的空间不同。 char,最多255个字符,与编码无关。 varchar,最多65535字符,与编码有关。 一条有效记录最大不能超过65535个字节。 utf8 最大为21844个字符,gbk 最大为32766个字符,latin1 最大为65532个字符 varchar 是变长的,需要利用存储空间保存 varchar 的长度,如果数据小于255个字节,则采用一个字节来保存长度,反之需要两个字节来保存。 varchar 的最大有效长度由最大行大小和使用的字符集确定。 最大有效长度是65532字节,因为在varchar存字符串时,第一个字节是空的,不存在任何数据,然后还需两个字节来存放字符串的长度,所以有效长度是64432-1-2=65532字节。 例:若一个表定义为 CREATE TABLE tb(c1 int, c2 char(30), c3 varchar(N)) charset=utf8; 问N的最大值是多少? 答:(65535-1-2-4-30*3)/3 -- b. blob, text ---------- blob 二进制字符串(字节字符串) tinyblob, blob, mediumblob, longblob text 非二进制字符串(字符字符串) tinytext, text, mediumtext, longtext text 在定义时,不需要定义长度,也不会计算总长度。 text 类型在定义时,不可给default值 -- c. binary, varbinary ---------- 类似于char和varchar,用于保存二进制字符串,也就是保存字节字符串而非字符字符串。 char, varchar, text 对应 binary, varbinary, blob. 3. 日期时间类型 一般用整型保存时间戳,因为PHP可以很方便的将时间戳进行格式化。 datetime 8字节 日期及时间 1000-01-01 00:00:00 到 9999-12-31 23:59:59 date 3字节 日期 1000-01-01 到 9999-12-31 timestamp 4字节 时间戳 19700101000000 到 2038-01-19 03:14:07 time 3字节 时间 -838:59:59 到 838:59:59 year 1字节 年份 1901 - 2155 datetime YYYY-MM-DD hh:mm:ss timestamp YY-MM-DD hh:mm:ss YYYYMMDDhhmmss YYMMDDhhmmss YYYYMMDDhhmmss YYMMDDhhmmss date YYYY-MM-DD YY-MM-DD YYYYMMDD YYMMDD YYYYMMDD YYMMDD time hh:mm:ss hhmmss hhmmss year YYYY YY YYYY YY 4. 枚举和集合 -- 枚举(enum) ---------- enum(val1, val2, val3...) 在已知的值中进行单选。最大数量为65535. 枚举值在保存时,以2个字节的整型(smallint)保存。每个枚举值,按保存的位置顺序,从1开始逐一递增。 表现为字符串类型,存储却是整型。 NULL值的索引是NULL。 空字符串错误值的索引值是0。 -- 集合(set) ---------- set(val1, val2, val3...) create table tab ( gender set('男', '女', '无') ); insert into tab values ('男, 女'); 最多可以有64个不同的成员。以bigint存储,共8个字节。采取位运算的形式。 当创建表时,SET成员值的尾部空格将自动被删除。
/ 选择类型 / -- PHP角度 1. 功能满足 2. 存储空间尽量小,处理效率更高 3. 考虑兼容问题 -- IP存储 ---------- 1. 只需存储,可用字符串 2. 如果需计算,查找等,可存储为4个字节的无符号int,即unsigned 1) PHP函数转换 ip2long可转换为整型,但会出现携带符号问题。需格式化为无符号的整型。 利用sprintf函数格式化字符串 sprintf("%u", ip2long('192.168.3.134')); 然后用long2ip将整型转回IP字符串 2) MySQL函数转换(无符号整型,UNSIGNED) INET_ATON('127.0.0.1') 将IP转为整型 INET_NTOA(2130706433) 将整型转为IP
/ 列属性(列约束) / ------------------ 1. PRIMARY 主键 - 能唯一标识记录的字段,可以作为主键。 - 一个表只能有一个主键。 - 主键具有唯一性。 - 声明字段时,用 primary key 标识。 也可以在字段列表之后声明 例:create table tab ( id int, stu varchar(10), primary key (id)); - 主键字段的值不能为null。 - 主键可以由多个字段共同组成。此时需要在字段列表后声明的方法。 例:create table tab ( id int, stu varchar(10), age int, primary key (stu, age)); 2. UNIQUE 唯一索引(唯一约束) 使得某字段的值也不能重复。 3. NULL 约束 null不是数据类型,是列的一个属性。 表示当前列是否可以为null,表示什么都没有。 null, 允许为空。默认。 not null, 不允许为空。 insert into tab values (null, 'val'); -- 此时表示将第一个字段的值设为null, 取决于该字段是否允许为null 4. DEFAULT 默认值属性 当前字段的默认值。 insert into tab values (default, 'val'); -- 此时表示强制使用默认值。 create table tab ( add_time timestamp default current_timestamp ); -- 表示将当前时间的时间戳设为默认值。 current_date, current_time 5. AUTO_INCREMENT 自动增长约束 自动增长必须为索引(主键或unique) 只能存在一个字段为自动增长。 默认为1开始自动增长。可以通过表属性 auto_increment = x进行设置,或 alter table tbl auto_increment = x; 6. COMMENT 注释 例:create table tab ( id int ) comment '注释内容'; 7. FOREIGN KEY 外键约束 用于限制主表与从表数据完整性。 alter table t1 add constraint `t1_t2_fk` foreign key (t1_id) references t2(id); -- 将表t1的t1_id外键关联到表t2的id字段。 -- 每个外键都有一个名字,可以通过 constraint 指定 存在外键的表,称之为从表(子表),外键指向的表,称之为主表(父表)。 作用:保持数据一致性,完整性,主要目的是控制存储在外键表(从表)中的数据。 MySQL中,可以对InnoDB引擎使用外键约束: 语法: foreign key (外键字段) references 主表名 (关联字段) [主表记录删除时的动作] [主表记录更新时的动作] 此时需要检测一个从表的外键需要约束为主表的已存在的值。外键在没有关联的情况下,可以设置为null.前提是该外键列,没有not null。 可以不指定主表记录更改或更新时的动作,那么此时主表的操作被拒绝。 如果指定了 on update 或 on delete:在删除或更新时,有如下几个操作可以选择: 1. cascade,级联操作。主表数据被更新(主键值更新),从表也被更新(外键值更新)。主表记录被删除,从表相关记录也被删除。 2. set null,设置为null。主表数据被更新(主键值更新),从表的外键被设置为null。主表记录被删除,从表相关记录外键被设置成null。但注意,要求该外键列,没有not null属性约束。 3. restrict,拒绝父表删除和更新。 注意,外键只被InnoDB存储引擎所支持。其他引擎是不支持的。
/ 建表规范 / ------------------ -- Normal Format, NF - 每个表保存一个实体信息 - 每个具有一个ID字段作为主键 - ID主键 + 原子表 -- 1NF, 第一范式 字段不能再分,就满足第一范式。 -- 2NF, 第二范式 满足第一范式的前提下,不能出现部分依赖。 消除符合主键就可以避免部分依赖。增加单列关键字。 -- 3NF, 第三范式 满足第二范式的前提下,不能出现传递依赖。 某个字段依赖于主键,而有其他字段依赖于该字段。这就是传递依赖。 将一个实体信息的数据放在一个表内实现。
/ SELECT / ------------------ SELECT [ALL|DISTINCT] select_expr FROM -> WHERE -> GROUP BY [合计函数] -> HAVING -> ORDER BY -> LIMIT a. select_expr -- 可以用 * 表示所有字段。 select * from tb; -- 可以使用表达式(计算公式、函数调用、字段也是个表达式) select stu, 29+25, now() from tb; -- 可以为每个列使用别名。适用于简化列标识,避免多个列标识符重复。 - 使用 as 关键字,也可省略 as. select stu+10 as add10 from tb; b. FROM 子句 用于标识查询来源。 -- 可以为表起别名。使用as关键字。 SELECT * FROM tb1 AS tt, tb2 AS bb; -- from子句后,可以同时出现多个表。 -- 多个表会横向叠加到一起,而数据会形成一个笛卡尔积。 SELECT * FROM tb1, tb2; -- 向优化符提示如何选择索引 USE INDEX、IGNORE INDEX、FORCE INDEX SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1=1 AND key2=2 AND key3=3; SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1=1 AND key2=2 AND key3=3; c. WHERE 子句 -- 从from获得的数据源中进行筛选。 -- 整型1表示真,0表示假。 -- 表达式由运算符和运算数组成。 -- 运算数:变量(字段)、值、函数返回值 -- 运算符: =, <=>, <>, !=, <=, <, >=, >, !, &&, ||, in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor is/is not 加上ture/false/unknown,检验某个值的真假 <=>与<>功能相同,<=>可用于null比较 d. GROUP BY 子句, 分组子句 GROUP BY 字段/别名 [排序方式] 分组后会进行排序。升序:ASC,降序:DESC 以下[合计函数]需配合 GROUP BY 使用: count 返回不同的非NULL值数目 count(*)、count(字段) sum 求和 max 求最大值 min 求最小值 avg 求平均值 group_concat 返回带有来自一个组的连接的非NULL值的字符串结果。组内字符串连接。 e. HAVING 子句,条件子句 与 where 功能、用法相同,执行时机不同。 where 在开始时执行检测数据,对原数据进行过滤。 having 对筛选出的结果再次进行过滤。 having 字段必须是查询出来的,where 字段必须是数据表存在的。 where 不可以使用字段的别名,having 可以。因为执行WHERE代码时,可能尚未确定列值。 where 不可以使用合计函数。一般需用合计函数才会用 having SQL标准要求HAVING必须引用GROUP BY子句中的列或用于合计函数中的列。 f. ORDER BY 子句,排序子句 order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]... 升序:ASC,降序:DESC 支持多个字段的排序。 g. LIMIT 子句,限制结果数量子句 仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合,按照记录出现的顺序,索引从0开始。 limit 起始位置, 获取条数 省略第一个参数,表示从索引0开始。limit 获取条数 h. DISTINCT, ALL 选项 distinct 去除重复记录 默认为 all, 全部记录
/ UNION / ------------------ 将多个select查询的结果组合成一个结果集合。 SELECT ... UNION [ALL|DISTINCT] SELECT ... 默认 DISTINCT 方式,即所有返回的行都是唯一的 建议,对每个SELECT查询加上小括号包裹。 ORDER BY 排序时,需加上 LIMIT 进行结合。 需要各select查询的字段数量一样。 每个select查询的字段列表(数量、类型)应一致,因为结果中的字段名以第一条select语句为准。
/ 子查询 / ------------------ - 子查询需用括号包裹。 -- from型 from后要求是一个表,必须给子查询结果取个别名。 - 简化每个查询内的条件。 - from型需将结果生成一个临时表格,可用以原表的锁定的释放。 - 子查询返回一个表,表型子查询。 select * from (select * from tb where id>0) as subfrom where id>1; -- where型 - 子查询返回一个值,标量子查询。 - 不需要给子查询取别名。 - where子查询内的表,不能直接用以更新。 select * from tb where money = (select max(money) from tb); -- 列子查询 如果子查询结果返回的是一列。 使用 in 或 not in 完成查询 exists 和 not exists 条件 如果子查询返回数据,则返回1或0。常用于判断条件。 select column1 from t1 where exists (select * from t2); -- 行子查询 查询条件是一个行。 select * from t1 where (id, gender) in (select id, gender from t2); 行构造符:(col1, col2, ...) 或 ROW(col1, col2, ...) 行构造符通常用于与对能返回两个或两个以上列的子查询进行比较。 -- 特殊运算符 != all() 相当于 not in = some() 相当于 in。any 是 some 的别名 != some() 不等同于 not in,不等于其中某一个。 all, some 可以配合其他运算符一起使用。
/ 连接查询(join) / ------------------ 将多个表的字段进行连接,可以指定连接条件。 -- 内连接(inner join) - 默认就是内连接,可省略inner。 - 只有数据存在时才能发送连接。即连接结果不能出现空行。 on 表示连接条件。其条件表达式与where类似。也可以省略条件(表示条件永远为真) 也可用where表示连接条件。 还有 using, 但需字段名相同。 using(字段名) -- 交叉连接 cross join 即,没有条件的内连接。 select * from tb1 cross join tb2; -- 外连接(outer join) - 如果数据不存在,也会出现在连接结果中。 -- 左外连接 left join 如果数据不存在,左表记录会出现,而右表为null填充 -- 右外连接 right join 如果数据不存在,右表记录会出现,而左表为null填充 -- 自然连接(natural join) 自动判断连接条件完成连接。 相当于省略了using,会自动查找相同字段名。 natural join natural left join natural right join select info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex from info, extra_info where info.stu_num = extra_info.stu_id;
/ 导入导出 / ------------------ select * into outfile 文件地址 [控制格式] from 表名; -- 导出表数据 load data [local] infile 文件地址 [replace|ignore] into table 表名 [控制格式]; -- 导入数据 生成的数据默认的分隔符是制表符 local未指定,则数据文件必须在服务器上 replace 和 ignore 关键词控制对现有的唯一键记录的重复的处理 -- 控制格式 fields 控制字段格式 默认:fields terminated by '\t' enclosed by '' escaped by '\\' terminated by 'string' -- 终止 enclosed by 'char' -- 包裹 escaped by 'char' -- 转义 -- 示例: SELECT a,b,a+b INTO OUTFILE '/tmp/result.text' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM test_table; lines 控制行格式 默认:lines terminated by '\n' terminated by 'string' -- 终止
/ INSERT / ------------------ select语句获得的数据可以用insert插入。 可以省略对列的指定,要求 values () 括号内,提供给了按照列顺序出现的所有字段的值。 或者使用set语法。 INSERT INTO tbl_name SET field=value,...; 可以一次性使用多个值,采用(), (), ();的形式。 INSERT INTO tbl_name VALUES (), (), (); 可以在列值指定时,使用表达式。 INSERT INTO tbl_name VALUES (field_value, 10+10, now()); 可以使用一个特殊值 DEFAULT,表示该列使用默认值。 INSERT INTO tbl_name VALUES (field_value, DEFAULT); 可以通过一个查询的结果,作为需要插入的值。 INSERT INTO tbl_name SELECT ...; 可以指定在插入的值出现主键(或唯一索引)冲突时,更新其他非主键列的信息。 INSERT INTO tbl_name VALUES/SET/SELECT ON DUPLICATE KEY UPDATE 字段=值, …;
/ DELETE / ------------------ DELETE FROM tbl_name [WHERE where_definition] [ORDER BY ...] [LIMIT row_count] 按照条件删除。where 指定删除的最多记录数。limit 可以通过排序条件删除。order by + limit 支持多表删除,使用类似连接语法。 delete from 需要删除数据多表1,表2 using 表连接操作 条件。
/ TRUNCATE / ------------------ TRUNCATE [TABLE] tbl_name 清空数据 删除重建表 区别: 1,truncate 是删除表再创建,delete 是逐条删除 2,truncate 重置auto_increment的值。而delete不会 3,truncate 不知道删除了几条,而delete知道。 4,当被用于带分区的表时,truncate 会保留分区
/ 备份与还原 / ------------------ 备份,将数据的结构与表内数据保存起来。 利用 mysqldump 指令完成。 -- 导出 mysqldump [options] db_name [tables] mysqldump [options] ---database DB1 [DB2 DB3...] mysqldump [options] --all--database 1. 导出一张表   mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql) 2. 导出多张表   mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(D:/a.sql) 3. 导出所有表   mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql) 4. 导出一个库   mysqldump -u用户名 -p密码 --lock-all-tables --database 库名 > 文件名(D:/a.sql) 可以-w携带WHERE条件 -- 导入 1. 在登录mysql的情况下:   source 备份文件 2. 在不登录的情况下   mysql -u用户名 -p密码 库名 < 备份文件
/ 视图 / ------------------ 什么是视图: 视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。 视图具有表结构文件,但不存在数据文件。 对其中所引用的基础表来说,视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表,或者其它视图。通过视图进行查询没有任何限制,通过它们进行数据修改时的限制也很少。 视图是存储在数据库中的查询的sql语句,它主要出于两种原因:安全原因,视图可以隐藏一些数据,如:社会保险基金表,可以用视图只显示姓名,地址,而不显示社会保险号和工资数等,另一原因是可使复杂的查询易于理解和使用。 -- 创建视图 CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] VIEW view_name [(column_list)] AS select_statement - 视图名必须唯一,同时不能与表重名。 - 视图可以使用select语句查询到的列名,也可以自己指定相应的列名。 - 可以指定视图执行的算法,通过ALGORITHM指定。 - column_list如果存在,则数目必须等于SELECT语句检索的列数 -- 查看结构 SHOW CREATE VIEW view_name -- 删除视图 - 删除视图后,数据依然存在。 - 可同时删除多个视图。 DROP VIEW [IF EXISTS] view_name ... -- 修改视图结构 - 一般不修改视图,因为不是所有的更新视图都会映射到表上。 ALTER VIEW view_name [(column_list)] AS select_statement -- 视图作用 1. 简化业务逻辑 2. 对客户端隐藏真实的表结构 -- 视图算法(ALGORITHM) MERGE 合并 将视图的查询语句,与外部查询需要先合并再执行! TEMPTABLE 临时表 将视图执行完毕后,形成临时表,再做外层查询! UNDEFINED 未定义(默认),指的是MySQL自主去选择相应的算法。
/ 事务(transaction) / ------------------ 事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败。 - 支持连续SQL的集体成功或集体撤销。 - 事务是数据库在数据晚自习方面的一个功能。 - 需要利用 InnoDB 或 BDB 存储引擎,对自动提交的特性支持完成。 - InnoDB被称为事务安全型引擎。 -- 事务开启 START TRANSACTION; 或者 BEGIN; 开启事务后,所有被执行的SQL语句均被认作当前事务内的SQL语句。 -- 事务提交 COMMIT; -- 事务回滚 ROLLBACK; 如果部分操作发生问题,映射到事务开启前。 -- 事务的特性 1. 原子性(Atomicity) 事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 2. 一致性(Consistency) 事务前后数据的完整性必须保持一致。 - 事务开始和结束时,外部数据一致 - 在整个事务过程中,操作是连续的 3. 隔离性(Isolation) 多个用户并发访问数据库时,一个用户的事务不能被其它用户的事物所干扰,多个并发事务之间的数据要相互隔离。 4. 持久性(Durability) 一个事务一旦被提交,它对数据库中的数据改变就是永久性的。 -- 事务的实现 1. 要求是事务支持的表类型 2. 执行一组相关的操作前开启事务 3. 整组操作完成后,都成功,则提交;如果存在失败,选择回滚,则会回到事务开始的备份点。 -- 事务的原理 利用InnoDB的自动提交(autocommit)特性完成。 普通的MySQL执行语句后,当前的数据提交操作均可被其他客户端可见。 而事务是暂时关闭“自动提交”机制,需要commit提交持久化数据操作。 -- 注意 1. 数据定义语言(DDL)语句不能被回滚,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。 2. 事务不能被嵌套 -- 保存点 SAVEPOINT 保存点名称 -- 设置一个事务保存点 ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点 RELEASE SAVEPOINT 保存点名称 -- 删除保存点 -- InnoDB自动提交特性设置 SET autocommit = 0|1; 0表示关闭自动提交,1表示开启自动提交。 - 如果关闭了,那普通操作的结果对其他客户端也不可见,需要commit提交后才能持久化数据操作。 - 也可以关闭自动提交来开启事务。但与START TRANSACTION不同的是, SET autocommit是永久改变服务器的设置,直到下次再次修改该设置。(针对当前连接) 而START TRANSACTION记录开启前的状态,而一旦事务提交或回滚后就需要再次开启事务。(针对当前事务)
/ 锁表 / 表锁定只用于防止其它客户端进行不正当地读取和写入 MyISAM 支持表锁,InnoDB 支持行锁 -- 锁定 LOCK TABLES tbl_name [AS alias] -- 解锁 UNLOCK TABLES
/ 触发器 / ------------------ 触发程序是与表有关的命名数据库对象,当该表出现特定事件时,将激活该对象 监听:记录的增加、修改、删除。 -- 创建触发器 CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt 参数: trigger_time是触发程序的动作时间。它可以是 before 或 after,以指明触发程序是在激活它的语句之前或之后触发。 trigger_event指明了激活触发程序的语句的类型 INSERT:将新行插入表时激活触发程序 UPDATE:更改某一行时激活触发程序 DELETE:从表中删除某一行时激活触发程序 tbl_name:监听的表,必须是永久性的表,不能将触发程序与TEMPORARY表或视图关联起来。 trigger_stmt:当触发程序激活时执行的语句。执行多个语句,可使用BEGIN...END复合语句结构 -- 删除 DROP TRIGGER [schema_name.]trigger_name 可以使用old和new代替旧的和新的数据 更新操作,更新前是old,更新后是new. 删除操作,只有old. 增加操作,只有new. -- 注意 1. 对于具有相同触发程序动作时间和事件的给定表,不能有两个触发程序。 -- 字符连接函数 concat(str1,str2,...]) concat_ws(separator,str1,str2,...) -- 分支语句 if 条件 then 执行语句 elseif 条件 then 执行语句 else 执行语句 end if; -- 修改最外层语句结束符 delimiter 自定义结束符号 SQL语句 自定义结束符号 delimiter ; -- 修改回原来的分号 -- 语句块包裹 begin 语句块 end -- 特殊的执行 1. 只要添加记录,就会触发程序。 2. Insert into on duplicate key update 语法会触发: 如果没有重复记录,会触发 before insert, after insert; 如果有重复记录并更新,会触发 before insert, before update, after update; 如果有重复记录但是没有发生更新,则触发 before insert, before update 3. Replace 语法 如果有记录,则执行 before insert, before delete, after delete, after insert
/ SQL编程 / ------------------ --// 局部变量 ---------- -- 变量声明 declare var_name[,...] type [default value] 这个语句被用来声明局部变量。要给变量提供一个默认值,请包含一个default子句。值可以被指定为一个表达式,不需要为一个常数。如果没有default子句,初始值为null。 -- 赋值 使用 set 和 select into 语句为变量赋值。 - 注意:在函数内是可以使用全局变量(用户自定义的变量) --// 全局变量 ---------- -- 定义、赋值 set 语句可以定义并为变量赋值。 set @var = value; 也可以使用select into语句为变量初始化并赋值。这样要求select语句只能返回一行,但是可以是多个字段,就意味着同时为多个变量进行赋值,变量的数量需要与查询的列数一致。 还可以把赋值语句看作一个表达式,通过select执行完成。此时为了避免=被当作关系运算符看待,使用:=代替。(set语句可以使用= 和 :=)。 select @var:=20; select @v1:=id, @v2=name from t1 limit 1; select * from tbl_name where @var:=30; select into 可以将表中查询获得的数据赋给变量。 -| select max(height) into @max_height from tb; -- 自定义变量名 为了避免select语句中,用户自定义的变量与系统标识符(通常是字段名)冲突,用户自定义变量在变量名前使用@作为开始符号。 @var=10; - 变量被定义后,在整个会话周期都有效(登录到退出) --// 控制结构 ---------- -- if语句 if search_condition then statement_list [elseif search_condition then statement_list] ... [else statement_list] end if; -- case语句 CASE value WHEN [compare-value] THEN result [WHEN [compare-value] THEN result ...] [ELSE result] END -- while循环 [begin_label:] while search_condition do statement_list end while [end_label]; - 如果需要在循环内提前终止 while循环,则需要使用标签;标签需要成对出现。 -- 退出循环 退出整个循环 leave 退出当前循环 iterate 通过退出的标签决定退出哪个循环 --// 内置函数 ---------- -- 数值函数 abs(x) -- 绝对值 abs(-10.9) = 10 format(x, d) -- 格式化千分位数值 format(1234567.456, 2) = 1,234,567.46 ceil(x) -- 向上取整 ceil(10.1) = 11 floor(x) -- 向下取整 floor (10.1) = 10 round(x) -- 四舍五入去整 mod(m, n) -- m%n m mod n 求余 10%3=1 pi() -- 获得圆周率 pow(m, n) -- m^n sqrt(x) -- 算术平方根 rand() -- 随机数 truncate(x, d) -- 截取d位小数 -- 时间日期函数 now(), current_timestamp(); -- 当前日期时间 current_date(); -- 当前日期 current_time(); -- 当前时间 date('yyyy-mm-dd hh:ii:ss'); -- 获取日期部分 time('yyyy-mm-dd hh:ii:ss'); -- 获取时间部分 date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j'); -- 格式化时间 unix_timestamp(); -- 获得unix时间戳 from_unixtime(); -- 从时间戳获得时间 -- 字符串函数 length(string) -- string长度,字节 char_length(string) -- string的字符个数 substring(str, position [,length]) -- 从str的position开始,取length个字符 replace(str ,search_str ,replace_str) -- 在str中用replace_str替换search_str instr(string ,substring) -- 返回substring首次在string中出现的位置 concat(string [,...]) -- 连接字串 charset(str) -- 返回字串字符集 lcase(string) -- 转换成小写 left(string, length) -- 从string2中的左边起取length个字符 load_file(file_name) -- 从文件读取内容 locate(substring, string [,start_position]) -- 同instr,但可指定开始位置 lpad(string, length, pad) -- 重复用pad加在string开头,直到字串长度为length ltrim(string) -- 去除前端空格 repeat(string, count) -- 重复count次 rpad(string, length, pad) --在str后用pad补充,直到长度为length rtrim(string) -- 去除后端空格 strcmp(string1 ,string2) -- 逐字符比较两字串大小 -- 流程函数 case when [condition] then result [when [condition] then result ...] [else result] end 多分支 if(expr1,expr2,expr3) 双分支。 -- 聚合函数 count() sum(); max(); min(); avg(); group_concat() -- 其他常用函数 md5(); default(); --// 存储函数,自定义函数 ---------- -- 新建 CREATE FUNCTION function_name (参数列表) RETURNS 返回值类型 函数体 - 函数名,应该合法的标识符,并且不应该与已有的关键字冲突。 - 一个函数应该属于某个数据库,可以使用db_name.funciton_name的形式执行当前函数所属数据库,否则为当前数据库。 - 参数部分,由"参数名"和"参数类型"组成。多个参数用逗号隔开。 - 函数体由多条可用的mysql语句,流程控制,变量声明等语句构成。 - 多条语句应该使用 begin...end 语句块包含。 - 一定要有 return 返回值语句。 -- 删除 DROP FUNCTION [IF EXISTS] function_name; -- 查看 SHOW FUNCTION STATUS LIKE 'partten' SHOW CREATE FUNCTION function_name; -- 修改 ALTER FUNCTION function_name 函数选项 --// 存储过程,自定义功能 ---------- -- 定义 存储存储过程 是一段代码(过程),存储在数据库中的sql组成。 一个存储过程通常用于完成一段业务逻辑,例如报名,交班费,订单入库等。 而一个函数通常专注与某个功能,视为其他程序服务的,需要在其他语句中调用函数才可以,而存储过程不能被其他调用,是自己执行 通过call执行。 -- 创建 CREATE PROCEDURE sp_name (参数列表) 过程体 参数列表:不同于函数的参数列表,需要指明参数类型 IN,表示输入型 OUT,表示输出型 INOUT,表示混合型 注意,没有返回值。
/ 存储过程 / ------------------ 存储过程是一段可执行性代码的集合。相比函数,更偏向于业务逻辑。 调用:CALL 过程名 -- 注意 - 没有返回值。 - 只能单独调用,不可夹杂在其他语句中 -- 参数 IN|OUT|INOUT 参数名 数据类型 IN 输入:在调用过程中,将数据输入到过程体内部的参数 OUT 输出:在调用过程中,将过程体处理完的结果返回到客户端 INOUT 输入输出:既可输入,也可输出 -- 语法 CREATE PROCEDURE 过程名 (参数列表) BEGIN 过程体 END
/ 用户和权限管理 / ------------------ -- root密码重置 1. 停止MySQL服务 2. [Linux] /usr/local/mysql/bin/safe_mysqld --skip-grant-tables & [Windows] mysqld --skip-grant-tables 3. use mysql; 4. UPDATE `user` SET PASSWORD=PASSWORD("密码") WHERE `user` = "root"; 5. FLUSH PRIVILEGES; 用户信息表:mysql.user -- 刷新权限 FLUSH PRIVILEGES; -- 增加用户 CREATE USER 用户名 IDENTIFIED BY [PASSWORD] 密码(字符串) - 必须拥有mysql数据库的全局CREATE USER权限,或拥有INSERT权限。 - 只能创建用户,不能赋予权限。 - 用户名,注意引号:如 'user_name'@'192.168.1.1' - 密码也需引号,纯数字密码也要加引号 - 要在纯文本中指定密码,需忽略PASSWORD关键词。要把密码指定为由PASSWORD()函数返回的混编值,需包含关键字PASSWORD -- 重命名用户 RENAME USER old_user TO new_user -- 设置密码 SET PASSWORD = PASSWORD('密码') -- 为当前用户设置密码 SET PASSWORD FOR 用户名 = PASSWORD('密码') -- 为指定用户设置密码 -- 删除用户 DROP USER 用户名 -- 分配权限/添加用户 GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password'] - all privileges 表示所有权限 - *.* 表示所有库的所有表 - 库名.表名 表示某库下面的某表 GRANT ALL PRIVILEGES ON `pms`.* TO 'pms'@'%' IDENTIFIED BY 'pms0817'; -- 查看权限 SHOW GRANTS FOR 用户名 -- 查看当前用户权限 SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER(); -- 撤消权限 REVOKE 权限列表 ON 表名 FROM 用户名 REVOKE ALL PRIVILEGES, GRANT OPTION FROM 用户名 -- 撤销所有权限 -- 权限层级 -- 要使用GRANT或REVOKE,您必须拥有GRANT OPTION权限,并且您必须用于您正在授予或撤销的权限。 全局层级:全局权限适用于一个给定服务器中的所有数据库,mysql.user GRANT ALL ON *.*和 REVOKE ALL ON *.*只授予和撤销全局权限。 数据库层级:数据库权限适用于一个给定数据库中的所有目标,mysql.db, mysql.host GRANT ALL ON db_name.*和REVOKE ALL ON db_name.*只授予和撤销数据库权限。 表层级:表权限适用于一个给定表中的所有列,mysql.talbes_priv GRANT ALL ON db_name.tbl_name和REVOKE ALL ON db_name.tbl_name只授予和撤销表权限。 列层级:列权限适用于一个给定表中的单一列,mysql.columns_priv 当使用REVOKE时,您必须指定与被授权列相同的列。 -- 权限列表 ALL [PRIVILEGES] -- 设置除GRANT OPTION之外的所有简单权限 ALTER -- 允许使用ALTER TABLE ALTER ROUTINE -- 更改或取消已存储的子程序 CREATE -- 允许使用CREATE TABLE CREATE ROUTINE -- 创建已存储的子程序 CREATE TEMPORARY TABLES -- 允许使用CREATE TEMPORARY TABLE CREATE USER -- 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。 CREATE VIEW -- 允许使用CREATE VIEW DELETE -- 允许使用DELETE DROP -- 允许使用DROP TABLE EXECUTE -- 允许用户运行已存储的子程序 FILE -- 允许使用SELECT...INTO OUTFILE和LOAD DATA INFILE INDEX -- 允许使用CREATE INDEX和DROP INDEX INSERT -- 允许使用INSERT LOCK TABLES -- 允许对您拥有SELECT权限的表使用LOCK TABLES PROCESS -- 允许使用SHOW FULL PROCESSLIST REFERENCES -- 未被实施 RELOAD -- 允许使用FLUSH REPLICATION CLIENT -- 允许用户询问从属服务器或主服务器的地址 REPLICATION SLAVE -- 用于复制型从属服务器(从主服务器中读取二进制日志事件) SELECT -- 允许使用SELECT SHOW DATABASES -- 显示所有数据库 SHOW VIEW -- 允许使用SHOW CREATE VIEW SHUTDOWN -- 允许使用mysqladmin shutdown SUPER -- 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。 UPDATE -- 允许使用UPDATE USAGE -- “无权限”的同义词 GRANT OPTION -- 允许授予权限
/ 表维护 /----------------------------------- -- 分析和存储表的关键字分布 ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ... -- 检查一个或多个表是否有错误 CHECK TABLE tbl_name [, tbl_name] ... [option] ... option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED} -- 整理数据文件的碎片 OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
/ 杂项 /------------------------------------- 1. 可用反引号(`)为标识符(库名、表名、字段名、索引、别名)包裹,以避免与关键字重名!中文也可以作为标识符! 2. 每个库目录存在一个保存当前数据库的选项文件db.opt。 3. 注释: 单行注释 # 注释内容 多行注释 /* 注释内容 */ 单行注释 -- 注释内容 (标准SQL注释风格,要求双破折号后加一空格符(空格、TAB、换行等)) 4. 模式通配符: _ 任意单个字符 % 任意多个字符,甚至包括零字符 单引号需要进行转义 \' 5. CMD命令行内的语句结束符可以为 ";", "\G", "\g",仅影响显示结果。其他地方还是用分号结束。delimiter 可修改当前对话的语句结束符。 6. SQL对大小写不敏感 7. 清除已有语句:\c
区块链
2019-12-05 10:59:00