# GO-区块链Demo **Repository Path**: qiangcxq/go-blockchain-demo ## Basic Information - **Project Name**: GO-区块链Demo - **Description**: No description available - **Primary Language**: Go - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-08-26 - **Last Updated**: 2021-08-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 一. 区块链技术的核心概念和原理 #### 1. 应用场景 > 资产: >> 数字资产发行, 支付(跨境支付), 交易, 结算等 > > 记账: >> 股权交易, 供应链金融, 商业积分等 > > 不可篡改: >> 硕源, 众筹, 医疗证明, 存在性证明等 > > 点对点: >> 共享经济, 物联网 > > 隐私(匿名): >> 匿名交易 #### 2. 去中心化记账 > 去中心化,就是把账本保存每个人的计算机中,无中心化 > 问题: >> 账本如何验证正确? >>> hash摘要 = hash(原始交易信息) \ >>> 区块:区块 = 区块头【序号+时间戳+hash摘要】 + 交易记录 \ >>> 区块链: >>>> 1. 区块0=【序号+时间戳+hash摘要】 + 交易记录 >>>> 2. 区块1=【序号+时间戳+hash摘要(区块0的hash+区块1的原理交易信息的hash)】 + 交易记录 >>>> 3. 区块2=【序号+时间戳+hash摘要(区块1的hash+区块2的原理交易信息的hash)】 + 交易记录 >>> >>> 这样每个区块直接都是链连接起来的 >>> >>> 每个交易只需要核对最后一个区块的交易信息 #### 3. 账户所有权 > 账户所有权的问题? >> - 非对称加密算法 >> - 账户就是一个地址,地址对应着一个私钥;私钥是不公开,并且是不能丢的;私钥可使用账户交易 >> - 私钥进行各种的推算可以得到账户地址,但是账户地址无法后推计算得到私钥 >> - 交易进行hash得到摘要;用私钥对摘要进行签名; 签名就代表着交易是合法并且是安全的;如果别人修改了交易,签名就会验证失败 > > 如何进行签名? >> - 交易摘要 = hash(原始交易记录) >> - sign(交易摘要 + 私钥) 等到签名 > > 广播交易 ? >> 通过各个节点向相邻的节点广播,来得到全节点广播 > > 验证交易 >> - 验证签名 >>> hash(交易记录) == 验证运算(签名+付款地址) >> - 写入账本,广播出去 > > 验证签名 >> - 签名 = sign(交易摘要, 私钥);我的理解sgin底层会用私钥把私钥推算成账户地址,然后再跟交易摘要加密,这个加密是可逆的 >> - 验证运算(签名, 账户地址) 是一个解密的过程 #### 4. 为什么记账 > - 记账会消耗计算机资源;占用计算机的资源 > - 但是记账会得到奖励 > - 多个人记账机会出现记账混乱,这时候就出现了工作量证明机制 > - 规则: >> 工作量证明: >>> 1. 一段时间内(10分钟)只能有一个人记账成功 >>> 2. 通过解决密码学难题(即工作量证明)竞争唯一的记账权 >>> 3. 其他节点复制其他记账结果 >>> >>> 例子: >>> >>>> hash(上一个hash值, 交易记录集) = 456ddffffafa \ >>>> hash(上一个hash值, 交易记录集, 随机数) = 0000fafafdd234开头满足n个0的hash值,就代表挖矿(记账成功) \ >>>不断换随机数得到满足要求 >>>> >>>>> 交易记录集: >>>>> - 收集广播中还没有被记录账本的交易 >>>>> - 交易的有效性验证 >>>>> - 添加一笔给自己转账的交易(挖矿奖励) #### 5. 共识机制 > 问题: > 如果两个人同时完成工作量证明,使用谁的区块? >> 共识机制的问题;通过下面的问题得到答案;就是大家都认同的,并且在此区块上延续区块,谁的区块链长,也就得到大家的共识,那这个区块就是挖矿成功,记账成功,而得到奖励 > > 为什么要遵守协议呢? >> 节点工作量只有在其他节点都认同其是有效的,才算记账成功 >>> 也就说就是累计工作量最大的区块链(最长的链) > > 区块链交叉解决 >> 如果哪个区块最长,下一个区块最快完成工作量证明;该区块链就就为记账成功 #### 6. 课外进阶 > - P2P的原理以及实现 > - Merkle树 > - UTXO模型以及交易脚本 ### 二. 区块链技术核心原理实现 #### 1. 环境准备 > 根据自己的熟悉的语言环境既可,此刻我用的go #### 2. 构建区块链的结构 ``` // 区块结构 type BlockChain struct { Index int64 //索引 Timestamp time.Time //时间戳 Transactions []Transaction //交易的信息 WorkProof int64 //工作量证明 PreHash string //上一个区块的hash值 } // 交易体的接口 type Transaction struct { Sender string `json:"sender"` //交易者 Recipient string `json:"recipient"` //接受者 Amount float64 `json:"amount"` //交易的金额 } ``` > - 新建区块 (NewBlockChain) > - 新建交易体 (NewTransaction) > - 增加交易体 (AddTransaction) > - 节点的区块链 (BlockChains) > - 区块的交易体(Transactions) > - 最后一个区块链(LastBlockChain) #### 3. 生成上一个hash > - 通过上一个区块,生成json字符串 > - 使用sha256加密得到摘要(散列值) ``` func GenerateHash(chain BlockChain) string { data, err := json.Marshal(chain) if err != nil { log.Println(err.Error()) return "" } hash := sha256.New() hash.Write(data) strBytes := hash.Sum(nil) return hex.EncodeToString(strBytes) } ``` #### 4. 工作量证明(挖矿) > - 得到上一个区块的工作量证明 > - 上一个工作量证明+当前测试的工作量证明拼接位utf8的字符串 > - 通过sha256加密拼接的字符串得到摘要(散列值),求得前面为4个0的散列值的当前工作量证明数 ``` func WorkProof(lastProof int64) int64 { proof := int64(0) for !VerifyWorkProof(lastProof, proof) { proof++ } fmt.Println() fmt.Println(proof) return proof } //验证工作量证明 func VerifyWorkProof(lastProof, currentProof int64) bool { proofStr := fmt.Sprintf("%d%d", lastProof, currentProof) hash := sha256.New() hash.Write([]byte(proofStr)) bytes := hash.Sum(nil) hashCode := hex.EncodeToString(bytes) fmt.Printf("\r%s", hashCode) if hashCode[0:4] == "0000" { return true } return false } ``` #### 5. 注册节点 > - 定义其他节点列表(Nodes) > - 定义注册节点(RegisterNode) ``` var Nodes = make([]string, 0) ``` >> - 所谓的节点就是通过url访问的host:port >> - 这块最好的实现就是放入redis中,实现所有节点都可访问 #### 6. 共识机制(解决节点的区块链的不一致) > - 把自己的节点的区块链与其他节点所有区块链做对比 > - 对比: 区块链的长度,区块的链合法性(上一个hash是否正确, 工作证明是否正确) > - 把自己的区块链替换为得到的最合法最长的区块链 ``` // 验证区块链的是否是合法的 func VerifyChains(chains []BlockChain) bool { lastBlock := chains[0] index := 1 for index < len(chains) { currentBlock := chains[index] if currentBlock.PreHash != GenerateHash(lastBlock) || !VerifyWorkProof(lastBlock.WorkProof, currentBlock.WorkProof) { return false } index++ lastBlock = currentBlock } return true } // 实现共识,多个节点如何获取最长最有效的区块链 func ResolveConflictFromNodes() bool { maxLength := len(BlockChains) newChains := make([]BlockChain, 0) for _, node := range Nodes { resp, err := http.Get(fmt.Sprintf("http://%s/blockChains", node)) if err != nil { log.Println(err.Error()) continue } contentBytes, err := io.ReadAll(resp.Body) resp.Body.Close() allChains := FullBlockChains{} json.Unmarshal(contentBytes, &allChains) if allChains.Length > maxLength && VerifyChains(allChains.BlockChains) { maxLength = allChains.Length newChains = allChains.BlockChains } } if len(newChains) > 0 { BlockChains = newChains return true } return false } ``` #### 7. 其他介绍 > - 代码未完成一些功能: >> - 账户创建 >> - 交易签名 >> - p2p的实现以及嵌入 >> - UTXO的实现 >> - Merkle树体现 > > 等了解更深了,会尝试去添加的 >