12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

nemAdvent Calendar 2021

Day 1

Symbolブロックチェーンで自分のアカウントへの署名要求を検知する

Last updated at Posted at 2022-01-01

Symbolブロックチェーンで自分に宛てらてたアグリゲートボンデッドトランザクションを検知する方法を紹介します。

Symbolはブロックチェーンに詳しくない他分野のスペシャリストでもローコード/ノーコードでセキュアかつデプロイレスなスマートコントラクトを記述できるブロックチェーンとして日本のエンジニアや研究者からも非常に注目される存在となり、いまでは元イーサリアムのプロトコルの改善提案者がコアチームに無報酬で参入するなどプラットフォームとしてその可能性を期待されています。

今回紹介する方法は、アプリ初期表示時の検知とアプリ起動中のリスナー検知の2種類に対応します。つまり、アプリを起動したときにすでに承認待ち状態であるトランザクションと、アプリ起動中に新規に発生した承認を要求するトランザクションを検知することで、すべてのトランザクションを検知対象とすることができます。また、承認待ちが複数人いる場合は自分が署名してもステータスとしては署名待ち状態となり、アプリを再起動するたびに検知してしまいます。すでに署名したトランザクションや、自分が署名する必要のないトランザクションには反応しないようにすることも重要です。

これらはWebSocketを利用してブロックチェーンの状態を確認するための重要なノウハウになりますので、ぜひマスターしておいてください。

検知対象アカウントの準備

alice = sym.PublicAccount.createFromPublicKey(
"" ,
networkType
);

すでに署名済みであるかどうかを調べるため、公開鍵からパブリックアカウントクラスを生成します。

通知ロジック

//アグリゲートトランザクション検知
bondedListener = listener.aggregateBondedAdded(alice.address);
bondedHttp = txRepo.search({
	address:alice.address,
	group:sym.TransactionGroup.Partial
})
.pipe(
	op.delay(2000),
	op.mergeMap(page => page.data)
);

bondedSubscribe = function(observer){
	observer.pipe(

		//すでに署名済みでない場合
		op.filter(_ => {
			return !_.signedByAccount(alice.publicKey);
		})
	).subscribe(_=>{

		txRepo.getTransactionsById(
			[_.transactionInfo.hash],
			sym.TransactionGroup.Partial
		)
		.pipe(
			op.filter(aggTx => aggTx.length > 0)
		)
		.subscribe(aggTx =>{

			//インナートランザクションの署名者に自分が指定されている場合
			if(
				aggTx[0].innerTransactions.find((inTx) 
				=> inTx.signer.equals(alice.publicAccount))!= undefined
			){
				//ここに通知ロジックを記述
			}
		});
	});
}

bondedSubscribe(bondedListener);
bondedSubscribe(bondedHttp);

解説

リスナー検知
bondedListener = listener.aggregateBondedAdded(alice.address);

リスナークラスから、ボンデッドトランザクションが追加されたイベントを取得します。

起動時検知
bondedHttp = txRepo.search({
    address:alice.address,
    group:sym.TransactionGroup.Partial
})
.pipe(
    op.delay(2000),
    op.mergeMap(page => page.data)
);

対象アドレスのパーシャルトランザクションの存在調べます。
delayにしているのはアプリの他の描画と時間差をつけたいためで、特に必要ではありません。
情報が取得できた場合、ページングされているのでmereMapで中身を取り出します。

証明済み?

上記二種類の検索結果は以下のファンクションに流し込まれます。

bondedSubscribe = function(observer){
    observer.pipe(

        //すでに署名済みでない場合
        op.filter(_ => {
            return !_.signedByAccount(alice.publicKey);
        })
    ).subscribe(_=>{

パーシャルTXは既に署名している可能性もあるため、signedByAccountで検査します。

トランザクション全体の取得と内容の検査
        txRepo.getTransactionsById(
            [_.transactionInfo.hash],
            sym.TransactionGroup.Partial
        )
        .pipe(
            op.filter(aggTx => aggTx.length > 0)
        )

まだ自分が署名していないとわかったら、TX全体を取得します。
これはリスナーイベントで取得した情報にはアグリゲートトランザクションの内部リスト(インナートランザクション)が含まれていない場合があるからです。

署名者に自分が指定されているかチェック
            //インナートランザクションの署名者に自分が指定されている場合
            if(
                aggTx[0].innerTransactions.find((inTx) 
                => inTx.signer.equals(alice.publicAccount))!= undefined
            ){
                //ここに通知ロジックを記述
            }

最後のチェックです。
パーシャルトランザクションは自分が送信者である場合も情報が取れてしまいます。
その情報が必要な場合もありますが、今回は署名要求の検知ですので取れない方がいいです。
なので、find関数でリスト内のsignerに自分の公開鍵が指定されているかどうかを調べます。

これで通知ロジックが完成しました。
ぜひお試しください。

12
5
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
12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?