Everyone knows what SatoshiDice is. Their core mechanic is gambling through the use of Bitcoin transactions with the payout being directly linked to the transaction that fuelled the bed to avoid double-spend attacks. My question is, how to implement such a mechanism? Can it be done in the Standard Client, or does it need some extra software to pick the exact inputs of a transaction?
3 Answers
Creating a SatoshiDice-like game is rather easy. Below are the high level steps involved in making such a game.
For each incoming transaction...
Get the customer amount and payment address
Call
bitcoind getrawtransaction [The incoming transaction ID] 1
. The 1 at the end will return the data in "verbose mode", which essentially the raw data in JSON format.From the raw transaction details, take the
txid
andvout
from thevin
object. With this transaction, again callbitcoind getrawtransaction
on thetxid
.From these raw transaction details find the
vout
object, referenced by thevout
index from step #2. Within thisvout
object, there should be a list of payment recipient addresses. Take and store the first address.
Determine the Win/Loss state of the round and return the results
Hash the
txid
+vout
index of the transaction. Seed your hash function with a secret key. As an aside note, you will need to provide your secret key on a periodic basis. Without updating and providing your secret keys, there is no way for your players to verify your fairness.Compare the last four bytes of your hash to determine the win/loss condition.
In case of a loss...
Call
bitcoind createrawtransaction
. You must pass in the originatingtxid
andvout
of your customers payment. With the customers address, include a small, fractional value to send back to the customer. This informs them that they've lost the round. Also, include a second payment address that will receive the remaining portion of bitcoins from the customers originating payment. This should be an address within your wallet.Call
bitcoind signrawtransaction
to sign the transaction. If it returns a value ofcomplete=true
, your transaction is valid.Call
bitcoind sendrawtransaction
and include the above constructed raw transaction.
In case of a win
Calculate the customers winning amount.
Call
bitcoind listunspent
. This will return a list of inputted transactions that have not been spent by your wallet.Create a list of transactions to process as payments. First, include the customer's originating
txid
andvout
index of their payment. Next, append to the list any number of unspent transactions (from step #1) that are necessary to pay your customer their winnings.Remember to include an additional payment address that will receive the remaining portion of bitcoins from the final unspent transaction that may contain overages above the player's winnings.
Call
bitcoind createrawtransaction
, passing in all of the transactions accumulated in step #3.Call
bitcoind signrawtransaction
to sign the transaction.Call
bitcoind sendrawtransaction
and include the above constructed raw transaction.
That's it! That's a very simplistic, SatoshiDice processor. You may want to add more validation, cache your transactions, monitor orphaned blocks and just integrate some other administrative routines.
It is worth mentioning that you always include a portion of the customers original payment with all of your return transactions. This is because if their payment is orphaned, or is marked as invalid, you want to be sure that your transaction is also removed from the block-chain.
Using this method you can actually respond near-instantaneously and there is no need for confirmations. If their transaction is malformed and rejected by the network, your transaction will also be thrown out by the network since it is a child of their original transaction.
-
I guess to get "For each incoming transaction...", you would just call listtransactions? Dec 1, 2013 at 3:09
-
You could easily write a piece of software that runs on the same machine as a bitcoin daemon and let it use the JSON-RPC API from the local bitcoin daemon.
There are JSON-RPC implementation examples for all popular programming languages like Python and Java.
This piece of software will poll for new transactions, validate them and applying your game rules, and again making new transactions. Note that a server with such a piece of software needs only to have it's bitcoin port open to the internet, while the RPC port can be limited to local connections for safety.
-
Well, after attempting to implement it through Bitcoin API, I ran into the problem that since 0.8 and the new database system, bitcoind does not have all information on old transactions, so finding out the sender of a given transaction can be problematic. Apr 9, 2013 at 5:54
-
How is an "old" transaction defined? SatoshiDice acts fast, right? I guess transaction details should be kept several blocks at least, no? Apr 11, 2013 at 20:24
-
Well, in order to determine the issuing address using the API, you need to look to a transaction previous to the one gambling, which can be arbitrarily old. Apr 11, 2013 at 22:08
-
You could keep track of previous transactions in a database, and then query that if it's older in the blockchain. Jun 8, 2013 at 19:07