JSON-RPC を使用したサンプルアカウントシステムが必要

4 件のメッセージ BitcoinTalk サトシ・ナカモト, RudeDude, dwdollar 2010年7月16日 — 2010年7月16日

JSON-RPC インターフェースを使用してアカウントシステムを作成する推奨方法を示すサンプルコード(できれば Python または Java)を誰かに書いてもらう必要がある。商品を販売するほとんどのサイトでは、このようなものが必要になる。ここの JSON-RPC スレッドを追いかけている方なら、どのように動作すべきかある程度わかるはずだ。

ユーザーがアカウントにログインしている時、資金を追加するために送金できるビットコインアドレスを表示する。表示する前に、それが使用済みかどうかを確認し、使用済みであれば新しいもの(getnewaddress <ユーザー名>)に置き換える。データベースにはそのアカウントの最新のビットコインアドレスのみ保持すればよい。(以前のスレッドでこのサンプルコードの断片を投稿した。getnewaddress で検索してほしい)

ユーザー名をラベルとして使用し、getreceivedbylabel <ユーザー名> でアカウントの「クレジット」金額を取得する。データベースには「デビット」金額を保持する必要がある。アカウントの現在の残高は(クレジット - デビット)だ。ユーザーがお金を使う時、デビットを増やす。

0回より多い承認を要求する場合は、現在の残高(0 承認)と利用可能残高(1回以上の承認)を表示すると親切だ。そうすれば、支払いが認識されたことをすぐに確認できる。すべてのサイトが承認を待つ必要があるわけではないので、現在と利用可能の二重表示はオプションにすべきだ。デジタル商品を販売するほとんどのサイトでは、0 承認でも問題ない。

これの良いサンプルアプリは、シンプルな銀行サイトで、上記の機能に加えて、ビットコインアドレスへの支払い送信オプションがあるものだ。サンプルコードは、動作するサイトにするための最小限の追加要素で、できるだけシンプルにすべきだ。

vekja.net がこのようなサイトの例だ。

RudeDude 2010年7月16日 原文 · 個別ページ

bitcoinmarket.com は現在これらすべてをやっている。あのサイトの作者もコードを共有してくれるかもしれない。

RudeDude 2010年7月16日 原文 · 個別ページ

このサイトに Python の JSON コードがあることも指摘しておく。 http://www.alloscomp.com/bitcoin/

具体的には、残高を確認して固定アドレスに送るこのコードだ。

#!/usr/bin/python
import jsonrpc
MyBCAddress = 'YOUR BITCOIN ADDRESS HERE'

b = jsonrpc.ServiceProxy("http://localhost:8332/")
bal = float(b.getbalance())

if bal > 0.01:
    print "We have a balance of {0:.2f}BC. Sending...".format(bal)
    b.sendtoaddress(MyBCAddress,bal)
else:
    print "No coins here."
dwdollar 2010年7月16日 原文 · 個別ページ

これをずっと投稿しようと思っていた。シンプルな例として整理して、理解しやすくしたかった。今やそのチャンスがいつになるか分からない。だから……このまま投稿することにする。誰かの役に立つかもしれない。

これはおそらく最良のアプローチではない(少し前にサトシと話した結果)。実際、後から追加されて Version .3 に入っている API の新機能はまだ適用していない。だが、実戦で検証されている。壊れていない(まだ)ものを直す必要があるか? Bitcoin サーバーを動かしているマシン上で別プロセスとして動く。唯一省略したのは while ループの break ハンドラだけだ。「list(something_inside)」を見たら、それは SQLObject を使ったデータベースへのクエリだと思ってくれ。

もう一度見直したら、ここに改訂版を投稿する。

#! /usr/bin/python

import jsonrpc
import time
import datetime

from database import *

class BitcoinInterface(object):

    def __init__(self):
        self.access = jsonrpc.ServiceProxy("http://127.0.0.1:8332")
        return

    def issueBitcoinAddresses(self):
        localBitcoinAddresses = list(Address.select(AND(Address.q.type_ == "localBitcoin", Address.q.value == None)))    # Get all unassigned local Bitcoin Addresses
        for localBitcoinAddress in localBitcoinAddresses:
            localBitcoinAddress.value = self.access.getnewaddress()
            client = Client.get(localBitcoinAddress.clientID)
            print "New Address:\nUsername:  %s\nClientID:  %i\nValue:  %s\n" % (client.username, client.id, localBitcoinAddress.value)
        return

    def takeDeposits(self):
        localBitcoinAddresses = list(Address.select(AND(Address.q.type_ == "localBitcoin", Address.q.value != None)))    # Get all assigned local Bitcoin Addresses
        for localBitcoinAddress in localBitcoinAddresses:
            amountReceived = self.access.getamountreceived(localBitcoinAddress.value)
            if amountReceived > localBitcoinAddress.amountReceived:
                client = Client.get(localBitcoinAddress.clientID)
                quantity = amountReceived - localBitcoinAddress.amountReceived
                client.bitcoins = client.bitcoins + quantity
                localBitcoinAddress.amountReceived = amountReceived
                transaction = Transaction(clientID = client.id)
                transaction.datetime = datetime.datetime.now()
                transaction.type_ = "Deposit"
                transaction.quantity = quantity    # Transaction quantity is positive for "Deposit"
                print "Deposit:\nUsername:  %s\nClientID:  %i\nQuantity:  %f\n" % (client.username, client.id, quantity)
        return

    def issueWithdrawals(self):
        clients = list(Client.select(Client.q.bitcoinsToWithdraw > 0))
        for client in clients:
            if client.bitcoinsToWithdraw <= client.bitcoins:    # Redundancy check
                foreignBitcoinAddress = list(Address.select(AND(Address.q.clientID == client.id, Address.q.type_ == "foreignBitcoin")))[0]
                try:
                    quantity = client.bitcoinsToWithdraw
                    self.access.sendtoaddress(foreignBitcoinAddress.value, quantity)
                    client.bitcoins = client.bitcoins - quantity
                    transaction = Transaction(clientID = client.id)
                    transaction.datetime = datetime.datetime.now()
                    transaction.type_ = "Withdrawal"
                    transaction.quantity = -quantity    # Transaction quantity is negative for "Withdrawal"
                    client.bitcoinsToWithdraw = 0
                    print "Withdrawal:\nUsername:  %s\nClientID:  %i\nQuantity:  %f\n" % (client.username, client.id, quantity)
                except:
                    print "Failed Withdrawal:\nUsername:  %s\nClientID:  %i\nQuantity:  %f\n" % (client.username, client.id, client.bitcoinsToWithdraw)
            else:
                print "Failed Withdrawal, Not Enough Bitcoins:\nUsername:  %s\nClientID:  %i\n" % (client.username, client.id)
        return

bitcoinInterface = BitcoinInterface()
while 1:
    bitcoinInterface.issueBitcoinAddresses()
    bitcoinInterface.takeDeposits()
    bitcoinInterface.issueWithdrawals()
    time.sleep(300)