JSON-RPC メソッドのアイデア:指定された txid より新しいトランザクションをリストする

davux 2010年12月8日 08:07 UTC 原文 ·

特定のトランザクション ID より新しいトランザクションをリストする JSON-RPC メソッドがあれば非常に便利であろう。これにより、開発者は最新の既知の txid を記録し、任意の頻度でそのメソッドをポーリングするだけで、新しいトランザクションを容易に監視できるようになる。

実現方法の一つとして、listtransactions を拡張してオプションの txid 引数を受け付けるようにすることが考えられる:

nelisky 2010年12月8日 17:44 UTC 原文 ·

+1

自分はまだその部分に手を付けていないし、時間を見つけて鍵のインポート/エクスポートに取り組みたいが、それは自分のスクリプトのいくつかにとって非常に助かるものだ。

davuxの投稿(2010年12月8日 08:07 UTC)

特定のトランザクション ID より新しいトランザクションをリストする JSON-RPC メソッドがあれば非常に便利であろう。これにより、開発者は最新の既知の txid を記録し、任意の頻度でそのメソッドをポーリングするだけで、新しいトランザクションを容易に監視できるようになる。

新しい取引を監視するコードを追加するなら、ギャビンの monitor パッチを含めるべきだ: https://github.com/gavinandresen/bitcoin-git/tree/monitorreceived

genjix 2010年12月8日 20:20 UTC 原文 ·

WalletTx はウォレットに順次追加されるのだから、古い txid はウォレットの前の方に現れると仮定できるのではないか?

そうであれば、単に線形検索を行い、その txid 以降の txid を出力し続けるだけで済む。

誰かこれを確認できるだろうか?

この方法で listtransactions を使うのは安全ではない。

listtransactions に消極的だったことで批判されてきたのは知っている。その消極的な理由を説明させてほしい。

トランザクションは動的だ。過去のトランザクションが未承認になったり、消えて戻ってきたり、無効になって消えたり、別の二重支払いに置き換えられたりする可能性がある。日付が変わったり、順序が変わったりすることもある。

プログラマーは自然に listtransactions をこう使いたがる:前回聞いた時以降の新しいトランザクションを教えてくれれば、自分で集計や静的な記録を保持する。これは通常の使用ではすべてうまく動作するように見えるが、金額を何かに使用する場合、非常に悪用可能だ:

  1. 過去のトランザクションが無効になって消えたことをどうやって知るのか?
  2. ブロックチェーンの再編成があった場合、トランザクションが再度承認された時に二重カウントするのは容易だ。
  3. トランザクションは異なる txid の二重支払いに置き換えられる可能性がある。両方の支払いをカウントしてしまうだろう。

以前のトランザクションは既に見たから新しいトランザクションだけ見ればよいというモデルは正しくない。古いトランザクションはいつでも変わり得る。

受け取った支払い金額に基づいてアクションを起こす時は、常に bitcoin に戻って現在の残高合計を問い合わせる(または move や sendfrom を使用する)必要があり、残高が減る可能性に備えなければならない。

正しい方法で行うことを容易にするアカウント機能ができた今、listtransactions を持つ準備がより整った。

genjixの投稿(2010年12月8日 11:20 UTC)

WalletTxはウォレットに順次追加されるのだから、古いtxidはウォレットの前の方に現れると仮定できるのではないか?

そうであれば、単に線形検索を行い、そのtxid以降のtxidを出力し続けるだけで済む。

ウォレットは key/value の db4 データベース(および RAM 内の key/value マップ)だ。

どちらのデータ構造も時間順に並んでいない。

mikegogulski 2010年12月8日 20:41 UTC 原文 ·

davux のリクエストの動機は理解できる。リリースした e コマースプラグインの開発中に、ウォレットに対する「ダンプ」メソッドの使用が長期的に実現可能かどうか疑問に思った。時間が経つにつれ返されるデータは増える一方だからだ。

アカウントやアドレスに JSON-RPC コールバック URL を添付でき、そのアカウントやアドレスの承認やその他のステータス変更のたびに呼び出され、コールバックがクリアされるまで続くのが理想だ。これでウォレットのポーリングの必要が完全になくなる。

それについての「機能リクエスト」投稿をどこかに書いた。

サトシ・ナカモトの投稿(2010年12月8日 11:21 UTC)

listtransactionsに消極的だったことで批判されてきたのは知っている。その消極的な理由を説明させてほしい。

