Lab 5 Details for MPCS 56605

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.

Lab 5   Due: 4:00 pm, Monday, July 24, 2023

Problem 1:  Smart Contracts and Testing: 

BACKGROUND:

Like all programming problems, learning a new technology is not an exercise in reading but rather an exercise in thinking and typing.  This lab is designed to give you more hands-on experience in some fundamental skills involved in smart contract development and testing.  In this lab, you will create from scratch a smart contract using Visual Studio Code with solidity with truffle and ganache to run a basic math smart contract (add, subtract, multiply and divide).  You will write tests to confirm that your math functions are executing properly.  You will then deploy your smart contract on Ganache and run the tests to confirm correct execution.  As we mentioned in the previous lab, this lab will assume you are conversant with the types of instructions in the previous lab for the creation, development and deployment of smart contracts onto Ganache, so our instructions in this lab will be less "hand-holding" and more directly efficient.  See the References section at the bottom of this lab for resources and help with Problem 1.

WHAT YOU NEED TO DO:

STEP 1:

At the command line, let's create a new directory (you can of course choose where you want to store your source code) and cd into it:

$ mkdir -p ~/56605/src/LABS/Lab.5/MPCSTesting

$ cd ~/56605/src/LABS/Lab.5/MPCSTesting

STEP 2:

Now we want to run "truffle init" (you installed truffle in Lab 1 and played around with it in Lab 4) in our new MPCSTesting directory:

$ truffle init

After running init, see what new files have appeared in your directory:

$ find .
.
./migrations
./migrations/1_initial_migration.js
./test
./test/.gitkeep
./contracts
./contracts/Migrations.sol
./truffle-config.js

