tp钱包正版app下载|比特币挖矿程序golang
tp钱包正版app下载|比特币挖矿程序golang
如何使用Go语言编写自己的区块链挖矿算法 - 知乎
如何使用Go语言编写自己的区块链挖矿算法 - 知乎首发于安全客切换模式写文章登录/注册如何使用Go语言编写自己的区块链挖矿算法小安有思想的安全新媒体译文声明本文是翻译文章,文章原作者Coral Health,文章来源:http://medium.com原文地址:https://medium.com/@mycoralhealth/code-your-own-blockchain-mining-algorithm-in-go-82c6a71aba1f一、前言随着近期比特币(Bitcoin)以及以太坊(Ethereum)挖矿热潮的兴起,人们很容易对此浮想联翩。对于刚进入该领域的新手而言,他们会听到各种故事,比如许多人将GPU堆满仓库来疯狂挖矿,每月能挖到价值数百万美元的加密货币(cryptocurrency)。那么就是什么是密币挖矿?挖矿的原理是什么?怎么样才能编写自己的挖矿算法?在本文中,我们会给大家一一解答这些问题,然后介绍如何编写自己的挖矿算法。我们将这种算法称为Proof of Work(工作量证明)算法,该算法是比特币及以太坊这两种最流行的加密货币的基础。无需担忧,我们会给大家介绍得明明白白。二、什么是密币挖矿物以稀为贵,对加密货币来说也是如此。如果任何人在任何时间都可以随意生产任意多的比特币,那么比特币作为一种货币则毫无价值可言(稍等,这不正是美联储常干的事吗……)。比特币算法每隔10分钟就会向比特币网络中的获胜成员颁发一次比特币,总量大约在122年内会达到最大值。这种颁发机制可以将通货膨胀率控制在一定范围内,因为算法并没有在一开始就给出所有密币,而是随着时间推移逐步产出。在这种算法下,为了获取比特币奖励,矿工们需要付出“劳动”,与其他矿工竞争。这个过程也称为“挖矿”,因为该过程类似于黄金矿工的采矿过程,为了找到一点黄金,工人们也需要付出时间及精力最终才能获取胜利果实(有时候也会竹篮打水一场空)。比特币算法会强制参与者(或节点)进行挖矿,同时相互竞争,确保比特币产出速度不至于太快。三、如何挖矿如果在Google上搜索“如何挖比特币?”,我们会看到大量结果,纷纷解释挖掘比特币需要节点(用户或者主机)来解决复杂的数学难题。虽然这种说法从技术角度来看没有问题,但简单称之为“数学”问题显然有点太过于僵硬,挖矿的过程其实非常有趣。我们要了解一些密码学知识以及哈希算法,才能理解挖矿的原理。密码学简介单向加密以人眼可读的数据作为输入(如“Hello world”),然后通过某个函数生成难以辨认的输出。这些函数(或者算法)在性质及复杂度上各不相同。算法越复杂,想逆向分析就越难。因此,加密算法在保护数据(如用户密码以及军事代码)方面至关重要。以非常流行的SHA-256算法为例,我们可以使用哈希生成网站来生成SHA-256哈希值。比如,我们可以输入“Hello world”,观察对应的哈希结果:我们可以重复计算“Hello world”的哈希值,每次都能得到相同的结果。在编程中,输入相同的情况下,如果每次都得到同样的输出,这个过程称之为“幂等性(idempotency)”。对于加密算法而言,我们很难通过逆向分析来推导原始输入,但很容易验证输出结果是否正确,这是加密算法的一个基本特性。比如前面那个例子,我们很容易就能验证“Hello world”的SHA-256哈希值是否正确,但很难通过给定的哈希值来推导原始输入为“Hello world”。这也是我们为何将这类加密方法称为单向加密的原因所在。比特币使用的是双重SHA-256算法(Double SHA-256),也就是说它会将“Hello world”的SHA-256哈希值作为输入,再计算一次SHA-256哈希。在本文中,为了方便起见,我们只计算一次SHA-256哈希。挖矿理解加密算法后,我们可以回到密币挖矿这个主题上。比特币需要找到一些方法,让希望获得比特币的参与者能通过加密算法来“挖矿”,以便控制比特币的产出速度。具体说来,比特币会让参与者计算一堆字母和数字的哈希值,直到他们算出的哈希值中“前导0”的位数超过一定长度为止。比如,回到前面那个哈希计算网站,输入“886”后我们可以得到前缀为3个0的哈希值。问题是我们如何才能知道“886”的哈希值开头包含3个零呢?这才是重点。在撰写本文之前,我们没有办法知道这一点。从理论上讲,我们必须尝试字母和数字的各种组合,对结果进行测试,直到获得满足要求的结果为止。这里我们事先给出了“886”的哈希结果以便大家理解。任何人都能很容易验证出“886”是否会生成3位前导零的哈希结果,这样就能证明我们的确做了大量测试、检查了大量字母和数字的组合,最终得到了这一结果。因此,如果我们是第一个获得这个结果的人,其他人可以快速验证“886”的正确性,这个工作量的证明过程可以让我赢得比特币。这也是为什么人们把比特币的一致性算法称之为Proof-of-Work(工作量证明)算法。但如果我的运气爆表,第一次尝试就生成了3个前导零结果呢?这种事情基本不可能发生,偶然的节点在首次尝试时就成功挖掘新块(向大家证明他们的确做了这项工作)的可能性微乎其微,相反其他数百万个节点需要付出大量工作才能找到所需的散列。你可以继续尝试一下,随便输入一些字母和数字的组合,我打赌你得不到3个前导零的结果。比特币的约束条件比这个例子更加复杂(要求得到更多位前导零!),并且它能动态调整难度,以确保工作量不会太轻或者太重。请记住,比特币算法的目标是每隔10分钟产出一枚比特币。因此,如果太多人参与挖矿,比特币需要加大工作量证明难度,实现难度的动态调整。从我们的角度来看,调整难度等同于增加更多位前导零。因此,大家可以明白比特币的一致性算法比单纯“解决数学难题”要有趣得多。四、开始编程背景知识已经介绍完毕,现在我们可以使用Proof-of-Work算法来构建自己的区块链(Blockchain)程序。我选择使用Go语言来实现,这是一门非常棒的语言。在继续之前,我建议你阅读我们之前的一篇博客:《用200行Go代码实现自己的区块链》。这不是硬性要求,但我们会快速掠过以下某些例子,如果你想了解更多细节,可以参考那篇文章。如果你已经了如指掌,可以直接跳到“Proof of Work”章节。整体架构如下:我们需要一台Go服务器,为了简单起见,我会将所有代码放在一个main.go文件中。这个文件提供了关于区块链逻辑的所有信息(包括Proof of Work),也包含所有REST API对应的处理程序。区块链数据是不可改变的,我们只需要GET以及POST请求即可。我们需要使用浏览器发起GET请求来查看数据,使用Postman来POST新的区块(也可以使用curl)。导入依赖首先我们需要导入一些库,请使用go get命令获取如下包:1、github.com/davecgh/go-spew/spew:帮助我们在终端中直接查看结构规整的区块链信息。2、github.com/gorilla/mux:用来搭建Web服务器的一个库,非常好用。3、github.com/joho/godotenv:可以从根目录中的.env文件中读取环境变量。首先我们可以在根目录中创建一个.env文件,用来存放后面需要的一个环境变量。.env文件只有一行:ADDR=8080。在根目录的main.go中,将依赖包以声明的方式导入:package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"strconv"
"strings"
"sync"
"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
Difficulty int
Nonce string
}
var Blockchain []Block
type Message struct {
BPM int
}
var mutex = &sync.Mutex{}difficulty是一个常量,用来定义哈希值中需要的前导零位数。前导零位数越多,我们越难找到正确的哈希值。我们先从1位前导零开始。Block是每个区块的数据模型。不要担心Nonce字段,后面我们会介绍。Blockchain由多个Block组成,代表完整的区块链。我们会在REST API中,使用POST请求提交Message以生成新的Block。我们声明了一个互斥量mutex,后面我们会使用该变量避免出现数据竞争,确保多个区块不会同一时间生成。Web服务器让我们快速搭一个Web服务器。首先创建一个run函数,main函数随后会调用这个函数来运行服务器。我们在makeMuxRouter()中声明了相应的请求处理函数。请注意,我们需要通过GET请求获取区块链,通过POST请求添加新的区块。区块链无法更改,因此我们不需要实现编辑或删除功能。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
}
func makeMuxRouter() http.Handler {
muxRouter := mux.NewRouter()
muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET")
muxRouter.HandleFunc("/", handleWriteBlock).Methods("POST")
return muxRouter
}httpAddr := os.Getenv("ADDR")这行语句会从我们前面创建的.env文件中提取:8080这个信息。我们可以通过浏览器访问http://localhost:8080/这个地址来访问我们构建的应用。现在我们需要编写GET处理函数,在浏览器中显示区块链信息。我们还需要添加一个respondwithJSON函数,一旦API调用过程中出现错误就能以JSON格式返回错误信息。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))
}
func respondWithJSON(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
w.Header().Set("Content-Type", "application/json")
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)
}请注意:如果觉得我们讲得太快,可以参考之前的文章,文章中详细解释了每个步骤。现在编写POST处理函数,这个函数可以实现新区块的添加过程。我们使用Postman来发起POST请求,向http://localhost:8080发送JSON数据(如{“BPM”:60}),其中包含前面你记录下的那个脉搏次数。func handleWriteBlock(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
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()
//ensure atomicity when creating new block
mutex.Lock()
newBlock := generateBlock(Blockchain[len(Blockchain)-1], m.BPM)
mutex.Unlock()
if isBlockValid(newBlock, Blockchain[len(Blockchain)-1]) {
Blockchain = append(Blockchain, newBlock)
spew.Dump(Blockchain)
}
respondWithJSON(w, r, http.StatusCreated, newBlock)
}请注意代码中mutex的lock以及unlock操作。在写入新的区块之前,我们需要锁定互斥量,不然多次写入就会造成数据竞争。细心的读者会注意到generateBlock函数,这是处理Proof of Work的关键函数,稍后我们会介绍。基本的区块链函数在介绍Proof of Work之前,先整理下基本的区块链函数。我们添加了一个isBlockValid函数,确保我们的索引能正确递增,并且当前区块的PrevHash与前一个区块的Hash相匹配。我们也添加了一个calculateHash函数,用来生成哈希值,以计算Hash以及PrevHash。我们将Index、Timestamp、BPM、PrevHash以及Nonce(稍后我们会介绍这个字段)串在一起,计算出一个SHA-256哈希。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 calculateHash(block Block) string {
record := strconv.Itoa(block.Index) + block.Timestamp + strconv.Itoa(block.BPM) + block.PrevHash + block.Nonce
h := sha256.New()
h.Write([]byte(record))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}五、Proof of Work现在来介绍挖矿算法,也就是Proof of Work。在新的Block加入blockchain之前,我们需要确保Proof of Work任务已经完成。我们先以一个简单的函数开始,该函数可以检查Proof of Work过程中生成的哈希是否满足我们设置的约束条件。我们的约束条件如下:1、Proof of Work生成的哈希必须具有特定位数的前导零。2、前导零的位数由程序刚开始定义的difficulty常量来决定(这里这个值为1).3、我们可以增加难度值来提高Proof of Work的难度。首先构造一个函数:isHashValid:func isHashValid(hash string, difficulty int) bool {
prefix := strings.Repeat("0", difficulty)
return strings.HasPrefix(hash, prefix)
}Go语言在strings包中提供了Repeat以及HasPrefix函数,使用起来非常方便。我们定义了一个prefix变量,用来表示前导零位数,然后检查哈希值的前导零位数是否满足要求,满足则返回True,不满足则返回False。接下来创建generateBlock函数。func generateBlock(oldBlock Block, BPM int) Block {
var newBlock Block
t := time.Now()
newBlock.Index = oldBlock.Index + 1
newBlock.Timestamp = t.String()
newBlock.BPM = BPM
newBlock.PrevHash = oldBlock.Hash
newBlock.Difficulty = difficulty
for i := 0; ; i++ {
hex := fmt.Sprintf("%x", i)
newBlock.Nonce = hex
if !isHashValid(calculateHash(newBlock), newBlock.Difficulty) {
fmt.Println(calculateHash(newBlock), " do more work!")
time.Sleep(time.Second)
continue
} else {
fmt.Println(calculateHash(newBlock), " work done!")
newBlock.Hash = calculateHash(newBlock)
break
}
}
return newBlock
}我们创建了一个newBlock变量,将前一个区块的哈希值保存到PrevHash字段中,确保区块链满足连续性要求。其他字段的含义应该比较明显:1、Index不断增加;2、Timestamp是当前时间的字符串表现形式;3、BPM是前面记录下的心率;4、Difficulty直接摘抄自最开头定义的那个常量。这个例子中我们不会使用这个字段,但如果我们想进一步验证,确保难度值与哈希结果一致(也就是说哈希结果的前导零位数为N,那么Difficulty的值应该也为N,否则区块链就会遭到破坏),那么这个字段就非常有用。这个函数中的for循环非常重要,我们详细介绍一下:1、获取i的十六进制形式,将该值赋给Nonce。我们需要一种方法来将动态变化的一个值加入哈希结果中,这样如果我们没有得到理想的哈希值,就可以通过calculateHash函数继续生成新的值。我们在calculateHash计算过程中添加的动态值就称为“Nonce”。2、在循环中,我们的i和Nonce值从0开始递增,判断生成的哈希结果中前导零位数是否与difficulty相等。如果不相等,我们进入新的迭代,增加Nonce,再次计算。3、我们加了1秒的休眠操作,模拟解决Proof of Work所需的时间。4、继续循环,直到计算结果中包含特定位数的前导零为止,此时我们成功完成了Proof of Work任务。只有在这种情况下,我们的Block才能通过handleWriteBlock处理函数添加到blockchain中。现在我们已经完成了所有函数,因此让我们完成main函数吧:func main() {
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
go func() {
t := time.Now()
genesisBlock := Block{}
genesisBlock = Block{0, t.String(), 0, calculateHash(genesisBlock), "", difficulty, ""}
spew.Dump(genesisBlock)
mutex.Lock()
Blockchain = append(Blockchain, genesisBlock)
mutex.Unlock()
}()
log.Fatal(run())
}使用godotenv.Load()语句我们可以完成环境变量(:8080端口)的加载,以便通过浏览器进行访问。区块链得有一个起点,所以我们使用一个go例程来创建创世区块。然后使用前面构造的run()函数启动Web服务器。六、大功告成大家可以访问Github获取完整版代码。来跑一下看看效果。首先使用go run main.go命令启动程序。然后在浏览器中访问http://localhost:8080:区块链中已经有一个创世区块。现在打开Postman,通过POST请求向服务器发送包含BPM字段(心率数据)的JSON数据。发送完请求后,我们可以在终端中观察操作结果。可以看到,我们的计算机会使用不断递增的Nonce值来创建新的哈希,直到计算出来的哈希满足前导零位数要求为止。完成Proof of Work任务后,我们可以看到一则提示消息:work done!。我们可以检验这个哈希值,发现它的确满足difficulty所设置的前导零位数要求。这意味着从理论上来讲,我们使用BPM = 60参数所生成的新区块现在应该已经添加到区块链中。刷新浏览器看一下结果:大功告成!我们的第二个区块已经添加到创世区块后面。也就是说,我们成功通过POST请求发送了区块,这个操作触发了挖矿过程,当且仅当Proof of Work得以解决时,新的区块才能添加到区块链中。七、下一步考虑非常好,前面学到的知识非常重要。Proof of Work是比特币、以太坊以及其他区块链平台的基础。我们前面的分析意义非凡,虽然这个例子使用的难度值并不大,但实际环境中Proof of Work区块链的工作原理就是把难度提高到较高水平而已。现在你已经深入了解了区块链技术的关键组成部分,后面的路需要你自己去走,我们建议你可以继续学习以下知识:1、学习区块链网络的工作原理,可以参考我们的网络教程。2、学习如何以分布式方式存储大型文件并与区块链交互,可以参考我们的IPFS教程。如果你还想继续深入学习,可以考虑了解一下Proof of Stake(权益证明)。尽管目前大多数区块链使用Proof of Work作为一致性算法,但公众越来越关注Proof of Stake。人们普遍认为,未来以太坊将从Proof of Work迁移至Proof of Stake。本文翻译自:medium.com如若转载,请注明出处:medium.com安全客 - 有思想的安全新媒体编辑于 2018-03-21 19:16挖矿Go 语言赞同 32添加评论分享喜欢收藏申请转载文章被以下专栏收录安全客安全客,致力于传播有思想的安 [译] 用 Go 编写你自己的区块链挖矿算法!-CSDN博客 [译] 用 Go 编写你自己的区块链挖矿算法! 最新推荐文章于 2024-03-15 15:29:28 发布 weixin_34163741 最新推荐文章于 2024-03-15 15:29:28 发布 阅读量1.1k 收藏 2 点赞数 文章标签: 区块链 json postman 原文链接:https://juejin.im/post/5ad6d2ff51882579ef4f7cf0 版权 原文地址:Code your own blockchain mining algorithm in Go!原文作者:Coral Health译文出自:掘金翻译计划本文永久链接:github.com/xitu/gold-m…译者:EmilyQiRabbit校对者:stormluke,mingxing47 如果你对下面的教程有任何问题或者建议,加入我们的 Telegram 消息群,可以问我们所有你想问的! 随着最近比特币和以太坊挖矿大火,很容易让人好奇,这么大惊小怪是为什么。对于加入这个领域的新人,他们会听到一些疯狂的故事:人们用 GPU 填满仓库,每个月赚取价值数百万美元的加密货币。电子货币挖矿到底是什么?它是如何运作的?我如何能试着编写自己的挖矿算法? 在这篇博客中,我们将会带你解答上述每一个问题,并最终完成一篇教你如何编写自己的挖矿算法的教程。我们将展示给你的算法叫做工作量证明,它是比特币和以太坊这两个最流行的电子货币的基础。别急,我们马上将为你解释它是如何运作的。 什么是电子货币挖矿 为了有价值,电子货币需要有一定的稀缺性。如果谁都可以随时生产出他们想要的任意多的比特币,那么作为货币,比特币就毫无价值了。(等一下,美国联邦储备不是这么做了么?打脸)比特币算法每十分钟将会发放一些比特币给网络中一个获胜成员,这样最多可以供给大约 122 年。由于定量的供应并不是在最一开始就全部发行,这种发行时间表在一定程度上也控制了膨胀。随着时间流逝,发行地速度将越来越慢。 决定胜者是谁并给出比特币的过程需要他完成一定的“工作”,并与同时也在做这个工作的人竞争。这个过程就叫做挖矿,因为它很像采矿工人花费时间完成工作并最终(希望)找到黄金。 比特币算法要求参与者,或者说节点,完成工作并相互竞争,来保证比特币不会发行过快。 挖矿是如何运作的? 一次谷歌快速搜索“比特币挖矿如何运作?”将会给你很多页的答案,解释说比特币挖矿要求节点(你或者说你的电脑)解决一个很难的数学问题。虽然从技术上来说这是对的,但是简单的把它称为一个“数学”问题太过有失实质并且太过陈腐。了解挖矿运作的内在原理是非常有趣的。为了学习挖矿运作原理,我们首先要了解一下加密算法和哈希。 哈希加密的简短介绍 单向加密的输入值是能读懂的明文,像是“Hello world”,并施加一个函数在它上面(也就是,数学问题)生成一个不可读的输出。这些函数(或者说算法)的性质和复杂度各有不同。算法越复杂,逆运算解密就越困难。因此,加密算法能有力保护像用户密码和军事代码这类事物。 让我们来看一个 SHA-256 的例子,它是一个很流行的加密算法。这个哈希网站能让你轻松计算 SHA-256 哈希值。让我们对“Hello world”做哈希运算来看看将会得到什么: 试试对“Hello world”重复做哈希运算。你每次都将会得到同样的哈希值。给定一个程序相同的输入,反复计算将会得到相同的结果,这叫做幂等性。 加密算法一个基本的属性就是(输出值)靠逆运算很难推算输入值,但是(靠输入值)很容易就能验证输出值。例如,用上述的 SHA-256 哈希算法,其他人将 SHA-256 哈希算法应用于“Hello world”很容易的就能验证它确实输出同一个哈希值结果,但是想从这个哈希值结果推算出“Hello world”将会非常困难。这就是为什么这类算法被称为单向。 比特币采用 双 SHA-256 算法,这个算法就是简单的将 SHA-256 再一次应用于“Hello world”的 SHA-256 哈希值。在这篇教程中,我们将只应用 SHA-256 算法。 挖矿 现在我们知道了加密算法是什么了,我们可以回到加密货币挖矿的问题上。比特币需要找到某种方法,让希望得到比特币参与者“工作”,这样比特币就不会发行的过快。比特币的实现方式是:让参与者不停地做包含数字和字母的哈希运算,直到找到那个以特定位数的“0”开头的哈希结果。 例如,回到哈希网站然后对“886”做哈希运算。它将生成一个前缀包含三个零的哈希值。 但是,我们怎么知道 “886” 能得出一个开头三个零的结果呢?这就是关键点了。在写这篇博客之前,我们不知道。理论上,我们需要遍历所有数字和字母的组合、测试结果,直到得到一个能够匹配我们需求的三个零开头的结果。给你举一个简单的例子,我们其实已经预先做了计算,发现 “886” 的哈希值是三个零开头的。 任何人都可以很轻松的验证 “886” 的哈希结果是三个零前缀,这个事实证明了:我做了大量的工作来对很多字母和数字的组合进行测试和检查以获得这个结果。所以,如果我是第一个得到这个结果的人,我就能通过证明我做了工作来得到比特币 - 证据就是任何人都能轻松验证 “886” 的哈希结果为三零前缀,正如我宣称的那样。这就是为什么比特币共识算法被称为工作量证明。 但是如果我很幸运,我第一次尝试就得到了三零前缀的结果呢?这几乎是不可能的,并且那些偶然情况下第一次就成功挖到了区块(证明他们做了工作)的节点会被那些做了额外工作来找到合适的哈希值的成千上万的其他区块所压倒。试试看,在计算哈希的网站上输入任意其他的字母和数字的组合。我打赌你不会得到一个三零开头的结果。 比特币的需求要比这个复杂很多(更多个零的前缀!),并且能够通过动态调节需求来确保工作不会太难也不会太容易。记住,目标是每十分钟发行一次比特币,所以如果太多人在挖矿,就需要将工作量证明调整的更难完成。这就叫难度调节(adjusting the difficulty)。为了达成我们的目的,难度调整就意味着需求更多的零前缀。 现在你就知道了,比特币共识机制比单纯的“解决一个数学问题”要有意思的多! 足够多背景介绍了。我们开始编程吧! 现在我们已经有了足够多的背景知识,让我们用工作量共识算法来建立自己的比特币程序。我们将会用 Go 语言来写,因为我们在 Coral Health 中使用它,并且说实话,棒极了。 开始下一步之前,我建议读者读一下我们之前的博文,Code your own blockchain in less than 200 lines of Go!。并不是硬性需求,但是下面的例子中我们将讲的比较粗略。如果你需要更多细节,可以参考之前的博客。如果你对前面这篇很熟悉了,直接跳到下面的“工作量证明”章节。 结构 我们将有一个 Go 服务,我们就简单的把所有代码就放在一个 main.go 文件中。这个文件将会提供给我们所需的所有的区块链逻辑(包括工作量证明算法),并包括所有 REST 接口的处理函数。区块链数据是不可改的,我们只需要 GET 和 POST 请求。我们将用浏览器发送 GET 请求来观察数据,并使用 Postman 来发送 POST 请求给新区块(curl 也同样好用)。 引包 我们从标准的引入操作开始。确保使用 go get 来获取如下的包 github.com/davecgh/go-spew/spew 在终端漂亮地打印出你的区块链 github.com/gorilla/mux 一个使用方便的层,用来连接你的 web 服务 github.com/joho/godotenv 在根目录的 .env 文件中读取你的环境变量 让我们在根目录下创建一个 .env 文件,它仅包含一个我们一会儿将会用到的环境变量。在 .env 文件中写一行:ADDR=8080。 对包作出声明,并在根目录的 main.go 定义引入: package main import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io" "log" "net/http" "os" "strconv" "strings" "sync" "time" "github.com/davecgh/go-spew/spew" "github.com/gorilla/mux" "github.com/joho/godotenv" ) 复制代码 如果你读了在此之前的文章,你应该记得这个图。区块链中的区块可以通过比较区块的 previous hash 属性值和前一个区块的哈希值来被验证。这就是区块链保护自身完整性的方式以及黑客组织无法修改区块链历史记录的原因。 BPM 是你的心率,也就是一分钟心跳次数。我们将会用一分钟内你的心跳次数作为我们放到区块链中的数据。把两个手指放到手腕数一数一分钟脉搏内跳动的次数,记住这个数字。 一些基础探测 让我们来添加一些在引入后将会需要的数据模型和其他变量到 main.go 文件 const difficulty = 1 type Block struct { Index int Timestamp string BPM int Hash string PrevHash string Difficulty int Nonce string } var Blockchain []Block type Message struct { BPM int } var mutex = &sync.Mutex{} 复制代码 difficulty 是一个常数,定义了我们希望哈希结果的零前缀数目。需要得到越多的零,找到正确的哈希输入就越难。我们就从一个零开始。 Block 是每一个区块的数据模型。别担心不懂 Nonce,我们稍后会解释。 Blockchain 是一系列的 Block,表示完整的链。 Message 是我们在 REST 接口用 POST 请求传送进来的、用以生成一个新的 Block 的信息。 我们声明一个稍后将会用到的 mutex 来防止数据竞争,保证在同一个时间点不会产生多个区块。 Web 服务 让我们快速连接好网络服务。创建一个 run 函数,稍后在 main 中调用他来支撑服务。还需要在 makeMuxRouter() 中声明路由处理函数。记住,我们只需要用 GET 方法来追溯区块链内容, POST 方法来创建区块。区块链不可修改,所以我们不需要修改和删除操作。 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 } func makeMuxRouter() http.Handler { muxRouter := mux.NewRouter() muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET") muxRouter.HandleFunc("/", handleWriteBlock).Methods("POST") return muxRouter } 复制代码 httpAddr := os.Getenv("ADDR") 将会从刚才我们创建的 .env 文件中拉取端口 :8080。我们就可以通过访问浏览器的 [http://localhost:8080](http://localhost:8080) 来访问应用。 让我们写 GET 处理函数来在浏览器上打印出区块链。我们也将会添加一个简易 respondwithJSON 函数,它会在调用接口发生错误的时候,以 JSON 格式反馈给我们错误消息。 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)) } func respondWithJSON(w http.ResponseWriter, r *http.Request, code int, payload interface{}) { w.Header().Set("Content-Type", "application/json") 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) } 复制代码 记住,如果觉得这部分讲解太过粗略,请参考在此之前的文章,这里更详细的解释了这部分的每个步骤。 现在来写 POST 处理函数。这个函数就是我们添加新区块的方法。我们用 Postman 发送一个 POST 请求,发送一个 JSON 的 body,比如 {“BPM”:60},到 [http://localhost:8080](http://localhost:8080),并且携带你之前测得的你的心率。 func handleWriteBlock(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") 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() //ensure atomicity when creating new block mutex.Lock() newBlock := generateBlock(Blockchain[len(Blockchain)-1], m.BPM) mutex.Unlock() if isBlockValid(newBlock, Blockchain[len(Blockchain)-1]) { Blockchain = append(Blockchain, newBlock) spew.Dump(Blockchain) } respondWithJSON(w, r, http.StatusCreated, newBlock) } 复制代码 注意到 mutex 的 lock(加锁) 和 unlock(解锁)。在写入一个新的区块之前,需要给区块链加锁,否则多个写入将会导致数据竞争。精明的读者还会注意到 generateBlock 函数。这是处理工作量证明的关键函数。我们稍后讲解这个。 基本的区块链函数 在开始工作量证明算法之前,我们先将基本的区块链函数连接起来。我们将会添加一个 isBlockValid 函数,来保证索引正确递增以及当前区块的 PrevHash 和前一区块的 Hash 值是匹配的。 我们也要添加一个 calculateHash 函数,生成我们需要用来创建 Hash 和 PrevHash 的哈希值。它就是一个索引、时间戳、BPM、前一区块哈希和 Nonce 的 SHA-256 哈希值(我们稍后将会解释它是什么)。 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 calculateHash(block Block) string { record := strconv.Itoa(block.Index) + block.Timestamp + strconv.Itoa(block.BPM) + block.PrevHash + block.Nonce h := sha256.New() h.Write([]byte(record)) hashed := h.Sum(nil) return hex.EncodeToString(hashed) } 复制代码 工作量证明 让我们来看挖矿算法,或者说工作量证明。我们希望确保工作量证明算法在允许一个新的区块 Block 添加到区块链 blockchain 之前就已经完成了。我们从一个简单的函数开始,这个函数可以检查在工作量证明算法中生成的哈希值是否满足我们设置的要求。 我们的要求如下所示: 工作量证明算法生成的哈希值必须要以某个特定个数的零开始零的个数由常数 difficulty 决定,它在程序的一开始定义(在示例中,它是 1)我们可以通过增加难度值让工作量证明算法变得困难 完成下面这个函数,isHashValid: func isHashValid(hash string, difficulty int) bool { prefix := strings.Repeat("0", difficulty) return strings.HasPrefix(hash, prefix) } 复制代码 Go 在它的 strings 包里提供了方便的 Repeat 和 HasPrefix 函数。我们定义变量 prefix 作为我们在 difficulty 定义的零的拷贝。下面我们对哈希值进行验证,看是否以这些零开头,如果是返回 True 否则返回 False。 现在我们创建 generateBlock 函数。 func generateBlock(oldBlock Block, BPM int) Block { var newBlock Block t := time.Now() newBlock.Index = oldBlock.Index + 1 newBlock.Timestamp = t.String() newBlock.BPM = BPM newBlock.PrevHash = oldBlock.Hash newBlock.Difficulty = difficulty for i := 0; ; i++ { hex := fmt.Sprintf("%x", i) newBlock.Nonce = hex if !isHashValid(calculateHash(newBlock), newBlock.Difficulty) { fmt.Println(calculateHash(newBlock), " do more work!") time.Sleep(time.Second) continue } else { fmt.Println(calculateHash(newBlock), " work done!") newBlock.Hash = calculateHash(newBlock) break } } return newBlock } 复制代码 我们创建了一个 newBlock 并将前一个区块的哈希值放在 PrevHash 属性里,确保区块链的连续性。其他属性的值就很明了了: Index 增量Timestamp 是代表了当前时间的字符串BPM 是之前你记录下的心率Difficulty 就直接从程序一开始的常量中获取。在本篇教程中我们将不会使用这个属性,但是如果我们需要做进一步的验证并且确认难度值对哈希结果固定不变(也就是哈希结果以 N 个零开始那么难度值就应该也等于 N,否则区块链就是受到了破坏),它就很有用了。 for 循环是这个函数中关键的部分。我们来详细看看这里做了什么: 我们将设置 Nonce 等于 i 的十六进制表示。我们需要一个为函数 calculateHash 生成的哈希值添加一个变化的值的方法,这样如果我们没能获取到我们期望的零前缀数目,我们就能用一个新的值重新尝试。这个我们加入到拼接的字符串中的变化的值 **calculateHash** 就被称为“Nonce”在循环里,我们用 i 和以 0 开始的 Nonce 计算哈希值,并检查结果是否以常量 difficulty 定义的零数目开头。如果不是,我们用一个增量 Nonce 开始下一轮循环做再次尝试。我们添加了一个一秒钟的延迟来模拟解决工作量证明算法的时间我们一直循环计算直到我们得到了我们想要的零前缀,这就意味着我们成功的完成了工作量证明。当且仅当这之后才允许我们的 Block 通过 handleWriteBlock 处理函数被添加到 blockchain。 我们已经写完了所有函数,现在我们来完成 main 函数: func main() { err := godotenv.Load() if err != nil { log.Fatal(err) } go func() { t := time.Now() genesisBlock := Block{} genesisBlock = Block{0, t.String(), 0, calculateHash(genesisBlock), "", difficulty, ""} spew.Dump(genesisBlock) mutex.Lock() Blockchain = append(Blockchain, genesisBlock) mutex.Unlock() }() log.Fatal(run()) } 复制代码 我们使用 godotenv.Load() 函数加载环境变量,也就是用来在浏览器访问的 :8080 端口。 一个 go routine 创建了创世区块,因为我们需要它作为区块链的起始点 我们用刚才创建的 run() 函数开始网络服务。 完成了!是时候运行它了! 这里有完整的代码。 mycoralhealth/blockchain-tutorial: blockchain-tutorial - Write and publish your own blockchain in less than 200 lines of Go_github.com 让我们试着运行这个宝宝! 用 go run main.go 来开始程序 然后用浏览器访问 [http://localhost:8080](http://localhost:8080): 创世区块已经为我们创建好。现在打开 Postman 然后发送一个 POST 请求,向同一个路由以 JSON 格式在 body 中发送之前测定的心率值。 发送请求之后,在终端看看发生了什么。你将会看到你的机器忙着用增加 Nonce 值不停创建新的哈希值,直到它找到了需要的零前缀值。 当工作量证明算法完成了,我们就会得到一条很有用的 work done! 消息,我们就可以去检验哈希值来看看它是不是真的以我们设置的 difficulty 个零开头。这意味着理论上,那个我们试图添加 BPM = 60 信息的新区块已经被加入到我们的区块链中了。 我们来刷新浏览器并查看: 成功了!我们的第二个区块已经被加入到创世区块之后。这意味着我们成功的在 POST 请求中发送了区块,这个请求触发了挖矿的过程,并且当且仅当工作量证明算法完成后,它才会被添加到区块链中。 接下来 很棒!刚才你学到的真的很重要。工作量证明算法是比特币,以太坊以及其他很多大型区块链平台的基础。我们刚才学到的并非小事;虽然我们在示例中使用了一个很低的 difficulty 值,但是将它增加到一个比较大的值就正是生产环境下区块链工作量证明算法是如何运作的。 现在你已经清楚了解了区块链技术的核心部分,接下来如何学习将取决于你。我向你推荐如下资源: 在我们的 Networking tutorial 教程中学习联网区块链如何工作。在我们的 IPFS tutorial 教程中学习如何以分布式存储大型文件并用区块链通信。 如果你做好准备做另一次技术上的跳跃,试着学习 股权证明(Proof of Stake) 算法。虽然大多数的区块链使用工作量证明算法作为共识算法,股权证明算法正获得越来越多的关注。很多人相信以太坊将来会从工作量证明算法切换到股权证明算法。 想看关于工作量证明算法和股权证明算法的比较教程?在上面的代码中发现了错误?喜欢我们做的事?讨厌我们做的事? 通过 加入我们的 Telegram 消息群 让我们知道你的想法!你将得到本教程作者以及 Coral Health 团队其他成员的热情应答。 想要了解更多关于 Coral Health 以及我们如何使用区块链来改进个人医药研究,访问我们的网站。 掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。 优惠劵 weixin_34163741 关注 关注 0 点赞 踩 2 收藏 觉得还不错? 一键收藏 知道了 0 评论 [译] 用 Go 编写你自己的区块链挖矿算法! 原文地址:Code your own blockchain mining algorithm in Go!原文作者:Coral Health译文出自:掘金翻译计划本文永久链接:github.com/xitu/gold-m…译者:EmilyQiRabbit校对者:stormluke,mingxing47如果你对下面的教程有任何问题或者建议,加入我们的 Telegram 消息群,可... 复制链接 扫一扫 区块链基础和以太坊入门 04-24 孟岩老师从比特币入手,深入分析区块链的基本原理和知识,在此基础上拨云见日地带领学员入门以太坊,让学员迅速掌握发币、转账、挖矿的基本步骤和技能。 记一次遇到挖矿程序的经历 热门推荐 xzxmustwin的博客 05-30 1万+ 就在几天前,遇到了一次挖矿程序偷偷装在ECS阿里云服务器上的经历。 那是一个风和日丽的上午,我和往常一样来到公司,倒杯水等待电脑打开,之后打开日常维护的几个系统。 结果其中有一个OA系统,发现无法正常打开。一开始我以为是网络问题,但是发现打开其他网站正常,于是登上服务器准备探个究竟。 登陆云服务器后,重启OA服务,发现报错,报错提示连接线程池连接不上。根据提示,怀疑是连不上部署在本地的数据服... 参与评论 您还未登录,请先 登录 后发表或查看评论 第一次直面挖矿程序 紫色飞猪 06-10 4279 话不多说上发现,解决的过程 昨晚11:01 阿里云给我发邮件。告知我以上事件。因为我最近正好看过相应案例。就准备今天中午亲自解决一下。 解决过程: 如上图所示:用top命令发现了一个26256的进程。一看这就是那个挖矿程序了。那就解决它吧。 如上如所示:查看这个26256进程是那些文件。 如上图所示:查看这个26256进程干了些什么。 如上图所示:使用iftop... 使用 C# 编写自己的区块链挖矿算法 05-07 221 文章原文来自:Code your own blockchain mining algorithm in Go! ,原始文章通过 Go 语言来实现的,这里仍然是承接上一篇文章,来使用 C# + .Net Core 实现我们的挖矿算法。 强烈建议阅读前先阅读这篇文章 什么是加密货币挖掘? 一个加密货币的价值体现在它的稀缺性上,如果任何人都可以任意构造一个比特币,那么比特币就毫无价值,所以比特... 区块链火了! 一图了解这些知识点.pdf 08-15 #资源达人分享计划# 区块链共识算法研究综述.pdf 08-15 #资源达人分享计划# 区块链共识算法的研究与应用 04-13 区块链共识算法的研究与应用 区块链共识算法综述.pdf 08-15 #资源达人分享计划# 基于ElGamal数字签名算法的区块链共识算法 07-07 对环签名算法进行正确性及匿名性分析,运用环签名方案改进PBFT算法的签名及验证过程,使用 Fabric中的区块链性能测试框架 Caliper对改进方案进行性能测试,结果表明,基于环签名方案的改进共识算法可较好地解决网络... Code your own blockchain mining algorithm in Go! 04-18 本资源为文章https://blog.csdn.net/alphags/article/details/79998487的英文原文 Go-基于DPoS算法P2P对等网络的简易区块链Go语言实现 08-14 基于DPoS算法、P2P对等网络的简易区块链Go语言实现 go语言-创建区块链(入门版本) 11-29 这个是用go语言写的一个最简单的创建区块链代码。只有一百多行代码。包含创建区块链,新建创世块,向区块链中添加区块内容 挖矿程序的处理方式及步骤 LeeKwen的专栏 04-16 3724 概述 随着币圈市场交易的活跃,币价也被日益推高。 从BTC兑美元的在线交易平台上可以看出,BTC的价格屡创新高,这与MG的2W亿脱不了干系。 “重赏之下,必有勇夫”,在互联网圈里也同样适用啊。 所以服务器被植入挖矿程序已经不是很稀奇的事情了,很多服务器因为漏洞、弱密码、禁用防火墙等等举措,而被做了提权后,置入了挖矿程序。 如果你接收到阿里云类似于挖矿程序的报警,那就不要慌。借用一句话就是:“遇事不要慌,先拍照,发个朋友圈”。 挖矿程序的处理方式 以下,简单地说一下遇到挖矿... 什么是去中心化,如何去中心化 wsl3465205046的博客 03-15 151 去中心化(Decentralization)是指在组织、管理或运作中减少或消除中心化机构或权力的控制和影响,使得决策和资源分配更加分散和民主化的一种管理模式。在数字化和信息化时代,去中心化成为了一个重要的概念,尤其在区块链技术的发展和应用中,去中心化得到了广泛关注和实践。本文将介绍去中心化的概念、意义以及如何实现去中心化的方法和途径。 永热爱 敢向前 | Paraverse平行云的2023 年终总结 mlj890211的博客 03-14 577 Paraverse云技术底座通过整合元宇宙与Web3.0两大前沿方向涉及的实时云渲染、云原生、区块链等底层技术,Paraverse打造了去中心化的实时云渲染平台ParaLab,和适用于3D应用的Web3交易流转平台ParaHere,企业和开发者可以快速搭建数字平行世界云技术底座,开启通往平行世界的通道,建立去中心化的数字资产交易基础服务。在新一代互联网的冲击下,以“元宇宙”和“Web3.0”为代表的虚实结合、智能化、去中心化的3D信息系统,以及具备公平透明等特点的互联网媒介已成为公认的未来主流媒介形态。 Solidity Uniswap V2 library contract 最新发布 The future is already here it's just not evenly distributed。 03-15 93 在 Solidity 中,库是一种无状态合约(即它没有可变状态),它实现了一组可被其他合约使用的函数--这是库的主要目的。函数的第一步是token地址排序--当我们想通过token地址查找pair地址时,总是要这样做。这就是我们下一步要做的事情:有了factory地址和排序过的token地址,我们就能获得pair地址--我们接下来会看看 pairFor 函数。在交换中,使用的是基于恒积公式的公式。Uniswap 使用的是更先进的方法,我们可以从 CREATE2 操作码的确定性地址生成中获的启发。 如何布局马斯克推特上喊的meme币赛道 QiJublockchain的博客 03-14 439 2024年的牛市正如火如荼的开展,截止当下,比特币已经站上了7.3万美元,远超2021年高点的6.9万美元,比特币的未来是一片大海。除了比特币的一枝独秀之外,meme板块可以说是市场资金最青睐的。尤其是马斯克在X分享PEPE相关图片后,PEPE短时涨超10%,日交易额达到了几十亿美元跻身加密世界前五的位置。Meme 币的起源可以追溯到 2013 年底的 Dogecoin (DOGE),并在 2021 年的牛市中达到峰值。 如何用go语言编写一个区块链 05-11 要编写一个区块链,需要了解区块链的基本概念和原理,以及使用Golang编写分布式应用程序的基础知识。 以下是编写区块链的基本步骤: 1. 定义区块结构 定义区块的结构,包括区块头和区块体。区块头包含区块的元数据,如区块的哈希值、时间戳、难度等信息。区块体包含实际的交易数据。 2. 实现区块链 在代码中定义一个区块链结构体,包含一个区块数组和一些方法,如添加新块、验证区块等。 3. 实现工作量证明算法 区块链需要一个工作量证明算法来保证安全性。这可以通过实现PoW(Proof of Work)算法来完成,该算法需要在计算一个区块的哈希值时,找到一个符合条件的哈希值,这个过程需要不断地猜测随机数,直到找到符合条件的哈希值。 4. 实现节点通信 区块链是一个分布式系统,节点之间需要进行通信。可以通过实现P2P(Peer-to-Peer)协议来实现节点之间的通信,这可以通过Go语言的网络库来完成。 5. 实现钱包 钱包是用于管理用户的加密货币的应用程序。可以使用Go语言的加密库来实现钱包功能,如生成公私钥对、签名交易等。 6. 测试和部署 编写完代码后,需要进行测试和部署。可以在本地网络上运行一个测试网络,或者将代码部署到公共区块链网络上。 以上是编写一个基本的区块链的基本步骤,当然,还有很多细节需要注意,如安全性、性能优化等。 “相关推荐”对你有帮助么? 非常没帮助 没帮助 一般 有帮助 非常有帮助 提交 weixin_34163741 CSDN认证博客专家 CSDN认证企业博客 码龄8年 暂无认证 145 原创 - 周排名 101万+ 总排名 120万+ 访问 等级 7303 积分 4774 粉丝 194 获赞 25 评论 1166 收藏 私信 关注 热门文章 Python 保存数据的方法(4种方法) 16583 abaqus重新划分网格 14616 git公钥出错"//.ssh/id_rsa" failed: No such file or directory 14366 如何实现json字符串和 BsonDocument的互相转换 7451 git命令(资源) 7376 最新评论 在ASP.NET MVC实现购物车,尝试一种不同于平常的购物车显示方式 qq_31265119: 启动不了啊 踩坑道路之——ubuntu下pt query digest无法分析慢查询日志 tizzybepeacejoy: 也可以可以升级到2.2.20这个版本 【跃迁之路】【579天】程序员高效学习方法论探索系列(实验阶段336-2018.09.07)... Deep Learning小舟: 加油!写的真棒。 SpringCloud微服务框架搭建 Tisfy: 好文!,正如:紫泉宫殿锁烟霞,欲取芜城作帝家。 Mybatis源码分析-整体设计(一) Tisfy: Nice!,古人云:流星飞玉弹,宝剑落秋霜。 您愿意向朋友推荐“博客详情页”吗? 强烈不推荐 不推荐 一般般 推荐 强烈推荐 提交 最新文章 iOS极光推送集成步骤 设计模式之——单例模式(Singleton)的常见应用场景 Font and PDF 2019年338篇 2018年658篇 2017年881篇 2016年557篇 2015年425篇 2014年289篇 2013年323篇 2012年265篇 2011年182篇 2010年149篇 2009年127篇 2008年96篇 2007年84篇 2006年44篇 2005年23篇 2004年7篇 2002年1篇 目录 目录 最新文章 iOS极光推送集成步骤 设计模式之——单例模式(Singleton)的常见应用场景 Font and PDF 2019年338篇 2018年658篇 2017年881篇 2016年557篇 2015年425篇 2014年289篇 2013年323篇 2012年265篇 2011年182篇 2010年149篇 2009年127篇 2008年96篇 2007年84篇 2006年44篇 2005年23篇 2004年7篇 2002年1篇 目录 评论 被折叠的 条评论 为什么被折叠? 到【灌水乐园】发言 查看更多评论 添加红包 祝福语 请填写红包祝福语或标题 红包数量 个 红包个数最小为10个 红包总金额 元 红包金额最低5元 余额支付 当前余额3.43元 前往充值 > 需支付:10.00元 取消 确定 下一步 知道了 成就一亿技术人! 领取后你会自动成为博主和红包主的粉丝 规则 hope_wisdom 发出的红包 实付元 使用余额支付 点击重新获取 扫码支付 钱包余额 0 抵扣说明: 1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。 余额充值 手把手带你用golang构建区块链(4)交易(译)第一部分 - 知乎首发于区块链与分布式系统切换模式写文章登录/注册手把手带你用golang构建区块链(4)交易(译)第一部分开心又高兴原文:引言交易时比特币的核心,区块链的唯一目的是安全的存储交易,达到交易一旦达成便不可篡改的目的。今天我们一起来构建交易。但是由于这是一个很大的话题,我会把它分为两个部分:第一,我们泛泛的构建交易,第二部分我们会查看交易细节。此外,由于代码量巨大,没有必要事无巨细的解释。没有勺子如果你有开发过web应用,为了付款你需要在本地创建数据库:账户和交易。一个账户会存储一个用户的信息,包括个人信息,余额。一个交易会存储资金的转移信息。在比特币中,支付用一种完全不同的方式实现。它们:没有账户。没有余额。没有地址。没有coins。没有发送者和接收者。由于区块链时一个公开的数据库,我们不会存储钱包所有者的敏感信息。区块链只有交易,那么交易里到底时什么。比特币交易一个交易是输入和输出的组合:交易的输入引用上一个交易的输出(有个例外,一会儿讨论)。输出是coin存储的地方。下图说明了交易之间的关系:注意到:1、没有不关联输入的输出2、在一个交易中,输入关联多个交易的输出。3、一个输入必须引用一个输出在文章中,我们使用money,coin,spend,send account的概念。但比特币中并没有这些概念。交易仅仅是脚本中锁定的值,被锁定的值只可以被锁定者解锁。交易的输出:我们首先看看输出:事实上,输出存储着coins(value)。并且存储意味用一个谜底解锁,谜底存储在ScriptPubKey中。比特币内部使用script语言,脚本用来定义输出锁定和解锁的逻辑。脚本语言非常原始(故意为之,避免潜在的攻击),但是我们并不讨论细节,细节在此here。在比特币中,vaule存储聪的值,并不是btc的数量。一聪是0.00000001 BTC,为btc中的最小单位。由于我们还没有地址,我们暂时不谈脚本逻辑。ScriptPubKey将存储任意字符串(钱包地址)顺便说一句,比特币脚本意味着比特币可以实现智能合约。另一个重要的事情,输出是不可分割,意味着不可引用其中的一部分。当输出在一个新交易中引用的时候,被当作一个整体花费。如果其值大于需要的,则将余额发送给自己。交易的输入:输入在此正如之前说,一个输入引用了之前的输出:tixd 存储交易的ID,vout存储输入的索引。ScriptSigis 提供数据,这个数据在输出的ScriptPubKey中使用。如果数据是正常的,输出可以被解锁,value可以用来产生新的输出;如果它不正确,则输出不可以被输入引用。这个机制保证了用户不能花费其他人的coins。另外,由于我们暂时还没有地址,ScriptSig将会存储任意用户定义的钱包地址,我们将在下届讨论公钥和签名机制。总结一下,输出是coins存储的地方。每个输出都有一个解锁脚本,脚本确定了解锁输出的逻辑。每个交易至少有一个输入和一个输出。输入引用了上一个交易的输出并在scriptsig中提供了解锁它的数据,并使用其value制造新的输出。但是到底先有输入还是现有输出:鸡蛋:在比特币中,鸡蛋在鸡之前。输入引用输出是经典的鸡在蛋前:输入产生输出并且输出使能输入(outputs make inputs possible)。在比特币中,输出先于输入。当一个矿工开始挖矿时,它在区块中加入一个coinbase 交易。coinbase交易是特殊的交易,其不依赖现有输出。有蛋没鸡,是矿工们挖矿新块的奖励。正如我们所知,区块链中有一个创世区块。创始区块制造第一个输出。创世区块无需任何先前输出和先前交易。我们一起来看coinbase交易:coinbase交易只有一个输入,在我们的程序中,它的txid是空的,并且vout是-1。此外,一个coinbase交易并不在scriptsig存储脚本。它的scriptsig可以为任意数据。在btc中,coinbase交易包含如下消息:“The Times 03/Jan/2009 Chancellor on brink of second bailout for banks”。subsidy是奖励总数,在btc中,这个值不是存在某个地方而只依赖于区块的总数:初始时奖励为50个btc,每21000个块奖励减半。我们代码中奖励是常量。交易的存储:从现在开始,每个块至少存储一个交易,而且并不允许除了交易以外任何出块方式。这意味着我们需要删除data成员,并存储交易:NewBlock和NewGenesisBlock同样需要改变:此外,还有区块链的创建方式:现在,这个函数有一个地址来接收挖矿奖励。POWPOWs算法必须考虑块中的交易来保证块中的一致性和可靠性。所以,我们修改ProofOfWork.prepareData方法:我们使用pow.block.HashTransactions()来代替pow.block.Data:我们再次使用hash机制作为数据的唯一标识。我们希望区块中每个交易都可以唯一使用hash来标识。为了达到目的,我们计算每个交易的哈希值,然后连接他们,最后对连接后的结果计算hash值作为交易的hash值。比特币使用更优雅的技术:它将区块中所有的交易表示为一个merkle树并使用树根的hash作为POW。这个方法使不用下载所有交易仅仅z知道树根的hash值便可以快速查看一个区块是否包含了某个交易成为可能。让我们测试下:我们的第一笔挖矿收入未花费交易输出:我们需要找到所有未花费交易输出UTXO,未花费意味着这个的输出没有被任何一个输入引用,对应上图中,就是这些:tx0, output 1;tx1, output 0;tx3, output 0;tx4, output 0.当然,我们查询余额时不需要这些全部,只需要用我们的key可以解锁的部分(当前系统并未实现key,只是用address替代)。首先,我们在输入输出上定义locking-unlocking的方法:这里,我们只用script和unlockingdata做比较,在我们实现了基于私钥的地址后将会做出改进。下一步,找到所有包含未花费输出的交易,这个很复杂:func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction { var unspentTXs []Transaction spentTXOs := make(map[string][]int) bci := bc.Iterator() for { block := bci.Next() for _, tx := range block.Transactions { txID := hex.EncodeToString(tx.ID) Outputs: for outIdx, out := range tx.Vout { // Was the output spent? if spentTXOs[txID] != nil { for _, spentOut := range spentTXOs[txID] { if spentOut == outIdx { continue Outputs } } } if out.CanBeUnlockedWith(address) { unspentTXs = append(unspentTXs, *tx) } } if tx.IsCoinbase() == false { for _, in := range tx.Vin { if in.CanUnlockOutputWith(address) { inTxID := hex.EncodeToString(in.Txid) spentTXOs[inTxID] = append(spentTXOs[inTxID], in.Vout) } } } } if len(block.PrevBlockHash) == 0 { break } } return unspentTXs}由于交易时在块中的,我们必须检查所有块,开始时:如果输出可以被我们的地址解锁,那这些输出就是我们需要的。但是在采纳它之前,我们需要检查这戏输出是否已经被引用: 我们忽略这些输入(这些value已经被发送到别的地方了)。这个函数返回了所有包含未华为输出的交易。为了计算余额我们需要另一个函数takes这些交易并仅仅返回输出。目前为止,我们实现了getbalance命令:账户余额时所有未花费余额的总和。在挖矿之后,我们来检查余额:这是我们的第一笔钱。发送coins现在,我们希望把币发送到其他人。为此,我们需要创建一个新交易,将它放进区块,并挖矿。到此,我们实现coinbase交易,现在我们需要一个一般交易。在创建新输出之前,我们首先找到所有未花费输出并保证有足够的资金。这是FindSpendableOutputs方法做的事情。在此之后,对每一个输出都有一个输入引用它,我们创建两个输出:1、一个使用收款人地址lock,这是发送给收款人的2、另一个使用自己的地址锁定。这只有所有未花费输出有的值超过了新的交易时才发生。FindSpendableOutputs方法基于FindUnspentTransactions方法:该方法迭代查询所有未花费输出并计算values。当总余额大于等于我们要发送的余额时,该函数返回。我们修改Blockchain.MineBlock方法:我们来实现发送命令:发送命令意味着创建一个交易并通过挖矿将其加入区块。但是btc并不立即执行这些操作。btc将所有的新交易放进内存池,当一个矿工准备挖矿时,它从内存池中接受所有的交易并创建一个候选块。交易只有在包含该交易的区块加入链上时才被确认。让我们来看看发送命令:现在,我们创建更多的交易并保证来自多个output的输入正常工作。现在,helen‘s的币被锁住两个输出,一个来自pedro另一个来自ivan。让我们把币发送给其他人。让我们测试失败:结论现在我们实现了交易,尽管一些关键特性仍然缺失:1、地址,我们没有基于私钥的地址2、奖励,挖矿没有奖励3、utxo集合,查询余额需要扫描整个区块链,这需要花费很长时间。并且验证后续交易同样耗时很长。utxo集合用来解决上述问题并让加速交易。4、内存池。这是交易在被打包至区块前存储的地方。在当前的实现中,一个区块仅仅包含了一个交易,这是非常不够的编辑于 2018-11-29 00:49区块链(Blockchain)比特币 (Bitcoin)Golang 最佳实践赞同添加评论分享喜欢收藏申请转载文章被以下专栏收录区块链与分布式系统用通俗的方式讲 深入底层:Go语言从零构建区块链(一): Hello, Blockchain - 知乎首发于深入底层:Go语言从零构建区块链切换模式写文章登录/注册深入底层:Go语言从零构建区块链(一): Hello, BlockchainLeo Cao唯刀百辟,唯心不易转自我的blog:Mingrui Cao's Blog前言有时觉得前言什么的可以省略,但作为一个教程还是应该在最开始的时候说两句。这个系列的教程目的是使用Golang由浅入深地还原PoW共识机制最基础区块链系统(参照比特币),适合想要快速入门区块链核心技术的读者,当然也适合刚学完Go基础语法希望练手的读者。相较于网络上其它Go语言实现区块链的教程,本系列教程以最终建立一个可以分布式运行的区块链系统为目标,使用新版本的Golang(v1.17)及相关包,在还原的过程中会尽量说明一些常规教程忽视的细节,给出所有的代码。大部分人对于区块链技术的学习常常停留在表象,了解了UTXO模型,共识机制,P2P网络后,总是迫不及待地就想用区块链往所有涉及隐私与安全的问题里套。我始终持有的观点是,可以允许区块链在各种应用场景中试错,但不应该过于推崇区块链,它不是万能的,要学习区块链就应该了解其本质,从事物的两面性去研究它。举个例子,如果我们把区块链当作一个分布式的数据库看待,那么它的性能无疑是拉跨的,但是如果充分理解区块链的本质,就能够明白比特币为什么仅仅用一段代码就能够在全球没有第三方机构的参与下实现资产信息的长久保存,稳定运行超过五年,感叹其精妙之处。如果想要了解区块链技术的本质,了解区块链技术的优缺点以及可能的研究方向,最直接的办法无疑是阅读比特币源码。但是比特币源码使用cpp进行编写,人们常常不知道从哪里开始进行学习理解,在耗费大量时间与精力的过程中,渐渐消磨学习者对区块链的兴趣。本人在学习区块链的过程中发现,通过理解区块链原理一步一步构建区块链系统比直接阅读比特币源码要有乐趣的多,学习速度也更快,而且最终都能达到同样的目的,就像B树的建立往往比B树的查找容易学习理解一样。为了达到使读者快速入门并理解区块链核心技术的目的,本教程不太注重对Go语言相关问题的讲解,关注的是代码背后的区块链原理与实现细节。读者需要做的只是创建一个空项目,从零开始跟随本教程敲下一行又一行的代码。对读者来说,重要的不是对我所写的代码进行改动,而是理解每一行代码的意义。由于本人Go语言也还处于学习阶段,故一些部分代码可能较为冗余。区块链实现细节有误的地方也随时欢迎讨论指正。完整的项目地址:https://github.com/leo201313/Blockchain_with_Go创建项目首先我们需要创建一个项目。创建一个文件夹命名为goblockchain(当然你也可以取一个霸气的名字,比如lighteningchain,goXchain等等),然后使用VS(Visual Studio Code,推荐使用VS作为IDE)打开文件夹,如下图。此时文件中什么都没有,我们使用go mod来初始化项目,点击VS左下方的小三角,在terminal中输入go mod init goblockchain.此时文件夹中将会多出一个go.mod文件,证明项目已经初始化成功。在goblockchain文件夹下创建main.go文件。区块与区块链区块链以区块(block)的形式储存数据信息,一个区块记录了一段时间内系统或网络中产生的重要数据信息,区块通过引用上一个区块的hash值来连接上一个区块这样区块就按时间顺序排列形成了一条链。每个区块应该包含头部(head)信息用于总结性的描述这个区块,然后在区块的数据存放区(body)中存放要保存的重要数据。首先我们需要初始化main.go,并导入一些基本的包。//main.go package main import ( "bytes" "crypto/sha256" "encoding/binary" "fmt" "log" "time" ) func main { } 然后定义区块的结构体。//main.go type Block struct{ Timestamp int64 Hash []byte PrevHash []byte Data []byte } 我们定义的区块中有时间戳,本身的哈希值,指向上一个区块的哈希这三个属性构成头部信息,而区块中的数据以Data属性表示。在获得了区块后,我们可以定义区块链。//main.go type BlockChain struct{ Blocks []*Block } 可以看到我们这里的区块链就是区块的一个集合。好了,现在你已经掌握了区块与区块链了,现在就可以去搭建自己的区块链系统了。哈希QVQ,好吧,我们现在来给我们的区块增加点细节,来看看它们是怎么连接起来的。对于一个区块而言,可以通过哈希算法概括其所包含的所有信息,哈希值就相当于区块的ID值,同时也可以用来检查区块所包含信息的完整性。哈希函数构造如下。//main.go func (b *Block) SetHash() { information := bytes.Join([][]byte{ToHexInt(b.Timestamp),b.PrevHash,b.Data},[]byte{}) hash := sha256.Sum256(information) b.Hash = hash[:] } func ToHexInt(num int64) []byte { buff := new(bytes.Buffer) err := binary.Write(buff, binary.BigEndian, num) if err != nil { log.Panic(err) } return buff.Bytes() } information变量是将区块的各项属性串联之后的字节串。这里提醒一下bytes.Join可以将多个字节串连接,第二个参数是将字节串连接时的分隔符,这里设置为[]byte{}即为空,ToHexInt将int64转换为字节串类型。然后我们对information做哈希就可以得到区块的哈希值了。区块创建与创始区块既然我们可以获得区块的哈希值了,我们就能够创建区块了。//main.go func CreateBlock(prevhash, data []byte) *Block { block := Block{time.Now().Unix(), []byte{}, prevhash, data} block.SetHash() return &block } 可以看到在创建一个区块时一定要引用前一个区块的哈希值,这里会有一个问题,那就是区块链中的第一个区块怎么创建?其实,在区块链中有一个创世区块,随着区块链的创建而添加,它指向的上一个区块的哈希值为空。//main.go func GenesisBlock() *Block { genesisWords := "Hello, blockchain!" return CreateBlock([]byte{}, []byte(genesisWords)) } 可以看到我们在创始区块中存放了 Hello, blockchain! 这段信息。现在我们来构建函数,使得区块链可以根据其它信息创建区块进行储存。//main.go func (bc *BlockChain) AddBlock(data string) { newBlock := CreateBlock(bc.Blocks[len(bc.Blocks)-1].Hash, []byte(data)) bc.Blocks = append(bc.Blocks, newBlock) } 最后我们构建一个区块链初始化函数,使其返回一个包含创始区块的区块链。//main.go func CreateBlockChain() *BlockChain { blockchain := BlockChain{} blockchain.Blocks = append(blockchain.Blocks, GenesisBlock()) return &blockchain } 运行区块链系统现在我们已经拥有了所有创建区块链需要的函数了,来看看我们的区块链是怎么运作的。//main.go func main() { blockchain := CreateBlockChain() time.Sleep(time.Second) blockchain.AddBlock("After genesis, I have something to say.") time.Sleep(time.Second) blockchain.AddBlock("Leo Cao is awesome!") time.Sleep(time.Second) blockchain.AddBlock("I can't wait to follow his github!") time.Sleep(time.Second) for _, block := range blockchain.Blocks { fmt.Printf("Timestamp: %d\n", block.Timestamp) fmt.Printf("hash: %x\n", block.Hash) fmt.Printf("Previous hash: %x\n", block.PrevHash) fmt.Printf("data: %s\n", block.Data) } } 在terminal中输入go run main.go,输出如下。D:\learngo\goblockchain>go run main.go Timestamp: 1632471455 hash: 289c596026a32c6ac5702fd2d3c96104d6b7178de49beb70a71c100ee839ac26 Previous hash: data: Hello, blockchain! Timestamp: 1632471456 hash: a29d04ef59529bb50b1526393203ebf7cc60d8f0ddfbb09900475c9dcf180d3b Previous hash: 289c596026a32c6ac5702fd2d3c96104d6b7178de49beb70a71c100ee839ac26 data: After genesis, I have something to say. Timestamp: 1632471457 hash: 69eb263ab680cc0d45530c5ba0db1514255c891e084c3f04bfb416f0f1b06a59 Previous hash: a29d04ef59529bb50b1526393203ebf7cc60d8f0ddfbb09900475c9dcf180d3b data: Leo Cao is awesome! Timestamp: 1632471458 hash: 453ff251f95183c92ace277dec4181d5c71582129dc31cce3ceb37c7b1377efc Previous hash: 69eb263ab680cc0d45530c5ba0db1514255c891e084c3f04bfb416f0f1b06a59 data: I can't wait to follow his github!你需要注意的是创始区块没有Previous Hash,同时后面的每一个区块都保留了前一个区块的哈希值。总结在本章中,我们构建了一个最简单的区块链模型。本章需要重点理解区块与区块链的关系,区块的哈希值的意义,以及创世区块的构建。在下一章中,我们将讲解PoW(Proof of Work)共识机制,并增加一些区块结构体的头部信息。编辑于 2021-10-05 15:18区块链(Blockchain)区块链技术Go 语言赞同 4014 条评论分享喜欢收藏申请转载文章被以下专栏收录深入底层:Go语言从零构建区块链使用Go语言重构基础区块链系统的 golang 实现区块链(Bitcoin)系列1 - 基本原型 | 登链社区 | 区块链技术社区 文章 问答 讲堂 专栏 集市 更多 提问 发表文章 活动 文档 招聘 发现 Toggle navigation 首页 (current) 文章 问答 讲堂 专栏 活动 招聘 文档 集市 搜索 登录/注册 golang 实现区块链(Bitcoin)系列1 - 基本原型 张小风 更新于 2020-02-15 16:16 阅读 12017 用 golang 从零开始构建简易的区块链,这是系列文章的第一篇。 本系列文章:
[golang 实现区块链(Bitcoin)系列 1 - 基本原型](https://learnblockchain.cn/article/577)
[golang 实现区块链(Bitcoin)系列 2 - 工作量证明](https://learnblockchain.cn/article/580)
[golang 实现区块链(Bitcoin)系列 3 - 持久化和命令行接口](https://learnblockchain.cn/article/586)
[golang 实现区块链(Bitcoin)系列 4 - 交易(1)](https://learnblockchain.cn/article/619)
[golang 实现区块链(Bitcoin)系列 5 - 地址](https://learnblockchain.cn/article/637)
[golang实现区块链(Bitcoin)系列6 - 交易(2)](https://learnblockchain.cn/article/674)
[golang实现区块链(Bitcoin)系列7 - 网络](https://learnblockchain.cn/article/677)
## 引言
区块链是 21 世纪最具革命性的技术之一,它仍然处于不断成长的阶段,而且还有很多潜力尚未显现。 本质上,区块链只是一个分布式数据库而已。 不过,使它独一无二的是,区块链是一个**公开**的数据库,而不是一个私人数据库,也就是说,每个使用它的人都有一个完整或部分的副本。 只有经过其他“数据库管理员”的同意,才能向数据库中添加新的记录。 此外,也正是由于区块链,才使得加密货币和智能合约成为现实。
在本系列文章中,我们将实现一个简化版的区块链,并基于它来构建一个简化版的加密货币。
## 区块
首先从 “区块” 谈起。在区块链中,真正存储有效信息的是区块(block)。而在比特币中,真正有价值的信息就是交易(transaction)。实际上,交易信息是所有加密货币的价值所在。除此以外,区块还包含了一些技术实现的相关信息,比如版本,当前时间戳和前一个区块的哈希。
不过,我们要实现的是一个简化版的区块链,而不是一个像比特币技术规范所描述那样成熟完备的区块链。所以在我们目前的实现中,区块仅包含了部分关键信息,它的数据结构如下:
```go
type Block struct {
Timestamp int64
Data []byte
PrevBlockHash []byte
Hash []byte
}
```
字段 | 解释
:----: | :----
`Timestamp` | 当前时间戳,也就是区块创建的时间
`PrevBlockHash` | 前一个块的哈希,即父哈希
`Hash` | 当前块的哈希
`Data` | 区块存储的实际有效信息,也就是交易
我们这里的 `Timestamp`,`PrevBlockHash`, `Hash`,在比特币技术规范中属于区块头(block header),区块头是一个单独的数据结构。
完整的 [比特币的区块头(block header)结构](https://en.bitcoin.it/wiki/Block_hashing_algorithm) 如下:
Field | Purpose | Updated when... | Size (Bytes)
:---- | :---- | :---- | :----
Version | Block version number | You upgrade the software and it specifies a new version | 4
hashPrevBlock | 256-bit hash of the previous block header | A new block comes in | 32
hashMerkleRoot | 256-bit hash based on all of the transactions in the block | A transaction is accepted | 32
Time | Current timestamp as seconds since 1970-01-01T00:00 UTC | Every few seconds | 4
Bits | Current target in compact format | The difficulty is adjusted | 4
Nonce | 32-bit number (starts at 0) | A hash is tried (increments) | 4
下面是比特币的 golang 实现 btcd 的 [BlockHeader](https://github.com/btcsuite/btcd/blob/01f26a142be8a55b06db04da906163cd9c31be2b/wire/blockheader.go#L20-L41) 定义:
```go
// BlockHeader defines information about a block and is used in the bitcoin
// block (MsgBlock) and headers (MsgHeaders) messages.
type BlockHeader struct {
// Version of the block. This is not the same as the protocol version.
Version int32
// Hash of the previous block in the block chain.
PrevBlock chainhash.Hash
// Merkle tree reference to hash of all transactions for the block.
MerkleRoot chainhash.Hash
// Time the block was created. This is, unfortunately, encoded as a
// uint32 on the wire and therefore is limited to 2106.
Timestamp time.Time
// Difficulty target for the block.
Bits uint32
// Nonce used to generate the block.
Nonce uint32
}
```
而我们的 `Data`, 在比特币中对应的是交易,是另一个单独的数据结构。为了简便起见,目前将这两个数据结构放在了一起。在真正的比特币中,[区块](https://en.bitcoin.it/wiki/Block#Block_structure) 的数据结构如下:
Field | Description | Size
:---- | :---- | :----
Magic no | value always 0xD9B4BEF9 | 4 bytes
Blocksize | number of bytes following up to end of block | 4 bytes
Blockheader | consists of 6 items | 80 bytes
Transaction counter | positive integer VI = VarInt | 1 - 9 bytes
transactions | the (non empty) list of transactions |
在我们的简化版区块中,还有一个 `Hash` 字段,那么,要如何计算哈希呢?哈希计算,是区块链一个非常重要的部分。正是由于它,才保证了区块链的安全。计算一个哈希,是在计算上非常困难的一个操作。即使在高速电脑上,也要耗费很多时间 (这就是为什么人们会购买 GPU,FPGA,ASIC 来挖比特币) 。这是一个架构上有意为之的设计,它故意使得加入新的区块十分困难,继而保证区块一旦被加入以后,就很难再进行修改。在接下来的内容中,我们将会讨论和实现这个机制。
目前,我们仅取了 `Block` 结构的部分字段(`Timestamp`, `Data` 和 `PrevBlockHash`),并将它们相互拼接起来,然后在拼接后的结果上计算一个 SHA-256,然后就得到了哈希.
```
Hash = SHA256(PrevBlockHash + Timestamp + Data)
```
在 `SetHash` 方法中完成这些操作:
```go
func (b *Block) SetHash() {
timestamp := []byte(strconv.FormatInt(b.Timestamp, 10))
headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{})
hash := sha256.Sum256(headers)
b.Hash = hash[:]
}
```
接下来,按照 Golang 的惯例,我们会实现一个用于简化创建区块的函数 `NewBlock`:
```go
func NewBlock(data string, prevBlockHash []byte) *Block {
block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}}
block.SetHash()
return block
}
```
## 区块链
有了区块,下面让我们来实现区块**链**。本质上,区块链就是一个有着特定结构的数据库,是一个有序,每一个块都连接到前一个块的链表。也就是说,区块按照插入的顺序进行存储,每个块都与前一个块相连。这样的结构,能够让我们快速地获取链上的最新块,并且高效地通过哈希来检索一个块。
在 Golang 中,可以通过一个 array 和 map 来实现这个结构:array 存储有序的哈希(Golang 中 array 是有序的),map 存储 **hash -> block** 对(Golang 中, map 是无序的)。 但是在基本的原型阶段,我们只用到了 array,因为现在还不需要通过哈希来获取块。
```go
type Blockchain struct {
blocks []*Block
}
```
这就是我们的第一个区块链!是不是出乎意料地简单? 就是一个 `Block` 数组。
现在,让我们能够给它添加一个区块:
```go
func (bc *Blockchain) AddBlock(data string) {
prevBlock := bc.blocks[len(bc.blocks)-1]
newBlock := NewBlock(data, prevBlock.Hash)
bc.blocks = append(bc.blocks, newBlock)
}
```
结束!不过,就这样就完成了吗?
为了加入一个新的块,我们必须要有一个已有的块,但是,初始状态下,我们的链是空的,一个块都没有!所以,在任何一个区块链中,都必须至少有一个块。这个块,也就是链中的第一个块,通常叫做创世块(**genesis block**). 让我们实现一个方法来创建创世块:
```go
func NewGenesisBlock() *Block {
return NewBlock("Genesis Block", []byte{})
}
```
现在,我们可以实现一个函数来创建有创世块的区块链:
```go
func NewBlockchain() *Blockchain {
return &Blockchain{[]*Block{NewGenesisBlock()}}
}
```
检查一个我们的区块链是否如期工作:
```go
func main() {
bc := NewBlockchain()
bc.AddBlock("Send 1 BTC to Ivan")
bc.AddBlock("Send 2 more BTC to Ivan")
for _, block := range bc.blocks {
fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash)
fmt.Printf("Data: %s\n", block.Data)
fmt.Printf("Hash: %x\n", block.Hash)
fmt.Println()
}
}
```
输出:
```bash
Prev. hash:
Data: Genesis Block
Hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Data: Send 1 BTC to Ivan
Hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Data: Send 2 more BTC to Ivan
Hash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1
```
## 总结
我们创建了一个非常简单的区块链原型:它仅仅是一个数组构成的一系列区块,每个块都与前一个块相关联。真实的区块链要比这复杂得多。在我们的区块链中,加入新的块非常简单,也很快,但是在真实的区块链中,加入新的块需要很多工作:你必须要经过十分繁重的计算(这个机制叫做工作量证明),来获得添加一个新块的权力。并且,区块链是一个分布式数据库,并且没有单一决策者。因此,要加入一个新块,必须要被网络的其他参与者确认和同意(这个机制叫做共识(consensus))。还有一点,我们的区块链还没有任何的交易!
进入 src 目录查看代码,执行 `make` 即可运行:
```bash
$ cd src
$ make
==> Go build
==> Running
Prev. hash:
Data: Genesis Block
Hash: 4693b71eee96760de4b0f051083376dcbed2f0711a44294ee5fd42fbeacc9579
Prev. hash: 4693b71eee96760de4b0f051083376dcbed2f0711a44294ee5fd42fbeacc9579
Data: Send 1 BTC to Ivan
Hash: 839380a2d0af1dc4686f16ade5423fecdc5f287db9322d9e18adcb4071e7c8ff
Prev. hash: 839380a2d0af1dc4686f16ade5423fecdc5f287db9322d9e18adcb4071e7c8ff
Data: Send 2 more BTC to Ivan
Hash: b38052a029bd2b1b9d4bb478af45b4c88605e99bc64e49031ba06d21ad4b0b38
```
参考:
[1] [Block hashing algorithm](https://en.bitcoin.it/wiki/Block_hashing_algorithm)
[2] [Building Blockchain in Go. Part 1: Basic Prototype](https://jeiwan.cc/posts/building-blockchain-in-go-part-1/)
---
bitcoin wiki 的[区块](https://en.bitcoin.it/wiki/Block)结构:
Field | Description | Size
:----: | :----: | :----:
Magic no | value always 0xD9B4BEF9 | 4 bytes
Blocksize | number of bytes following up to end of block | 4 bytes
Blockheader | consists of 6 items | 80 bytes
Transaction | counter positive integer VI = VarInt | 1 - 9 bytes
transactions | the (non empty) list of transactions |
源码:https://github.com/Jeiwan/blockchain_go
转自:https://github.com/liuchengxu/blockchain-tutorial 本系列文章: golang 实现区块链(Bitcoin)系列 1 - 基本原型 golang 实现区块链(Bitcoin)系列 2 - 工作量证明 golang 实现区块链(Bitcoin)系列 3 - 持久化和命令行接口 golang 实现区块链(Bitcoin)系列 4 - 交易(1) golang 实现区块链(Bitcoin)系列 5 - 地址 golang实现区块链(Bitcoin)系列6 - 交易(2) golang实现区块链(Bitcoin)系列7 - 网络 引言 区块链是 21 世纪最具革命性的技术之一,它仍然处于不断成长的阶段,而且还有很多潜力尚未显现。 本质上,区块链只是一个分布式数据库而已。 不过,使它独一无二的是,区块链是一个公开的数据库,而不是一个私人数据库,也就是说,每个使用它的人都有一个完整或部分的副本。 只有经过其他“数据库管理员”的同意,才能向数据库中添加新的记录。 此外,也正是由于区块链,才使得加密货币和智能合约成为现实。 在本系列文章中,我们将实现一个简化版的区块链,并基于它来构建一个简化版的加密货币。 区块 首先从 “区块” 谈起。在区块链中,真正存储有效信息的是区块(block)。而在比特币中,真正有价值的信息就是交易(transaction)。实际上,交易信息是所有加密货币的价值所在。除此以外,区块还包含了一些技术实现的相关信息,比如版本,当前时间戳和前一个区块的哈希。 不过,我们要实现的是一个简化版的区块链,而不是一个像比特币技术规范所描述那样成熟完备的区块链。所以在我们目前的实现中,区块仅包含了部分关键信息,它的数据结构如下: type Block struct { Timestamp int64 Data []byte PrevBlockHash []byte Hash []byte } 字段 解释 Timestamp 当前时间戳,也就是区块创建的时间 PrevBlockHash 前一个块的哈希,即父哈希 Hash 当前块的哈希 Data 区块存储的实际有效信息,也就是交易 我们这里的 Timestamp,PrevBlockHash, Hash,在比特币技术规范中属于区块头(block header),区块头是一个单独的数据结构。 完整的 比特币的区块头(block header)结构 如下: Field Purpose Updated when... Size (Bytes) Version Block version number You upgrade the software and it specifies a new version 4 hashPrevBlock 256-bit hash of the previous block header A new block comes in 32 hashMerkleRoot 256-bit hash based on all of the transactions in the block A transaction is accepted 32 Time Current timestamp as seconds since 1970-01-01T00:00 UTC Every few seconds 4 Bits Current target in compact format The difficulty is adjusted 4 Nonce 32-bit number (starts at 0) A hash is tried (increments) 4 下面是比特币的 golang 实现 btcd 的 BlockHeader 定义: // BlockHeader defines information about a block and is used in the bitcoin // block (MsgBlock) and headers (MsgHeaders) messages. type BlockHeader struct { // Version of the block. This is not the same as the protocol version. Version int32 // Hash of the previous block in the block chain. PrevBlock chainhash.Hash // Merkle tree reference to hash of all transactions for the block. MerkleRoot chainhash.Hash // Time the block was created. This is, unfortunately, encoded as a // uint32 on the wire and therefore is limited to 2106. Timestamp time.Time // Difficulty target for the block. Bits uint32 // Nonce used to generate the block. Nonce uint32 } 而我们的 Data, 在比特币中对应的是交易,是另一个单独的数据结构。为了简便起见,目前将这两个数据结构放在了一起。在真正的比特币中,区块 的数据结构如下: Field Description Size Magic no value always 0xD9B4BEF9 4 bytes Blocksize number of bytes following up to end of block 4 bytes Blockheader consists of 6 items 80 bytes Transaction counter positive integer VI = VarInt 1 - 9 bytes transactions the (non empty) list of transactions 在我们的简化版区块中,还有一个 Hash 字段,那么,要如何计算哈希呢?哈希计算,是区块链一个非常重要的部分。正是由于它,才保证了区块链的安全。计算一个哈希,是在计算上非常困难的一个操作。即使在高速电脑上,也要耗费很多时间 (这就是为什么人们会购买 GPU,FPGA,ASIC 来挖比特币) 。这是一个架构上有意为之的设计,它故意使得加入新的区块十分困难,继而保证区块一旦被加入以后,就很难再进行修改。在接下来的内容中,我们将会讨论和实现这个机制。 目前,我们仅取了 Block 结构的部分字段(Timestamp, Data 和 PrevBlockHash),并将它们相互拼接起来,然后在拼接后的结果上计算一个 SHA-256,然后就得到了哈希. Hash = SHA256(PrevBlockHash + Timestamp + Data) 在 SetHash 方法中完成这些操作: func (b *Block) SetHash() { timestamp := []byte(strconv.FormatInt(b.Timestamp, 10)) headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{}) hash := sha256.Sum256(headers) b.Hash = hash[:] } 接下来,按照 Golang 的惯例,我们会实现一个用于简化创建区块的函数 NewBlock: func NewBlock(data string, prevBlockHash []byte) *Block { block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}} block.SetHash() return block } 区块链 有了区块,下面让我们来实现区块链。本质上,区块链就是一个有着特定结构的数据库,是一个有序,每一个块都连接到前一个块的链表。也就是说,区块按照插入的顺序进行存储,每个块都与前一个块相连。这样的结构,能够让我们快速地获取链上的最新块,并且高效地通过哈希来检索一个块。 在 Golang 中,可以通过一个 array 和 map 来实现这个结构:array 存储有序的哈希(Golang 中 array 是有序的),map 存储 hash -> block 对(Golang 中, map 是无序的)。 但是在基本的原型阶段,我们只用到了 array,因为现在还不需要通过哈希来获取块。 type Blockchain struct { blocks []*Block } 这就是我们的第一个区块链!是不是出乎意料地简单? 就是一个 Block 数组。 现在,让我们能够给它添加一个区块: func (bc *Blockchain) AddBlock(data string) { prevBlock := bc.blocks[len(bc.blocks)-1] newBlock := NewBlock(data, prevBlock.Hash) bc.blocks = append(bc.blocks, newBlock) } 结束!不过,就这样就完成了吗? 为了加入一个新的块,我们必须要有一个已有的块,但是,初始状态下,我们的链是空的,一个块都没有!所以,在任何一个区块链中,都必须至少有一个块。这个块,也就是链中的第一个块,通常叫做创世块(genesis block). 让我们实现一个方法来创建创世块: func NewGenesisBlock() *Block { return NewBlock("Genesis Block", []byte{}) } 现在,我们可以实现一个函数来创建有创世块的区块链: func NewBlockchain() *Blockchain { return &Blockchain{[]*Block{NewGenesisBlock()}} } 检查一个我们的区块链是否如期工作: func main() { bc := NewBlockchain() bc.AddBlock("Send 1 BTC to Ivan") bc.AddBlock("Send 2 more BTC to Ivan") for _, block := range bc.blocks { fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash) fmt.Printf("Data: %s\n", block.Data) fmt.Printf("Hash: %x\n", block.Hash) fmt.Println() } } 输出: Prev. hash: Data: Genesis Block Hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168 Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168 Data: Send 1 BTC to Ivan Hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1 Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1 Data: Send 2 more BTC to Ivan Hash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1 总结 我们创建了一个非常简单的区块链原型:它仅仅是一个数组构成的一系列区块,每个块都与前一个块相关联。真实的区块链要比这复杂得多。在我们的区块链中,加入新的块非常简单,也很快,但是在真实的区块链中,加入新的块需要很多工作:你必须要经过十分繁重的计算(这个机制叫做工作量证明),来获得添加一个新块的权力。并且,区块链是一个分布式数据库,并且没有单一决策者。因此,要加入一个新块,必须要被网络的其他参与者确认和同意(这个机制叫做共识(consensus))。还有一点,我们的区块链还没有任何的交易! 进入 src 目录查看代码,执行 make 即可运行: $ cd src $ make ==> Go build ==> Running Prev. hash: Data: Genesis Block Hash: 4693b71eee96760de4b0f051083376dcbed2f0711a44294ee5fd42fbeacc9579 Prev. hash: 4693b71eee96760de4b0f051083376dcbed2f0711a44294ee5fd42fbeacc9579 Data: Send 1 BTC to Ivan Hash: 839380a2d0af1dc4686f16ade5423fecdc5f287db9322d9e18adcb4071e7c8ff Prev. hash: 839380a2d0af1dc4686f16ade5423fecdc5f287db9322d9e18adcb4071e7c8ff Data: Send 2 more BTC to Ivan Hash: b38052a029bd2b1b9d4bb478af45b4c88605e99bc64e49031ba06d21ad4b0b38 参考: [1] Block hashing algorithm [2] Building Blockchain in Go. Part 1: Basic Prototype bitcoin wiki 的区块结构: Field Description Size Magic no value always 0xD9B4BEF9 4 bytes Blocksize number of bytes following up to end of block 4 bytes Blockheader consists of 6 items 80 bytes Transaction counter positive integer VI = VarInt 1 - 9 bytes transactions the (non empty) list of transactions 源码:https://github.com/Jeiwan/blockchain_go 转自:https://github.com/liuchengxu/blockchain-tutorial 学分: 264 分类: Go 标签: go 比特币 点赞 9 收藏 12 分享 Twitter分享 微信扫码分享 本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。 你可能感兴趣的文章 2024 年 2 月公链行业研报:DeFi 腾飞,比特币 Layer 2 异军突起 62 浏览 Go1.21标准库 slog,日志新选择! 624 浏览 RoochBTC - 用链上索引器实现比特币二层 865 浏览 重新思考闪电网络 825 浏览 深入探讨比特币二层概念 1838 浏览 TI 专访 Merlin Protocol:构建在比特币网络上的资产适配协议 547 浏览 相关问题 如何使用GO语言获取TRX区块信息,以及对应块交易记录,那位大佬有链接或者代码可供参考一下嘛? 5 回答 如何开发一个NIZK(非交互式零知识证明)的DApp?能提供一个大致的学习路线吗? 1 回答 配置golang环境 1 回答 【招聘】【北京】【上市公司】区块链项目(商业探索三年半,Dapp已落地)招solidity和go工程师 0 回答 大家好,我是新手一枚,请多关照。 11 回答 比特币隔离地址怎么构造离线交易 1 回答 0 条评论 请先 登录 后评论 张小风 0xD305...609D 关注 贡献值: 869 学分: 4172 ETH 文章目录 关于 关于我们 社区公约 学分规则 Github 伙伴们 DeCert ChainTool GCC 合作 广告投放 发布课程 联系我们 友情链接 关注社区 Discord Twitter Youtube B 站 公众号 关注不错过动态 微信群 加入技术圈子 ©2024 登链社区 版权所有 | Powered By Tipask3.5| 粤公网安备 44049102496617号 粤ICP备17140514号 粤B2-20230927 增值电信业务经营许可证 × 发送私信 请将文档链接发给晓娜,我们会尽快安排上架,感谢您的推荐! 发给: 内容: 取消 发送 × 举报此文章 垃圾广告信息: 广告、推广、测试等内容 违规内容: 色情、暴力、血腥、敏感信息等内容 不友善内容: 人身攻击、挑衅辱骂、恶意行为 其他原因: 请补充说明 举报原因: 取消 举报 × 如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作! 200行Go代码实现区块链 —— 挖矿算法-CSDN博客 200行Go代码实现区块链 —— 挖矿算法 最新推荐文章于 2022-12-07 10:30:50 发布 VIP文章 高可用架构 最新推荐文章于 2022-12-07 10:30:50 发布 阅读量742 收藏 5 点赞数 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/weixin_45583158/article/details/100143343 版权 在本系列前两篇文章中[1][2],我们向大家展示了如何通过精炼的Go代码实现一个简单的区块链。包括生成块,验证块数据,广播通信等等,这一篇让我们聚焦在如何实现 PoW算法。 大家都无不惊呼比特币、以太坊及其他加密电子货币的持续狂热,特别是对于刚接触这个领域的新手,不断得听到张三李四通过 GPU “挖矿”而聚集价值数万乃至数百万加密电子货币。那么“挖矿”到底是什么? 它是如何工作的? 相信对于程序员来说,没有什么比自己动手实践一遍“挖矿”算法更好的学习办法了。在这篇文章中,让我们一起逐个解读每一个问题,并最终编写出自己的“挖矿”算法。这个算法称为工作证明算法(Proof-of-Work)[3],它是比特币和以太坊这两种最流行的加密货币的基础。 什么是“挖矿”? 加密电子货币因为稀缺才具有价值。以现在的比特币为例,如果任何人任何时候都可以随意“制造”比特币,那么作为电子货币它会变得毫无价值。比特币通过算法来控制产出的速率并在大约122年内达到最大量。这种随着时间推移缓慢、稳定并逐步产出的方式有效避免了通货膨胀。比特币的产出是通过给予“获胜矿工”奖励来实现,为了获取比特币奖励矿工之间会进行竞争。这个过程之所以被称为“挖矿”,是因为它类似于“Gold Rush”[4]时每个黄金矿工通过辛苦劳作并最终(希望)找到一点黄金。 “挖矿”是如何工作的? 如果 Google 一下这个问题,你会得到大量的结果。简单来说,“挖矿”就是“解决一个数学难题”的过程。我们先来了解一些密码学和哈希算法的知识。 密码学简要介绍 单向加密以人类可读的文本(明文)作为输入,比如“Hello world”这个字符串,再通过一个数学函数产生出难以辨认的输出(密文)。 这类函数或算法的性质和复杂性各不相同。 算法越复杂,逆向工程就越困难。 以流行的 SHA-256 算法为例。 通过这个网站[5]可以让你计算任意给定输入的输出,也就是 SHA-256 哈希值。比如让我们输入“Hello world”,看看得到了什么: 通过不断尝试计算“Hello world”的哈希值。你会发现每次的结果都完全相同。 这个过程称为幂等性。加密算法一个最基本的特性是,非常难以通过反向工程来求解输入,但是非常容易验证输出。比如上面的例子,你可以很容易验证给定输入“Hello world”的SHA-256哈希值是否正确,但很难通过给定的哈希值判断它的输入是什么。这就是为什么将这种类型的算法称为单向加密。比特币使用 Double SHA-256,它将 SHA-256 求得的哈希值作为输入再次计算 SHA-256 哈希值。 为了简化,我们只使用一次SHA-256。 挖矿 回到加密电子货币中,比特币就是通过让参与者利用这样的加密算法求解出符合特定条件的哈希值来实现“挖矿”过程。具体来说,比特币要求参与者通过 double SHA-256 算法计算出“前导0 最低0.47元/天 解锁文章 优惠劵 高可用架构 关注 关注 0 点赞 踩 5 收藏 觉得还不错? 一键收藏 知道了 0 评论 200行Go代码实现区块链 —— 挖矿算法 在本系列前两篇文章中[1][2],我们向大家展示了如何通过精炼的Go代码实现一个简单的区块链。包括生成块,验证块数据,广播通信等等,这一篇让我们聚焦在如何实现 PoW算法... 复制链接 扫一扫 go语言包管理测试代码 10-11 每个Go语言程序,都以package xxx开头,即申明本文件定义的所有函数、结构体,均从属于xxx包。当项目文件较多时,这种管理方式是所有编程语言的必然选择。相应地,通过import来调用包也是情理之中了,但低版本的Go语言很坑,并不支持import相对路径,故而本文对导入包的介绍,只在1.18以上的Go语言版本中有效。 博文地址:https://tinycool.blog.csdn.net/article/details/133766128 黄金矿工源码 05-07 黄金矿工源码,cocoscreator,仅供学习参考使用,可以直接运行 参与评论 您还未登录,请先 登录 后发表或查看评论 用Go语言打造区块链[1] KD的疯狂实验室 11-20 9342 最早由李笑来处了解到。 中文翻译文字部分看这里: https://zhuanlan.zhihu.com/p/29971930学好Go语言走遍天下都不怕。以下代码建立了一个非常原始的电子账本: go语言实现简易比特系统(八):总结 qq_31639829的博客 04-10 553 1. 系统流程图 这是代码要实现的功能 2. 主函数 func main () { //创建一个区块链, 指定输出地址 bc := NewBlockChain("1KzwEHm9adpgyT3DhDQPX7m99wQ4juXtiw") //调用命令行命令 cli := CLI{bc} //处理相应请求 cli.Run() } 3. 命令行函数 type CLI struct { bc *BlockChain } const Usage = ` printChain 正向打印区块链 Go语言实现区块链(四) zhongliwen1981的专栏 04-28 876 一、比特币交易介绍 1. 比特币交易与传统银行交易的区别? 传统银行的每个账户都有一个数据库保存用户的信息,例如:姓名、卡号、余额等信息。每产生一笔交易,银行系统都会更新用户账户的余额字段。 比特币的数据库只有交易,没有用户帐号信息。那么比特币系统如何维护用户的比特币呢? 不像银行系统,比特币系统中每个交易都是以之前的交易为基础。用户的比特币零散分布在不同的交易中。如果想要知道某个钱包... [译] 用 Go 编写你自己的区块链挖矿算法! weixin_34163741的博客 04-18 1121 原文地址:Code your own blockchain mining algorithm in Go! 原文作者:Coral Health 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m… 译者:EmilyQiRabbit 校对者:stormluke,mingxing47 如果你对下面的教程有任何问题或者建议,加入我们的 Telegram 消息群,可... 《区块链技术与应用》-07-BTC-挖矿难度 weixin_41029475的博客 12-07 517 为什么要调整挖矿难度 挖矿难度 SHA-256产生的输出有256位,输出空间为2^256个可能取值,调整目标空间大小,简单来说就是满足输出值的前面几位是0。 挖矿难度和目标阈值成反比,如下图所示,其中difficulty_1_target为是挖矿难度为1时候的target(0111111…),即最小挖矿难度。 改变挖矿难度的原因 系统总算力加强,区块难度不变的话,出块时间会变短,而不能维持人为选择的参数10min。 出块时间短存在的问题 假设出块1s,传播几十秒,两个节点同时收到一个区块,又同时发布了一个 2021-04-27 weixin_44759007的博客 04-27 137 CDO 批量 mask不规则区域:https://blog.csdn.net/Shraon_L/article/details/115161756 挖矿算法简单理解 Alex的博客 08-19 2365 每个区块的hash值是由以下几点决定: f(index+previous hash+data+timestamp+nonce)=hash previous hash:上一个区块的hash值 data:当前区块的交易数据 一个有效的区块有一个带有四个前四位为零的hash,前面的零的个数成为difficulty:难度 hash是一个十六进制固定长度的64位的唯一标识 挖矿的过程就是找到一个... 以太坊挖矿源码:clique算法 weixin_30666943的博客 04-09 483 上文我们总结了以太坊最主要的共识算法:ethash算法,本文将重点分析以太坊的另一个共识算法:clique。 关键字:clique,共识算法,puppeth,以太坊地址原理,区块校验,认证结点,POA,选举投票,snapshot,Comma-ok断言 clique 以太坊的官方共识算法是ethash算法,这在前文已经有了详细的分析: 它是基于POW的共识机制的,矿工需要通过计算nonce... 拟态区块链——区块链安全解决方案.pdf 08-15 #资源达人分享计划# 区块链——重塑新的媒介传播生态.pdf 08-15 #资源达人分享计划# 区块链——健康险的信任保护伞.pdf 08-15 #资源达人分享计划# 区块链——企业财务管理的新时代.pdf 08-15 #资源达人分享计划# 贪心问题(Python代码实现)——磁带最优存储问题 01-21 今早任务——贪心算法,Python代码实现算法课的作业。 磁带最优存储问题 设有n 个程序{1,2,…, n }要存放在长度为L的磁带上。程序i存放在磁带上的长度是Li, 1≤i≤n。这n 个程序的读取概率分别是p1,p2,…,pn,且p1+... gensim-3.5.0-cp35-cp35m-manylinux1_x86_64.whl.zip 03-15 gensim-3.5.0-cp35-cp35m-manylinux1_x86_64.whl.zip 基于STM32 人群定位、调速智能风扇设计(程序、设计报告、视频演示).zip 最新发布 03-15 stm32,物联网,智能家居,是一个综合不错的例程,适合毕业设计、课程设计作业,所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答! stm32,物联网,智能家居,是一个综合不错的例程,适合毕业设计、课程设计作业,所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答! stm32,物联网,智能家居,是一个综合不错的例程,适合毕业设计、课程设计作业,所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答! 语音质量客观评价——pesq算法及matlab代码实现 11-16 PESQ(Perceptual Evaluation of Speech Quality)是一种用于语音质量客观评价的算法。它可以通过对比原始语音和压缩或传输后的语音之间的差异来评估语音质量。 PESQ算法的实现可以使用MATLAB进行。MATLAB是一种功能强大的数学计算和数据分析工具,可以用于信号处理和语音分析。 在MATLAB中,可以使用波形分析、滤波和频谱分析等技术来实现PESQ算法。以下是一个简单的MATLAB代码示例,实现了PESQ算法的基本功能: ```matlab % 输入原始语音和压缩/传输后的语音文件 original_file = 'original.wav'; processed_file = 'processed.wav'; % 读取原始语音和处理后的语音 [x, fs] = audioread(original_file); [y, fs] = audioread(processed_file); % 做必要的前处理,例如滤波器和增益调整 % 计算PESQ得分 pesq_score = pesq(x, y, fs); disp(['PESQ Score: ', num2str(pesq_score)]); ``` 上述代码中,我们首先读取原始语音和处理后的语音文件。然后可以对原始语音和处理后的语音进行一些预处理,例如滤波或增益调整,以模拟实际环境中的传输或压缩条件。 最后,我们通过调用`pesq()`函数来计算PESQ得分。该函数将原始语音、处理后的语音和采样率作为输入参数,并返回一个表示语音质量的数值。得分越高,表示语音质量越好。 需要注意的是,这只是一个简单的示例代码,实际的PESQ算法可能需要更多的处理步骤和参数设置。 总的来说,PESQ算法可用于语音质量客观评价,并可以使用MATLAB来实现。这种客观评价方法可以帮助我们判断语音信号在压缩或传输过程中的质量损失程度。 “相关推荐”对你有帮助么? 非常没帮助 没帮助 一般 有帮助 非常有帮助 提交 高可用架构 CSDN认证博客专家 CSDN认证企业博客 码龄5年 暂无认证 408 原创 16万+ 周排名 1万+ 总排名 67万+ 访问 等级 4947 积分 512 粉丝 331 获赞 109 评论 1974 收藏 私信 关注 热门文章 Rust Web框架怎么选?研究本文就够了! 31241 为何大量网站不能抓取?爬虫突破封禁的6种常见方法 28111 JDK 16 对 ZGC 的增强 16870 保证分布式系统数据一致性的6种方案 14903 Rust 和 C 性能对比:排序 11322 最新评论 揪出一个导致GC慢慢变长的JVM设计缺陷 夕阳再美不如你: 假如我不知道系统中存在哪些对JavaScript的调用,我怎么去定位是哪一块的代码导致的 专访微软亚洲研究院首席研发经理邹欣:AI 时代程序员将往哪走? SoftwareTeacher: 引用「例如大家跑一百米,很多人没什么准备就全力跑,途中不太讲究姿势和动作,就是放飞自我,最多二十秒就过去了」 要跑马拉松。 分布式任务调度系统设计:详解Go实现任务编排与工作流 菜鸟程序猿_c: 请问一下如果下一个任务需要上一个任务的结果怎么办 3大问题!Redis缓存异常及处理方案总结 归去来 兮: 为什么要放照片啊,看到照片吓了一跳 领域驱动设计(DDD)在爱奇艺打赏业务的实践 z18856046025: 能提供一下代码地址不 您愿意向朋友推荐“博客详情页”吗? 强烈不推荐 不推荐 一般般 推荐 强烈推荐 提交 最新文章 数据库不应放在容器中?- B站Kubernetes有状态服务实践(Elasticsearch/Clickhouse) 真心建议大家冲一冲新兴领域,工资高前景好!人才缺口极大!! 一文详解全栈可观测的实现路径 2024年25篇 2023年56篇 2022年111篇 2021年170篇 2020年164篇 2019年85篇 2018年110篇 2017年110篇 2016年124篇 2015年50篇 目录 目录 最新文章 数据库不应放在容器中?- B站Kubernetes有状态服务实践(Elasticsearch/Clickhouse) 真心建议大家冲一冲新兴领域,工资高前景好!人才缺口极大!! 一文详解全栈可观测的实现路径 2024年25篇 2023年56篇 2022年111篇 2021年170篇 2020年164篇 2019年85篇 2018年110篇 2017年110篇 2016年124篇 2015年50篇 目录 评论 被折叠的 条评论 为什么被折叠? 到【灌水乐园】发言 查看更多评论 添加红包 祝福语 请填写红包祝福语或标题 红包数量 个 红包个数最小为10个 红包总金额 元 红包金额最低5元 余额支付 当前余额3.43元 前往充值 > 需支付:10.00元 取消 确定 下一步 知道了 成就一亿技术人! 领取后你会自动成为博主和红包主的粉丝 规则 hope_wisdom 发出的红包 实付元 使用余额支付 点击重新获取 扫码支付 钱包余额 0 抵扣说明: 1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。 余额充值 比特币挖矿机开发(三)【go语言学习】 - Go语言中文网 - Golang中文社区 主题 文章 项目 资源 图书 Go网址导航 下载 官方文档 英文文档 中文文档 标准库中文版 Go指南 注册登录 分享 首页 文章
比特币挖矿机开发(三)【go语言学习】
modiziri
· · 2335 次点击 ·
·
开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。 第一次,站长亲自招 Gopher 了>>> 这里讲一下project A的开始代码。同时测试代码也会给你的操作评分评等级。还有文件里的两个简单输出,服务器和客户端(分别在srunner 和 crunner里)可以帮你测试自己的代码是否按照要求运行。注意,上面的这些代码和指令都是假设你把go语言的路径设定在根目录“p1”下的。 如果你有任何建立,安装和测试文件的问题,http://golang.org/doc/code.html可以去这里看看“ How to Write Go Code”。这是一个学习go工作区运行和组织语言的一个好资源。还有,这个关于go语言的命令学习资源也很有用。“http://golang.org/cmd/go/” 现在我们开始学习怎么写go语言: 直接讲文字太虚,我先贴一段go语言的helloworld package main import "fmt" func main() { fmt.Println("Hello, 世界") } 这里推荐一个资料和背景的链接go语言资料 这里还有一个很好玩的编译器和学习软件 google学习群,详细学习中文文档,windows环境搭建 有疑问加站长微信联系(非本文作者) 本文来自:CSDN博客 感谢作者:modiziri 查看原文:比特币挖矿机开发(三)【go语言学习】 入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889 2335 次点击 加入收藏 微博 赞 收入我的专栏 上一篇:Golang的不定参数 下一篇:比特币挖矿机开发(二) 代码 挖矿 http 根目录 0 回复 暂无回复 添加一条新回复 (您需要 登录 后才能回复 没有账号 ?) 编辑 预览 请尽量让自己的回复能够对别人有帮助 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码` 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet 图片支持拖拽、截图粘贴等方式上传 提交 用户登录 记住登录状态 没有账号?注册 忘记密码? 或 GitHub 登录 Gitea 登录 Go今日面试题 今日阅读排行 一周阅读排行 关注我 扫码关注领全套学习资料 加入 QQ 群: 192706294(已满) 731990104(已满) 798786647(已满) 729884609(已满) 977810755(已满) 815126783(已满) 812540095(已满) 1006366459(已满) 692541889 加入微信群:liuxiaoyan-s,备注入群 也欢迎加入知识星球 Go粉丝们(免费) × 给该专栏投稿 写篇新文章 每篇文章有总共有 5 次投稿机会 × 收入到我管理的专栏 新建专栏 关于 •
FAQ •
贡献者 •
晨读 •
Github •
新浪微博 •
Play •
免责声明 •
联系我们 •
捐赠 •
酷站 •
Feed订阅 •
243116 人在线
最高记录 5390
©2013-2024 studygolang.com Go语言中文网,中国 Golang 社区,致力于构建完善的 Golang 中文社区,Go语言爱好者的学习家园。
Powered by StudyGolang(Golang + MySQL) • · CDN 采用 七牛云 VERSION: V4.0.0 · 8.780658ms · 为了更好的体验,本站推荐使用 Chrome 或 Firefox 浏览器 京ICP备14030343号-1 X 登录和大家一起探讨吧 用户名 密码 记住登录状态
登录
GitHub 登录
忘记密码? 还不是会员现在注册[译] 用 Go 编写你自己的区块链挖矿算法!-CSDN博客
>手把手带你用golang构建区块链(4)交易(译)第一部分 - 知乎
深入底层:Go语言从零构建区块链(一): Hello, Blockchain - 知乎
golang 实现区块链(Bitcoin)系列1 - 基本原型 | 登链社区 | 区块链技术社区
200行Go代码实现区块链 —— 挖矿算法-CSDN博客
>比特币挖矿机开发(三)【go语言学习】 - Go语言中文网 - Golang中文社区
Golang语言情怀--第70期 区块链技术-挖矿流程-腾讯云开发者社区-腾讯云
ng语言情怀--第70期 区块链技术-挖矿流程-腾讯云开发者社区-腾讯云李海彬Golang语言情怀--第70期 区块链技术-挖矿流程关注作者腾讯云开发者社区文档建议反馈控制台首页学习活动专区工具TVP最新优惠活动文章/答案/技术大牛搜索搜索关闭发布登录/注册首页学习活动专区工具TVP最新优惠活动返回腾讯云官网李海彬首页学习活动专区工具TVP最新优惠活动返回腾讯云官网社区首页 >专栏 >Golang语言情怀--第70期 区块链技术-挖矿流程Golang语言情怀--第70期 区块链技术-挖矿流程李海彬关注发布于 2022-05-19 13:41:395680发布于 2022-05-19 13:41:39举报文章被收录于专栏:Golang语言社区Golang语言社区步骤一:发起交易用户进入钱包,执行一个交易操作,他将一个加密货币或者一个token发送给另一个用户。步骤二:进入交易池现在这个交易被钱包广播,等待区块链上的矿工们来拾取它。在被拾取前,它会一直在“未确认交易池”中等待。所有等待被处理的交易都会在未确认交易池中,未确认交易池不是网络上的一个巨大的池,而是很多小的分散在矿工本地的缓存池。步骤三:确认待打包的交易区块链网络上的矿工(有时叫节点)从未确认交易池中选择交易打包成数据块。除了一些额外的元数据外,数据块基本上就是交易数据(此时仍然是未确认交易)。每个矿工打包它们拾取的交易数据块,多个矿工可以选择同样的交易数据打包。例如,两个矿工,矿工A和矿工B都决定打包交易X。每个区块链对数据块都有最大限制。在比特币区块链上,这个最大值是1MB。在打包交易前,矿工需要先根据区块链的历史数据检查这个交易是否有资格被打包。根据区块链历史数据记录,如果支付者的钱包里有足够的余额,这笔交易被认为是有效的,并且可以被打包上链。假如一个比特币持有者想要加速他的交易进度,他可以选择支付更高的挖矿奖励。矿工通常会优先打包这些支付更高挖矿奖励的交易。步骤四:计算签名出块矿工的工作就是选择交易数据并打包成块。要把这些块添加到区块链上(这意味着让区块链上所有节点都接受这个块的数据),这个数据块首先需要签名(也叫“工作证明”)。这个签名是在解决了一个非常复杂的数学问题后得到的,这个签名是独一无二的。每个区块需要解决的数学问题难度是一样的。为了解决这个数学问题,需要耗费相当多的算力(所以,要消耗相当多的电力)。这个过程就被叫做挖矿。如果你想知道更多关于这个问题的内容,请继续阅读,如果你只想简单了解一下,请跳到步骤五。挖矿即哈希(工作量证明)矿工在打包块时需要解决的数学问题实际上就是找到一个以一定量的零开头的哈希函数的输出结果(就是签名)。这听起来很复杂对吗?但是它并不难理解。开始之前,我们需要先了解一下什么是哈希函数。哈希函数很难解,但其结果非常容易验证。哈希函数的输入值可以是任意字符串,随机输出一个32位的字母和数字的字符串。如果输入中有任何一点小小的变动,输出也将会随机改变。然而,同样的输入字符串只会得到同样的输出。矿工要打包的交易数据就是一个字符串,将它进行哈希计算,就会得到一个32位的输出值。比特币区块链有一个规则,要求打包的数据块签名必须以一定数量的零开头。然而哈希计算的输出值是对它的每个输入值都是随机的,那么,输入的字符串哈希后没有得到这么多零开头的值怎么办呢?这就是为什么矿工需要不断的去改变块里面一个叫"nonce"的值,每改变一次nonce的值,就会改变块的数据,哈希运算后得到的签名也会不一样,也就是,每改变一次nonce的值,就会得到一个全新的签名。矿工无限次重复改变nonce的值,直到得到一个符合要求的签名。下图例子中,签名是以7个零开头的。但是具体需要多少个零,取决于区块链上的区块难度。区块难度的问题相对要难一些 。这就是矿工们为什么需要为它们打包的数据块找到一个合格的签名,也是需要那么多算力来解决这个数学问题的原因。试想一下需要这么多次更改nonce值并计算需要多少时间和算力呀。此外,当更多的矿工加入到区块链,哈希运算的难度也将增加并且会导致更高的电费支出。现在我们继续第五步。注意:此过程实际上不是定义为数学问题,而是定义确定性问题 - 计算机对数字执行预先确定的操作,以查看输出是否可取。步骤五:广播区块矿工找到了一个合格的签名,他就可以向其他所有矿工广播他的数据块和签名。步骤六:验证区块其他矿工现在要确认通过广播收到的数据块的签名合法性,他们要对这个数据块进行哈希运算检查它是否输出一个以这么多零开头的签名。如果检查通过,其他矿工就会认为这个数据块有效,并且同意将它添加到区块链上(他们达成了共识,即他们所有矿工都同意彼此,所以术语叫共识算法)。这也是“工作量证明”的来源。签名就是矿工工作的证明(已花费的算力),现在,数据块可以加到区块链上了,并且分发到网络上所有其他节点。只要这个数据块中的所有交易数据都跟区块链上的历史数据符合,其他节点将接收这个数据块并将其保存。步骤七当一个数据块被添加到区块链上后,这条区块链上的所有块都认为它是正确的。例如,我的交易包含在第502号块中,并且这条区块链现在最长是第507号块,它的意思就是说我的交易数据被确认过5次(507-502)。它被认为是正确的,因为每次有其他块上链的时候,区块链都会就所有交易记录达成共识,包括你的交易和你的块。你可以说,到这个时候,你交易已经被确认了5次。这也是Etherscan在显示交易详细信息时所指的。你的交易被确认的次数越多(即嵌入区块链越深),攻击者就越难更改它。每当新的交易加入到区块链,所有矿工都需要从第三步重新开始,打包一个新的交易数据块。参考资料:Go语言中文文档http://www.golang.ltd/Go语言官方文档
https://golang.google.cn/Golang语言情怀
ID:wwwGolangLtd www.Golang.Ltd游戏服务器架构丨分布式技术丨大数据丨Go语言学习本文参与 腾讯云自媒体分享计划,分享自微信公众号。原始发表:2022-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除打包编程算法区块链比特币本文分享自 Golang语言情怀 微信公众号,前往查看如有侵权,请联系 cloudcommunity@tencent.com 删除。本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!打包编程算法区块链比特币评论登录后参与评论0 条评论热度最新登录 后参与评论推荐阅读LV.关注文章0获赞0目录步骤一:发起交易步骤二:进入交易池步骤三:确认待打包的交易步骤四:计算签名出块挖矿即哈希(工作量证明)步骤五:广播区块步骤六:验证区块步骤七相关产品与服务区块链云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。产品介绍2024新春采购节领券社区专栏文章阅读清单互动问答技术沙龙技术视频团队主页腾讯云TI平台活动自媒体分享计划邀请作者入驻自荐上首页技术竞赛资源技术周刊社区标签开发者手册开发者实验室关于社区规范免责声明联系我们友情链接腾讯云开发者扫码关注腾讯云开发者领取腾讯云代金券热门产品域名注册云服务器区块链服务消息队列网络加速云数据库域名解析云存储视频直播热门推荐人脸识别腾讯会议企业云CDN加速视频通话图像分析MySQL 数据库SSL 证书语音识别更多推荐数据安全负载均衡短信文字识别云点播商标注册小程序开发网站监控数据迁移Copyright © 2013 - 2024 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有 深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档Copyright © 2013 - 2024 Tencent Cloud.All Rights Reserved. 腾讯云 版权所有登录 后参与评论00
Go语言简单实现比特币挖矿原理 - 简书
简单实现比特币挖矿原理 - 简书登录注册写文章首页下载APP会员IT技术Go语言简单实现比特币挖矿原理佛系博主关注赞赏支持Go语言简单实现比特币挖矿原理区块链基本概念区块链本质上是一个对等网络(peer-to-peer)的分布式账本数据库,
比特币的底层就采用了区块链的技术架构。区块链本身其实是一串链接的数据区块,每相邻区块之间相互连接,其链接指针是采用密码学哈希算法对区块头进行处理所产生的区块头哈希值。每一个区块数据块中记录了一组采用哈希算法组成的树状交易状态信息,这样保证了每个区块内的交易数据不可篡改,区块链里链接的区块也不可篡改。
比特币的交易记录会保存在数据区块中,比特币系统中大约每10分钟会产生一个区块,每个数据区块一般包含区块头(Header)和区块体(Body)两部分,如图所示。
1-1.jpg
区块头封装了当前的版本号(Version)、前一区块地址(Prev-Block)、时间戳(Timestamp)、随机数(Nonce)、当前 区块的目标哈希值(Bits)、Merkle数的根值(Merkle-root)等信息。
区块头分析
前80个字节是区块头
{
"hash": "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506",
"ver": 1,
"prev_block": "000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250",
"mrkl_root": "f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766",
"time": 1293623863,
"bits": 453281356,
"nonce": 274148111
}
字节
字段
说明
4
版本
区块版本号,表示区块遵守的验证规则
32
父区块头哈希值
前一区块的哈希值,使用SHA(SHA256(父区块头))计算
32
Merkle根
该区块中交易的Merkle树根的哈希值,同样采用SHA(SHA256(父区块头))计算
4
时间戳
该区块产生的近似时间,精确到秒的UNIX时间戳,必须严格大于前11个区块时间的中值,同时全节点也会拒绝那些超出自己2个小时时间戳的区块
4
难度目标
该区块工作量算法的难度目标,已经使用特定算法编码
4
Nonce
为了找到满足难度目标所设定的随机数,为了解决32位随机数在算力飞升的情况下不够用的问题,规定时间戳和coinbase交易信息均可更改,以此扩展nonce的位数
挖矿
区块在挖矿过程中产生。所谓的挖矿实际上是穷举随机数的算法,把上个区块的哈希值加上十分钟内的全部交易单打包,再加上一个算计数,算出一个256位的字符串哈希值,输入的随机数Nonce 使哈希值满足一定的条件就获得这个区块的交易记账权。新产生的区块需要快速的广播出去,以便其他的节点对其进行验证,以防止造假。当记账成功的时候,即获得区块奖励,也就是挖到了比特币。
获得比特币
随着随机数(Nonce)的不断变化,就会产生不同的哈希值,当产生的哈希值左面的连续位数的0值个数大于等于当前区块难度值的时候,即碰撞成功,找到随机数,获得记账权,获得比特币。如下图:
1-2.png
这个难度为4,碰撞出的随机数是87471.随着难度的不断提高,碰撞出随机数的概率就越低。目前比特币矿机最大的算力为蚂蚁大陆的S9矿机(14TH/s)。我就有两台哦,不过现在每天的产量只有0.0009个BTC,少的可怜。。。
代码实现
定义block结构体
type block struct {
ver int //版本号
prev_block string //父区块的哈希值
mekl_root string //该区块merkle树的哈希值
time string //时间戳
bits int // 难度
}
获取哈希值
func getHashValueStr(nonce int,blc block) string {
//拼接区块版本号,时间戳,父区块,merkle树,随机数为hv字符串
hv := strconv.Itoa(blc.ver) + blc.time + blc.prev_block+
blc.mekl_root + strconv.Itoa(nonce)
first := sha256.New()
first.Write([]byte(hv))
// first.Sum(nil)返回值为[]byte 类型的数组,
而哈希值由每位字符16进制字符组成,所以应用fmt.Springtf
函数将数组转化为单个字节为16进制拼接而成的哈希字符串
return fmt.Sprintf("%x",first.Sum(nil))
}
检验随机数生产的哈希函数是否符合条件
func mining(hashStr string, diff int) bool {
var I int
for i = 0; i < len(hashStr); i++ {
//如果i位数 的值不为0,不满足条件,跳出循环
if hashStr[i] != '0' {
break
}
}
//判断i的值是否大于当前的难度,大于碰撞成功,否则失败
return i >= diff
}
获取随机数
func getNonce(blc block)int {
nonce := 0
//改变nonce的值,如果返回false,nonce++
for !mining(getHashValueStr(nonce,blc), blc.bits) {
fmt.Println(getHashValueStr(nonce,blc))
nonce ++
}
fmt.Println(getHashValueStr(nonce,blc))
fmt.Println("出块成功!")
return nonce
}
主函数
func main() {
prev_block := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
mrkl_root := "000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250"
time := "1293623863"
bits := 4
block := block{1, prev_block, mrkl_root, time, bits}
nc := getNonce(block)
fmt.Println(nc)
}
运行结果
1-3
总结
代码只是简单的实现了比特币的挖矿原理,实际上可能比这处理的更细致,考虑的更全面一些。
至于挖矿的事情,兵法有云“兵贵神速”,17年比特币大涨,那时候难度还不是很高,去云南四川那边投资矿厂的人都赚的盆满钵满,我就认识了一位17年初挖矿的矿工,最高峰拥有20000台S9,一年赚了将近10亿,投资成本据说是几十万。当然这些也都需要一些眼光,勇气,我只是在现在看过去罢了,至于那个时候谁都不知道比特币能涨这么猛。包括现在我之所以还会继续购置矿机,是因为我同样认为目前比特币还远远未到达它应有的价值,产量虽然少,但是挖出的币我是不会卖的,5年以后,10年以后再看,那可能同样现在看过去的感觉。当然这些不是重点,也不构成投资建议。重点看代码,看代码!
github源代码
据说找工作github的Star很重要,哈哈哈。喜欢就star一下吧!
作者原创,转载请注明出处,如有错误描述,请评论纠正,谢谢大家!
最后编辑于 :2018.04.27 19:34:15©著作权归作者所有,转载或内容合作请联系作者人面猴序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...沈念sama阅读 147,998评论 1赞 315死咒序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...沈念sama阅读 63,184评论 1赞 263救了他两次的神仙让他今天三更去死文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...开封第一讲书人阅读 98,595评论 0赞 217道士缉凶录:失踪的卖姜人 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...开封第一讲书人阅读 41,982评论 0赞 188港岛之恋(遗憾婚礼)正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...茶点故事阅读 49,919评论 1赞 266恶毒庶女顶嫁案:这布局不是一般人想出来的文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...开封第一讲书人阅读 39,299评论 1赞 183城市分裂传说那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...沈念sama阅读 30,845评论 2赞 282双鸳鸯连环套:你想象不到人心有多黑文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...开封第一讲书人阅读 29,607评论 0赞 175万荣杀人案实录序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...沈念sama阅读 33,040评论 0赞 222护林员之死正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...茶点故事阅读 29,690评论 2赞 225白月光启示录正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...茶点故事阅读 31,047评论 1赞 236活死人序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...沈念sama阅读 27,485评论 2赞 219日本核电站爆炸内幕正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...茶点故事阅读 31,958评论 3赞 215男人毒药:我在死后第九天来索命文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...开封第一讲书人阅读 25,747评论 0赞 9一桩弑父案,背后竟有这般阴谋文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...开封第一讲书人阅读 26,253评论 0赞 175情欲美人皮我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...沈念sama阅读 34,074评论 2赞 239代替公主和亲正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...茶点故事阅读 34,222评论 2赞 241评论0赞33赞4赞赞赏更
200行Go代码实现区块链之三 —— 挖矿算法_var newblock block-CSDN博客
>200行Go代码实现区块链之三 —— 挖矿算法_var newblock block-CSDN博客
200行Go代码实现区块链之三 —— 挖矿算法
最新推荐文章于 2024-03-15 14:58:59 发布
阿卡司机
最新推荐文章于 2024-03-15 14:58:59 发布
阅读量1.4k
收藏
5
点赞数
分类专栏:
区块链
文章标签:
go
区块链
区块链
专栏收录该内容
39 篇文章
4 订阅
订阅专栏
在本系列前两篇文章中[1][2],我们向大家展示了如何通过精炼的Go代码实现一个简单的区块链。包括生成块,验证块数据,广播通信等等,这一篇让我们聚焦在如何实现 PoW算法。
大家都无不惊呼比特币、以太坊及其他加密电子货币的持续狂热,特别是对于刚接触这个领域的新手,不断得听到张三李四通过 GPU “挖矿”而聚集价值数万乃至数百万加密电子货币。那么“挖矿”到底是什么? 它是如何工作的? 相信对于程序员来说,没有什么比自己动手实践一遍“挖矿”算法更好的学习办法了。在这篇文章中,让我们一起逐个解读每一个问题,并最终编写出自己的“挖矿”算法。这个算法称为工作证明算法(Proof-of-Work)[3],它是比特币和以太坊这两种最流行的加密货币的基础。
什么是“挖矿”?
加密电子货币因为稀缺才具有价值。以现在的比特币为例,如果任何人任何时候都可以随意“制造”比特币,那么作为电子货币它会变得毫无价值。比特币通过算法来控制产出的速率并在大约122年内达到最大量。这种随着时间推移缓慢、稳定并逐步产出的方式有效避免了通货膨胀。比特币的产出是通过给予“获胜矿工”奖励来实现,为了获取比特币奖励矿工之间会进行竞争。这个过程之所以被称为“挖矿”,是因为它类似于“Gold Rush”[4]时每个黄金矿工通过辛苦劳作并最终(希望)找到一点黄金。
“挖矿”是如何工作的?
如果 Google 一下这个问题,你会得到大量的结果。简单来说,“挖矿”就是“解决一个数学难题”的过程。我们先来了解一些密码学和哈希算法的知识。
密码学简要介绍
单向加密以人类可读的文本(明文)作为输入,比如“Hello world”这个字符串,再通过一个数学函数产生出难以辨认的输出(密文)。 这类函数或算法的性质和复杂性各不相同。 算法越复杂,逆向工程就越困难。 以流行的 SHA-256 算法为例。 通过这个网站[5]可以让你计算任意给定输入的输出,也就是 SHA-256 哈希值。比如让我们输入“Hello world”,看看得到了什么:
通过不断尝试计算“Hello world”的哈希值。你会发现每次的结果都完全相同。 这个过程称为幂等性。加密算法一个最基本的特性是,非常难以通过反向工程来求解输入,但是非常容易验证输出。比如上面的例子,你可以很容易验证给定输入“Hello world”的SHA-256哈希值是否正确,但很难通过给定的哈希值判断它的输入是什么。这就是为什么将这种类型的算法称为单向加密。比特币使用 Double SHA-256,它将 SHA-256 求得的哈希值作为输入再次计算 SHA-256 哈希值。 为了简化,我们只使用一次SHA-256。
挖矿
回到加密电子货币中,比特币就是通过让参与者利用这样的加密算法求解出符合特定条件的哈希值来实现“挖矿”过程。具体来说,比特币要求参与者通过 double SHA-256 算法计算出“前导0”超过若干位的哈希值,第一个求解出来的参与者就是“获胜的矿工”。比如,我们求“886”这个字符串的 SHA-256 哈希值:
可以看到,是一个“前导0”为3位的哈希值(前三位是0)。回忆我们前面说到的“单向加密”的特点:任何人都可以很容易地验证“886”是否产生3位“前导0”的哈希值。但为了找到这样一个能产生3位“前导0”的输入(就是这里的“886”),我们做了大量繁琐的计算工作:从一个很大的数字和字母集合中逐个计算它们的哈希值并判断是否满足上述条件。如果我是第一个找到“886”的人,那其他人通过验证就能判断我做了这样大量繁琐的工作。在比特币、以太坊中这样的过程就称为工作证明算法。“如果我运气非常好,第一次尝试就找到了一个符合条件的(输入)值呢?” —— 这是非常不可能的,你可以试试随意输入一些字母和数字。比特币中实际的算法和约束要比上说要求复杂,当然也更难(要求更多位的“前导0”)。同时它也可以动态调整难度,目标是确保每隔10分钟产出一次比特币,不管参与“挖矿”的人多还是少。
差不多可以动手了
了解了足够的背景知识,接着我们就用 Go 语言来编码实践下工作量证明(Proof-of-Work)算法。
建议你阅读之前的《用200行Go代码实现自己的区块链》系列文章,因为下面工作证明算法部分会涉及之前的代码。
Proof-of-work
创建新块并加入到链上之前需要完成“工作量证明”过程。我们先写一个简单的函数来检查给定的哈希值是否满足要求。
哈希值必须具有给定位的“前导0”“前导0”的位数是由难度(difficulty)决定的可以动态调整难度(difficulty)来确保 Proof-of-Work 更难解
下面就是 isHashValid 这个函数:
func isHashValid(hash string, difficulty int) bool { prefix := strings.Repeat("0", difficulty) return strings.HasPrefix(hash, prefix)}
Go 语言的 strings 包中提供了方便的 Repeat 和 HasPrefix 函数。我们定 prefix 变量,它代表“前导0”,接着检查哈希值是否具有满足条件的“前导0”,然后返回 True 或 False 。我们修改之前生成块的generateBlock 函数:
func generateBlock(oldBlock Block, BPM int) Block { var newBlock Block t := time.Now() newBlock.Index = oldBlock.Index + 1 newBlock.Timestamp = t.String() newBlock.BPM = BPM newBlock.PrevHash = oldBlock.Hash newBlock.Difficulty = difficulty for i := 0; ; i++ { hex := fmt.Sprintf("%x", i) newBlock.Nonce = hex if !isHashValid(calculateHash(newBlock), newBlock.Difficulty) { fmt.Println(calculateHash(newBlock), " do more work!") time.Sleep(time.Second) continue } else { fmt.Println(calculateHash(newBlock), " work done!") newBlock.Hash = calculateHash(newBlock) break } } return newBlock}
创建一个新块 newBlock ,里面的 PrevHash 包含前一个块的哈希值,Timestamp 是时间戳,BPM 是心率数据,Difficulty 就是前面提到的难度,它的值决定了“前导0”的位数。这里的 for 循环很重要:
获得 i 的十六进制表示 ,将 Nonce 设置为这个值,并传入 calculateHash 计算哈希值。之后通过上面的 isHashValid 函数判断是否满足难度要求,如果不满足就重复尝试。这个计算过程会一直持续,知道求得了满足要求的 Nonce 值,之后通过 handleWriteBlock 函数将新块加入到链上。
篇幅有限,我们已经将完整代码发布在 Github上,可以从这里[6]获得。
跑起来看看
启动程序:
go run main.go在浏览器中访问 http://localhost:8080
接着通过 Postman 来发送一个包含心率数据的POST 请求。
接着我们观察命令行窗口,不断得计算哈希值,如果不满足难度要求就继续重试,直到找到满足要求的哈希值及 Nonce
可以看到最后一个哈希值满足我们设定的难度要求(1位“前导0”)。我们再来刷新下浏览器:
可以看到第二个块创建成功并加到链上了,其中Nonce 就是通过Proof-of-Work计算出来满足难度要求的值。
下一步
到这里要先祝贺你,上面的内容很有价值。尽管我们的示例中使用了非常低的难度,但本质上,工作证明算法就是比特币、以太坊等区块链的重要组成。对于下一步应该深入区块链的哪个方向,我们推荐可以学习如何通过 IPFS [7]存取大文件并与区块链打通。此外相比 Proof-of-Work,Proof-of-Stake 算法[8]正越来越受到关注和青睐,你也可以学习如何将本文的 PoW 算法改为实现 PoS 算法。
优惠劵
阿卡司机
关注
关注
0
点赞
踩
5
收藏
觉得还不错?
一键收藏
知道了
0
评论
200行Go代码实现区块链之三 —— 挖矿算法
在本系列前两篇文章中[1][2],我们向大家展示了如何通过精炼的Go代码实现一个简单的区块链。包括生成块,验证块数据,广播通信等等,这一篇让我们聚焦在如何实现 PoW算法。大家都无不惊呼比特币、以太坊及其他加密电子货币的持续狂热,特别是对于刚接触这个领域的新手,不断得听到张三李四通过 GPU “挖矿”而聚集价值数万乃至数百万加密电子货币。那么“挖矿”到底是什么? 它是如何工作的? 相信对于程序员来...
复制链接
扫一扫
专栏目录
lifecalendarworm蠕虫病毒 Life Calendar查杀 蠕虫查杀 蠕虫病毒查杀 挖矿蠕虫查杀工具
03-09
lifecalendarworm挖矿蠕虫查杀工具
内含三款病毒查杀工具,都是国外知名软件,国内软件就不推荐了
Lifecalendarworm是一种恶意软件,也被称为"Life Calendar"或"LimeRAT",它是一种后门蠕虫,可以允许攻击者远程控制受感染的计算机。
Lifecalendarworm可以在被感染的计算机上执行多种操作,包括窃取敏感信息(例如密码、账户信息等)、下载和安装其他恶意软件、发起网络攻击、破坏或删除文件等。
Lifecalendarworm通常通过垃圾邮件、社交媒体诈骗和恶意下载等方式传播,因此用户应该始终保持警惕,并避免下载和安装来自未知来源的软件。
如果您认为自己的计算机可能感染了Lifecalendarworm蠕虫,请立即运行一款可靠的反病毒软件,以检测和清除感染。
Scratch挖矿游戏作品:挖矿喵
03-14
可售出矿石,获得钱币,以购买“稿子”“护盾”等。干货满满,欢迎转载,记得注明原作者。此后仍有各热门或有趣游戏,请关注原作者,且点赞加收藏,记得推荐好友。下载即可玩,快点来下载吧!
参与评论
您还未登录,请先
登录
后发表或查看评论
挖矿交易的基本概念【go语言】(一)
weixin_45270330的博客
01-17
779
神秘的比特币,今天就用go语言解开它的谜团!!!
工业环境勒索与挖矿技术专项解决方案.pptx
01-22
工控安全
勒索病毒防范
挖矿技术防范解决方案
勒索病毒是一种常见的网络攻击,为了防范勒索病毒,可以采取以下措施:
安装并更新防病毒软件:及时更新防病毒软件,定期扫描计算机。
不要轻易下载不明来源的附件或文件。
避免使用未经验证的外部设备或存储介质。
定期备份重要数据,以防止数据丢失。
如果收到可疑邮件或信息,应及时删除并报告给相关机构。
在进行网上银行、在线支付等操作时,要确保所使用的浏览器和操作系统是安全的。
不要随意点击来历不明的链接或下载未知附件。
定期清理系统垃圾和临时文件,保持系统运行速度。
关闭不必要的端口和服务,减少潜在的安全风险。
不要在公共场所(如网吧)登录个人账户或进行网上交易。
总之,预防勒索病毒需要从多个方面入手,包括加强安全意识、安装防毒软件、避免下载不明来源的文件等。只有综合运用各种手段,才能有效地防范勒索病毒的威胁。
linux挖矿检测脚本
07-25
执行自动检测
091.Block And Var 块与局部变量
iOS开发学习笔记
07-19
452
---------------
main.m
---------------
#import
int
main()
{
int
a = 20;
void
(^printMy)(void) = ^(void)
{
NSLog(@"a:%d", a);
//
可以访问外面的局部变量
200行Go代码实现区块链 —— 挖矿算法
weixin_45583158的博客
03-07
742
在本系列前两篇文章中[1][2],我们向大家展示了如何通过精炼的Go代码实现一个简单的区块链。包括生成块,验证块数据,广播通信等等,这一篇让我们聚焦在如何实现 PoW算法...
《区块链技术与应用》-07-BTC-挖矿难度
weixin_41029475的博客
12-07
517
为什么要调整挖矿难度
挖矿难度
SHA-256产生的输出有256位,输出空间为2^256个可能取值,调整目标空间大小,简单来说就是满足输出值的前面几位是0。
挖矿难度和目标阈值成反比,如下图所示,其中difficulty_1_target为是挖矿难度为1时候的target(0111111…),即最小挖矿难度。
改变挖矿难度的原因
系统总算力加强,区块难度不变的话,出块时间会变短,而不能维持人为选择的参数10min。
出块时间短存在的问题
假设出块1s,传播几十秒,两个节点同时收到一个区块,又同时发布了一个
2021-04-27
weixin_44759007的博客
04-27
137
CDO 批量 mask不规则区域:https://blog.csdn.net/Shraon_L/article/details/115161756
挖矿算法简单理解
Alex的博客
08-19
2365
每个区块的hash值是由以下几点决定:
f(index+previous hash+data+timestamp+nonce)=hash
previous hash:上一个区块的hash值
data:当前区块的交易数据
一个有效的区块有一个带有四个前四位为零的hash,前面的零的个数成为difficulty:难度
hash是一个十六进制固定长度的64位的唯一标识
挖矿的过程就是找到一个...
黄金矿工源码
05-07
黄金矿工源码,cocoscreator,仅供学习参考使用,可以直接运行
区块链头号玩家——区块链:以寂静以狂欢.pdf
08-15
#资源达人分享计划#
算法之美——Python语言实现——递归算法
02-23
传统递归算法合集 递归求解斐波那契数列 递归求解全部排列 汉诺塔算法等
算法之美——Python语言实现——排序算法
03-05
传统排序合集 冒泡排序 选择排序 插入排序 希尔排序 快速排序 归并排序
算法之美——Python语言实现——检索算法
03-20
传统检索算法合集 线性查找 二分查找 插值插值 斐波那契查找 分块查找 哈希查找 回溯查找
代码 基于遗传算法的优化计算——建模自变量降维代码
06-04
代码 基于遗传算法的优化计算——建模自变量降维代码代码 基于遗传算法的优化计算——建模自变量降维代码代码 基于遗传算法的优化计算——建模自变量降维代码代码 基于遗传算法的优化计算——建模自变量降维代码代码...
什么是去中心化,如何去中心化
最新发布
wsl3465205046的博客
03-15
151
去中心化(Decentralization)是指在组织、管理或运作中减少或消除中心化机构或权力的控制和影响,使得决策和资源分配更加分散和民主化的一种管理模式。在数字化和信息化时代,去中心化成为了一个重要的概念,尤其在区块链技术的发展和应用中,去中心化得到了广泛关注和实践。本文将介绍去中心化的概念、意义以及如何实现去中心化的方法和途径。
永热爱 敢向前 | Paraverse平行云的2023 年终总结
mlj890211的博客
03-14
577
Paraverse云技术底座通过整合元宇宙与Web3.0两大前沿方向涉及的实时云渲染、云原生、区块链等底层技术,Paraverse打造了去中心化的实时云渲染平台ParaLab,和适用于3D应用的Web3交易流转平台ParaHere,企业和开发者可以快速搭建数字平行世界云技术底座,开启通往平行世界的通道,建立去中心化的数字资产交易基础服务。在新一代互联网的冲击下,以“元宇宙”和“Web3.0”为代表的虚实结合、智能化、去中心化的3D信息系统,以及具备公平透明等特点的互联网媒介已成为公认的未来主流媒介形态。
windows挖矿木马
09-08
对于 Windows 系统的挖矿木马,以下是一些常见的问题和解决方案:
1. 如何防止 Windows 系统感染挖矿木马?
- 安装有效的杀毒软件,并始终保持其更新。
- 避免从不可信的来源下载和安装软件。
- 及时更新 Windows 操作系统和其他软件补丁。
2. 如何检测和删除挖矿木马?
运行杀毒软件全面扫描系统,确保其能检测并删除挖矿木马。
- 使用安全软件或工具来检测和清除恶意文件和注册表项。
- 对可疑进程和网络连接进行检查,并关闭或删除它们。
3. 如果我怀疑自己的系统被感染了,该怎么办?
- 立即运行杀毒软件进行系统扫描。
- 如果杀毒软件无法解决问题,可以尝试使用专门的挖矿木马清除工具。
- 如果问题仍然存在,可以考虑重装操作系统来清除感染。
请注意,这些只是一些基本的建议。如果你遇到了一个真实的威胁,最好咨询专业人士或技术支持来帮助你解决问题。
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
阿卡司机
CSDN认证博客专家
CSDN认证企业博客
码龄14年
暂无认证
70
原创
4万+
周排名
3万+
总排名
38万+
访问
等级
3977
积分
483
粉丝
320
获赞
187
评论
2210
收藏
私信
关注
热门文章
逆变器的重复控制
31310
springboot+thymeleaf之表单提交
29233
PFC双闭环控制仿真
21546
迭代学习控制方式Simulink建模与仿真
17622
spring boot操作mysql数据库:自动建表,数据添加、查询和修改
17307
分类专栏
运动控制
11篇
机器人
4篇
算法
7篇
区块链
39篇
自动控制
7篇
服务器
10篇
最新评论
迭代学习控制方式Simulink建模与仿真
求你早点睡吧:
离散化了吗
逆变器的重复控制
liangtiao164:
e[K]中的K就是相位补偿吧
PFC双闭环控制仿真
qq_43529562:
限幅是多少呢
PFC双闭环控制仿真
G4739766:
大佬大佬,能分享一下仿真源文件吗,已打赏感谢大佬3486511095@qq.com
迭代学习控制方式Simulink建模与仿真
aBeeeeeBa:
不太懂,闭环迭代没有Uk+1哪来的ek+1啊?
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
卡尔曼滤波器设计及实例
刻字机尖角补偿
旋转偏心裁切刀切向跟踪及半径补偿
2023年5篇
2022年5篇
2020年9篇
2019年5篇
2018年57篇
2017年2篇
目录
目录
分类专栏
运动控制
11篇
机器人
4篇
算法
7篇
区块链
39篇
自动控制
7篇
服务器
10篇
目录
评论
被折叠的 条评论
为什么被折叠?
到【灌水乐园】发言
查看更多评论
添加红包
祝福语
请填写红包祝福语或标题
红包数量
个
红包个数最小为10个
红包总金额
元
红包金额最低5元
余额支付
当前余额3.43元
前往充值 >
需支付:10.00元
取消
确定
下一步
知道了
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝
规则
hope_wisdom 发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
0
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。
余额充值