Lab
5 Details for MPCS 56600
Each
lab
will consist of a small problem and details of how to proceed.
Each lab is intended to give every student hands-on experience
with the core concepts and technologies covered during the
course. A student may concentrate, as a team member, on
one technology over another for the final project, but labs are
designed to give each and every student exposure to all the
technologies that come into play. You need to submit labs
to the TAs for grading--see submission instructions below.
Generally, unless otherwise specified, you will have one week to
complete each assigned lab.
See
the
syllabus for information on grading. Turning in lab
assignments on time is required, without exception, and all late deliveries will be
penalized, regardless
of cause. Submit your assignments to the
subversion repository according to the directions on the
syllabus page.
You
may
write these solutions in any programming language of
your choice. Our suggestion is now is not the time to
learn a new programming language along with the concepts
themselves. So our suggestion is to use whatever
programming language you know best.
Lab 5
Due: 5:00 pm, Monday, May 6, 2019
Problem
1: Transaction laboratory:
BACKGROUND:
You
will create a new raw transaction and you will send it to the
TESTNET blockchain. You will submit a text file named
"my.transaction.out". This lab assumes you have
successfully accomplished Lab 1.
WHAT YOU NEED TO DO:
YOU ARE TO WORK IN THE TESTNET ENVIRONMENT.
This means running the bitc alias that you created in Lab 1.
Make sure bitd is running.
STEP 1:
You need to install some software. Simple go
to: https://stedolan.github.io/jq/
and grab the appropriate installation for your system and install
it. Make sure you environment is updated so that you can
call jq. JQ is a lightweight and flexible command-line JSON
processor that does nice things with the JSON output from
bitcoin-core tools (and others). A tutorial on JQ is here.
The user manual is here.
Validate that you've got JQ installed by typing at a command
prompt:
$ jq --version
jq-1.5
The precise version will not matter.
STEP 2:
Open a terminal window, and type the following (of
course you will not type the initial '$' prompt):
$ echo $BLOCKCHAIN
You should see: testnet
If you do not see testnet output, execute:
$ export BLOCKCHAIN='testnet'
STEP 3:
At the command line, execute:
$ bitc getbalance
Note your balance. It may be 0.00. That's ok, and
that's about to change.
STEP 4:
At the command line, execute:
$ recipient=$(bitc getnewaddress)
Then type:
$ echo $recipient
You should see a bitcoin address print out. Copy this
address to your clipboard.
STEP 5:
Open a browser and navigate
to the following TESTNET faucet: https://testnet-faucet.mempool.co
There are other faucets available if you prefer which you can google.
Prove you're not a robot by solving a difficult mathematical puzzle and in the prompt area, paste your
bitcoin address you created in STEP X. Then enter an amount (with the guidelines per request) and click on the
"Send" button.
Note the TX ID output. Save that transaction id. You
can watch that transaction on Testnet by going to Watch on: https://tbtc.bitaps.com or live.blockcypher.com. Just enter your transaction id in the prompt.
STEP 6:
At the command line, execute:
$ bitc getbalance
Note your balance. Let's
pretend the faucet delivered and your balance is now 2.0000.
At the prompt, enter:
$ bitc listunspent
and pick an available transaction output (you may have just
one...the transaction the faucet just sent you), AND NOTE ITS
TRANSACTION ID AND 'vout' NUMBER. Your output should look
something like (at a minimum):
{
"txid": "3b8ebc563b843d9b89d3e6JoZ5Xgw26669b66e9347a43c6c2c1e15944be3fe2",
"vout": 1,
...
"amount": 2.00000000,
...
}
Select and copy the hexadecimal "txid" value (in our example, 3b8ebc563b843d9b89d3e6JoZ5Xgw26669b66e9347a43c6c2c1e15944be3fe2)
STEP 7:
At the prompt, create a txn_id
variable and paste the transaction id that you copied above:
$ txn_id='3b8ebc563b843d9b89d3e6JoZ5Xgw26669b66e9347a43c6c2c1e15944be3fe2'
Confirm this by typing:
$
echo $txn_id
And you should see:
3b8ebc563b843d9b89d3e6JoZ5Xgw26669b66e9347a43c6c2c1e15944be3fe2
STEP 8:
At the prompt, enter:
$ changeaddress=$(bitc getrawchangeaddress)
$ echo $changeaddress
2NBAZ5Xebpo5DRbrTHhhqCJbkBPUikogwK1
Your own changeaddress will of course be different. This
one is made up.
STEP 9:
Go back to the output from
listunspent command above, and note the transaction 'vout'
number for transaction $txn_id. It should look something
like:
"vout":
1,
It may say 0, or some other number. At the
prompt, enter (assuming the vout for the transaction you want
to use is '1'):
$ utxo_vout_no=1
STEP 10:
NOW DO THE MATH:
Assume an amount (from listunspent) of 2.0000 (as per our
example). (Note you may have less than this...that is fine. Just enter some portion of your available satoshis).
I want you to pay half of the available output of 2.0000 (or half
of whatever value you have in the transaction), which in our
example is 1.0000, to the recipient address that you
created above (stored in $recipient).
That leaves 1.0000 (or whatever) change available to come back to
you.
BUT, you also need to calculate the transaction fee (let's be safe
and set it to .0005 BTC to be sure to get some miners
interested...), so:
Your remaining 1.0000 - .0005 = 0.9995 remainder that will be
coming back to you, via your changeaddress that you created
earlier in STEP X. So to sum up, you are taking a
transaction in the amount of 2.0000 (again per our example) and
sending 1.0000 to your (own) recipient address and you are sending
0.9995 to your change address, and the miners will take
.0005. Thus:
2.0000 - 1.0000 - 0.9995 - 0.0005 = 0 (you've absorbed the
entirety of the transaction's value).
STEP 11:
NOW PACKAGE UP AND SEND YOUR TRANSACTION TO TESTNET (Note
you will need to change the amounts in the command below to
whatever math you've calculated!!!):
$ rawtxhex=$(bitc -named createrawtransaction inputs='''[ {
"txid": "'$txn_id'", "vout": '$utxo_vout_no' } ]''' outputs='''{
"'$recipient'": 1.0000, "'$changeaddress'": 0.9995 }''')
Note you do not specify the transaction fee of 0.0005. The
miners will calculate that automatically.
Now sign the transaction:
$ signedtx=$(bitc -named signrawtransactionwithwallet
hexstring=$rawtxhex | jq -r '.hex')
Now send the transaction to TESTNET:
$ bitc -named sendrawtransaction hexstring=$signedtx
6c3733d8c958e36033ec3a56760a74e59065b936bb23bcda2424a6b980fa2780
(returned txid...note this is made up...)
The value returned is the transaction id of your new
transaction you just created on the TESTNET
blockchain. Note this as you will use it below in Step 13.
STEP 12:
AFTER CLEARING:
Look at your transaction on the TESTNET (MAY TAKE A FEW MINUTES):
bitc getrawtransaction 6c3733d8c958e36033ec3a56760a74e59065b936bb23bcda2424a6b980fa2780
1
(copy and paste your own transaction id returned from the
sendrawtransaction command above and do not forget the '1' at the end...)
Now, look at your new balance (again, if you received no error
messages, you may need to wait a few minutes...)
$ bitc getbalance
1.99950000 [Should reflect slight deduction for
transaction fee, as per our example: 2.0000 - 0.0005 = 1.9995]
Finally, look at your new list of unspent transactions
$ bitc listunspent
(see unspent transactions modified...original one is gone but the
change address amount is new)
STEP 13:
When done:
Copy the raw transaction id that you got (we are using our example
id of 6c3733d8c958e36033ec3a56760a74e59065b936bb23bcda2424a6b980fa2780).
Execute the following command,
substituting your actual new transaction id for our sample
below, and submit the file:
echo '6c3733d8c958e36033ec3a56760a74e59065b936bb23bcda2424a6b980fa2780'
> my.transaction.out; bitc getbalance >>
my.transaction.out; bitc listunspent >> my.transaction.out
REMEMBER, you will substitute YOUR actual new transaction id you
obtained in step 11 above for the '6c3733...' transaction above.
Submit my.transaction.out file as per the instructions below.
Problem
2: Blockchain laboratory:
BACKGROUND:
Now
it is time to begin to build your own blockchain. From
scratch. Needless to say, our intention here is not to
replicate Bitcoin Core. That might be a bit much.
Over the remaining labs, you will build a simple blockchain that
implements a simple cryptocurrency that can be mined and
distributed across nodes. You will generally find the
References section below helpful in addition to the required and
recommended reading.
WHAT YOU NEED TO DO:
STEP 1:
You are to produce the following UML description in
code using a programming language of your choice. For those
using non- or quasi-object-oriented-languages, use some alternate
form of a class, whatever makes the most sense, for instance, a
structure or other such data type that makes the most sense to
you. For those of you using an object-oriented-capable
language (such as python, ruby, C++, Java, C#, etc.), you are to
use classes.
The UML for the blockchain you are to build is this:

When we specify types in the above, these are indicators.
What that means is that you are to come as close as you can to
that datatype in the language that you are using. For those
using strongly-typed languages (C++, Java, etc.), this will be
trivial. For those using late-binding languages (python,
ruby, etc.), just do your best. You will not be downgraded
because a data is not of the correct "type". In the above,
if you see a default type specified (such as "int" for 0xD9B4BEF9
for the MagicNumber in the Block class), you are expected to
implement that default at the time of class instantiation.
For further elucidation as to the meanings of the above, see the
bitcoinwiki pages in the References section below.
Specifics:
The Header's hashPrevBlock is a double-SHA256 hash of the previous
block's header (serialized/stringified as necessary and
concatenated). You do not need to worry about big-endian or
little-endian issues with your blockchain. Simply use
whatever comes most natural to you. We are not looking for a
precise algorithm to do this. Just do it and be consistent
for your own sake. The minimum set of specific fields you
are to concatenate (and hash) from the header are:
TimeStamp + hashMerkleRoot + Bits + Nonce + previousHash.
These fields will represent a Block's Blockhash. If you find
that your implementation would benefit from hashing additional
information, such as an index or count, etc., that is entirely up
to you. You are free to add to the above UML model as your
implementation evolves. You do not need to ask permission to
add attributes (data fields) or methods or functions. The
Block's Blockhash is a hash of the current block's header.
What this means is that in our simplified case, a block holds a
hash of it's own Header information, and it's header holds a hash
of the previous block's hash, and so on.
For the Transactions ListOfIntputs, any list object or list-like
data structure will be fine, including a map or a dictionary; this
is all up to you. The actual inputs and outputs can
be a string for the moment (i.e., making the ListOfIntputs a list
of strings). The Transaction's TransactionHash is a hash of
the concatenated (serialized/stringified) fields of VersionNumber,
InCounter, ListOfInputs, OutCounter, and ListOfOutputs. We
will leave it to you to decide some means of
serializing/stringifying your ListOfInputs and ListOfOutputs
(which again, can be lists of simple strings). You may wish
to implement the Block's Transactions list as a map or dictionary,
where each key is the actual Transaction's TransactionHash.
For the hashMerkleRoot in the Header, you are to create a Merkle
Tree and store its Merkle Root hash in this field. You may
actually store the transactions internally in the Block as a
Merkle Tree (is in Block's Transactions list), what data structure
you actually use to construct your tree is entirely up to
you. We've simply designated it as a "list". That is
not meant to be prescriptive. You may re-use your Merkle
Tree work from Lab 4 here. Even if it's not a list.
The character and form and parameters of constructors, methods,
etc., are entirely up to you. You will notice that we have
only specified data elements in the above UML model. You are
granted carte blanche to design and implement your
blockchain as you see fit, as long as these core requirements are
met.
Finally, you will notice that we have not specified a particular
class called a Blockchain! This is intentional. You
may design your Blockchain class or structure as you see fit, as
long as it stores blocks (in memory only) that are
cryptographically linked and the blocks themselves contain
Transactions as specified above (Transaction inputs and outputs do
not need to be linked or associated at this time). For
example, you may implement your blockchain as a list or other data
structure, such a stack or a queue, in memory. There are no
requirements that your blockchain be persisted on disk.
If you have no immediate need for a given element (for instance, a
Block's Nonce or Bits values), you can simply leave them with a
default value for the time being. Again, default values
should be set at the time of object instantiation.
You are free to implement the printing of block data and
transaction data (via printBlock() and printTransaction()) as you
see fit. This may imply a less anonymous
blockchain where plain data is printed (i.e., from input strings
and output strings) or you may encrypt these strings and print out
the hashes (thus creating a more anonymous
blockchain). This again, is up to you. You might find
it simply easier to leave the data in plaintext in this first
version to make debugging a little easier.
Other than the above requirements, there are a few other general
requirements:
Function 1. There must be some means of asking your
Blockchain for a given block by block height and by block
hash. It is up to you how to implement this.
Function 2. There must be some means of searching the
Blockchain for a given Transaction by TransactionHash, which
should return the Transaction being searched. It is up to
you how to implement this.
Everything else should be self-explanatory, including the meaning
of the indicator "SHA256Doublehash". You should know what
that means by now.
Most importantly: Anything not specifically
spelled out as a requirement above may be interpreted and
implemented as you wish. You can think of this as
creative license.
STEP 2:
You are to write a test case (can be a simple main
function or an actual test harness from a framework) in which you
manually (read: hard-code) instantiate 10 new transactions,
where each transaction has one input and one output (can be
anything you wish at the moment). You will create a new
Blockchain and by doing so you will create your genesis block.
When instantiating the
Blockchain, you are to create a Genesis Block which will have
the hashPrevBlock hash set to all 0's. You can set the
genesis block's Transaction Input and Output strings to be
anything you wish. You may set the genesis block's
Transaction Output string to be anything you wish.
Basically understand that the genesis block and its transactions
are hard-coded.
You will manually add the first 5 transactions to a new
block that you instantiate at height number 1. Block 0 will
be your genesis block. You are to create a third
block which will be at height number 2, and you will add the
remaining 5 transactions to that third block.
After building your blockchain, you are to use Function 1
above to find and return a block by height and then print that
block. You are then to use Function 2 to find and return a
transaction from the blockchain (searching by transaction id hash)
and print out that transaction. Again, you may implement
these two functions any way you see fit.
Submit all code and related files (if any) as specified below.
Finally, and importantly, there are many implementations of
"simple block chains" around the internet. Feel free to look
at any of them. But remember, your submission had best not closely
resemble any of them in such a way that it would indicate direct
copying.
References:
You
may
find the following references helpful (in addition to the links
from previous labs):
Learning
Bitcoin from the Command Line
The Bitcoinwiki
Page on Transactions
The Bitcoinwiki
Page on Raw Transactions
The Bitcoinwiki Page
on Blocks
Submitting:
Use the folder named "lab5" in your
Subversion repository. See the syllabus for more info about
submission using Subversion. Upload your Lab 5 code and any
supporting materials to the repo. Please include a README text
file to explain what parts of the work you are submitting, where
the different parts of the work are located and please provide a
little info on how to compile and run your code.