Útmutató pythonos és djangós Bitcoin-Instawallet-klón készítéséhez

2012-01-12

Szerző: Jeremias Kangas

A Bitcoin egy fantasztikus innováció; az általa biztosított globális, szinte ingyenes elektronikus pénzátutalás akár egyenesen forradalmi lehetőségnek is bizonyulhat. Jelenleg azonban a rendszer még nagyon fiatal, és csak az idő a megmondhatója, hogy valóban befut-e majd vagy sem. A sikerhez azonban mindenféleképp óriási infrastruktúrára lesz szüksége. Ezért készült el a django-bitcoin könyvtár is, hogy megkönnyítse a webes Bitcoin-alkalmazások fejlesztését.

Fejlesztői szemszögből a Bitcoin már csak azért is nagyon jó, mert a bitcoinok igen könnyen mozgathatóak, is így automatizálhatjuk a pénzátutalás szó szerint minden aspektusát. Ebben az útmutatóban azt vázolom fel, hogy hogyan hozhatsz létre egy egyszerű Instawallet-klónt python nyelven, django web frameworkkel és a django-bitcoin-könyvtárral. A jelen útmutató eredményeként kapott kódot megtalálhatod a githubon is.

Az Instawallet egy igen egyszerű webes Bitcoin-alkalmazás, melynek segítségével bárki könnyen létrehozhat magának egy egyszerű Bitcoin-tárcát, melyben aztán értelemszerűen tárolhatja a bitcoinjait és könnyedén mozgathatja is azokat tetszése szerint anélkül, hogy ehhez bármiféle Bitcoin-kliens telepítésével kellene szöszölnie. Hátránya – ahogy az összes többi ilyen jellegű szolgáltatásnak is -, hogy ehhez meg kell bíznod a szolgáltatóban. Előnye azonban, hogy még névtelenebbé teszi a bitcoin-átutalásokat és még könnyebbé az általános bitcoin-használatot.

Akkor hát lássunk is neki a kódolásnak! Ehhez először is djangóból kell beállítanunk az alkalmazást. Indítunk hát egy új django-alkalmazást, egy új “wallets” django-alkalmazást és klónozzuk a django_bitcoint a githubról.

Megjegyzés: bár most épp nem élünk vele, általában mégis jó ötlet használni a virtualenvet.

pip install django
django-admin.py startproject instawallet
cdinstawallet
python manage.py startapp wallets
git clone git://github.com/kangasbros/django-bitcoin.git
cd django-bitcoin
python setup.py install

Ezt követően össze kell állítanunk a django projektünk beállításait a “settings.py” fájlba. Ehhez a projekthez sqlite-ot használunk, amit először is telepítünk parancssorból.

pip install pysqlite

Az sqlite-adatbázisfájlt “dev.db” néven hozzuk létre. Ezután hozzáadjuk a “django_bitcoin”-t és a “wallets”-t az INSTALLED-APPS-hez, hogy a django megtalálhassa az alkalmazásainkat. Meghatározunk továbbá egy sablonok-könyvtárat is: hozzunk létre egy “templates” könyvtárat a projekt gyökérkönyvtárában.

INSTALLED_APPS = (
….
‘django_bitcoin’,
‘wallets’,
)
import os
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
TEMPLATE_DIRS = (
os.path.join(PROJECT_ROOT, “templates”),
)

És végül be kell még állítanunk a bitcoin daemon-t is. Ehhez le kell töltenünk a hivatalos Bitcoin-klienst és megszerkeszteni a bitcoin.conf fájlt. Egy példa bitcoin.conf fejlesztői célú felhasználására:

testnet=1
server=1
rpcuser=admin
rpcpassword=1234
rpcallowip=*

Ezután hozzá kell konfigurálnunk a Bitcoin-daemont a django settings.py fájlhoz. Tesztelési célokra most 0 megerősítést használunk.

BITCOIND_CONNECTION_STRING = “http://login:password@localhost:8332”
BITCOIN_MINIMUM_CONFIRMATIONS = 0

Most már minden készen áll, kezdődhet az igazi kódolás, elsőként a modellekkel. Ebben az alkalmazásban csak egy modellt fogunk használni. vagyis az online tárcát. Ennek is csak két mezője lesz: az egyik a tárca egyedi és véletlenszerű azonosítója (uuid), míg a másik egy idegen kulcs a tényleges tranzakciók lebonyolítását biztosító django_bitcoin Wallet objektumhoz. A következő modell tehát a “wallets/models.py” fájlba kerül.

