Как получить/вычислить CommitDigest при фиксации транзакции в AWS QLDB?

Я читал документы, пытаясь понять, как зафиксировать транзакцию в QLDB, и для этого требуется CommitDigest, и документы описывают это как:

Указывает дайджест фиксации транзакции, которую нужно зафиксировать. Для каждой активной транзакции должен быть передан дайджест фиксации. QLDB проверяет CommitDigest и отклоняет фиксацию с ошибкой, если дайджест, вычисленный на клиенте, не соответствует дайджесту, вычисленному QLDB.

Таким образом, CommitDigest должен быть вычислен, но я не совсем уверен, что требуется для его вычисления, учитывая этот пример:

// ** Start Session **
const startSessionResult = await qldbSession.sendCommand({
        StartSession: {
            LedgerName: ledgerName
        }
    }).promise(),
    sessionToken = startSessionResult.StartSession!.SessionToken!;

// ** Start Transaction **
const startTransactionResult = await qldbSession.sendCommand({
        StartTransaction: {},
        SessionToken: sessionToken
    }).promise(),
    transactionId = startTransactionResult.StartTransaction!.TransactionId!;

// ** Insert Document **
const executeStatementResult = await qldbSession.sendCommand({
        ExecuteStatement: {
            TransactionId: transactionId,
            Statement: `INSERT INTO sometable { 'id': 'abc123', 'userId': '123abc' }`
        },
        SessionToken: sessionToken
    }).promise(),
    documentId = getDocumentIdFromExecuteStateResult(executeStatementResult)

// ** Get Ledger Digest
const getDigestResult = await qldb.getDigest({
        Name: ledgerName
    }).promise(),
    ledgerDigest = getDigestResult.Digest;


// ** Commit Transaction **
// ** **The API call in question** **
const commitTransactionResult = await qldbSession.sendCommand({
    CommitTransaction: {
        TransactionId: transactionId,
        CommitDigest: `${commitDigest}` // <-- How to compute?
    },
    SessionToken: sessionToken
}).promise();
// *******************************


// ** End Session **
const endSession = await qldbSession.sendCommand({
    EndSession: {},
    SessionToken: sessionToken
}).promise();

Что мне нужно хэшировать для CommitDigest в вызове API CommitTransaction?


person Mike Richards    schedule 14.09.2019    source источник


Ответы (2)


Обновление: теперь доступен драйвер Node.js. Взгляните на https://github.com/awslabs/amazon-qldb-driver-nodejs/.

На момент написания драйвер QLDB Node.js все еще находился в разработке. Будет довольно сложно, если вы попытаетесь создать его самостоятельно, поэтому я бы предостерег вас от этого. Тем не менее, я могу объяснить как цель, так и алгоритм CommitDigest.

Цель довольно проста: гарантировать, что транзакции будут зафиксированы только в том случае, если сервер обработал точный набор операторов, отправленных клиентом (все по порядку, без дубликатов). HTTP — это запрос-ответ, и поэтому возможно, что запросы могут быть удалены, обработаны не по порядку или дублированы. Драйверы QLDB правильно управляют связью с QLDB, но наличие дайджеста фиксации в протоколе делает невозможным для реализации неправильный повтор запросов и по-прежнему фиксирует транзакцию. Например, рассмотрите возможность увеличения баланса банка дважды, потому что HTTP-сообщение повторяется, даже если первый запрос был успешным.

Алгоритм также довольно прост: хеш-значение заполняется идентификатором транзакции, а затем обновляется с помощью оператора «точка» QLDB. Каждое обновление «точки» в хэше инструкции (sha256 строки PartiQL), а также в IonHash всех значений привязки. Оператор точки — это способ, с помощью которого QLDB объединяет хеш-значения (это тот же оператор, который используется в API проверки) и определяется как хеш конкатенации двух хэшей, упорядочены побайтовым сравнением двух хэшей (со знаком, прямым порядком байтов). Клиент и сервер запускают этот алгоритм синхронно, и сервер будет обрабатывать команду фиксации только в том случае, если значение, переданное клиентом, совпадает с вычисленным сервером. Таким образом, сервер никогда не совершит транзакцию, которая не соответствует запросу клиента.

