Lab 4 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 4
Due: 5:00 pm, Thursday, July 19,
2018
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.manu.backend.hamburg/faucet
Prove you're not a robot and in the prompt area, paste your bitcoin
address you created in STEP X. Then click on the "Send me some
bitcoins" button.
Note the "Sent! TX ID: [some transaction id]" output in green.
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).
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 signrawtransaction 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 3 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 "lab4" in your Subversion repository. See the syllabus
for more info about submission using Subversion.
Upload your Lab 4 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.