0

区块链技术理解起来非常简单,如下图所示:

+---------+       +---------+
| payload |       | payload |
| nonce   | ----> | nonce   | ----> ...
| preHash |       | preHash |
+---------+       +---------+

简单来说,收集一段时间内的数据,做为一个区块,计算该区块满足条件的hash值,然后就可以将该区块append到链上,并且记下前一个区块的hash值。如此这样,如果某人想要篡改历史数据,那么hash值就会改变,首先改变的hash值一般不会满足条件,即使碰巧满足条件,也需要继续篡改后续区块。

所谓的满足条件也就是共识机制,bitcoin使用的是PoW,但是由于其过于浪费计算资源(因而篡改的成本也比较高),所以近来又涌现了不少新的共识机制,比如PoS、PBFT。

本文简要介绍区块生成和上链的基本流程,示例代码来自izqui/blockchain

ECDSA密钥

type Keypair struct {
	Public  []byte `json:"public"`  // base58 (x y)
	Private []byte `json:"private"` // d (base58 encoded)
}

func GenerateNewKeypair() *Keypair {

	pk, _ := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)

	b := bigJoin(KEY_SIZE, pk.PublicKey.X, pk.PublicKey.Y)

	public := base58.EncodeBig([]byte{}, b)
	private := base58.EncodeBig([]byte{}, pk.D)

	kp := Keypair{Public: public, Private: private}

	return &kp
}

当某个节点加入网络,首先生成ECDSA密钥,公钥做为该节点的标识,私钥用于签名。

Blockchain数据结构

//Transaction也就是节点每次的操作的信息
//在bitcoin的场景下就是转账事务
type Transaction struct {
	Header    TransactionHeader
	Signature []byte //signed(sha256(header))
	Payload   []byte
}

type TransactionHeader struct {
	From          []byte //发起节点的公钥
	To            []byte //目标节点的公钥
	Timestamp     uint32
	PayloadHash   []byte //sha256(payloadData)
	PayloadLength uint32 //payloadData长度
	Nonce         uint32 //Proof of work
}

type TransactionSlice []Transaction
//block header
type BlockHeader struct {
	Origin     []byte //打包该块的节点的公钥
	PrevBlock  []byte //前一个block header的sha256
	MerkelRoot []byte //transaction的sha256
	Timestamp  uint32
	Nonce      uint32
}

//block
type Block struct {
	*BlockHeader
	Signature []byte //signed(sha256(header))
	*TransactionSlice
}
type BlockSlice []Block

type Blockchain struct {
	CurrentBlock Block //当前时间区间接收到的transaction
	BlockSlice //所谓的区块链

	TransactionsQueue // 接收其他节点发来的transaction的chan
	BlocksQueue // 接收其他节点发来的block的chan
}

创建Transaction

func CreateTransaction(txt string) *Transaction {
	t := NewTransaction(Core.Keypair.Public, nil, []byte(txt))
	// 循环遍历**满足条件**的Nonce
	t.Header.Nonce = t.GenerateNonce(TRANSACTION_POW)
	t.Signature = t.Sign(Core.Keypair)

	return t
}

func (t *Transaction) GenerateNonce(prefix []byte) uint32 {
	newT := t
	for {
		if CheckProofOfWork(prefix, newT.Hash()) {
			break
		}
		newT.Header.Nonce++
	}
	return newT.Header.Nonce
}

PoW检查

var (
	TRANSACTION_POW = helpers.ArrayOfBytes(TRANSACTION_POW_COMPLEXITY, POW_PREFIX)
	BLOCK_POW       = helpers.ArrayOfBytes(BLOCK_POW_COMPLEXITY, POW_PREFIX)

	TEST_TRANSACTION_POW = helpers.ArrayOfBytes(TEST_TRANSACTION_POW_COMPLEXITY, POW_PREFIX)
	TEST_BLOCK_POW       = helpers.ArrayOfBytes(TEST_BLOCK_POW_COMPLEXITY, POW_PREFIX)
)

//简单来说就是要使得hash的前几个byte与prefix相同
//POW_COMPLEXITY在bitcoin中有一套增加难度的算法[Difficulty](https://en.bitcoin.it/wiki/Difficulty),
//这里就先不详细介绍了
func CheckProofOfWork(prefix []byte, hash []byte) bool {
	if len(prefix) > 0 {
		return reflect.DeepEqual(prefix, hash[:len(prefix)])
	}
	return true
}

接收Transaction


		select {
		case tr := <-bl.TransactionsQueue:
			// 如果sig相同,表示已经收到
			if bl.CurrentBlock.TransactionSlice.Exists(*tr) {
				continue
			}
			// 验证payload hash、pow、sig
			if !tr.VerifyTransaction(TRANSACTION_POW) {
				fmt.Println("Recieved non valid transaction", tr)
				continue
			}
			// 有效的transaction添加到CurrentBlock
			bl.CurrentBlock.AddTransaction(tr)
			interruptBlockGen <- bl.CurrentBlock

			//Broadcast transaction to the network
			mes := NewMessage(MESSAGE_SEND_TRANSACTION)
			mes.Data, _ = tr.MarshalBinary()

			time.Sleep(300 * time.Millisecond)
			Core.Network.BroadcastQueue <- *mes

创建Block

		block := <-interrupt
	loop:
		fmt.Println("Starting Proof of Work...")
		block.BlockHeader.MerkelRoot = block.GenerateMerkelRoot()
		block.BlockHeader.Nonce = 0
		block.BlockHeader.Timestamp = uint32(time.Now().Unix())

		for true {

			sleepTime := time.Nanosecond
			if block.TransactionSlice.Len() > 0 {

				if CheckProofOfWork(BLOCK_POW, block.Hash()) {

					block.Signature = block.Sign(Core.Keypair)
					bl.BlocksQueue <- block
					sleepTime = time.Hour * 24
					fmt.Println("Found Block!")

				} else {

					block.BlockHeader.Nonce += 1
				}

			} else {
				sleepTime = time.Hour * 24
				fmt.Println("No trans sleep")
			}

			select {
			case block = <-interrupt:
				goto loop
			case <-helpers.Timeout(sleepTime):
				continue
			}
		}

接收Block

		case b := <-bl.BlocksQueue:
			// 如果sig相同,表示已经收到
			if bl.BlockSlice.Exists(b) {
				fmt.Println("block exists")
				continue
			}
			// 验证merkel、pow、sig
			if !b.VerifyBlock(BLOCK_POW) {
				fmt.Println("block verification fails")
				continue
			}

			if !reflect.DeepEqual(b.PrevBlock, bl.CurrentBlock.PrevBlock) {
				// I'm missing some blocks in the middle. Request'em.
				fmt.Println("Missing blocks in between")
			} else {

				fmt.Println("New block!", b.Hash())

				transDiff := TransactionSlice{}

				if !reflect.DeepEqual(b.BlockHeader.MerkelRoot, bl.CurrentBlock.MerkelRoot) {
					// Transactions are different
					fmt.Println("Transactions are different. finding diff")
					transDiff = DiffTransactionSlices(*bl.CurrentBlock.TransactionSlice, *b.TransactionSlice)
				}
				// 满足条件就上链
				bl.AddBlock(b)

				//Broadcast block and shit
				mes := NewMessage(MESSAGE_SEND_BLOCK)
				mes.Data, _ = b.MarshalBinary()
				Core.Network.BroadcastQueue <- *mes

				//New Block
				bl.CurrentBlock = bl.CreateNewBlock()
				bl.CurrentBlock.TransactionSlice = &transDiff

				interruptBlockGen <- bl.CurrentBlock
			}