class InstaWallet(models.Model):
“””A wallet model”””
uuid = models.CharField(blank=True, max_length=50)
wallet = models.ForeignKey(Wallet, null=True)
def __unicode__(self):
return u”Wallet “+self.uuid+” “+self.name
def url(self):
return “/wallet/”+self.uuid

Szükségünk lesz továbbá egy formára is ehhez az alkalmazáshoz, aminek pedig a “wallets/forms.py” fájlban van a helye. Ezt a formát használjuk a tranzakciók indításához egy meghatározott instawalletből.

class SendForm(forms.Form):
address_to = forms.CharField(min_length=3, max_length=40)
amount = forms.DecimalField(min_value=Decimal(“0.0001”))

Immár tehát meghatároztuk az adatbázis-struktúrát a models.py-ben, így már szinkronizálhatjuk a kiinduló adatbázist.

python manage.py syncdb

Most következik az alkalmazás logikai része (“wallets/views.py”). Mielőtt azonban beépíthetnénk ezt a logikát, előbb meg kell határoznunk az “urls.py”-fájlt, amely azt határozza meg, hogy milyen url-eket használhatunk.

Ehhez az alkalmazáshoz két címet határozunk meg: a “home” címet, amely mindig egyszerűen csak generál egy újabb tárcát és továbbít ahhoz, valamint egy címet minden egyes instawallethez.

urlpatterns = patterns(”,
url(r’^$’, ‘wallets.views.home’, name=’home’),
url(r’^wallet/(?P<uuid>.*?)$’, ‘wallets.views.wallet’, name=’wallet’),
)

Lássuk akkor most a tényleges nézeteket, először is a home nézetet. Ebben a nézetben generálunk egy új tárcát egy véletlen uuid-vel. Ehhez az os.urandom() rendszer-random funkciót használjuk, mivel ez lényegesen jobb, mint a python álrandom funkciója. Azonnal elvégezzük tehát a továbbítást a tárcacímhez.

def home(request):
# just generate a new wallet
new_wallet=InstaWallet.objects.create(uuid=generateuniquehash(extradata=str(os.urandom(32))),\
wallet=Wallet.objects.create())
return HttpResponseRedirect(new_wallet.url())

Most pedig jöhet a tényleges tárca-nézet, az instawalletünk magja. Ehhez a tárca uuid-jét használjuk paraméterként. Ha az InstaWallet-objektum nem található ebben az uuid-ben, akkor 404-hez továbbítunk.

GET kérés esetén nincs mit tenni. Egyéb esetben tranzakció-kérést kaptunk.

Kétféle tranzakciót generálhatunk az instawalletünkkel. Ha a megadott cím hossza 30-37 karakter között mozog, akkor feltételezhetjük, hogy ez egy tényleges Bitcoin-cím, és ezért generálunk is egy bitcoin-tranzakciót. Ehhez a django_bitcoin “Wallet” objektum send_to_address() funkcióját használjuk.

Egyébként azt feltételezzük, hogy a felhasználó egy másik instawallet-alkalmazáshoz próbál pénzt küldeni. Keresünk tehát, hátha találunk megfelelő, a megadott címmel kezdődő uuid InstaWallet-objektumot. Ha találunk, úgy bitcoint küldünk rá a send_to_wallet() funkcióval. Tényleges bitcoin-tranzakciót ebben az esetben nem generálunk, a pénz ilyenkor csak a webes alkalmazásunk felhasználói között mozog.

És hogy ez miért hasznos? Azért, mert így a felhasználók azonnal lebonyolíthatják egymás között a tranzakcióikat anélkül, hogy a Bitcoin rendszerére kellene várniuk.

