---
# System prepended metadata

title: CS 251 - 2020 Practice Exam

---

# CS 251 - 2020 Practice Exam

See the link to the exam [here](https://cs251.stanford.edu/hw/final2020.pdf).

## Problem 1
(a.) An Ethereum re-entrancy attack occurs when a smart contract transfer an asset -- whether it be ETH, ERC-20, ERC-721, etc. -- to another contract. If this contract does not make the proper `require` checks at a certain location around the actual transfer, an adversarial contract can implement a `fallback` or `ERCReceived` function in order to repeatedly call the function and drain the main function of ETH, NFTs, etc. 

Summary [here](https://solidity-by-example.org/hacks/re-entrancy/): re-entrancy allows a contract to call back into another contract before they are finished executing.

(b.) Pertinent slide is slide 34 [here](https://cs251.stanford.edu/lectures/lecture3.pdf). My initial hunch here would be no: you might be able to rederive the public keys with the information here, but you can't rederive the secret keys, which are equal to $sk_i = k_1 + HMAC(k_2, i)$ for all $i = 1, 2, ...$. 

(c.) I don't like any of the answers given in the doc. My initial hunch would be that if you were only checking if all the inputs were positive, this would represent some sort of deposit/transfer, indicating you have these funds. However, a negative output could mean you are removing money from someone, not sending them money. So if only the inputs had to positive, and the sum of the outputs has to be equal to the sum of the inputs, then couldn't you have two inputs equal to two outputs, but one output be very positive (i.e. a transfer) and another output be negative (i.e. losing money) as an attack?

(d.) We did not learn about Zcash in this class, so I would refer to the Final Exam [collab](https://docs.google.com/document/d/1O506czTwpKeZHw6W-7vIBpYWBEiVc4g5iQDzM1uFZs0/edit#).

(e.) On this question, my first thought process was that for UTXOs that are about to expire, transaction fees would be incredibly high since there would be high demand to spend them. I also like the alternative answer in the [collab](https://docs.google.com/document/d/1O506czTwpKeZHw6W-7vIBpYWBEiVc4g5iQDzM1uFZs0/edit#): there's potential that there will be more txs since you can't just hold your bitcoin: it has to be used in a transaction.

(f.) Off-chain collateral systems, like USDC and USDT, work by sending your crypto to a company/regulated custodian, and then they mint the amount of the stablecoin on the blockchain. On the contrary, on-chain collateral systems work be locking up your crypto in a vault, typically overcollateralized, and then unlocking said stablecoin in return. You have to pay interest, and your position can also get liquidated. Due to the public nature of the blockchain and smart contracts, only the on-chain collateral verifies that the collateral is properly managed and maintained [here](https://docs.google.com/document/d/1O506czTwpKeZHw6W-7vIBpYWBEiVc4g5iQDzM1uFZs0/edit#).

## Problem 2

(a.) Similar to one of the problems on 2021 exam -- you want to wait for the blocks to confirmed. Note that the confirmation rule in Nakamoto Consensus is that each miner confirms the block (along with its prefix) that is $k$-deep within the longest chain in its view. Thus, the merchant should wait until the block is confirmed. There could also be a fork.

(b.) Note that in Nakamoto Consensus, at any given time, each honest miner attempts to extend the heaviest chain, or that with the highest difficulty. Thus, longest chain will not matter.

## Problem 3

(a.) Note that the functionality lies in the code `uint256 maxAmount = (totalSupply - this.balance + (1 ether))`. The key is that the producer can only withdraw 1 more ether than has ever been withdrawn. At the first month, we know that we have withdrawn none, so we can get 1. Then, we see that after the second month, we've only withdrawn 1, so we can withdraw 2. After the third month, we've withdrawn 3 so far, so we can withdraw 4. Finally, in the past, we've withdrawn 4+2+1 = 7, so we can withdraw 8.

(b.) Recall that an unsigned int works such that a negative value is an arbitrarily large positive value. Thus, imagine if film director was able to send over funds to the address of the contract before initializing the contract. This would make `this.balance > 0`. Then, when they initialize `MovieToken`, they can set `totalSupply = 0` by not supplying ETH to the contract. Then, when calculating `maxAmount`, we know that `totalSupply - this.balance` would result in a negative number, leading to a high positive number. They can then call `withdraw` with any `amount` value less than to redeem all the funds.

(c.) Same as above, but now, we just self-destruct a contract that pushes ETH into the `MovieToken` contract after `totalSupply` has been initialized. This will cause the same underflow bug.

(d.) The answer from the collab would be to keep a global `totalWithdrawals` variable that would determine how much you could withdraw. You could also just update `totalSupply` continually any time you receive ETH (i.e. `onETHRecived`, `fallback`, etc.)

# Problem 4

(b.) Optimistic rollups use fraud proofs to prevent against a fraudulent rollup coordinator: the coordinator submits an update to the blockchain without proof. Within 7 days, if a user can prove (by showing a divergence in the Merkle tree) the coordinator submitted fraudulently, the update is cancelled and the coordinator's stake is slashed. If the user submitted an incorrect proof, the user pays a penalty.

(c.) Only thing ever mentioned - Dapps live on different chains, so hard to interoperate/compose between different Dapps now

# Problem 5

(a.) The vulnerability occurs when Alice tries to register a domain name `alice.eth` using a transaction calling the NameCoin contract. Bob sees the transaction posted to the chain, albeit not confirmed, and immediately posts his own transaction registering `alice.eth` but attaching a higher `maxPriorityFee` (EIP1559 tip) such that his transaction would be considered before Alice's in the mempool. This would allow Bob to register `alice.eth` even though he called the NameCoin contract after Alice did.

(b.)

```solidity
contract NameCoin {
    struct NameEntry {
        address owner;
        bytes32 value;
    }
    
    mapping (bytes32 => nameEntry) data;
    mapping (bytes32 => bytes32) commitments;
    
    function NameNewBegin(bytes32 commitment) {
        if (msg.value >= 100 && commitments[msg.sender] == 0) {
            commitments[msg.sender] = commitment;
            emit Register(msg.sender, name);
        }
    }
    
    function NameNewDo(bytes32 name, bytes32 r) {
        if (
            data[name] == 0
            && commitments[msg.sender] == sha3(name, r)
        ) {
            data[name].owner = msg.sender;
        }
    }
}
```

(c.) (a) This would once again allow front-running: from part (a), Bob can see that Alice has submitted a transaction for `alice.eth`, and can front-run this with his own transaction if he can get `alice.eth` out of Alice's commitment.

(c.) (b) This would allow Bob to forge a transaction for Alice as having bought the arbitrary domain name.