# 创建签名交易

在 Aptos 区块链上执行的所有交易都必须经过签名。出于安全原因，此要求由链强制执行。

## **生成签名消息**

签署交易的第一步是从交易中生成签名消息。要生成这样的签名消息，您可以使用：

* Aptos 节点的 REST API。 Aptos 节点将生成签名消息、交易签名并将签名的交易提交到 Aptos 区块链。但是，这种方法并不安全。请参阅以 BCS 与 JSON 提交交易。 - 另请参阅说明此方法的教程“您的首次交易”。
* 但是，您可能更希望您的客户端应用程序（例如硬件安全模块 (HSM)）负责生成签名交易。在这种方法中，在提交交易之前，客户必须： - 将交易序列化为字节，以及 - 使用帐户私钥对字节进行签名。有关帐户和私钥的工作原理，请参阅帐户。 本指南将介绍构建交易背后的概念，使用 BCS 序列化生成适当的签名消息，以及在 Aptos 中进行签名的各种方法。&#x20;

{% hint style="info" %}
我们强烈建议您使用 BCS 格式向 Aptos 区块链提交交易。
{% endhint %}

## 概述

创建准备在 Aptos 区块链上执行的交易需要以下四个步骤：

1. 创建原始交易，`RawTransaction`，也称为未签名交易。
2. 生成包含适当盐（`prefix_bytes`）的签名消息，并使用客户端的私钥生成原始交易的签名。
3. 创建 `Authenticator` 和签名的交易，以及
4. BCS 序列化已签名的交易（未在概览部分的图表中显示）。

信息 本节中的代码示例在 Typescript 中。

请参阅下面的高级流程图，显示原始交易如何成为签名交易：

<figure><img src="https://1298478727-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9FI8oYwrsIrHQeIJd3qm%2Fuploads%2FWinmqFdIyaqrfSqelwjP%2FUntitled.png?alt=media&#x26;token=27f1a483-0f62-4223-9534-f7cdc494397e" alt=""><figcaption></figcaption></figure>

未签名的交易称为“RawTransaction”。它们包含有关如何在 Aptos 中对帐户执行操作的所有信息。但他们缺乏带有签名或“身份验证器”的适当授权。 在 Aptos 区块链中，所有数据都被编码为 BCS（二进制规范序列化）。 Aptos 支持许多不同的方法来签署交易，但默认为使用 Ed25519 的单一签名者。 在交易签名期间产生的“Authenticator”授权 Aptos 区块链代表账户所有者执行交易。

## **关键概念**

### **原始交易**

原始交易由以下字段组成：&#x20;

* **sender（地址）：**&#x53D1;件人的帐户地址。 sequence\_number (uint64)：本次交易的序列号。这必须与交易执行时存储在发件人帐户中的序列号匹配。&#x20;
* **payload：**&#x41;ptos 区块链的指令，包括发布模块、执行脚本函数或执行脚本负载。 max\_gas\_amount (uint64)：此交易花费的最大总gas。账户必须有超过这个气体，否则交易将在验证期间被丢弃。
* &#x20;**gas\_unit\_price (uint64)：**&#x6BCF;个 gas 单位要支付的价格。在执行期间，total\_gas\_amount 的计算公式为：total\_gas\_amount = total\_gas\_units\_consumed \* gas\_unit\_price，不得超过 max\_gas\_amount，否则交易将在执行期间中止。 total\_gas\_units\_consumed 表示执行交易时消耗的气体总单位。
* **expire\_timestamp\_secs (uint64)：**&#x533A;块链将丢弃此交易的区块链时间戳。&#x20;
* **chain\_id (uint8)：**&#x8BE5;交易打算在其上运行的区块链的链 ID。

### BCS

BCS 二进制规范序列化 (BCS) 是一种应用于原始（未签名）交易的序列化格式。有关 BCS 设计目标的说明，请参阅 BCS。 BCS 不是一种自我描述的格式。因此，为了反序列化消息，必须提前知道消息类型和布局。 BCS 如何序列化字符串的示例如下所示：

{% code lineNumbers="true" %}

```
// A string is serialized as: byte length + byte representation of the string. The byte length is required for deserialization. Without it, no way the deserializer knows how many bytes to deserialize.
const
bytes: Unint8Array = bcs_serialize_string("aptos");
assert(bytes == [5, 0x61, 0x70, 0x74, 0x6F, 0x73]);
```

{% endcode %}

### **签名留言**

BCS 序列化原始交易的字节称为**签名消息**。 此外，在 Aptos 中，任何经过签名或散列的内容都会使用唯一的前缀进行加盐处理，以将其与其他类型的消息区分开来。这样做是为了确保内容只能在预期的场景中使用。 RawTransaction 的签名消息以`prefix_bytes`为前缀，即`sha3_256("APTOS::RawTransaction")`。所以： `signing_message = prefix_bytes | bcs_bytes_of_raw_transaction.`。 `|` 表示连接。

{% hint style="info" %}
前缀步骤未显示在概览部分的图表中。
{% endhint %}

### 签名

签名是使用客户端私钥对签名消息进行散列处理的结果。默认情况下，Aptos 使用 Ed25519 方案来生成原始交易的签名。

