bitcoin

如果有时光机的话,我要做的第一件事情肯定就是穿梭回过去买比特币:),算了,不意淫了,还是学习要紧,虽然再也不能靠买比特币一夜暴富了,但是自己按照比特币实现一个山寨比特币的能力还是有的,比特币可以说是现在大红大紫的区块链的始祖,要全部了解它的原理可能还是要埋头啃个几个月的(并不简单)。

虽然比特币交易确认时间长,消耗资源多,但依旧无法掩盖其作为区块链始祖的光环。

bitcoin

Block & BlockChain

比特币中有两个重要的基本概念,区块和区块链,如果将区块想象成珍珠,那么区块链就是将这些珍珠都串起来的珍珠项链,这个珍珠项链没有尽头,新加入的珍珠和次新的珍珠彼此靠近,并通过某种关系紧密联系在一起,牢不可破。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type Block struct {
idx int
timestamp string
hash string
prevHash string
difficulty int
nonce string
}

type BlockChain struct {
sync.Mutex
blocks []Block
}

func (bc *BlockChain) AddBlock(block Block) {
bc.Lock()
defer bc.Unlock()
bc.blocks = append(bc.blocks, block)
}

var blockchain BlockChain

Proof of Work

生成区块的过程就相当于打磨珍珠的过程,只有符合要求的珍珠才能最终被加入到珍珠项链中去,那么话说回来生成区块的过程是怎么样的呢,对于一个特定的区块,需要不断改变其中一个值(nonce),这里的 nonce 值从0开始逐渐递增,然后计算特定 nonce 对应的区块哈希值,只有哈希值符合相应的要求之后,才能说这个区块是有效的,才能被加入到区块链中,生成区块的过程也被叫做挖矿。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func generateBlock(oldBlock Block, difficulty int) Block {
var newBlock Block

newBlock.idx = oldBlock.idx + 1
newBlock.timestamp = time.Now().String()
newBlock.prevHash = oldBlock.hash
newBlock.difficulty = diff

for i := 0; ; i++ {
hex := fmt.Sprintf("%x", i)
newBlock.nonce = hex
if !isHashValid(calculateHash(newBlock), newBlock.difficulty) {
continue
} else {
fmt.Println(calculateHash(newBlock), " work done!")
newBlock.Hash = calculateHash(newBlock)
break
}
}
return newBlock
}

func calculateHash(block Block) string {
record := strconv.Itoa(block.idx) + block.timestamp + block.prevHash + block.difficulty + block.nonce
h := sha256.New()
h.Write([]byte(record))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}

那么什么样的区块才是有效的呢,简单来说就是对于一个哈希值,其开头部分都是0就可以了(0越多,难度越高)。像这种,找到答案很困难但验证答案却非常轻松的算法就是 Proof of Work 的精髓。

1
2
3
4
func isHashValid(hash string, difficulty int) bool {
prefix := strings.Repeat("0", difficulty)
return strings.HasPrefix(hash, prefix)
}

一个难度逐渐递增的区块链

下面实现了一个难度逐渐递增的区块链,运行时就会发现产生区块的时间间隔越来越长,因为 CPU 需要经过更多的计算才能找到符合条件的哈希值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func main() {
difficulty := 1
genesisBlock := Block{}
genesisBlock = Block{
idx: 0,
timestamp: time.Now().String(),
hash: calculateHash(genesisBlock),
prevHash: "",
difficulty: difficulty,
nonce: "",
}
blockchain.AddBlock(genesisBlock)

var block Block
block = genesisBlock
for {
block = generateBlock(block, diff)
difficulty++
blockchain.AddBlock(block)
}
}
Pieces of Valuable Programming Knowledges