質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.34%

Go言語によるコントラクトコードのイベント監視方法

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 927

score 9

前提・実現したいこと

下記書籍に沿って、スマートコントラクトを実装したDAppsの開発演習をしています。
「試して学ぶ スマートコントラクト開発(マイナビ出版)」

実際にropstenネットワークにコントラクトコードをデプロイし、トランザクションの発行まで確認したのですが、イベントの発火が行われません。イベントが発火するとブラウザ常に新しいトークルームが生成されるというものになっています。

発生している問題・エラーメッセージ

トランザクションとイベントの監視を、Go言語によって行なっています。
エラーメッセージは出ていないのですが、Go言語の無限ループがされていないように見えます。
ソースコードとログを下記に記載いたします。

もしくはtopics["RoomCreated"]が入ってきていないのではないかと思っています。
何かご意見ありましたら参考にさせていただきたく投稿いたしました

solidityによるコントラクトコードです。

contract RoomFactory is Destructible, Pausable {

    event RoomCreated(
        address indexed _creator,
        address _room,
        uint256 _depositedValue
    );

    function createRoom() external payable whenNotPaused {
        address newRoom = (new Room).value(msg.value)(msg.sender);
        emit RoomCreated(msg.sender, newRoom, msg.value);
    }
}

Go言語によるイベント監視コードです。

想定では、for文直下のlog.Println("イベント検知中")により、ログに「イベント監視中」が無限に出続けるのではないかと考えています。

func main() {

    log.Println("Starting Event Server!!")
    db := connectDB()
    defer db.Close()

    // ③Ethereumネットワークに参加中のノードに接続
    client, err := ethclient.Dial(os.Getenv("GETH_URL"))
    // client, err := ethclient.Dial("ws://127.0.0.1:8545")
    if err != nil {
        log.Fatalf("err: %v\n", err)
    }

    // ④Solidityで定義したイベントをハッシュ化する
    topics := map[string]common.Hash{
        "RoomCreated": crypto.Keccak256Hash([]byte("RoomCreated(address,address,uint256)")),
    }
    log.Println("solidityで定義したイベントをハッシュ化する", topics)

    // ⑤どのコントラクトのどのTopicを対象にイベントを検知処理するか設定
    query := ethereum.FilterQuery{
        Addresses: []common.Address{common.HexToAddress(os.Getenv("ROOM_FACTORY_ADDRESS"))},
        Topics: [][]common.Hash{{
            topics["RoomCreated"],
        }},
    }
    log.Println("どのコントラクトのどのTopicを対象にイベントを検知処理するか設定:", query)

    // ⑥client.SubscribeFilterLogsでコントラクトとの接続を開始
    event := make(chan types.Log)
    sub, err := client.SubscribeFilterLogs(context.Background(), query, event)
    if err != nil {
        log.Fatal(err)
    }
    log.Println("コントラクトとの接続:", event, sub, err)

    roomFactoryAbi, err := abi.JSON(strings.NewReader(string(bindings.RoomFactoryABI)))
    if err != nil {
        log.Fatal(err)
    }
    log.Println("roomFactoryAbiをオブジェクト化:", roomFactoryAbi, err)

    // ⑦イベント検知のための無限ループ

    for {

        log.Println("イベント検知中")

        // ⑧select文を使ってチャネルの監視を行い、コントラクトとの接続が切断された場合はエラーメッセージを返す
        select {

        case err := <-sub.Err():
            log.Println("イベントエラー")
            log.Println(err)
            close(event)

        case vLog := <-event:
            log.Println("Topicsのエラー")
            if len(vLog.Topics) == 0 {
                log.Println("Topicsが存在しません")
            }

            // ⑩イベントを検知した場合はeventチャンネルを通じてイベントデータを返す。
            log.Println("イベント検知準備")

            switch vLog.Topics[0] {
            case topics["RoomCreated"]:
                var roomCreatedEvent RoomCreatedEvent
                log.Println("イベントを検知")
                if err := roomFactoryAbi.Unpack(&roomCreatedEvent, "RoomCreated", vLog.Data); err != nil {
                    log.Printf("Failed unpack: %v\n", err)
                    continue
                }

                // データベースに新しいデータを登録する処理
                room := Room{
                    Address:      roomCreatedEvent.Room.Hex(),                         // デプロイされた新しいルームのコントラクトアドレス
                    CreateTxHash: vLog.TxHash.Hex(),                                   // Transaction Hash
                    OwnerAddress: common.BytesToAddress(vLog.Topics[1].Bytes()).Hex(), // デプロイしたユーザーのアドレス
                    WeiBalance:   roomCreatedEvent.DepositedValue.Uint64(),            // デプロイ時に指定したDeposit額
                    EventCode:    getEventCode(4),                                     // イベントコード
                    OwnerID:      1,                                                   // ダミー
                }

                if err := db.Create(&room).Error; err != nil {
                    log.Printf("Failed create room: %v\n", err)
                }

                break
            }
        }
    }
}