Sweet! as they say.  You will once again be modifying truffle-config.js (changing the compiler and network port--see STEP 8 of Lab 4 if you've forgotten) and will concentrate on the the new migrations and contracts in the remainder of this section of the lab.

STEP 3:

Add the starter file SimpleMath.sol to your contracts directory, and add the starter file 2_contracts_migration.js to your migrations directory.  The SimpleMath.sol file contains starter code for a simple calculator (it only adds at the moment...you'll soon fix that).  The 2_contracts_migration.js file provides the migration instructions for the SimpleMath contract.

STEP 4:

To start testing, let's use truffle to get us started.  In your MPCSTesting directory, use truffle to create a test:

$ truffle test SimpleMath

Notice that after running, you've got a new javascript test in your workspace under test:

Right out the gate, we can run our brand new base test.  In VS Code's terminal window (you should be in the MPCSTesting directory), run the command:

$ truffle test
Using network 'development'.


Compiling your contracts...
===========================
> Compiling ./contracts/SimpleMath.sol
> Compilation warnings encountered:

    project:/contracts/SimpleMath.sol:17:5: Warning: Function state mutability can be restricted to pure
    function add(uint _i1, uint _i2) public view returns (uint sum)  {
    ^ (Relevant source part starts here and spans across multiple lines).

> Artifacts written to /var/folders/mt/2wzh5nb144g44l496xrdkf3r0000gn/T/test--3221-Z3iDK5SBpqhu
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang


  Contract: SimpleMath
    should assert true


  1 passing (60ms)


What you are looking for is that very happy "1 passing" summary in green.  Green is good.  Red is bad. 

Now, let's add a new test (add this code to the simple_math.js file):

contract("SimpleMath add", () => {
  describe("add(2,2)", () => {
  it("the sum should be correct", async () => {
      // Try to add 2 + 2 and make sure it equals 4
      const mathtest = await SimpleMath.deployed();
      const expected = 4;
      const result = await mathtest.add(2,2);
      assert.equal(result, expected, "add method should return 4");
    });
  });


Now, let's run the tests again:

$ truffle test
Using network 'development'.


Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


  Contract: SimpleMath
    ✔ should assert true

  Contract: SimpleMath add
    add(2,2)
      the sum should be correct


  2 passing (96ms)

Everything looks good.  Now, let's break our test.  In simple_math.js file, change the line that reads:

const expected = 4;

to read:

const expected = 0;

Now of course we know that 2 + 2 != 0.  So our test should fail.  Save the file, and rerun the tests (we don't need to redeploy our contracts because only the javascript test has changed, not our contracts):

$ truffle test
Using network 'development'.

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.

  Contract: SimpleMath
    ✔ should assert true

  Contract: SimpleMath add
    add(2,2)
      1) the sum should be correct
    > No events were emitted

  1 passing (101ms)
  1 failing

  1) Contract: SimpleMath add
       add(2,2)
         the sum should be correct:
     AssertionError: add method should return 4: expected <BN: 4> to equal 0
      at Context.<anonymous> (test/simple_math.js:22:14)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)

This looks very good.  We see red, which is what we'd expect, because 2 +2 == 4 and not 0.  Let's change that const expected value back to 4 and rerun the tests:

$ truffle test
Using network 'development'.

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.

  Contract: SimpleMath
    should assert true

  Contract: SimpleMath add
    add(2,2)
      the sum should be correct

  2 passing (86ms)

Oh Happy Day!  We see green again.

STEP 5:

Now, we need to create a new test to test for a boundary situation.  Add the following code to your test (at the bottom of the file):

contract("SimpleMath add", () => {
  describe("add(UINT_MAX,1)", () => {
    it("the sum should never overflow UNIT256", async () => {
      try {
        // Try to add 2 + 2 and make sure it equals 4
        const mathtest = await SimpleMath.deployed();
        //const expected = 4;
        const result = await mathtest.add(UINT_MAX, 1);
        assert.ok(false, 'Threw an exception instead of overflowing');
      } catch( ohoh ) {
        assert.ok(true, "Caught the exception")
      }
    })
  })
});


Now, save the test file and rerun the tests:

$ truffle test
Using network 'development'.


Compiling your contracts...
===========================
> Compiling ./contracts/SimpleMath.sol
> Artifacts written to /var/folders/mt/2wzh5nb144g44l496xrdkf3r0000gn/T/test--9352-tpvYPNZtMlZi
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang

  Contract: SimpleMath
    should assert true

  Contract: SimpleMath add
    add(2,2)
      the sum should be correct

  Contract: SimpleMath add
    add(INT_MAX,1)
      the sum should never overflow UNIT256

  3 passing (124ms)

Well, that should get you started.

STEP 6:

Now, for you to do a little more work.  Your first job is to add to the SimpleMath contract additional new functions for subtraction, multiplication, and division.  You are also to add numerous new tests to hammer add(), subtract(), multiply() and divide().

Your tests should test for the following error conditions:

1.  Overflows (numeric exceptions)
2.  Underflows (numeric exceptions)
3.  Valid return values (like 2 + 2 == 4 and nothing else, etc.)
4.  Boundary conditions (see the require(sum >= _i1); line in SimpleMath.sol)


Problem 2:  Cryptocurrency and Mining: 

BACKGROUND:

Like all programming problems, learning a new technology is not an exercise in reading but rather an exercise in thinking and typing.  This lab is designed to give you more hands-on experience in some fundamental skills involved in mining cryptocurrencies.  You will generally find the References section below helpful in addition to the required and recommended reading.  You should be especially aware of Antonopoulos's chapter 10 on Mining and Consensus.

In this lab, you will add a cryptocurrency and mining to your blockchain.  You will be building on your code from Lab 5.

You may write the solutions in this Problem 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.

WHAT YOU NEED TO DO:

STEP 1:

You may have noticed that in the last lab, the blockchain magically got created by just adding new transactions.  We are going to modify that in this lab, to make it a tad bit more realistic.

First, you will need to think up a name for your new cryptocurrency you will be mining on your blockchain.  You can't call it bitcoin or ether or any other existent cryptocurrency.  Barring that, there are no rules.  You could call it "Barbaracoin" or "Yapstone" or "Foolsgold" or "Capnjack" or whatever you'd like.  You will create a Miner class (see below).  Your Miner will take newly-created transactions and collect transactions into blocks.  Each new block will include a "coinbase" transaction that creates "Barbaracoins" (or whatever).  The naming of your cryptocurrency is entirely up to you.  Have fun.

Your cryptocurrency should be denominated in fractional form (similar to satoshis in bitcoin), and we will keep it simple:  you will need to denominate your cryptocurrency in 1/1000s (milli-coins).  So, as an example, 1 "Barbarinsky" is 10-3, or 0.001, "Barbaracoins".  You get the idea.  You will use the fractional form when designating the Value of an Output (see below). 

You are to create a new class/structure called TxnMemoryPool, which can of any type you wish, but a simple list of Transaction objects/structures will do (order is unimportant), and this will store your transactions in memory during processing.  Note you will no longer be automatically adding transactions to blocks on creation of the transactions.  Rather, you will add them to the TxnMemoryPool on creation.  This will simulate receiving them from the network. 

If you plan to use multiple threads, you should set up a method or function that creates a new unique transaction every 1-10 seconds (if using threads, you can make this decision as you progress through your testing) and adds each new transaction to the TxnMemoryPool.  If you plan not to use multiple threads, you may simply pre-create 91 new transactions and add them to your TxnMemoryPool before beginning mining, which may prove easier.  You should modify your blockchain code code there is a new MAX_TXNS field, which is the maximum number of transactions per block.  You should set this to 10 (including the coinbase transaction).  So 9 transactions + 1 coinbase transaction = 10 Max.

If you're wondering what in the world will go in your inputs and outputs, you might remember that even a SHA-256 hash of a single character, such as 'a', will always result in a 256-bit, 32-byte hash, every time, ad infinitum.  This means that you could simply stuff a hash of the current timestamp+some_randomly_generated_number into the inputs, and no one will be the wiser.  Again, we are not concerning ourselves at this point with "connecting-up" the outputs to the inputs.  Now, speaking of outputs, it's time now to create a more formal definition of an output:  an Output class/structure.  Let's make our new Output look like this:

Note that it is up to you to determine the best "decimal" format for your particular language.  That may be a Decimal object (serialized), or an int (knowing that any Value is denominated in 1/1000s of your currency), etc.  That's your call.  So if you placed a "1500" in your Value, that would mean 1.5 "Barbaracoins" (or "CapnJacks", etc.).  At this point, you can put anything you want in the string Script.  See above conversation on inputs.

STEP 2:

You will create a new Miner class/function, that will go through the TxnMemoryPool (which will eventually be growing at a steady rate), and your Miner will attempt to create a block whose Blockhash is less than the target you will set.  In this lab, our target will be calculated as:

Target = coefficient * 2(0x8 * (exponent – 0x3))

Your Header.Bits (for all blocks) will default to
0x207fffff, with is the difficulty bits for Regtest.  This means that your coefficient will be '0x7fffff' and your exponent will be '0x20'.  Note that this is just a starting default.  It's designed to make mining a slight challenge but nothing you're going to spend eternity waiting on (on average...your mileage may vary...).  Feel free to adjust your bits in order to play around with different levels of difficulty if you get bored.  In our case for this lab, you will not need to worry about automatically adjusting the mining difficulty.  For example, for a little more challenge, you could try the difficulty bits value used on Testnet:  0x1d00ffff.  When you are done experimenting, you will want to reset your Header.Bits to the default of 0x207fffff for final submission.

As you build your candidate blocks, keep in mind you will need a coinbase transaction as the first transaction in each of the blocks.  This coinbase transaction will create an amount of your cryptocurrency that is also up to you.  You could follow the bitcoin model and start out with 50 bitcoins, or you could be more or less generous.  That's entirely up to you.

Hopefully you adequately encapsulated the creation of the genesis block in your blockchain.

Beyond this, nothing much changes from Lab 5.  And as usual, unless specified, everything else is up to you.

STEP 3:

You are to write a test case (can be a simple main function or an actual test harness from a framework) in which you run your new Blockchain mining.  You will create a new Blockchain and by doing so you will create your genesis block.  After mining the transactions in the TxnMemoryPool, print out the block height of the tip of the chain.

Submit all code and related files (if any) as specified below.

Finally, and importantly, you are of course free, and encouraged, to look at the actual bitcoin source code for mining.  But remember, your submission had best not closely resemble any of that source in such a way that it would indicate direct copying.

References:

Problem 1:

You may find the following references helpful (in addition to the links from previous labs):

Truffle Suite javascript testing
Testing contracts using Truffle
Mocha testing introduction
Writing tests in Solidity
Use Truffle Develop and the Console

Problem 2:

You may find the following references helpful (in addition to the links from previous labs):

The Bitcoinwiki Article on Target
The Bitcoinwiki on Difficulty
Bit-Ish Data Article on Building a Blockchain:  Difficulty Explained
freeCodeCamp
Article on Mining
The Bitcoinwiki Page on Block Hashing Algorithm
The Bitcoinwiki Page on Transactions
The Bitcoinwiki Page on Raw Transactions
The Bitcoinwiki Page on Blocks
Sample program that mines
Bitcoin Developer Reference on Target
Stack Exchange conversation on mining

Submitting:

Each assignment will have an invitation to create a Github repository. You will use the lab[1-7]-YOUR_GITHUB_USERID to submit your homework.