トランザクションは動的だ。過去のトランザクションが未承認になったり、消えて戻ってきたり、無効になって消滅したり、異なる二重支払いに置き換えられたりする。日付が変わることも、順序が変わることもある。

プログラマーは自然とlisttransactionsを次のように使いたがる:前回聞いた以降の新しいトランザクションを教えてくれ、自分で集計や静的な記録を保持するから。これは通常の使用ではうまくいくように見えるが、金額を何かに使う場合は非常に悪用しやすい:

  1. 過去のトランザクションが無効になり消えたことをどうやって知るのか?
  2. ブロックチェーンの再編成が起きた場合、再承認されたときにトランザクションを二重にカウントしやすい。
  3. トランザクションが異なるtxidの二重支払いに置き換えられることがある。両方の支出をカウントしてしまう。

ある時点で、取引を受け入れるウェブサイトや人は、このリスクを受け入れなければならない。listreceivedbyaddress を使おうと listtransactions を使おうと、これは避けられない。これが listtransactions への消極的姿勢がとても奇妙に見える理由だ。

Bitcoin を受け入れるほぼすべての取引所やウェブサイトは、取引が承認され商品が発送されるか金銭が交換される二値の決定点に達する。その二値の決定点以降、ブロックチェーンが再編成されたり取引が消えたりしても、ウェブサイトにできることは損失を受け入れることだけだ。

ウェブサイトの観点からは、「listtransactions 6」と「listreceivedbyaddress 6」の間に実効的な違いはゼロだ。ウェブサイト運営者にとっての最終結果は同じだからだ:商品は発送済み/注文は承認済み/金銭は交換済み。

では、引用したメッセージで私が挙げた問題にどう対処しますか?

これらのことは、ある時点以降は listreceivedbyaddress であっても避けられず安全でないという重要なポイントだと思う。そこで、現在のメインライン Bitcoin でのウェブサイトの動作と listtransactions を比較することが有益だと思う。これを承認ポイントと呼ぼう。あなたの質問に答えると……

サトシ・ナカモトの投稿(2010年12月8日 13:36 UTC)
  1. 過去のトランザクションが無効になり消えたことをどうやって知るのか?

bitcoinmarket や mtgox などのサイトは、6 承認を「承認ポイント」、つまりトランザクションが「安全」と見なせる瞬間としている。過去のトランザクションが無効になり消えた場合、ウェブサイトは潜在的な損失を避けられない。ユーザーはすでに PayPal-USD や LR-USD や Pecunix GAU を受け取って消えているからだ。

ウェブストアや実店舗でも同じだ。顧客が商品を受け取る承認ポイントがある。その後に TX が無効になった場合、店舗は避けられない損失を被る。顧客はすでに購入した商品を持って去っているからだ。

サトシ・ナカモトの投稿(2010年12月8日 13:36 UTC)
  1. ブロックチェーンの再編成が起きた場合、再承認されたときにトランザクションを二重にカウントしやすい。

txid 0x1234 の承認数が、大量のブロック再編成のために 0 から 10 に、また 0 にと激しく変動していると仮定しよう。

listreceivedbyaddress であれ listtransactions であれ、トランザクションが「店舗承認済み」の信頼レベルを超える瞬間という二値の承認ポイントがある。その承認ポイントで顧客は購入した商品を持って去り、それ以降のブロックチェーンや TX の動作に関係なく店舗は損失を被る。

プログラマーがミスをして、承認数が常に増加すると仮定する可能性があることは同意する。しかし、そのヒューマンエラーも listreceivedbyaddress で使用した場合に危険をもたらす。

サトシ・ナカモトの投稿(2010年12月8日 13:36 UTC)
  1. トランザクションが異なるtxidの二重支払いに置き換えられることがある。両方の支出をカウントしてしまう。

この点については、txid が変わるため、listtransactions がここで追加的な危険をもたらすことに同意する。ただし、新しい二重支払いが JSON-RPC ユーザーが探している宛先 Bitcoin アドレスと一致する場合に限る

それでもこの場合も、ユーザーのセキュリティは完全に信頼レベルに依存する:TX が 6 承認前に置き換えられた場合、ソフトウェアはおそらく何も気づかない。TX が 6 承認後に置き換えられた場合、顧客はすでに購入した商品を持って去っており、Bitcoin ユーザーは損失を被る。

