DEV Community

EgorMajj
EgorMajj

Posted on

Руководство по Созданию подписанной транзакции

Все транзакции, выполняемые на блокчейне Aptos, должны быть подписаны. Это требование вводится сетью из соображений безопасности.

Генерирование сообщения для подписи

Первым шагом в подписании транзакции является создание сообщения для подписания транзакции. Чтобы сгенерировать такое сообщение для подписи, вы можете использовать:

REST API ноды Aptos. Нода Aptos сгенерирует сообщение для подписи, подпись транзакции и отправит подписанную транзакцию в блокчейн Aptos. Однако такой подход небезопасен. См. раздел Отправка транзакций в BCS против JSON.
Также смотрите руководство "Ваша первая транзакция", в котором объясняется этот подход.
Однако вы можете предпочесть, чтобы за создание подписанной транзакции отвечало ваше пользовательское приложение, например, аппаратный модуль безопасности . При таком подходе перед отправкой транзакций пользователь должен:
Сериализовать транзакции в байты, и
Подписать байты закрытым ключом учетной записи. Как работает учетная запись и закрытый ключ, смотрите в разделе Учетные записи.
В этом руководстве мы познакомимся с концепциями построения транзакции, генерации соответствующего сообщения для подписи с помощью BCS-сериализации, а также с различными методами подписи в Aptos.

СОВЕТ
Мы настоятельно рекомендуем вам использовать формат BCS для отправки транзакций в блокчейн Aptos.

Обзор

Создание транзакции, готовой к исполнению на блокчейне Aptos, требует выполнения следующих четырех шагов:

  1. Создайте необработанную транзакцию, RawTransaction, также называемую неподписанной транзакцией.
  2. Сгенерируйте сообщение для подписи, содержащее соответствующее - (prefix_bytes), и создайте подпись необработанной транзакции с помощью закрытого ключа пользователя.
  3. Создайте Authenticator и подписанную транзакцию, и
  4. BCS-сериализация подписанной транзакции (не показана на диаграмме в разделе "Обзор").

ИНФОРМАЦИЯ
Примеры кода в этом разделе написаны на языке Typescript.

Беззнаковые транзакции известны как RawTransactions. Они содержат всю информацию о том, как выполнить операцию над учетной записью в Aptos. Но им не хватает соответствующей авторизации с помощью подписи или Authenticator.

В блокчейне Aptos все данные кодируются как BCS (Binary Canonical Serialization).

Aptos поддерживает множество различных подходов к подписанию транзакции, но по умолчанию используется подпись одного лица, использующего Ed25519.

Authenticator, созданный во время подписания транзакции, дает разрешение блокчейну Aptos на выполнение транзакции от имени владельца учетной записи.

Основные понятия

Необработанная транзакция состоит из следующих полей:

  • sender (Адрес): Адрес учетной записи отправителя.
  • sequence_number (uint64): Порядковый номер данной транзакции. Он должен совпадать с номером последовательности, хранящимся на учетной записи отправителя на момент выполнения транзакции.
  • payload: Инструкции для блокчейна Aptos, включая публикацию модуля, выполнение функции скрипта или выполнение полезной нагрузки скрипта.
  • max_gas_amount (uint64): Максимальная общая сумма газа, которую можно потратить на эту транзакцию. На учетной записи должно быть больше этой суммы газа, иначе транзакция будет отклонена при проверке.
  • gas_unit_price (uint64): Цена, которая будет уплачена за единицу газа. Во время выполнения транзакции total_gas_amount, рассчитываемая следующим образом: total_gas_amount = total_gas_units_consumed * gas_unit_price, не должна превышать max_gas_amount, иначе транзакция будет прервана во время выполнения. total_gas_units_consumed представляет собой общее количество единиц газа, потребленных во время выполнения транзакции.
  • expiration_timestamp_secs (uint64): Временная метка блокчейна, по истечении которой блокчейн отменит эту транзакцию.
  • chain_id (uint8): Идентификатор сети блокчейн, на которой должна быть выполнена данная транзакция.

BCS

Binary Canonical Serialization (BCS) - это формат сериализации, применяемый к необработанной ( неподписанной) транзакции. Описание целей разработки BCS см. в разделе BCS.

BCS не является самоописывающимся форматом. Поэтому, чтобы десериализовать сообщение, необходимо заранее знать его тип и структуру.

Пример того, как BCS сериализует строку, показан ниже:

// 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]);
Enter fullscreen mode Exit fullscreen mode

Сообщение для подписи
Байты BCS-сериализованной необработанной транзакции называются сообщением для подписи.

