Go区块链之交易一

引言:

交易是比特币的核心,区块链唯一的目的就是安全可靠的存储交易数据,使得交易数据在创建之后不可更改。由于实现真正的交易比较复杂,我们将交易分为2部分来实现。本文将大体实现交易机制,交易的具体细节实现,容后再述。

什么是交易?

一般的web应用需要创建如下数据表用于实现支付逻辑:用户账户、交易。用户账户表用于存储用户信息和余额,交易信息表用于存储钱从一个账户转账到另一个账户。然而在比特币交易的实现方式完全不同:

1.没有账户的概念

2.没有余额的概念

3.没有地址

4.没有金币

5.没有发送方和接收方

由于区块链是一个公开透明的数据库,并不希望存储用户的钱包等敏感信息。金币不在账户中保存,钱不再从一个地址转到另一个地址,没有账户保存账户余额,区块链仅保存交易信息。那交易又包含什么信息呢?

比特币交易

一个交易由输入输出构成:

go交易结构

一笔新的交易的输入指向之前一笔旧的交易的输出(矿工费除外,即每个区块的第一笔交易)。交易输出是真正保存金币的地方。

交易间相互关联的示意图

需要注意的是:

1.存在未被输入引用的输出,即未被花费的金币

2.在一笔交易中,输入可能来源于多比旧的交易的输出

3.一笔输入必须引用一个交易的输出

在本文中,我们将继续使用钱、金币、花费、发送、账户等字眼。但是在比特币中并不存在这种概念,交易仅仅将价值由脚本锁定,该脚本指定只有锁定这笔交易的用户可以解锁使用该笔交易的输出。

交易输出

交易输出结构

实际上,比特币使用交易输出存储金币(Value),存储的意思是使用一个脚本对交易输出加锁。在比特币中,该脚本定义了输出加锁解锁的逻辑。这种脚本语言非常底层(为了避免黑客攻击或者误用)。由于我们尚未实现地址的概念,因此这里不再赘述该脚本的加解锁。我们可以直接定义加解密使用设定的字符串。

需要注意的是一笔交易中的输出是一个整体,不可分割,即每个交易输出的Value都不可分割。

交易输入

交易输入

交易输入指向以前交易的输出,因此交易输入中的TxId为指向交易的Id,Vout为指向交易的交易输出的索引,ScriptKey为交易输出提供数据。如果数据正确,交易输出可以解锁,即该笔交易输出的Value可以用于生成新的交易输出。这种机制保证了,一个用户只能使用自己加锁的金币。

先有鸡还是先有蛋?

在比特币中,交易输入来源于交易输出的逻辑类似鸡蛋问题。在比特币中,先有蛋而后有鸡。交易输入来源于交易输出,交易输出为交易输入提供来源。

当一个矿工在挖掘一个区块的时候,他会在区块的交易前加一笔coinbase交易,该交易输入不需要指向之前的交易输出,这笔交易是对矿工挖出区块的奖励。

CoinBase 交易

一笔coinbase交易只有一个交易输入,该交易输入的TxId为空,Vout为-1,同时CoinBase交易不使用ScriptKey,保存特定字符串。

区块链保存交易数据

区块结构
数据库存储区块使用序列化和反序列化工具

相应的创世区块和区块生成需要修改:

区块新建

ProofOfWork需要做相应的修改:

pow挖矿计算

在这里,我们仍然使用哈希来代表每个区块交易,其算法如下图:

我们简单的将所有交易的id进行join然后计算出其哈希,作为挖矿的数据准备。在比特币中,采用merlerk tree对交易进行处理。容后再述。

未花费交易输出

为了实现交易,我们需要找到某个用户所有的未花费交易输出(Unspent Transaction Outpus,UTXO)。未花费意味着,该交易输出未被新的交易输入引用。对应第一张图中的:

1.Tx0 Output1

2.Tx1 Output0

3.Tx3 Output0

4.Tx4 Output0

当然,当我们查看余额时,我们只需要对应地址可以解锁的输出。在交易输入输出中,我们定义了简单的加锁逻辑。

在交易中,为了找到UTXO,我们可先查找有交易输出未被引用的交易,其实现如下:

在以上代码中,我们将被交易输入引用的交易存储在spentTXO中,循环每个交易查看,交易输出,若满足交易输出未被引用则将其append到unspentTX中。

在上述代码中,我们找到了存在未被引用的output的交易,且存在output可以被指定address解锁的交易序列。接下来,我们从中找出,address锁定的output,即UTXOs:

若想查看address对余额,我们只需要将UTXO中的Value相加即可,具体实现如下:

转账

为了将coin从一个address转入另一个address,我们需要实现一笔交易(非coinBase)。首先我们需要从未花费交易中找到足够的余额和对应tx,作为新的一笔交易的输入引用。

用以上交易,作为新的交易的输入,并生成新的交易输出,建立交易。

最后,我们将一笔笔交易加入区块,并计入区块链。

测试

区块三:lisi转给wangwu5Coin(交易来源区块一的第0个输出),区块四:wangwu转给zhaoliu8Coin(交易来源区块二,区块三两笔交易)
区块一:zhangsan转给lisi10Coin(交易来源创世区块中交易的第1(序号从0开始)个输出),区块二:zhangsan转给wangwu5Coin(交易来源区块一交易的第1(序号从0开始)个输出)
创世区块,奖励zhangsan50Coin

你可能感兴趣的:(Go区块链之交易一)