LoginSignup
4
0

More than 5 years have passed since last update.

nem catapult バイトレベルで理解する その4 Cosignature Transaction

Last updated at Posted at 2018-06-24

前置き

Cosignature Transactionは、Aggregate Bonded Transactionに署名する時に使います。

image.png

このトランザクションを作成するときは、はじめに引数としてAggregate Transactionをとります。

次に、秘密鍵で署名をすると、Cosignature Sined Transactionになり、アナウンス可能になります[1]

image.png

アナウンスするときも、それ専用のものが用意されています[2]

これがどういう処理になっているのか気になったので、調べてみます。

手法がわかったら、なるべくデータを扱う方法で、実行してみます。

環境

Alpaca版

Aggregate Bonded Transactionの基本的な流れ

このようなシーンを想定します。トランジションを作るのはAliceです。

aggegateorder (2).png

  1. Aliceは、必要な内部トランザクションを作成する
  2. Aliceは、Aggregate Bonded Transactionを作成する
  3. Aliceは、LockFunds Transactionを作成し、送信する
  4. Aliceは、Aggregate Bonded Transactionを送信する
  5. Carolは、ネットワークからAggregate Bonded Transactionを取りに行く
  6. Carolは、Cosignature Transactionを作成する
  7. Carolは、署名してCosignature Signed Transactionを作成する
  8. Carolは、Cosignature Signed Transactionを送信する

今回は、6~8を詳しく見ていきます

調べてみた

Cosignature Transactionを作成する

[3] CosignatureTransaction.ts

CosignatureTransaction.ts
/**
 * Create a cosignature transaction
 * @param transactionToCosign - Transaction to cosign.
 * @returns {CosignatureTransaction}
 */
public static create(transactionToCosign: AggregateTransaction) {
    if (transactionToCosign.isUnannounced()) {
        throw new Error('transaction to cosign should be announced first');
    }
    return new CosignatureTransaction(transactionToCosign);
}

まず、CosignatureTransaction.createによって作成します。

ここで、引数にとったAggregate Transactionは、isUnannounced()で、TransactionInfoがあるかチェックされます。オフラインでトランザクション作成しただけでは、ここではじかれます。

なので、AccountHttpを使って、ネットワークから取得するのが通常の方法のようです。

そのあと、コンストラクタが呼ばれます。

CosignatureTransaction.ts
/**
 * @param transactionToCosign
 */
constructor(/**
             * Transaction to cosign.
             */
            public readonly transactionToCosign: AggregateTransaction) {

}

何もないっぽい。

署名してCosignature Signed Transactionを作成する

CosignatureTransaction.ts
/**
 * @internal
 * Serialize and sign transaction creating a new SignedTransaction
 * @param account
 * @returns {CosignatureSignedTransaction}
 */
public signWith(account: Account): CosignatureSignedTransaction {
    const aggregateSignatureTransaction = new CosignaturetransactionLibrary(this.transactionToCosign.transactionInfo!.hash);
    const signedTransactionRaw = aggregateSignatureTransaction.signCosignatoriesTransaction(account);
    return new CosignatureSignedTransaction(signedTransactionRaw.parentHash,
        signedTransactionRaw.signature,
        signedTransactionRaw.signer);
}

Cosignature Transactionが作成されたので、署名を作成してCosignature Signed Transactionにします。

CosignatureTransaction.signWithによって署名が作成されます。まずは、これの流れを見ていきます。

最初に、Aggregate TransactionのHashを引数にして、CosignaturetransactionLibraryのインスタンスを作成し、aggregateSignatureTransactionに格納する。

ソースを追っていったけど、基本的には変数を格納する処理でした。

次に、署名を作成する処理。

CosignaturetransactionLibrary.signCosignatoriesTransactionを呼び出している。

CosignaturetransactionLibraryは、下記のimport文を見ると、nem2-libraryのCosignatureTransactionってことのようだ。

import {CosignatureTransaction as CosignaturetransactionLibrary} from 'nem2-library';

なので、実際の処理は、[4] CosignatureTransaction.jsの親クラス[5] VerifiableTransaction.jsに書いてある。

VerifiableTransaction.js
/**
 * @param {KeyPair} keyPair KeyPair instance
 * @returns {module:model/TransactionPayload} Returns TransactionPayload instance
 */
signCosignatoriesTransaction(keyPair) {
    const signature = KeyPair.sign(keyPair, new Uint8Array(this.bytes));
    return {
        parentHash: convert.uint8ToHex(this.bytes),
        signature: convert.uint8ToHex(signature),
        signer: keyPair.publicKey
    };
}