試したこと

イベント監視コードのログです

ログに「イベント検知中」が一回しか出ていません。
なので、イベント監視のコードが常時監視していないのではないかと思っています。

test_event  | 2019/09/05 02:56:37 Starting Event Server!!
test_event  | 2019/09/05 02:56:37 データベースに接続
test_event  | 2019/09/05 02:56:38 solidityで定義したイベントをハッシュ化する map[RoomCreated:[104 73 247 164 9 173 151 211 156 95 250 7 75 247 101 51 11 241 165 116 218 153 212 196 131 17 150 236 215 126 168 218]]
test_event  | 2019/09/05 02:56:38 どのコントラクトのどのTopicを対象にイベントを検知処理するか設定: {<nil> <nil> <nil> [[125 137 92 95 62 226 4 96 16 225 156 245 254 164 133 206 67 15 12 205]] [[[104 73 247 164 9 173 151 211 156 95 250 7 75 247 101 51 11 241 165 116 218 153 212 196 131 17 150 236 215 126 168 218]]]}
test_event  | 2019/09/05 02:56:39 コントラクトとの接続: 0xc000075680 &{0xc000414680 0xb37700 {0xa5d340 0xc000075680 18} eth 0x1feed340575875d6fe33bb68948a66c4 0xc0000757a0 {{0 0} 0} 0xc000075740 {{0 0} 0} 0xc0004476e0} <nil>
test_event  | 2019/09/05 02:56:39 roomFactoryAbiをオブジェクト化: {function () returns() map[createRoom:function createRoom() returns() destroy:function destroy() returns() destroyAndSend:function destroyAndSend(address _recipient) returns() owner:function owner() constant returns(address) pause:function pause() returns() paused:function paused() constant returns(bool) renounceOwnership:function renounceOwnership() returns() transferOwnership:function transferOwnership(address _newOwner) returns() unpause:function unpause() returns()] map[OwnershipRenounced:event OwnershipRenounced(address indexed previousOwner) OwnershipTransferred:event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) Pause:event Pause() RoomCreated:event RoomCreated(address indexed _creator, address _room, uint256 _depositedValue) Unpause:event Unpause()]} <nil>
test_event  | 2019/09/05 02:56:39 イベント検知中

なにかヒントになることがありましたらご教示頂けますと助かります。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

イベントが届けば

  • イベントを検知
  • イベント検知中

というように表示されるのではないでしょうか。
「イベントが届いてない、エラーも発生していない」から一度表示してイベントの受信待ちになっていると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/05 15:05

    確かに先日、何かの原因でWebSocket通信が切れた時に「イベント検知中」のログが表示されたのを確認してます。(他の仕込んであるログ表示もされました)
    イベント情報が渡されていない可能性で少し深掘りしてみます。

    ご意見出していただきありがとうございます!

    キャンセル

  • 2019/09/05 21:52

    event := make(chan types.Log)
    でチャネルを作成しているのはわかったのですが、チャネルにデータを渡す記述がないため、イベントの発火が検知できていないということでしょうか?

    キャンセル

  • 2019/09/06 04:03

    張り付いた結果、なんとかイベント検知できるようになりました!
    ```
    []common.Address{common.HexToAddress(os.Getenv("ROOM_FACTORY_ADDRESS"))}

    この文を変更 ↓

    []common.Address{common.HexToAddress("コントラクトアドレス")}
    ```
    としたら検知しました!
    docker-compose.ymlで環境変数を設定していたのですが、それがよくなかったのかもしれません。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る