go语言实现区块链交易(一)数据结构

简介

比特币交易是比特币系统中最重要的部分。根据比特币系统的设计原理,系统中任何其他的部分都是为了确保比特币交易可以被生成、能在比特币网络中得以传播和通过验证,并最终添加入全球比特币交易总账簿(比特币区块链)。比特币交易的本质是数据结构,这些数据结构中含有比特币交易参与者价值转移的相关信息。比特币区块链是一本全球复式记账总账簿,每个比特币交易都是在比特币区块链上的一个公开记录。

数据结构

一笔比特币交易的数据结构如下所示:

{
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "txid":"7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
      "vout": 0,
      "scriptSig": "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
      "sequence": 4294967295
    }
 ],
  "vout": [
    {
      "value": 0.01500000,
      "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": 0.08450000,
      "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
    }
  ]
}

交易原理

对于每一笔新的交易,它的输入会引用(reference)之前一笔交易的输出(除coinbase 交易),引用就是花费的意思。所谓引用之前的一个输出,也就是将之前的一个输出包含在另一笔交易的输入当中,就是花费之前的交易输出。交易的输出,就是币实际存储的地方。下面的图示阐释了交易之间的互相关联:go语言实现区块链交易(一)数据结构_第1张图片
所以我们在进行交易之前要找到发送方对应的余额,也就是发送方所有的未花费的输出。由于交易被保存在区块中,所以它会对区块链里面的每一个区块进行迭代,检查里面的每一笔交易。截止 2017 年 9 月 18 日,在比特币中已经有 485,860 个块,整个数据库所需磁盘空间超过 140 Gb。这意味着一个人如果想要验证交易,必须要运行一个全节点。此外,验证交易将会需要在许多块上进行迭代。
整个问题的解决方案是有一个仅有未花费输出的索引,这就是 UTXO 集要做的事情:这是一个从所有区块链交易中构建(对区块进行迭代,但是只须做一次)而来的缓存,然后用它来计算余额和验证新的交易。截止 2017 年 9 月,UTXO 集大概有 2.7 Gb。
所以我们定义我们的交易的数据结构为

type Transaction struct {
    ID   []byte
    Vin  []TXInput
    Vout []TXOutput
}

交易输出

"vout": [
  {
    "value": 0.01500000,
    "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY
OP_CHECKSIG"
  },
  {
    "value": 0.08450000,
    "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
  }
]

所以比特币交易输出通常包含:
- 一定量的比特币
- 确定花费输出的所需条件的加密难题
这个加密难题也被称为锁定脚本(locking script), 见证脚本(witness script), 或脚本公钥 (scriptPubKey)。锁定脚本是一个放置在输出上面的花费条件:它指定了今后花费这笔输出必须要满足的条件。 由于锁定脚本往往含有一个公钥或比特币地址(公钥哈希值),在历史上它曾被称为脚本公钥(scriptPubKey)。由于认识到这种脚本技术存在着更为广泛的可能性,在本书中,我们将它称为“锁定脚本”(locking script)。在大多数比特币应用程序中,我们所称的“锁定脚本”将以scriptPubKey的形式出现在源代码中。您还将看到被称为见证脚本(witness script)的锁定脚本(参见[隔离见证]章节),或者更一般地说,它是一个加密难题(cryptographic puzzle)。 这些术语在不同的抽象层次上都意味着同样的东西。为了实现的方便性,我们不考虑脚本,故实现时候的数据结构为

type TXOutput struct {
    Value      int
    PubKeyHash    []byte  //公钥的hash
}

交易输入

"vin": [
  {
    "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
    "vout": 0,
    "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
    "sequence": 4294967295
  }
]

交易输入将UTXO(通过引用)标记为将被消费,并通过解锁脚本提供所有权证明。
要构建一个交易,一个钱包从它控制的UTXO中选择足够的价值来执行被请求的付款。 有时一个UTXO就足够,其他时候不止一个。 对于将用于进行此付款的每个UTXO,钱包将创建一个指向UTXO的输入,并使用解锁脚本解锁它。
让我们更详细地看一下输入的组件。输入的第一部分是一个指向UTXO的指针,通过指向UTXO被记录在区块链中所在的交易的哈希值和序列号来实现。 第二部分是解锁脚本,钱包构建它用以满足设定在UTXO中的支出条件。 大多数情况下,解锁脚本是一个证明比特币所有权的数字签名和公钥,但是并不是所有的解锁脚本都包含签名。 第三部分是序列号,稍后再讨论。
输入包含四个元素:
- 一个交易ID,引用包含正在使用的UTXO的交易
- 一个输出索引(vout),用于标识来自该交易的哪个UTXO被引用(第一个为零)
- 一个 scriptSig(解锁脚本),满足放置在UTXO上的条件,解锁它用于支出
- 一个序列号
该输入表示的意思是交易ID为“7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18”的第1个UTXO输出,解锁脚本是付款方所创建的,首先检索引用的UTXO,检查其锁定脚本,然后使用它来构建所需的解锁脚本以满足此要求。
解锁脚本是一个“解决”或满足被锁定脚本在一个输出上设定的花费条件的脚本,它将允许输出被消费。解锁脚本是每一笔比特币交易输入的一部分,而且往往含有一个由用户的比特币钱包(通过用户的私钥)生成的数字签名。由于解锁脚本常常包含一个数字签名,因此它曾被称作ScriptSig。在大多数比特币应用的源代码中,ScriptSig便是我们所说的解锁脚本。你也会看到解锁脚本被称作“见证”(witness 参见[隔离见证]章节)。在本文中,我们将它称为“解锁脚本”,用以承认锁定脚本的需求有更广的范围。但并非所有解锁脚本都一定会包含签名。
故我们简化的交易输入模型为:

type TXInput struct {
    Txid      []byte
    Vout      int
    Signature []byte    //签名
    PubKey    []byte    //公钥
}

那么我们就完成了我们简易版本区块链的数据结构了
关于区块链的其他的数据结构如下:

 //UTXO集合的数据结构
type UTXOSet struct {    
    Blockchain *Blockchain
}
//区块的数据结构
type Block struct {
    Timestamp     int64
    Transactions  []*Transaction
    PrevBlockHash []byte
    Hash          []byte
    Nonce         int
    Height        int
}
//区块链的数据结构
type Blockchain struct {
    tip []byte
    Db  *bolt.DB
}

你可能感兴趣的:(go语言实现区块链交易(一)数据结构)