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に自分の公開鍵が指定されているかどうかを調べます。
これで通知ロジックが完成しました。
ぜひお試しください。