Go up to the CCC HW page (md) | view one-page version
This homework will take you through the process of compiling, deploying, and running a decentralized application (dApp) on our private Ethereum blockchain. This assignment does not focus on the programming aspects of Solidity – that’s in a future assignment, as well as the lectures.
You will have to have completed the connecting to the private Ethereum blockchain (md) assignment. You should have a few (fake) ETH from the faucet. For some of the tasks below you will need to launch your geth node, connecting to the course server, and start up a geth Javascript terminal; how to do all that is all described in the connecting to the private Ethereum blockchain (md) assignment. If you have not successfully completed that assignment then you will not be able to complete this assignment.
Warning to Mac OS X users: there is one part in this assignment that Safari seems to have issues with. This part is indicated when you get to it, and you may have to switch to a different browser (Firefox or Chrome) to complete that part.
Giving credit where credit is due: The particular smart contract being used here was inspired by the one in this github repo by Dapp University (disclaimer: they are not an actual accredited university; but they do have great online tutorials).
In addition to your source code, you will submit an edited version of dappintro.py (src).
Any changes to this page will be put here for easy reference. Typo fixes and minor clarifications are not listed here. So far there aren’t any significant changes to report.
To deploy and run a smart contract, you need to be able to the standard development tasks – editing, compilation, testing, and deployment. The third one – testing – is tricky, as you have to be running in an environment that simulates a blockchain and (fake) accounts with (fake) ETH. Once it’s compiled, you have to then be able to load it onto the blockchain, whether that blockchain is simulated (for testing) or real (for deployment).
For the development tasks, we are going to use Remix, which is an IDE designed specifically for Solidity smart contracts on an Ethereum blockchain. You can use it online at remix.ethereum.org, or you can download the latest version on your computer via remix’s github repo. Each method has it’s pros and cons.
We recommend to download and install the desktop version, despite the occasional issues, but the choice is yours. If you do try the desktop version, and it is not working well, you can always switch to the online version. The directions herein will apply to both options, as the user interface is the same. Remix’s source code is available on github, and it is released under the MIT license; some of the Remix icons are included herein.
Remix allows you to develop, compile, and test your code on a fake blockchain it simulates with fake accounts. It cannot, all by itself, deploy to a blockchain. For that, we are going to use geth. We will connect Remix to geth for our deployment, and geth will be the conduit to deploy to the blockchain. More on this later in the assignment.
There are many different tool chains that one can use to compile and deploy smart contracts – Truffle and Ganache, Hardhat / Foundry, command-line compilation with solc and deployment with geth, etc. We had to pick one, and Remix seemed the most straight-forward and realistic choice. It also is the choice that works best across all the platforms on the computers for the students in this course. We will see how to interact with the blockchain through the geth Javascript console in an in-class activity in the Solidity lecture slide set.
The same process described herein can be used to deploy on the real Ethereum blockchain. The only difference is that you would run geth to connect to the real Ethereum blockchain, rather than our private course blockchain. And of course you would need real ether to pay for the gas fees. Everything else is exactly the same.
For this assignment we will be providing the Solidity code to use: the interface IPoll.sol (src) and a smart contract that implements that interface: Poll.sol (src). The code will allow voting for something via the blockchain – an election, your favorite color, or anything else. Election dApps are fairly common as first examples of Solidity programs. Note that while you should be able to gain a rough idea of what is going on in the code, the tasks herein are not to necessarily understand the code, but to be able to compile and deploy it. Understanding the code, and writing your own, is in the next assignment and upcoming course lectures.
The IPoll interface, and the implementing Poll contract, allows for only a single election per deployed contract. This is inefficient – a better implementation would be to allow a single contract to host many polls. However, to keep this first example simple, the contract presented only allows one poll per contract.
While we provide the necessary code, you will need to make two small modifications. You are going to start an election on something other than the default (which is one’s favorite color). Pick something interesting to host a poll for. Edit the Poll source code to add your own choices to your Poll contract. In particular, you should ONLY change two things: the addChoice()
calls in the constructor (you can add more or remove some, as needed) and the value of the purpose
string. It is important that you do not change any other code in the contract, else it will not work properly when we are testing and grading it! Please choose something that is not controversial – there are many great ways to fight for, and to voice opinions for, things that you believe in and that others may find controversial. Our private Ethereum blockchain for this course is not one of them.
In addition to your Poll.sol source file, you will have to submit the dappintro.py (src) file. This file will contain the various transaction hashes and account information that you will be generating as you work through this assignment.
There are a few very important hints that will make your life SO MUCH easier if you follow them throughout the semester.
Directories: Keep all your Solidity code, for all your assignments in this course, in the same directory. Much of the code will be re-used between assignments. There will never be two different files that have the same name but different content. Some of the later assignments will have a dozen or so files that are included (imported). And many assignments will use the same set of imported files. And many assignments will import the same (large) set of files. Having everything in the same directory will make it much easier to manage.
Desktop Remix: Desktop Remix likes to scan your directory structure so that it knows where the .sol files are. But this can take a looooooong time if the file explorer pane is opened up to your root directory. Instead, do a File -> Open Directory, and open up the directory created just above. This will make Remix much faster in all aspects. You will see how to do this in the next few steps, but we wanted to include this hint here as well.
Desktop Remix, again: Sometimes the desktop version of Remix has issues. If issues happen, try to solve it, but be willing to switch to the web browser version if this occurs. So far we have found solutions to all the issues that have come up, and a few tips for how to work well with Remix will be discussed in lecture.
Desktop Remix, yet again: As the Remix installation is not signed, the relevant operating systems (notably Windows and Mac OS X) will not want to run it after it is installed. In Mac, you can change this in the Privacy & Security settings. Windows should allow you to run it after clicking through a number of dialogs. If this all makes you uncomfortable, you are always welcome to use the online version.
Web Remix: The web version of Remix also has issues – in particular, it saves your code on remote servers, and is tied to a cookie in your web browser. If you lose the computer, reset your cookies, or are using a different machine, then you will not be able to access your files. This means you will have to cut-and-paste the code to a locally saved file to ensure you can access it elsewhere.
Geth node: You will have to start a local geth node to deploy your contracts. You did this in the private Ethereum Blockchain (md) assignment. There are extra options that we will be using, but those options are already in the geth-config.toml file that you configured in the last assignment (md).
Remix is an IDE for developing Ethereum smart contracts in Solidity. Remix provides an easy way to read compiler error messages and makes it really easy to test your smart contract as you are developing it. You can either use the online editor at remix.ethereum.org or you can install it locally via the Remix download page. The web interface on remix.ethereum.org is designed to look just like the IDE, and you are welcome to use either – the directions herein apply the same to both, as they have the same user interface. However, if you do use the web interface, make sure you save your text file back to your computer.
purpose
string appropriately), and also modify the addChoice()
calls in the constructor (you can add or remove them as needed). You should not make any other changes to the Poll.sol code.view
or pure
functions – they do not require writing a transaction to the blockchainview
and pure
functions; if it’s a regular transaction, you have to look at the decoded output section described abovevoid
return type), but there is now a “transaction hash” field.voted
mapping on line 32), and then ensuring that the current voter has not already voted (the first line of the vote()
method via a require()
call). If a require()
call fails, then the state of everything is reverted back to what it was before the transaction occurs (although you still lose your gas fees).JUMP
commands and similar), and is a lot more complex.Testing a blockchain application is very counter-intuitive. There are no print statements and no viable debuggers. We can deploy it and then try it out, but that’s not a great way to test.
You should ensure you are familiar with the Testing and Debugging section of the Solidity slide set.
This task will show you how to develop unit tests for your Solidity application. To set this up:
~/tests/
. You will need to find where it is on your OS via a file search.checkFailure()
function, change Assert.notEqual()
to Assert.equal()
, and re-run the tests. They should all pass now.function checkChioceCreation() public {
Poll p = new Poll();
p.addChoice("test1");
Assert.equal(uint(p.num_choices()),uint(7),"Choice not added");
}
checkSenderAndValue()
function. These comments specify the particular account that is passed in, and how much ether (actually wei) that is passed in as well. You can see a full definition of these types of comments here.You do not need to submit the Poll_test.sol file. The purpose of this section was to show you how to start writing unit tests. You will need this when you start developing Solidity applications in the next assignment.
The Poll_test.sol file that was auto-generated from the default Poll.sol file is as follows. You do not need to read through this code; it’s only here as a reference.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
// This import is automatically injected by Remix
import "remix_tests.sol";
// This import is required to use custom transaction context
// Although it may fail compilation in 'Solidity Compiler' plugin
// But it will work fine in 'Solidity Unit Testing' plugin
import "remix_accounts.sol";
import "../Dropbox/git/ccc/hws/dappintro/Poll.sol";
// File name has to end with '_test.sol', this file can contain more than one testSuite contracts
contract testSuite {
/// 'beforeAll' runs before all other tests
/// More special functions are: 'beforeEach', 'beforeAll', 'afterEach' & 'afterAll'
function beforeAll() public {
// <instantiate contract>
Assert.equal(uint(1), uint(1), "1 should be equal to 1");
}
function checkSuccess() public {
// Use 'Assert' methods: https://remix-ide.readthedocs.io/en/latest/assert_library.html
Assert.ok(2 == 2, 'should be true');
Assert.greaterThan(uint(2), uint(1), "2 should be greater than to 1");
Assert.lesserThan(uint(2), uint(3), "2 should be lesser than to 3");
}
function checkSuccess2() public pure returns (bool) {
// Use the return value (true or false) to test the contract
return true;
}
function checkFailure() public {
Assert.notEqual(uint(1), uint(1), "1 should not be equal to 1");
}
/// Custom Transaction Context: https://remix-ide.readthedocs.io/en/latest/unittesting.html#customization
/// #sender: account-1
/// #value: 100
function checkSenderAndValue() public payable {
// account index varies 0-9, value is in wei
Assert.equal(msg.sender, TestsAccounts.getAccount(1), "Invalid sender");
Assert.equal(msg.value, 100, "Invalid value");
}
}
There are many versions of the Ethereum Virtual Machine (EVM) – the part of the Ethereum node that runs the opcodes when executing a smart contract. As new updates to Ethereum come out, they release updated EVM versions. All EVM versions are named after cities (London, Paris, Shanghai, etc.), and there are over a dozen EVM versions so far.
We are specifically using the London version of the EVM for the course blockchain. The default is Shanghai, which is newer. The Shanghai version is a super-set of the London version – which means any London EVM program will work just fine in Shanghai. However, a program targeted for the Shanghai EVM will not work on a London EVM. You will have to make a few changes in Remix to ensure that you are targeting the London version rather than the Shanghai version.
To target the London EVM, on the compilation pane, click on the “Advanced Configurations” drop-down, then on the “EVM version” drop-down, then select “london” (“shanghai” or “default” will likely be selected). You have to re-compile it after you make this change. You can see this in the image to the right, which shows only the relevant part of the Compilation pane.
This doesn’t matter when targeting the Javascript blockchain emulator – which is why you left it as “Remix VM (Shanghai)” above. As the Shanghai is a super-set of London (mostly), you can compile it under either, and it will run just fine on the “Remix VM (Shanghai)” environment that you used, above.
The difference matters on the course blockchain – that is only set to London, and a program compiled for the Shanghai EVM will NOT work. Fortunately, Remix will let you know if you try to deploy a Shanghai EVM targeted smart contract on a London blockchain (like our course blockchain) – Remix will complain that the PUSH0
opcode will fail (that opcode is new to Shanghai, but not in London).
Why not use the latest version? Because the latest version (Shanghai) requires a lot of additional configuration, as it uses something called the Beacon Chain, which is a second blockchain. The London version does not use this, so the configuration on our end is much easier. If we were to use Shanghai, we would have to set up another program, similar to geth, to sync another blockchain that geth would then interact with. The functionality for running smart contracts is the exact same – there is no difference in the code it can compile.
At this point we can edit, compile, and test our program on Remix. We have also made changes to the addChoice()
calls in the Poll.sol constructor, as well as to the purpose
string. Now we are going to use Remix to deploy to our private Ethereum blockchain.
We need to start geth, as we did in the connecting to the private Ethereum blockchain assignment.
Once that command is run to start the local node, you will see a line that says, “HTTP server started”, which is what the various options in the geth-config.toml file did. Note that these particular options will only allow the Remix that we are using – either as a stand-alone IDE or through the browser – on the same machine to connect. So you can’t run geth on another host (VirtualBox, Amazon AWS, etc.) and Remix on your host machine, for example.
Now that geth is started, we have to attach to it IN A SEPARATE WINDOW via geth attach /path/to/ethprivate/geth.ipc
(or, in Windows, either geth attach ipc:\\\\.\\pipe\\geth.ipc
or geth attach \\.\pipe\geth.ipc
). Wait for it to finish syncing (check eth.syncing
). Then eth.blockNumber
should match the highest block number on our Ethereum blockchain explorer.
Just to check: at this point, you should have TWO geth processes running in separate windows. The first is the full node with the five or six additional flags as above. The second is a geth terminal via geth attach
.
You should have Poll.sol loaded into Remix, and you should have made the modifications to the addChoice()
calls in the constructor and the value of the purpose
string. You should have compiled it WITHOUT optimizations.
Read these instructions through before starting them!
http://127.0.0.1:8545
.
--http.corsdomain
command-line parameter. See a screen shot of that value here. We are going to put it into our geth-config.toml
file as the second value in the list for the HTTPCors
key (keep that first value in that list!). You will need to restart the geth node once you have made that config file edit (and possibly re-attach the geth Javascript terminal).eth.coinbase
one selectedpersonal.unlockAccount()
command. You can run it as personal.unlockAccount(eth.coinbase,"password",0)
– filling in your own password – to unlock it until the end of the session. It should report back true
.web3.fromWei(eth.getBalance(eth.coinbase), "ether")
. You can also see your balance in Remix – in the Deployment pane, when selecting the account, it will state the balance next to the account number.web3.fromWei(eth.getBalance(eth.coinbase), "ether")
. You will see that your gas fees were deducted.
[block:12345 txIndex:0] from: 0x123...bcdef to: Poll.(constructor) value: 0 wei data: 0x608...57221 logs: 0 hash: 0x123...bcdef
num_choices()
, choices()
, voted()
, and unnecessaryFunction()
.
view
and pure
methods do not require writing to the blockchain, so they will report back the answer immediately – and without having the call mined into a block. Other transactions require the method call to be sent as a transaction to the blockchain and then mined into a block before reporting the success (or failure) of the method call.interfacesImplemented
entry). We’ll discuss the IERC165 interface later in the course. It does this by checking the result of calling supportsInterface()
, which we provided the code for in Poll.solinput
field lists the size of the contract – about 5.5 Kb. If we had optimized it during compilation, it would be about 3 Kb.functionCall
and inputDecode
.
functionCall
fieldinputDecode
fieldreturnValue
field, which is not present in this example
view
and pure
functions). If this is the case, you can view the transaction in the explorer.We wanted to show you that you can create a web page to interact with a smart contract on the blockchain. The code of the poll viewing web page uses the web3 Javascript library, which is what allows you to connect to the blockchain from Javascript. In our case, we use it to connect to a node running geth that is connected to our private course blockchain. The URL for this web page is on the Canvas landing page – once there, enter your smart contract’s contract address (with the leading 0x
) for your deployed smart contract, and it will display the choices.
You are not expected to understand any of the code on that web page! This will be gone over in future assignments, and you will be writing multiple web pages toward the end of the semester to interact with the blockchain. But not now.
On the course blockchain explorer, you can find other contract addresses – look at the transactions page, and see which ones have a value listed in the ‘contract address’ column. You can also view just the contract accounts as well. You can click on a contract address to see which interfaces it implements – if it implements the IPoll interface (which it does via the supportsInterface()
function), then you can copy that address and use it in the poll viewer web page. This allows you to see what choices your classmates selected. You are welcome to vote on their polls, but that is not necessary (see the next section for how to do this). Note that you won’t know who deployed that particular smart contract. Also note that this web page will only work with the version of the Poll code used in this assignment. Specifically, it will only work with a smart contract that has the same ABI that IPoll.sol generates; you can see that ABI in the Javascript source code of the poll viewer web page.
How this all works is beyond the scope of this assignment, but will be something we will be going over later in the semester. Feel free to look over the Javascript code in that web page – the only other requirement is that a local geth node has to be running on the server with some additional configuration paramters in geth-config.toml to allow the web page to connect to it (we have not seen those flags yet). One can also have a web page initiate a transaction onto the blockchain, such as casting a vote – we will see that in a future assignment as well; that requires a browser plugin, such as MetaMask, that allows for posting of transactions to a web page using a specific Ethereum account.
I have loaded a Poll smart contract onto our private Ethereum blockchain, and you all must vote! The only information we will tell you is that the contract address for this is on the Canvas landing page, and that it fulfills the IPoll.sol (src) interface. You have to figure out what the options are, and then vote for one. This one poll cannot be viewed through the poll web page viewer. You will need to submit the transaction hash where you voted.
In Remix, you can call a different contract with the same codebase. In particular, it has to have the same ABI. For this, you can (and should) use the IPoll.sol file. Specifically, you should NOT use Poll.sol, as you do not know if additional functions (such as unnecessaryFunction()
) are in the deployed contract; only that it implements the functions in IPoll.sol. On the Canvas landing page is the address of a deployed Poll contract – copy that address.
In Remix, in the Deployment pane, switch to IPoll. Switch to the compilation pane, and click “Compile IPoll.sol”. Then switch to the deployment pane. At the bottom, and above the “Deployed contracts” list is a blue “At Address” button – copy the contract address there, and click that button. This now gives us a connection to a different IPoll implementing contract. Use this to vote. You have to vote on the course poll. You are welcome to vote (or not) on your fellow classmates polls; how to find their contract addresses is described above.
Note that Remix may complain if an Ethernet address is not checksummed. This is a warning, not an error, and it should still work fine. (Although it will become an error when such an address is in code being compiled.) But you still have to remove the warning, otherwise the compilation when you submit code containing non-checksummed addresses it will appear to fail when you submit your code to Gradescope. Remix will provide, in the warning, the checksummed address – you are welcome to use that value (cut-and-paste it into your code) instead to silence this warning. You can also use ethsum.netlify.app to checksum an Ethernet address.
The assumption is that the account you will vote with is your eth.coinbase
account. It’s fine if you want to use a different account address than you used in the last assignment, but when you submit your information at the end of this assignment, be sure to submit the account that you used for the deployment and voting herein. As your account information will be in the voted
mapping, we will be able to determine who has voted and who has not. You get credit for this part as along as you vote on the course smart contract; it does not matter what choice you vote for.
Please turn off your geth node when you are done with this assignment. You can always turn it back on again when needed.
You will need to fill in the various values from this assignment into the dappintro.py (src) file. That file clearly indicates all the values that need to be filled in. That file, along with your Solidity source code (only Poll.sol), are the only files that must be submitted. The sanity_checks
dictionary is intended to be a checklist to ensure that you perform the various other aspects to ensure this assignment is fully submitted.
There are three forms of submission for this assignment; you must do all three. Other than the Gradescope submission, they are all listed in the sanity_checks
dictionary.
Submission 1: You must deploy your Poll smart contract to our private Ethereum blockchain. It’s totally fine if you deploy it a few times to test it – just submit the information about the most recent submission. The contract address of this deployment are entered into the dappintro.py
file that you submit.
Submission 2: You must vote on both your Poll contract and also on the course-wide Poll contract. The transaction hashes for these two transactions are entered into the dappintro.py
file.
Submission 3: You should submit your Poll.sol
file and your completed dappintro.py
file, and ONLY those two files, to Gradescope (don’t submit IPoll.sol
). All your Solidity code should be in the first file, and you should specifically import the IPoll.sol
interface. The IPoll.sol
file will be placed in the same directory on Gradescope when you submit so that it can compile. NOTE: Gradescope cannot fully test this assignment, as it does not have access to the private blockchain. So it can only do a few sanity tests (correct files submitted, successful compilation, valid values in dappintro.py, etc.).