This is a ruby library for interacting with the bitcoin protocol/network.
Some of the main features are:
Bitcoin::Util provides the basic bitcoin utility functions for base58, ECC, etc.
Bitcoin::Protocol can parse/create (almost?) all protocol messages
Bitcoin::Network::Node connects to peers, fetches the blockchain and keeps it up to date (see NODE for usage)
Bitcoin::Validation validates block and transaction rules
Bitcoin::Storage stores the blockchain and can be queried for transaction data
Bitcoin::Script implementation, create/run scripts and verify signatures
Bitcoin::Key provides a high-level API for creating and handling keys/addresses
Bitcoin::Builder provides a high-level API for creating transactions (and blocks)
Bitcoin::Wallet is a draft implementation of a simple wallet
Bitcoin::Namecoin implements all the namecoin-specific differences (see NAMECOIN)
Bitcoin::Litecoin implements all the litecoin-sepcific differences
ruby 1.9.3
ruby 2.0.0
We assume you already have a ruby 1.9 or 2.0 compatible interpreter and rubygems environment.
git clone https://github.com/lian/bitcoin-ruby.git; cd bitcoin-ruby ruby -Ilib bin/bitcoin_node
if you want to have it available system-wide, just build the gem and install it:
gem build bitcoin-ruby.gemspec && gem install bitcoin-ruby-0.0.5.gem
now you can just call bitcoin_node from anywhere.
Note that some aspects of the library (such as networking, storage, etc.) need additional dependencies which are not specified in the gemspec. The core requirements are intentionally kept to a minimum, so nobody has to install unneeded dependencies.
eventmachineto run a node / connect to peerssequel,sqlite3/pg/mysqlto use a storage backendem-dnsornslookupto get peer addrs from DNS seedsgir_ffifor the guibaconto run the specsscryptto use a much faster scrypt hash implementation for Litecoin
If you would like to install using Bundler, put it in your Gemfile and run bundle install
gem'bitcoin-ruby', git:'https://github.com/lian/bitcoin-ruby', branch:'master', require:'bitcoin'
There is a node which connects to the network and downloads the blockchain into a database. see NODE, Bitcoin::Network::Node.
It also opens an extra socket where local clients can query statistics, monitor blockchain data, and relay their own transactions to the network. see NODE, Bitcoin::Network::CommandHandler, Bitcoin::Network::CommandClient.
There is a WALLET implementation to manage a set of keys, list balances and create transactions. see WALLET, Bitcoin::Wallet.
There are different aspects to the library which can be used separately or in combination. Here are some ideas of what you could do. There are also some demo scripts in examples/, see EXAMPLES.
Generate a Bitcoin::Key
key = Bitcoin::generate_keykey#=> [<privkey>, <pubkey>]
Get the address from a public key
address = Bitcoin::pubkey_to_address(key[1]) address#=> <bitcoin address>
Check if an address is valid
Bitcoin::valid_address?(address) #=> true
Parse a Bitcoin::Protocol::Block
raw_block = File.open('spec/bitcoin/fixtures/rawblock-0.bin', 'rb') {|f|f.read} blk = Bitcoin::Protocol::Block.new(raw_block) blk.hash#=> 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048blk.tx.count#=> 1blk.to_hash#=> ...Bitcoin::Protocol::Block.from_json( blk.to_json )
Parse a Bitcoin::Protocol::Tx
raw_tx = File.open('spec/bitcoin/fixtures/rawtx-01.bin', 'rb') {|f|f.read} tx = Bitcoin::Protocol::Tx.new(raw_tx) tx.hash#=> 6e9dd16625b62cfcd4bf02edb89ca1f5a8c30c4b1601507090fb28e59f2d02b4tx.in.size#=> 1tx.out.size#=> 2tx.to_hash#=> ...Bitcoin::Protocol::Tx.from_json( tx.to_json ) Bitcoin::Script.new(tx.out[0].pk_script).to_string#=> "OP_DUP OP_HASH160 b2e21c1db922e3bdc529de7b38b4c401399e9afd OP_EQUALVERIFY OP_CHECKSIG"
Get the matching transactions (in this example tx1 is the spending transaction)
rawtx1 = File.open("spec/bitcoin/fixtures/rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin", 'rb') {|f|f.read} rawtx2 = File.open("spec/bitcoin/fixtures/rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin", 'rb') {|f|f.read} tx1 = Bitcoin::Protocol::Tx.new(rawtx1) tx2 = Bitcoin::Protocol::Tx.new(rawtx2)
Then simply ask the transaction to verify an input
tx1.verify_input_signature(0, tx2) #=> true
If you want to control the Bitcoin::Script yourself, you can do so
txin = tx1.in.firsttxout = tx2.out[txin.prev_out_index] script = Bitcoin::Script.new(txin.script_sig+txout.pk_script) result = script.rundo|pubkey, sig, hash_type|hash = tx1.signature_hash_for_input(0, nil, txout.pk_script) Bitcoin.verify_signature(hash, sig, pubkey.unpack("H*")[0]) endresult#=> true
You need to know the previous output you want to spend (tx hash and output index), as well as the private key for the address required to sign for it.
# use testnet so you don't acidentially your whole money!Bitcoin.network = :testnet3# make the DSL methods available in your scopeincludeBitcoin::Builder# the previous transaction that has an output to your addressprev_hash = "6c44b284c20fa22bd69c57a9dbff91fb71deddc8c54fb2f5aa41fc78c96c1ad1"# the number of the output you want to useprev_out_index = 0# fetch the tx from whereever you like and parse itprev_tx = Bitcoin::P::Tx.from_json(open("http://test.webbtc.com/tx/#{prev_hash}.json")) # the key needed to sign an input that spends the previous outputkey = Bitcoin::Key.from_base58("92ZRu28m2GHSKaaF2W7RswJ2iJYpTzVhBaN6ZLs7TENCs4b7ML8") # create a new transaction (and sign the inputs)new_tx = build_txdo|t|# add the input you picked out earliert.inputdo|i|i.prev_outprev_txi.prev_out_indexprev_out_indexi.signature_keykeyend# add an output that sends some bitcoins to another addresst.outputdo|o|o.value50000000# 0.5 BTC in satoshiso.script {|s|s.recipient"mugwYJ1sKyr8EDDgXtoh8sdDQuNWKYNf88" } end# add another output spending the remaining amount back to yourself# if you want to pay a tx fee, reduce the value of this output accordingly# if you want to keep your financial history private, use a different addresst.outputdo|o|o.value49000000# 0.49 BTC, leave 0.01 BTC as feeo.script {|s|s.recipientkey.addr } endend# examine your transaction. you can relay it through http://test.webbtc.com/relay_tx# that will also give you a hint on the error if something goes wrongputsnew_tx.to_json
The Bitcoin::Network::Node can connect to peers and download the blockchain into a Bitcoin::Storage backend. For now it works completely self-contained:
node = Bitcoin::Network::Node.new(options) # options = {network: :bitcoin, ...}node.run
In the future you will be able to register callbacks to the node and control many aspects of its operation yourself. Also see NODE.
If you want to implement your own node, see lib/bitcoin/connection.rb or lib/bitcoin/network/node.rb for examples.
There is support for different storage backends. Each backend can be used with sqlite, postgres or mysql. All backends implement the interface defined in Bitcoin::Storage::Backends::StoreBase and return Bitcoin::Storage::Models.
store = Bitcoin::Storage.sequel(:db=>"sqlite://bitcoin.db") # in-memory dbstore.get_head#=> blocktxouts = store.get_txouts_for_address("15yN7NPEpu82sHhB6TzCW5z5aXoamiKeGy") txouts.first.value#=> 5000000000txouts.first.type#=> :pubkeytxouts.first.get_address#=> "15yN7NPEpu82sHhB6TzCW5z5aXoamiKeGy"
See also STORAGE, Bitcoin::Storage::Backends::UtxoStore, Bitcoin::Storage::Backends::SequelStore and Bitcoin::Storage::Backends::DummyStore for details.
Always trying to improve, any help appreciated! If anything is unclear to you, let us know!
Documentation is generated using RDoc
rakerdoc
The specs are also a good place to see how something works.
The specs can be run with
rakebacon
or, if you want to run a single spec
rubyspec/bitcoin/bitcoin_spec.rb
To test the postgres/mysql storage backend, create a database and set it as an environment variable:
echo "create database bitcoin_test" | psql TEST_DB_POSTGRES="postgres:/bitcoin_test" rake bacon
If you make changes to the code or add functionality, please also add specs.
Any help or feedback is greatly appreciated! From getting knee-deep into elliptic-curve acrobatics, to cleaning up high-level naming conventions, there is something for everyone to do. Even if you are completely lost, just pointing out what is unclear helps a lot!
If you are curious or like to participate in development, drop by #bitcoin-ruby on irc.freenode.net!
Available here: [COPYING]