def wallet(request, uuid):
try:
instawallet=InstaWallet.objects.get(uuid=uuid)
except:
return HttpResponseRedirect(‘/404’)
if request.method == ‘POST’: # If the form has been submitted…
form = SendForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# check if
if len(form.cleaned_data[“address_to”])>30 \
and len(form.cleaned_data[“address_to”])<37:
try:
instawallet.wallet.send_to_address(form.cleaned_data[“address_to”], form.cleaned_data[“amount”])
messages.add_message(request, messages.SUCCESS, \
_(u”Transaction successfully sent to bitcoin address “+form.cleaned_data[“address_to”]))
except:
messages.add_message(request, messages.ERROR, sys.exc_info()[0])
else:
otherwallets=InstaWallet.objects.filter(uuid__startswith=form.cleaned_data[“address_to”])
if len(otherwallets)==1:
instawallet.wallet.send_to_wallet(otherwallets[0].wallet, form.cleaned_data[“amount”])
messages.add_message(request, messages.SUCCESS, \
_(u”Transaction successfully sent to another instawallet “+form.cleaned_data[“address_to”]))
else:
messages.add_message(request, messages.ERROR, _(u”Address not an valid bitcoin address or wallet uuid not found.”))
else:
form = SendForm() # An unbound form
return render_to_response(“instawallet.html”, {
“instawallet”: instawallet,
“form”: form,
}, context_instance=RequestContext(request))

Már majdnem készen is vagyunk! Most már csak a HTML-sablont kell elkészítenünk az alkalmazáshoz. Ez lesz a “templates/instawallet.html” fájl.

Számos, a django_bitcoin sabloncímke-fájl által biztosított sabloncímkét (templatetag) használunk, először is a wallet_tagline-t, amely a bitcoin-egyenlegünket jeleníti meg, valamint az elküldött és fogadott pénzt, plusz az egyenlegünk megközelítő USD-értékét.

Másodszor a bitcoin_payment_qr-t, amely egy egyszerű qr-kódot jelenít meg a fogadó Bitcoin-címünkről. A tárca fogadó címét a Wallet.receiving_address() funkció mutatja, erre küldhetjük a bitcoinokat.

Végül pedig még a wallet_history címkét is, amely táblázat formájában mutatja meg az összes bitcoin-tranzakciónkat.

{% load i18n %}
{% load currency_conversions %}
<html>
<head>
<title>{% trans “Bitcoin Instawallet” %}: {{ instawallet.uuid }}</title>
</head>
<body>
<h1>{% trans “Your instawallet” %}: {{ instawallet.uuid }}</h1>
{% if messages %}
<ul class=”messages”>
{% for message in messages %}
<li{% if message.tags %} class=”{{ message.tags }}”{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<b>{% wallet_tagline instawallet.wallet %}</b><br/>
{% trans “Send bitcoins to following address to receive coins” %}:
{% bitcoin_payment_qr instawallet.wallet.receiving_address %}
<h2>{% trans “Send payments” %}</h2>
<form id=”newform” action=”{{ instawallet.url }}” method=”POST”>{% csrf_token %}
{{ form.as_p }}
<input type=”submit” value=”Send!”/>
</form>
<h2>{% trans “Transaction log” %}</h2>
{% wallet_history instawallet.wallet %}

Ezzel pedig már létre is hoztuk az összes kódot, futtathatjuk és tesztelhetjük is az alkalmazást a “http://localhost:8000/” címen.

python manage.py runserver

Most már láthatjuk, hogy az instawallet valóban működik, és tesztelhetjük is az érmeküldést ide-oda.

Láthatjuk tehát, hogy már minimális kódmennyiséggel is létrehozhatunk egy instawallet-szerű alkalmazást, mivel a legtöbb szükséges funkciót már eleve biztosítja a django_bitcoin könyvtár. Nyugodtan fejleszd tovább a projektet a saját szakálladra és fedezd fel a django_bitcoin könyvtárat.

Ha szándékodban áll élesben is beindítani egy django_bitcoin-alapú alkalmazást, úgy ne felejtsd el átállítani a megerősítésszámláló-beállítást egy magasabb értékre, és nagyon alaposan teszteld le az egészet, mielőtt beindítanád!

A kódot itt találhatod meg.

És végül, ha tetszett ez az útmutató, úgy erre a címre küldhetsz egy kis adományt: 1DaVAZ1kytYPqaDVse9HUcrCQfD6NpNamp 😉

Forrás: Kangas Bros. Innovations Blog

A lap szövege Creative Commons Nevezd meg! – Ne add el! – Így add tovább! 3.0 licenc alatt áll, felhasználni csak forrásmegjelöléssel, és ide mutató linkkel szabad.