これは単に Bitcoin 自体に固有のものだ。ブロックチェーンの再編成は 50 ブロック後に起こるかもしれない。しかし、ウェブサイトはユーザーに商品を受け取る前に 50 ブロック待たせたくない。これはよく知られた自動販売機問題だ。listtransactions は listreceivedbyaddress ですでに脆弱なもの以上にこの問題に何も追加しない。

取引は二値の「承認ポイント」の後に置き換えられる可能性がある。Bitcoin のすべてのユーザーは、クレジットカードのチャージバックリスクや万引きリスクと同様に、これをビジネスプランに織り込む必要がある。

davux 2010年12月8日 23:40 UTC 原文 ·
サトシ・ナカモトの投稿(2010年12月8日 11:21 UTC)

受け取った支払い金額に基づいてアクションを起こす時は、常に bitcoin に戻って現在の残高合計を問い合わせる(または move や sendfrom を使用する)必要があり、残高が減る可能性に備えなければならない。

つまりそれは開発者のアプリにおける設計上の問題であり、listtransactions に固有の問題ではない。listtransactions を不注意に使うと危険になりうるということだ。OK、しかし多くのプログラミングツールにもトラップがある。例えば、スレッドを使ったプログラミングは設計上のトラップだらけだ。だからといってそのツールを開発者に提供すべきではないということではなく、ドキュメントでそれらのトラップについて強く警告すべきだということだ。

私の主張:listtransactions を利用可能にしつつ、API として正確にドキュメント化し、使用時に犯してはならない設計ミスを説明しよう。

所定の minconf レベルでの通常のリスクの話をしているのではなく、この方法で使用した場合の listtransactions の追加的な落とし穴について話している。

サトシ・ナカモトの投稿(2010年12月8日 13:36 UTC)
  1. ブロックチェーンの再編成が起きた場合、再承認されたときにトランザクションを二重にカウントしやすい。

OP の listtransactions [count=10] [txid]の例は、プログラマーが前回の listtransactions 呼び出しの最後の txid を渡せば同じトランザクションを二度と見ることはないと非常に簡単に仮定してしまうことを暗示しており、それは事実ではない。既に受け入れた txid を追跡するための独自の永続マップや辞書を維持しなければ、支払いを二重カウントするのは非常に容易だ。

ある明らかな方法で使うために特注されたように見える関数があり、その方法が目立たない罠であるというのは正しくないように思う。

ジェフ・ガージックの投稿(2010年12月8日 14:07 UTC)
サトシ・ナカモトの投稿(2010年12月8日 13:36 UTC)
  1. トランザクションは、異なるtxidを持つ二重支払いで置き換えられる可能性がある。両方の支払いをカウントしてしまう。

両方の支払いが同じアドレス宛てだとする。getreceivedbyaddress は常にどの時点でも一方か他方の支払いだけをカウントし、両方をカウントすることは決してない。

listtransactions を使うと、両方をカウントするのは非常に容易だ。最初の支払いを見て、カウントする。2番目の支払いを見て、カウントする。合計は二重カウントだ。

より後に発生したトランザクションを一覧する」を持たないもう一つの理由を追加しよう:

move の「トランザクション」にはトランザクション ID がないが、アカウント残高には影響する(listtransactions にも表示される)。

listtransactions を呼び出して、返された最後のアイテムの txid を保存しようとすると、コードがぐちゃぐちゃになる。categorymove だった場合、txid は存在しない

ポーリングの排除について:かなり近いうちに monitorreceived パッチをクリーンアップする予定だ。トランザクションが入ってきたりブロックが承認されたりした時に URL に POST する…しかし accounts から学んだ教訓に基づいて再設計するためにじっくり考える必要がある。非常にミニマルな API になるかもしれない。通知は「おい、txid <123ae4221…>が N 回の確認に達したぞ、gettransaction と getbalance を呼んで最新情報を取得した方がいいかもしれない」というものだ。

ギャビン・アンドレセンの投稿(2010年12月8日 15:41 UTC)

より後に発生したトランザクションを一覧する」を持たないもう一つの理由を追加しよう:

あなたとサトシの「txid 以降の tx」についての意見に同意する。自分の listtransactions(現在は xlisttransactions)パッチは、意図的にその機能を持っておらず、これまでも持ったことがない。

ribuck 2010年12月9日 11:48 UTC 原文 ·
ジェフ・ガージックの投稿(2010年12月8日 14:07 UTC)