これを見ると、単純にAggregate Transactionのハッシュ値に対して署名をしているようです。

戻り値には、parentHashsignaturesignerが揃っているので、これを使ってCosignatureSignedTransactionを作成する。

Cosignature Signed Transactionを送信する

[6] transactionHttp.ts

transactionHttp.ts
/**
 * Send a cosignature signed transaction of an already announced transaction
 * @param cosignatureSignedTransaction - Cosignature signed transaction
 * @returns Observable<TransactionAnnounceResponse>
 */
public announceAggregateBondedCosignature(
    cosignatureSignedTransaction: CosignatureSignedTransaction): Observable<TransactionAnnounceResponse> {
    return Observable.fromPromise(this.transactionRoutesApi.announceCosignatureTransaction(cosignatureSignedTransaction))
        .map((transactionAnnounceResponseDTO) => {
            return new TransactionAnnounceResponse(transactionAnnounceResponseDTO.message);
        });
}

アナウンスしているのはこの箇所かな

this.transactionRoutesApi.announceCosignatureTransaction(cosignatureSignedTransaction)

[7] TransactionRoutesApi.js

TransactionRoutesApi.js
/**
 * Creates cosignature transaction
 * Announce a cosignature transaction to the network
 * @param {module:model/TransactionPayload} payload Transaction payload
 * @return {Promise} a {@link https://www.promisejs.org/|Promise}, with an object containing data of type {@link Object} and HTTP response
 */
announceCosignatureTransactionWithHttpInfo(payload) {
    let postBody = payload;

    // verify the required parameter 'payload' is set
    if (payload === undefined || payload === null) {
        throw new Error("Missing the required parameter 'payload' when calling announceCosignatureTransaction");
    }


    let pathParams = {};
    let queryParams = {};
    let headerParams = {};
    let formParams = {};

    let authNames = [];
    let contentTypes = [];
    let accepts = ['application/json'];
    let returnType = Object;

    return this.apiClient.callApi(
        '/transaction/cosignature', 'PUT',
        pathParams, queryParams, headerParams, formParams, postBody,
        authNames, contentTypes, accepts, returnType
    );
}

APIのエンドポイントは、/transaction/cosignatureにPUTで、
送信データはpostBody、これはCosignatureSignedTransactionのインスタンスそのもの。

CosignatureSignedTransactionは、parentHashsignaturesignerを持ってる

やってみる

Aggregate Transactionの作成と送信

まず、Aggregate TransactionとLockFunds Transactionの作成と送信。

コードはこれを使う。

$ node aggregate.js
lockFundsTransactionSigned.hash  : 4FA5CF0063BE9577F0A39DB0D69B99404108021C1D6E5EE44A9F686922019546
lockFundsTransactionSigned.signer: 5D9513282B65A12A1B68DCB67DB64245721F7AE7822BE441FE813173803C512C
aggregateTransactionSigned.hash  : 222C1C99033BC372A655042C311CA5251279AD47907A6E2804DDAB606851CB3A
aggregateTransactionSigned.signer: 5D9513282B65A12A1B68DCB67DB64245721F7AE7822BE441FE813173803C512C
TransactionAnnounceResponse {
  message: 'packet 9 was pushed to the network via /transaction' }
TransactionAnnounceResponse {
  message: 'packet 500 was pushed to the network via /transaction/partial' }

送信したAggregate Transactionのハッシュ値は、このような値になります。

222C1C99033BC372A655042C311CA5251279AD47907A6E2804DDAB606851CB3A

これにCosignerの秘密鍵で署名を作成します。

Cosignature Signed Transactionを作成する

コードはこれ

sign.js
const nem2lib = require("nem2-library");

const signData = `222C1C99033BC372A655042C311CA5251279AD47907A6E2804DDAB606851CB3A`;

const privateKey = 'B332E3CA7B31D0BC663232B66D7C282BC2FE1DC0C01BB0159586A2CBEADD6B2A';
const keypair = nem2lib.KeyPair.createKeyPairFromPrivateKeyString(privateKey);

const signature = nem2lib.KeyPair.sign(keypair, signData);

console.log('publicKey: ' + nem2lib.convert.uint8ToHex(keypair.publicKey));
console.log('signature: ' + nem2lib.convert.uint8ToHex(signature));
# node sign.js
publicKey: 543BB01DFEEA0D9A25ADDE515DACC72F2125A8AAE85EDD682D77251E2C4EC174
signature: B3641A69BEC08631036B984A6206503EE928DDD3902D083D9C28030B88FD36D40EC397ACB0FFEADCC03225CF9288F08D50F5D1B506FBB0C0A47B469A3C4B4E0C

