比特币账户模型UTXO

UTXO模型概述

比特币使用了UTXO(unspent transaction outputs未花费的交易输出)模型来跟踪比特币的所有权和交易历史。在这个模型中,每个比特币交易包含一个或多个输入(Input)和一个或多个(找零)输出(Output)。该模型资产转移时需要签名并发送一笔交易,交易中的Input是指目前发起交易的用户所拥有的Output,交易成功后用户的Output被消耗,而产生新的Output,新的Output在消耗时又作为Input,以此形成一个前后相关的链条,即一个Input指向的是前面区块的某个Output,只有Coinbase交易(矿工奖励的铸币交易)没有输入。所以,任何交易都可以由Input溯源到Coinbase交易。
一图胜千言:图中5BTC的Output交易时作为Input,交易成功后生成两个Output(1.85BTC和3.15BTC)
在这里插入图片描述比特币底层使用默克尔树结构存储交易信息,花费UXTO时钱包需要向节打包点发送如下信息:

打包节点验证过程:节点根据Output的默克尔路径逐步向上计算出默克尔根hash,然后与区块头中的根hash比较,如果相等则说明交易合法

比特币区块中交易数据存储结构

钱包余额和UTXO

钱包的当前余额是指钱包地址关联的所有UTXO金额之和。如果刚装了一个新钱包,导入了一组私钥,在钱包扫描完整个比特币区块之前,是无法得知当前管理的地址余额的。而查询给定地址的余额并非实时遍历所有区块数据,而是由节点服务器返回。节点服务器在部署时会从创始块起遍历整个区块链,并使用数据库(如:LevelDB)保存地址与余额的映射关系(表主要字段:地址、余额、块号)。收到新的区块时更新对应数据库表,Input对应地址的余额减少,Output对应的地址余额增加。

addressbalancelastUpdatedAtBlock
address-150.00
address-20.53
address-313.5300
address-410.03

交易的构建过程

  1. 选择足够的UTXO作为输入,以支付给接收者。
  2. 为每一个UTXO构建解锁脚本。
  3. 构建一个或多个(找零)输出(Output)。
    以下为UTXO账户模型转帐的伪代码:
// 定义一个比特币交易
class BitcoinTransaction {
  constructor(inputs, outputs) {
    this.inputs = inputs;   // 交易的输入,每个输入引用了一个之前的UTXO
    this.outputs = outputs; // 交易的输出,每个输出指定了新的UTXO
  }
}

// 定义一个UTXO
class UTXO {
  constructor(txOutput, index) {
    this.txOutput = txOutput; // 交易输出
    this.index = index;      // 输出在交易中的索引
  }
}

// 创建初始的UTXO集合
let utxos = [new UTXO(txOutput1, 0), new UTXO(txOutput2, 0), ...];

// 定义一个转账交易函数
function createTransaction(sender, receiver, amount, utxos) {
  let inputs = [];
  let outputs = [];
  let total = 0;

  // 选择足够的UTXO作为输入,以支付给接收者
  for (let utxo of utxos) {
    if (total < amount) {
      inputs.push(utxo);
      total += utxo.txOutput.value;
    } else {
      break;
    }
  }

  // 创建一个输出,支付给接收者
  let change = total - amount;
  outputs.push(new Output(amount, receiver));
  if (change > 0) {
    outputs.push(new Output(change, sender));
  }

  // 创建并广播交易
  let newTransaction = new BitcoinTransaction(inputs, outputs);
  return newTransaction;
}

// 更新UTXO集合
function updateUTXOs(utxos, newTransaction) {
  for (let input of newTransaction.inputs) {
    // 从utxos中移除已经花费的UTXO
    utxos = utxos.filter(utxo => utxo !== input);
  }
  for (let output of newTransaction.outputs) {
    // 添加新的UTXO到utxos中
    utxos.push(new UTXO(output, newTransaction.outputs.indexOf(output)));
  }
}

