# 交易

# 什么是交易

区块链由一组不可变且通过加密链接的交易构成。每一个交易包含一到多个输入,以及一到多个输出。一个输入既可发行一种新的资产单元,也可将先前一笔交易输出中已存在的资产单元作为转账的来源。输出从输入中获取资产单元并定义它们的分配方式。单个输出包含一笔资产数额以及对应的控制程序来指定在未来如何被花费。或者一个输出可以销毁资产单元,将它们从流通中移除。
一笔交易可以有多个输入和输出,且包含许多不同类型资产,不同来源以及不同的目的地。一笔交易中的所有动作(发行、花费、接收以及销毁资产)将会作为单个原子操作同时发生,不会存在一个时间点只有部分被执行。
在一笔交易中,输入的资产总数必须等于输出的资产总数。为了创建新的资产单元,我们在一个输入中发行资产并用一到多个输出来接收;为了转移资产单元,我们在一个输入中将其花费并用一到多个输出中来接收;为了销毁资产单元,我们在输入中将其花费并在一个输出中进行销毁。

# 核心数据结构

字段 类型 描述
ID Hash 交易ID的哈希值
Entries map[Hash]Entry 接口
InputIDs *Hash 交易输入ID的哈希值
SpentOutputIDs *Hash UTXO ID哈希
GasInputIDs *Hash 交易输入手续费ID哈希

# Input

# input 核心数据结构

字段 类型 描述
AssetVersion uint64 Asset版本
TypedInput TxInput 接口
CommitmentSuffix *byte 交易承诺的后缀
WitnessSuffix *byte 交易见证的后缀

# 交易类型

  • **IssuanceInput:**发行资产的UTXO。
  • **SpendInput:**手续费的UTXO。
  • **CoinbaseInput:**这是每个区块中的首个交易的交易输入。 这种交易存在的原因是作为对挖矿的奖励而产生全新的可用于支付的币给“赢家”矿工。这也就是为什么该币可以在挖矿过程中被创造出来。

# Output

# output 核心数据结构

字段 类型 描述
AssetVersion uint64 Asset版本
OutputCommitment OutputCommitment 输出承诺数据结构
CommitmentSuffix *byte 未使用的交易承诺和交易见证的后缀

# 创建交易的Action

在比原中,并不强制你直接操作输入和输出,而是通过下面列出的几种高层次的actions来构建交易。

# Input action

  • **issue:**发行一种新的资产单元。
  • **spend_account:**从一个指定的账户中花费指定的资产单元,比原将自动从未花费输出中找到足够的资产单元,并创建找零输出。
  • **spend_account_unspent_output:**从一个账户中指定一个完整的未花费输出,找零需要通过其他actions手动处理。

# Output action

  • **control_address:**接收一笔资产单元,接收方式为地址模式。
  • **control_program:**接收一笔资产单元,接收方式为合约模式。
  • **retire:**销毁指定的资产单元。

# 消费一个完整的未花费输出

当创建一个输入时,即从一个较早交易的输出中花费一定数额的资产,该输出中所有数目的资产都必须被完全花费掉。如果你不想转移所有的资产到你的目的接受者中,则需要返还到自己的账户中,这种方式称之为找零。因此,从一个输入中花费一笔资产经常需要提供两个输出。其中一个作为目的输出,另一个输出用来返还剩余的资产。一般来说,比原会自动为你管理找零输出。

# 合并未花费的输出

一些支付可能需要很多的资产单元,其数额超过任何一个未花费输出的大小。当从账户中进行一笔消费时,只要账户中存在足够的资产,比原将会自动选择未花费输出来满足本次支付。

# 创建交易

创建一笔交易总共包含以下几个步骤:

# 构建交易

用来定义交易需要做什么,是为了发行一笔资产还是从账户中花费资产,或者使用另一个账户接收资产。

交易脚本