過去のトランザクションが無効になり消えた場合、ユーザーは既にPayPal-USDやLR-USDやPecunix GAUを受け取って消えているため、ウェブサイトは潜在的な損失を避けられない。

それが常に当てはまるわけではない。顧客がウェブサイトに残高を持っている場合もある。ウェブサイトの運営者は、過去の取引が無効になり消えた場合、確実に知りたいだろう。

ribuckの投稿(2010年12月9日 02:48 UTC)
ジェフ・ガージックの投稿(2010年12月8日 14:07 UTC)

過去の取引が無効になり消えた場合、ウェブサイトは潜在的な損失を回避できない。ユーザーはすでにPayPal-USDやLR-USDやPecunix GAUを受け取って消えているからだ。

それが常に当てはまるわけではない。顧客がウェブサイトに残高を持っている場合もある。ウェブサイトの運営者は、過去の取引が無効になり消えた場合、確実に知りたいだろう。

確かに、それは取引で十分簡単に追跡できる。

ジェフ・ガージックの投稿(2010年12月8日 15:58 UTC)

あなたとサトシの「txid 以降の tx」についての意見に同意する。自分の listtransactions(現在は xlisttransactions)パッチは、意図的にその機能を持っておらず、これまでも持ったことがない。

ユーザーに最近の N 件のトランザクション履歴を表示するようなものに設計されている限り、問題ない。アカウント機能により正しい方法で支払い検出を行うことが容易になった今はなおさらだ。

ギャビン、listtransactions にすべてのアカウントのトランザクションをリストするオプションを付けられるか?

インターフェースがどうあるべきかわからない。もしかすると: listtransactions [count]

ただしコマンドラインからは難しいだろう。

インターフェースの良い解決策が思いつかないのが問題だ。""のような特殊ケースとして""かもしれない。ユーザーがアカウント名""を作成できないようにする必要があるだろう。

ジェフ・ガージックの投稿(2010年12月9日 07:13 UTC)

確かに、それは取引で十分簡単に追跡できる。

トランザクションで「簡単に」追跡できるというのがどういうことかわからない。

davux 2010年12月9日 19:23 UTC 原文 ·
サトシ・ナカモトの投稿(2010年12月9日 18:08 UTC)

ギャビン、listtransactions にすべてのアカウントのトランザクションをリストするオプションを付けられるか?

それは素晴らしいだろうな!

サトシ・ナカモトの投稿(2010年12月9日 18:08 UTC)

どんなインターフェースにすべきかは分からないが、たとえば: listtransactions [count]

ただしコマンドラインからは難しいだろう。

空文字列はどうだ?プログラム的なコンテキスト(例えば Python)でも使いやすいし、シェルのコンテキストでも使いやすい:

bitcoind listtransactions ''

さらに、空文字列は既に「任意のアカウント」を意味するものとして sendfrom などで(そして恐らく他の場面でも)使われているので、現行 API との整合性も取れる。微妙に異なる特殊ケースをいくつも作るのはやめよう。シンプルなほど良い。

サトシ・ナカモトの投稿(2010年12月9日 18:08 UTC)

ギャビン、listtransactionsに全アカウントのトランザクションを一覧表示するオプションを追加できないか?

どんなインターフェースにすべきかは分からないが、たとえば: listtransactions [count]

ただしコマンドラインからは難しいだろう。

インターフェースの良い解決策が思いつかないのが問題だ。""のような特殊ケースとして""かもしれない。ユーザーがアカウント名""を作成できないようにする必要があるだろう。

ああ、listtransactions "" という形は実現可能だ。他のアカウント関連ルーチンも、""を渡された場合は新しい「invalid account name」エラーを返すようにすればいい。

ただし、これには 2 つの懸念がある:

  1. listtransactions ”*” はウォレット内のすべてのトランザクションを走査する必要がある(トランザクションは時刻でインデックス化されていない)。大きなウォレットでは遅くなるし、時間とともにさらに遅くなっていく。listtransactions * を高速化するためだけにトランザクションをインデックス化するのは、「使わないオプション機能はコストを発生させるべきではない」という原則に反する。

2.「全アカウントを横断して直近 N 件のトランザクションを一覧表示する」のユースケースは何だ?私が思いつくのは、JSON-RPC 経由で bitcoind と通信する代替 GUI を開発するケースだけだ。ただ、それをサポートするには同時に他の機能もいくつか追加する必要がある(たとえば、listtransactions が返すオブジェクトにアカウント情報やビットコインアドレス情報を追加する必要がある……)。