// 示例:Alice向Bob转账10个比特币
let alice = "Alice's Public Key";
let bob = "Bob's Public Key";
let amount = 10;
let newTransaction = createTransaction(alice, bob, amount, utxos);
updateUTXOs(utxos, newTransaction);

签名与验证

数字签名

发送方想要花费之前的UTXO,他们需要创建一个新的交易,并在输入中提供解锁脚本(Input Script),其过核心如下:

  1. 发送方(交易的创建者)首先创建一笔交易,并选择要花费的UTXO。对于每个输入,他们需要提供以下信息:
  • UTXO的交易哈希(txHash)和输出索引(output index)。
  • 解锁脚本(Input Script):包括发送方的公钥和数字签名。
  1. 发送方从其私钥生成数字签名,用于签署交易。数字签名通常使用ECDSA(椭圆曲线数字签名算法)进行生成。
  2. 发送方将数字签名添加到解锁脚本中,这样接收方在后续验证时可以使用。

数字签名验证

  1. 接收方想要花费之前的UTXO,他们需要创建一个新的交易,并在输入中提供解锁脚本(Input Script)。解锁脚本应包括数字签名和发送方的公钥。
  2. 在验证过程中,比特币网络会执行以下操作:
  • 从UTXO中提取锁定脚本(Output Script)中的公钥哈希。
  • 使用解锁脚本中的数字签名、发送方的公钥和被签署的数据来验证数字签名的有效性。

加锁脚本(公钥脚本)和解锁脚本

加锁脚本

Output中包含金额和加锁脚本,加锁脚本定义了谁可以花费UTXO,它包含接收者(该Output的接收者)的公钥哈希和一些操作码,以确保只有拥有相应私钥的人才能花费UTXO。

// 加锁脚本:要求使用接受者的公钥和数字签名来解锁
const lockingScript = `
  OP_DUP  	//OP_DUP 复制栈顶元素,以备后续的比对。
  OP_HASH160 <接受者的公钥哈希>  	//OP_HASH160 将栈顶元素计算SHA-256哈希,并然后计算RIPEMD-160哈希,用于检查公钥哈希。
  OP_EQUALVERIFY		//OP_EQUALVERIFY 比对栈中的两个元素是否相等,如果相等则继续,否则中断。
  OP_CHECKSIG			//OP_CHECKSIG 使用栈中的公钥和数字签名验证交易的有效性。
`;

解锁脚本

当用户花费Output中的金额时需要构建解锁脚本。解锁脚本由数字签名和发送方公钥(花费该Output的公钥)组成。
注:非对称加密中私钥和公钥成对出现,引处私钥用于签名交易生成数据签名,公钥直接使用

// 解锁脚本:包含数字签名和发送方的公钥
const unlockingScript = `
  <数字签名>
  <发送方的公钥>
`;
解锁脚本的构建过程:
  1. 由于解锁脚本中的数字签名需要交易本身才能生成,而交易本身还在构建中,因此暂时还不知道真正的解锁脚本。所以用 UTXO 中的加锁脚本暂时代替交易输入的解锁脚本,从而构建一个临时的原始交易。
  2. 构建原始交易之后,在交易的二进制末尾加上签名类型,一般是 0x01000000,然后进行两次 sha256,就得到了原始交易的 hash。
  3. 使用 UTXO 的私钥对原始交易的 hash 签名,末尾加上编码类型 0x01。
  4. 开头加上一个字节的签名长度编码(注意,编码长度是签名长度加 1,因为末尾加了一个字节的编码类型)。这样就得到了解锁脚本的签名部分(Sig)。
  5. 解锁脚本的公钥部分()比较简单,获取 UTXO 对应的秘钥的公钥,然后在公钥的二进制开头加上一个字节的公钥长度,就得到了公钥部分。
  6. 拼接 ,就是解锁脚本。
  7. 用上步的解锁脚本更新步骤1中相应字段。

注:需要特别注意的是,如果交易有多个输入,在计算解锁脚本构建原始交易的时候,除了当前正在构建的输入,其他输入的解锁脚本字段(signatureScript)需要设置为空。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值