// Build builds or adds on to a transaction.
// Initially, inputs are left unconsumed, and destinations unsatisfied.
// Build partners then satisfy and consume inputs and destinations.
// The final party must ensure that the transaction is
// balanced before calling finalize.
func Build(ctx context.Context, tx *types.TxData, actions []Action, maxTime time.Time, timeRange uint64) (*Template, error) {
	builder := TemplateBuilder{
		base:      tx,
		maxTime:   maxTime,
		timeRange: timeRange,
	}

	// Build all of the actions, updating the builder.
	var errs []error
	for i, action := range actions {
		err := action.Build(ctx, &builder)
		if err != nil {
			log.WithFields(log.Fields{"module": logModule, "action index": i, "error": err}).Error("Loop tx's action")
			errs = append(errs, errors.WithDetailf(err, "action index %v", i))
		}
	}

	// If there were any errors, rollback and return a composite error.
	if len(errs) > 0 {
		builder.Rollback()
		return nil, errors.WithData(ErrAction, "actions", errs)
	}
type Template struct {
	Transaction         *types.Tx             `json:"raw_transaction"`
	SigningInstructions []*SigningInstruction `json:"signing_instructions"`
	Fee                 uint64                `json:"fee"`
	// AllowAdditional affects whether Sign commits to the tx sighash or
	// to individual details of the tx so far. When true, signatures
	// commit to tx details, and new details may be added but existing
	// ones cannot be changed. When false, signatures commit to the tx
	// as a whole, and any change to the tx invalidates the signature.
	AllowAdditional bool `json:"allow_additional_actions"`
}type Template struct {
	Transaction         *types.Tx             `json:"raw_transaction"`
	SigningInstructions []*SigningInstruction `json:"signing_instructions"`
	Fee                 uint64                `json:"fee"`
	// AllowAdditional affects whether Sign commits to the tx sighash or
	// to individual details of the tx so far. When true, signatures
	// commit to tx details, and new details may be added but existing
	// ones cannot be changed. When false, signatures commit to the tx
	// as a whole, and any change to the tx invalidates the signature.
	AllowAdditional bool `json:"allow_additional_actions"`
}
	// Build the transaction template.
	tpl, tx, err := builder.Build()
	if err != nil {
		builder.Rollback()
		return nil, err
	}

	return tpl, nil
}
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 签名交易

使用私钥授权资产支出或者发行新的资产单元。

为了让一笔交易被区块链接收,它的输入必须包含有效的签名。对于资产发行输入,签名必须与资产发行程序中的公钥相对应;对于花费(spending)输入,签名必须与所花费输出中控制程序的公钥相对应。

交易签名为区块链提供了安全性,加密技术可以防止每个人在没有相关私钥的情况下生成有效的交易签名。

**隔离见证:**隔离见证就是把区块内的数字签名信息拿出去,让每个区块可以承载更多比交易,从而达到扩容的目的。

// Template represents a partially- or fully-signed transaction.
type Template struct {
	Transaction         *types.Tx             `json:"raw_transaction"`
	SigningInstructions []*SigningInstruction `json:"signing_instructions"`
	Fee                 uint64                `json:"fee"`
	// AllowAdditional affects whether Sign commits to the tx sighash or
	// to individual details of the tx so far. When true, signatures
	// commit to tx details, and new details may be added but existing
	// ones cannot be changed. When false, signatures commit to the tx
	// as a whole, and any change to the tx invalidates the signature.
	AllowAdditional bool `json:"allow_additional_actions"`
}
1
2
3
4
5
6
7
8
9
10
11
12

# 提交交易

提交一个完整的、签名交易到区块链上,并且传播到主网的其他节点上。

一旦交易的输入输出是平衡的并且所有输入被签名过,它就被认为是有效的且可以被提交到区块链上。本地节点率先将交易添加到区块链,并广播到主网的其他节点上。

Last Updated: 3/30/2020, 11:49:24 AM