Aggregate Transactionのハッシュ値は、これ。

222C1C99033BC372A655042C311CA5251279AD47907A6E2804DDAB606851CB3A

そして、これに署名をした結果は、このようになりました。

B3641A69BEC08631036B984A6206503EE928DDD3902D083D9C28030B88FD36D40EC397ACB0FFEADCC03225CF9288F08D50F5D1B506FBB0C0A47B469A3C4B4E0C

署名者の公開鍵は、こちら。

543BB01DFEEA0D9A25ADDE515DACC72F2125A8AAE85EDD682D77251E2C4EC174

この3つのデータをそのまま送信してもよいし、nem2-sdkでCosignatureSignedTransactionインスタンスを作ってもよいと思う。

今回はそのまま送信する。

Cosignature Signed Transactionを送信する

それでは、このデータを送信します。

{ "parentHash": "222C1C99033BC372A655042C311CA5251279AD47907A6E2804DDAB606851CB3A",
  "signature": "B3641A69BEC08631036B984A6206503EE928DDD3902D083D9C28030B88FD36D40EC397ACB0FFEADCC03225CF9288F08D50F5D1B506FBB0C0A47B469A3C4B4E0C",
  "signer": "543BB01DFEEA0D9A25ADDE515DACC72F2125A8AAE85EDD682D77251E2C4EC174" }

PUTしなければならないので、今回はcurlを使います。

REST用の便利なツールがたくさんあるので探してみるのもいいかもしれません。

Insomniaとかも便利だと思います。

$ curl -X PUT -H 'Content-Type:application/json' -d '{ "parentHash": "222C1C99033BC372A655042C311CA5251279AD47907A6E2804DDAB606851CB3A",  "signature": "B3641A69BEC08631036B984A6206503EE928DDD3902D083D9C28030B88FD36D40EC397ACB0FFEADCC03225CF9288F08D50F5D1B506FBB0C0A47B469A3C4B4E0C",  "signer": "543BB01DFEEA0D9A25ADDE515DACC72F2125A8AAE85EDD682D77251E2C4EC174" }' http://localhost:3000/transaction/cosignature
{"message":"packet 501 was pushed to the network via /transaction/cosignature"}

ちゃんとconfirmedになったかどうか

$ curl http://localhost:3000/transaction/222C1C99033BC372A655042C311CA5251279AD47907A6E2804DDAB606851CB3A/status
{"group":"confirmed","status":"Success","hash":"222C1C99033BC372A655042C311CA5251279AD47907A6E2804DDAB606851CB3A","deadline":[1650699429,16],"height":[161822,0]}

confirmedになってるし、ブロック高161822に取り込まれたことがわかります

Refference

[1] https://nemtech.github.io/nem2-sdk-typescript-javascript/classes/_model_transaction_cosignaturetransaction_.cosignaturetransaction.html

[2] https://nemtech.github.io/nem2-sdk-typescript-javascript/classes/_infrastructure_transactionhttp_.transactionhttp.html

[3] https://github.com/nemtech/nem2-sdk-typescript-javascript/blob/3c8c740/src/model/transaction/CosignatureTransaction.ts

[4] https://github.com/nemtech/nem2-library-js/blob/master/src/transactions/CosignatureTransaction.js

[5] https://github.com/nemtech/nem2-library-js/blob/master/src/transactions/VerifiableTransaction.js

[6] https://github.com/nemtech/nem2-sdk-typescript-javascript/blob/3c8c740/src/infrastructure/TransactionHttp.ts

[7] https://github.com/nemtech/nem2-library-js/blob/master/src/api/TransactionRoutesApi.js

関連

nem catapult バイトレベルで理解する その1 トランザクションハッシュ
https://qiita.com/planethouki/items/d7a7fc7adf8c8bc48668

nem catapult バイトレベルで理解する その2 TransferTransaction
https://qiita.com/planethouki/items/025d44f2ebe6cfcb4b1f

nem catapult バイトレベルで理解する その3 トランザクション署名
https://qiita.com/planethouki/items/932d96ee17bd4f305368

nem catapult バイトレベルで理解する その4 Cosignature Transaction
https://qiita.com/planethouki/items/fcac3c9d329b0278c4b7

nem catapult バイトレベルで理解する その5 SecretLock/Proof Transaction
https://qiita.com/planethouki/items/4c91c2e6c722283c50f1

nem catapult バイトレベルで理解する その6 空ブロック
https://qiita.com/planethouki/items/da717595a1ff58d0d84f

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0