Кроме того, в Aptos любое содержимое, которое подписывается или хэшируется, солят уникальным префиксом, чтобы отличить его от других типов сообщений. Это делается для того, чтобы гарантировать, что содержимое может быть использовано только в предусмотренных скриптах. Сообщение для подписи RawTransaction имеет префикс prefix_bytes, который равен sha3_256("APTOS::RawTransaction"). Поэтому:
signing_message = prefix_bytes|bcs_bytes_of_raw_transaction.. | обозначает конкатенацию.

Подпись
Подпись - это результат хэширования подписываемого сообщения с помощью закрытого ключа пользователя. По умолчанию Aptos использует схему Ed25519 для генерации подписи необработанной транзакции.

  • Подписывая сообщение подписи закрытым ключом, клиенты доказывают Aptos Blockchain, что они разрешили выполнение транзакции.
  • Aptos Blockchain проверит подпись с помощью открытого ключа учетной записи пользователя, чтобы убедиться, что представленная транзакция действительно подписана пользователем.

Подписанная транзакция

Подписанная транзакция состоит из:

  • необработанной транзакции и
  • аутентификатор. Аутентификатор содержит открытый ключ пользователя и подпись необработанной транзакции.

Эта подписанная транзакция далее BCS-сериализуется , после чего подписанная транзакция готова к передаче в интерфейс Aptos REST.

Транзакции с несколькими подписями

Блокчейн Aptos поддерживает несколько методов подписания транзакций, включая однократную подпись, K-of-N multisig и другие.

Транзакция с несколькими подписями K-of-N означает, что для выполнения такой транзакции необходимо, чтобы по крайней мере K из N авторизованных подписантов подписали транзакцию и прошли проверку, проводимую в сети.

Подписи транзакций обернуты в Authenticator. Блокчейн Aptos проверяет транзакции, представленные пользователями, используя данные Authenticator. См. несколько примеров ниже:

На языке Typescript вот как выглядит аутентификатор с одной подписью:

interface Authenticator {
  public_key: Uint8Array,
  signature: Uint8Array
}
Enter fullscreen mode Exit fullscreen mode

Пример с несколькими подписями аутентификатора показан ниже:

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
}
Enter fullscreen mode Exit fullscreen mode

Детальные шаги

  1. Создание транзакции RawTransaction.
  2. Подготовка сообщения для подписи и его подписание.
  3. Создание аутентификатора и подписанной транзакции.
  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
  };
}
Enter fullscreen mode Exit fullscreen mode

ПРИМЕЧАНИЕ
Сериализация BCS, показанная в приведенном выше коде, не совпадает с операцией сериализации BCS, показанной в разделе "Обзор".

Шаг 2. Создание сообщения для подписи и его подписание

  1. Сгенерируйте префикс (prefix_bytes) с SHA3_256 хэшем байтов строки APTOS::RawTransaction.
  2. Байты BCS сериализованной RawTransaction.
  3. Конкатенация префикса и байтов BCS.
  4. Подписание байтов закрытым ключом учетной записи.
import * as Nacl from "tweetnacl";

function hashPrefix(): Buffer {
  let hash = SHA3.sha3_256.create();
  hash.update(`APTOS::RawTransaction`);
  return Buffer.from(hash.arrayBuffer());
}

function bcsSerializeRawTransaction(txn: RawTransaction): Buffer {
  ...
}

// This will serialize a raw transaction into bytes
function serializeRawTransaction(txn: RawTransaction): Buffer {
  // Generate a hash prefix
  const prefix = hashPrefix();

  // Serialize txn with BCS
  const bcsSerializedTxn = bcsSerializeRawTransaction(txn);

  return Buffer.concat([prefix, bcsSerializedTxn]);
}

const rawTxn = createRawTransaction();
const signature = Nacl.sign(hashRawTransaction(rawTxn), ACCOUNT_PRIVATE_KEY);
Enter fullscreen mode Exit fullscreen mode

Шаг 3. Создание аутентификатора и подписанной транзакции

interface Authenticator {
  public_key: Uint8Array,
  signature: Uint8Array
}

interface SignedTransaction {
  raw_txn: RawTransaction,
  authenticator: Authenticator
}

const authenticator = {
  public_key: PUBLIC_KEY,
  signature: signature
}

const signedTransaction: SignedTransaction = {
  raw_txn: rawTxn,
  authenticator: authenticator
};
Enter fullscreen mode Exit fullscreen mode

Шаг 4. Сериализация SignedTransaction

Сериализация SignedTransaction в байты с помощью BCS.

const signedTransactionPayload = bcsSerializeSignedTransaction(signedTransaction);
Enter fullscreen mode Exit fullscreen mode

Отправка подписанной транзакции

Наконец, отправка транзакции с обязательным заголовком "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
Enter fullscreen mode Exit fullscreen mode

Latest comments (1)

Collapse
 
vivekascoder profile image
VivekAsCoder

What's the point you just copied the whole doc?