A bitcoin transaction script language / vm implementation in python. Built based on info from the bitcoin wiki.
- Install bitcoind
- Guide for installing using Macports on Maverick guide
- Enable the bitcoin rpc server and historical transaction indexing in ~/bitcoin.conf by
adding/uncommenting the following lines and replacing bracketed
things:
- txindex=1
- server=1
- rpcuser=[yourUser]
- rpcpassword=[yourPass]
- rpcport=8332
- rpcconnect=127.0.0.1
- Spin up a bitcoind daemon, rebuilding the historical index. This will take some time to complete; about a day for all transactions. You will be able to work with the current state of the index, though, so transactions from early blocks should work pretty quickly.
bitcoind -conf=/path/to/your/bitcoin.conf -daemon -reindex
- Get bitrans:
git clone https://github.com/hackscience/bitrans.git
cd bitrans
- Install the python ecdsa lib.
- Fire up python:
python
- Establish a connection to the bitcoind daemon
>>> import rpc
>>> s = rpc.jsonrpc("yourUser","yourPass")
- Grab a transaction
- the transaction id could be found in https://blockchain.info/
- for testing, we use txid = ‘fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4’.
- Note that if your bitcoind hasn’t finished reindex, the current rpcserver will just return NoneType Error.Just grab a different txid or wait until reindex finishes.
>>> import transaction
>>> t = transaction.transaction('fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4',s)
- Verify the transaction:
t.verify()
this is outdated Here’s how it works:
There are three primary abstractions: opcodes, bytestreams, and machines. A stream is a sequence of bytes; it is implemented as a wrapper around python strings of human readable hex (like ‘AFAF’). A machine consists of two stacks (a primary and alternative stack). An opcode takes a stream and a machine as input and does stuff (maybe mutates) one, both, or neither.
Byte streams will be a mixture of opcodes and ‘raw’ data. The
elements of the stacks are themselves bytestreams. Raw data is
interpreted as variable-length little-endian signed integers.
Opcodes are one-byte unsigned little-endian big-endian ints.
There doesn’t seem to be any reason to compile anything. A script
is interpreted by continually reading an opcode from a stream
representing the script and applying the opcode to the stream and a
machine. I think scripts have headers but I haven’t quite figured
it out yet. (Multiple) scripts are embedded in transactions which
provide some metadata. A transaction is valid if all scripts do not
fail during interpretation and the top stack item after
interpretation is true.
- ops.py: Opcode implementations.
- opfns.py: Implementations of the functions that opcodes are built from.
- machine.py: Stack machine implementation.
- bytestream.py: Bytestream implementation.
- script.py: Implements a script.
- transaction.py: Parses and represents entire transactions.
- Implement remaining opfns and ops
- Write a higher-level representation which compiles to bytestreams.
- Animate the process of interpreting a script.
- Throw a whole bunch of garbage at the vm and see if anything causes it to lock up or overflow or something.
Install and run nose:
pip install nose
nosetests