person Marc    schedule 16.09.2019
comment
Спасибо @Marc, вы в команде AWS QLDB? Полностью понять назначение хэша. Я пробовал несколько разных реализаций для вычисления хеша, используя ваше описание и примеры, но пока безуспешно. Есть ли сроки, когда драйвер QLDB Node.js сможет это сделать? - person Mike Richards; 20.09.2019
comment
@MikeRichards Я не думаю, что вы сможете вычислить значение, не имея доступа к реализации IonHash в Node.js. Что касается сроков, я не могу предоставить ничего другого, кроме как сказать, что он находится в процессе. - person Marc; 23.09.2019
comment
См. Ответ @FroiD на IonHash для Javascript, который находится в активной разработке. Однако в своем комментарии он берет IonHash оператора-с-литералом, что не является алгоритмом, который я описал. Правильная реализация состоит в том, чтобы взять sha256 любого оператора (с любыми литералами PartiQL, которые могут быть там), а затем IonHash каждого IonValue, переданного в качестве параметра. Итак, в его примере IonHash вообще не используется (используется только sha256), а если бы его оператор был INSERT INTO Vehicle ? тогда вам также нужно будет поставить точку в IonHash стоимости транспортного средства. - person Marc; 25.09.2019
comment
спасибо за расширение на этом. Чтобы упростить ситуацию на секунду, игнорируя на данный момент IonHash IonValues, если у меня есть один оператор в моем грубом примере, тогда псевдокод вычисления дайджеста фиксации должен быть: dot(sha256(transactionId), sha256("INSERT INTO Vehicle { 'VIN': '123' }")), верно? А dot должен вернуть sha256(combine(byteSort(hash1, hash2)))? - person Mike Richards; 25.09.2019
comment
Чтобы уточнить, dot = (hash1, hash2) => { if byteCompare(hash1, hash2) < 0 return sha256(concat(hash1, hash2)) else return sha256(concat(hash2, hash1)) } - person Mike Richards; 25.09.2019
comment
@MikeRichards Извините, я должен был быть более конкретным. Все хеширование выполняется через IonHash с использованием sha256. Идентификатор транзакции и операторы PartiQL преобразуются в IonValues, а затем передаются через хэшер. IonHash-with-sha256 для IonString не совпадает с sha256 байтов UTF8 этой строки. Дайте мне знать, если это имеет смысл. - person Marc; 30.09.2019
comment
А, хорошо, я вижу, имеет смысл. Я поиграю еще с пакетом ion-hash-js - person Mike Richards; 01.10.2019
comment
Есть ли какие-нибудь новости о прогрессе библиотеки node.js для QLDB? Я также хочу иметь возможность фиксировать транзакции в QLDB и застрял в правильном вычислении дайджеста. Можем ли мы получить необработанный пример того, как добиться этого для простого оператора INSERT? - person Alko; 07.10.2019
comment
@Alko нет новостей, которыми я могу поделиться, кроме как сказать, что мы над этим работаем. Что касается примеров, мы только что выпустили предварительную версию драйвера Python для GitHub: github. com/awslabs/amazon-qldb-driver-python. Если вы знакомы с Python, вы сможете найти решение для Node.js. Тем не менее, я бы по-прежнему не рекомендовал создавать собственный драйвер. Мы работаем, чтобы доставить его вам как можно быстрее. - person Marc; 29.10.2019
comment
И сегодня у нас есть предварительная версия драйвера Node.js. Подробности на twitter.com/marcbowes/status/1192969400506171392. - person Marc; 09.11.2019
comment
@Marc, есть новости о драйвере PHP? - person Petah; 19.08.2020
comment
Пока нет возможности поделиться. - person Marc; 24.08.2020
comment
@Petah вот руководство по началу работы с драйвером Python docs.aws.amazon.com/qldb/latest/developerguide/ - person emilebaizel; 23.11.2020

У меня недостаточно репутации, чтобы добавить комментарий, но я обнаружил, что вот эта библиотека может помочь: https://github.com/amzn/ion-hash-js

Я сейчас здесь:

const ionHashJS = require("ion-hash-js/dist/commonjs/es5/src/IonHash");
const ionStr =
  "INSERT INTO Vehicle { 'VIN': '12345', 'Type': 'Semi', 'Year': '2020', 'Make': 'Frank', 'Model': '313373', 'Color': 'Blue'  }";
const hashReader = ionHashJS.makeHashReader(
  ionJs.makeReader(ionStr),
  ionHashJS.cryptoIonHasherProvider("sha256")
);
hashReader.next();
hashReader.next();
const digest = hashReader.digest();
person FroiD    schedule 23.09.2019
comment
Вы случайно не догадались об остальном? Я попробовал ваше решение, а также попытался объединить его с идентификатором транзакции, как объяснил @Marc, и все еще получаю неправильный дайджест. - person Alko; 07.10.2019