* 通过使用私钥签署签名消息，客户向 Aptos 区块链证明他们已授权执行交易。
* Aptos Blockchain 将使用客户账户的公钥验证签名，以确保提交的交易确实由客户签名。

### 签名交易

签名交易 签署的交易包括：

* 原始交易，以及
* 身份验证器。身份验证器包含客户的公钥和原始交易的签名。 此已签名交易进一步 BCS 序列化（未在概览部分的图表中显示），之后已签名交易准备好提交到 Aptos REST 接口。

### **多重签名交易**

Aptos 区块链支持多种交易签名方法，包括单一签名、K-of-N 多重签名等。 K-of-N 多重签名交易意味着要执行这样的交易，N 个授权签名者中至少有 K 个已经签署了该交易并通过了链的检查。 交易签名包含在 Authenticator 中。 Aptos 区块链使用 Authenticator 数据验证客户提交的交易。请参阅下面的几个示例： 在 Typescript 中，单签名者身份验证器如下所示：

```
interface
Authenticator {
public_key: Uint8Array,
signature: Uint8Array
}
```

**多重签名验证器示例如下所示：**

```
interface
MultiEd25519PublicKey {
// A list of public keys
public_keys: Uint8Array[],
// At least threshold signatures must be valid
threshold: Uint8,
}
interface
MultiEd25519Signature {
// A list of signatures
signatures: Uint8Array[],
// 4 bytes, at most 32 signatures are supported.
// If Nth bit value is 1, the Nth signature should be provided in signatures. Bits are read from left to right
bitmap: Uint8Array,
}
interface
MultisigAuthenticator {
public_key: MultiEd25519PublicKey,
signature: MultiEd25519Signature
}
```

## **详细步骤**

1. 创建一个 RawTransaction。
2. 准备要签名的消息并签名。
3. 创建一个 Authenticator 和一个 SignedTransaction。
4. 序列化 SignedTransaction。

### **步骤 1. 创建 RawTransaction** 下面的示例假设转账具有脚本函数负载。

```
interface AccountAddress { // 32-byte array address: Uint8Array }
interface ModuleId { address: AccountAddress, name: string }
interface ScriptFunction { module: ModuleId, function: string, ty_args: string[], args: Uint8Array[] }
interface RawTransaction { sender: AccountAddress, sequence_number: number, payload: ScriptFunction, max_gas_amount: number, gas_unit_price: number, expiration_timestamp_secs: number, chain_id: number, }
function createRawTransaction(): RawTransaction { const payload: ScriptFunction = { module: { address: hexToAccountAddress("0x01"), name: "AptosCoin" }, function: "transfer", ty_args: [], args: [ BCS.serialize(hexToAccountAddress("0x02")), // receipient of the transfer BCS.serialize_uint64(2), // amount to transfer ] }
return { "sender": hexToAccountAddress("0x01"), "sequence_number": 1n, "max_gas_amount": 2000n, "gas_unit_price": 1n, // Unix timestamp, in seconds + 10 minutes "expiration_timestamp_secs": Math.floor(Date.now() / 1000) + 600, "payload": payload, "chain_id": 3 }; }
```

{% hint style="info" %}
上面代码中显示的 BCS 序列化与概述部分中显示的 BCS 序列化操作不同。
{% endhint %}

### 步骤 2. 创建签名消息并对其进行签名

1. 使用字符串 `APTOS::RawTransaction` 的 SHA3\_256 哈希字节生成前缀 (`prefix_bytes`)。
2. BCS 序列化 RawTransaction 的字节数。
3. 连接前缀和 BCS 字节。
4. 使用帐户私钥对字节进行签名

<figure><img src="https://1298478727-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9FI8oYwrsIrHQeIJd3qm%2Fuploads%2FEuwCsINuO2zhNMt2TooQ%2FUntitled%201.png?alt=media&#x26;token=0d7ad5e9-05d4-4c55-9db8-5b3ea2a68cd4" alt=""><figcaption></figcaption></figure>

### 步骤 3. 创建 Authenticator 和 SignedTransaction

<figure><img src="https://1298478727-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9FI8oYwrsIrHQeIJd3qm%2Fuploads%2F1swr7aJ9yPzBfKMF7yU6%2FUntitled%202.png?alt=media&#x26;token=20d60893-452b-495e-bb09-4463e349d640" alt=""><figcaption></figcaption></figure>

### **步骤 4. 序列化 SignedTransaction**

{% hint style="info" %}
此步骤未显示在 \[概述] 部分的流程图中。
{% endhint %}

使用 BCS 将 SignedTransaction 序列化为字节。

```
const signedTransactionPayload = bcsSerializeSignedTransaction(signedTransaction);
```

**提交签署的交易**

最后，使用所需的标头“Content-Type”提交交易。 要提交 BCS 格式的签名交易，客户端必须传入特定的标头，如下例所示：

```
curl -X POST -H "Content-Type: application/x.aptos.signed_transaction+bcs" --data-binary "@path/to/file_contains_bcs_bytes_of_signed_txn" https://some_domain/transactions
```
