Jakobi Haskell
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- tags: Projects --- # Coin :::info **Released:** March 3rd, 11:59pm EST **Due:** March 21st, 11:59pm EST ::: Clone the stencil [here](https://classroom.github.com/a/t0X7NUuh)! ## Introduction In Chain, we learned how a cryptocurrency might implement a blockchain for block storage and validation. Now it's time to flesh out the rest of the system! You've heard about nodes, miners, and wallets in class (or will soon). Now's your chance to dive into the details of how these parts come together. This project builds on the blockchain that you implemented for your first project. Don't worry if you didn't pass all of our tests on Chain -- we've provided our solution for the blockchain. ## Components Coin consists of several main components. Here's a quick overview: 1. **Blockchain** - See [Chain](https://hackmd.io/@KOnWTzqNQeG_fcTmpWZdTw/r1RPZNSDke). 2. **Miner** - The Miner handles our proof of work (POW) consensus mechanism. It's in charge of finding a winning nonce for the blocks it forms. The miner keeps track of a Transaction Pool, which contains transactions passed to it by the node. Off to the races! 3. **Node** - The node handles all top level logic. Among its various duties, it validates incoming blocks (using our blockchain), broadcasts transaction requests from the wallet, and tells the miner (if it has one) when to stop and start mining. Whenever it sees a valid block that appends to its chain, the node should tell its miner to get busy on a new block. 4. **Wallet** - The wallet keeps track of our coins and creates transactions, which it passes along to its node. The node can then broadcast these transactions to the network. Miners of nodes that hear about these transactions will add them to their transaction pools. Given a large enough fee (or enough space on a block), the miner will include the transaction in their block. 5. **Server** - If we wanted to, we could start a server and run our very own cryptocurrency out of Brown. We're skeptical this would be a good idea, since there are plenty of bugs lurking around in the code base. But we still could! **You don't need to worry about servers for this assignment**, but we still wanted to mention it here. ## Assignment For this assignment, you will implement the functions listed below. We recommend that you tackle them in the following order: 1. `CalculateNonce` 2. `GenerateCoinbaseTransaction` 3. `Mine` 4. `HandleTransactions` 5. `RequestTransaction` 6. `BroadcastTransaction` 7. `HandleMinerBlock` To see how difficult we think each function is, check out our [grading breakdown](##Grading). ### (1) mine.go The infamous miners. Greedy miners compile the transactions that give them the highest reward into blocks, which they then race to find a winning nonce (number only used once) for. As soon as they hear about another block, they have to start from scratch. It's a rat race. Not only does the miner get to keep all transaction fees, they also get the minting reward for each block. Recall that minting rewards halve every 10,000 blocks. Our halvings occur more frequently. **Here's an overview of the relevant `Miner` fields:** :::info * **`Config`**: our miner’s configuration options. For this project, you'll only really have to worry about `Config.NonceLimit` * **`TxPool`** all of the transactions that the miner can pull from to create their block. `TxPool` is an enhanced priority queue that also keeps track of total priority, to know whether or not the miner should mine at all. * **`MiningPool`**: the transactions that the miner is actively mining in the current block. This is a subset of the `TxPool`. * **`PreviousHash`**: the hash of the current last block on the main chain, so that our miner knows where to point to when constructing its new block. * **`ChainLength`**: used by the miner to calculate the current minting reward. * **`SendBlock`**: the channel that the node monitors to know when the miner has successfully mined a block. See `node.Start` for how this is used. * **`PoolUpdated`**: the channel used to send information about TxPool updates to the miner. * **`DifficultyTarget`**: the level of difficulty that a winning nonce's resulting hash must beat. ::: #### Uhm... what's`context.Context`? * We use `context` to send cancellation signals to goroutines, which take on lives of their own once spawned. * If you're still a bit fuzzy on context, here is the [documentation](https://pkg.go.dev/context) and some [example code](https://gobyexample.com/context). #### Why are we using `atomic` variables? * Since our miner runs concurrently using goroutines, we must be mindful of any potential synchronization issues that could arise. * The `atomic` package provides low-level atomic memory primitives useful for implementing synchronization algorithms -- it basically allows us to read/write to shared memory without having to deal with mutexes. * Ask us on Ed if you have questions about concurrency or synchronization (especially if you haven't taken a systems course like cs0300 or cs0330). * **Fun fact:** Multi-processor synchronization is one of Dr. Herlihy's specialties, so if you geek about this kind of stuff, go talk to him about it at his office hours! :::info **Important! A note on `select`:** * Go's `select` statement allows you to wait for results from multiple channels. It's really just a fancy version of the classic switch statement, where your cases are channel results. * For examples of how the select statement might be used, check out **[this post](https://gobyexample.com/select)** and `node.Start`. We usually combine select statements with infinite loops, so that a process just monitors relevant channels until it's terminated. ::: #### Implement: ```go! // CalculateNonce finds a winning nonce for a block. It uses // context to know whether it should quit before it finds a nonce // (if another block was found). ASICSs are optimized for this task. func (m *Miner) CalculateNonce(ctx context.Context, b *block.Block) bool ``` ##### Overview: * This is what miners spend the majority of their time doing: they update the block header's Nonce until they find a hash smaller than the difficulty target. * **Note:** our hashes are not technically hex, so we'll be comparing byte values. * Don't forget about `context`! How can we use it to monitor whether our nonce calculations are still a worthwhile pursuit? * Returns `true` if we find a valid hash, `false` otherwise. ##### Some helpful functions: * context's `Done() <-chan struct{}`. #### Implement: ```go! // GenerateCoinbaseTransaction generates a coinbase // transaction based off the transactions in the mining pool. // It does this by adding the fee reward to the minting reward. func (m *Miner) GenerateCoinbaseTransaction(txs []*block.Transaction) *block.Transaction ``` ##### Overview: * The miner works so hard in hopes of securing a coinbase transaction, in which it receives transaction fees and the minting reward. * Transaction fees are implicit: they're the sum of the inputs minus the sum of the outputs. * You should aggregate all of the fees for the transactions, get the minting reward, and make sure this transaction is addressed to you! How can we get that from our `Id`? ##### Some helpful functions: * `func CalculateMintingReward(c *Config, chainLength uint32) uint32`: we need to know what the reward is for this chain length! * `func (m *Miner) getInputSums(txs []*block.Transaction) ([]uint32, error)` : our miner uses its `GetInputSums` channel to request this information from the node. Once it receives the request, the node will get the input sums for each transaction from the blockchain and return it to the miner via the `InputSums` channel #### Implement: ```go! // When asked to mine, the miner selects the transactions // with the highest priority to add to the mining pool. func (m *Miner) Mine() *block.Block ``` ##### Overview: * In our cryptocurrency, a miner needs to be sure it's even worth mining a block. After all, CPU usage can get pricey. Thus, there better be enough transactions worth mining. Hint: check out the `TxPool`'s functions. * If we're set to mine, then we should set our `Mining` field to true. * Now, our miner should select the very best transactions to mine. We suggest you look at the `MiningPool`. * Once we figure out which transactions we want to mine, it's time to construct the block. * Then, we do the dirty work: we try and find a winning nonce for our block, so that our node can broadcast it to rest of our network and get our sweet reward. * After successfully(or unsuccessfully finding our nonce), we can safely set our `Mining` field to false. We're done. * If we were successful in finding a winning nonce, we should send the block so that our node can hear about it, then we should handle the block ourselves (in order to remove the block's transactions from our `TxPool`) ##### Some helpful functions: * atomic's `func (x *Bool) Store(v bool)`: this is how we update an atomic boolean. * context's`WithTimeout(context.Background(), 2*time.Second)` to create a context that times out after 2 seconds. This will give your program enough time to find a hash value while timing out in case of a bug. * You should be able to figure out which other functions to use based on the overview above! :::danger Note: the `TestMine` tests requires a valid `HandleMinerBlock` implementation as well! ::: ### (2) wallet.go The vast majority of cryptocurrency holders trust a third-party to take care of their coins (e.g. services like [Coinbase](https://coinbase.com) and [FTX](https://claims.ftx.com/welcome)). Even investment management companies like Blackrock and Fidelity are now offering custodial crypto [ETFs](https://www.blackrock.com/us/financial-professionals/investments/products/bitcoin-investing). Nodes, on the other hand, keep track of their own holdings. You'll learn more about wallets in a future lecture. **Here's an overview of the relevant `Wallet` fields:** :::info * **`Config`**: our wallet's configuration options. For this project, you only need to worry about `Config.SafeBlockAmount`. * **`Id`** : our wallet's `SimpleID` keeps track of the node's public and private keys. More complicated configurations--such as **[hierarachical deterministic wallets](https://en.bitcoin.it/wiki/Deterministic_wallet)**--are both more secure and more complex. We opted for keeping things simple: our wallet can only process transactions sent to our sole `PublicKey`. * **`TransactionRequests`**: the channel that our wallet uses to send transaction requests to the `Node`, which can then broadcast this transaction to its peers. * **`CoinCollection`**: this mapping contains all of the owner's coins that have been confirmed enough times (see `config.SafeBlockAmount`). * **`UnseenSpentCoins`**: this mapping contains all of the coins that we've spent (by requesting a transaction) but haven't yet seen in a Block. Until we see our transaction actually included in a Block on the Chain, it hasn't happened! * **`UnconfirmedSpentCoins`**: Once we've seen one of our spent coins on the chain, we should move it from `UnseenSpentCoins` to `UnconfirmedSpentCoins`. Even though we've seen our coin included in a block, we still have to wait until enough confirmations (new blocks added to the chain) have occurred until we can safely spend our coin. * **`UnconfirmedReceivedCoins`**: Since we're an active cryto-user, we need a way to handle coins sent to us from our friends and peers, as well as the change from our own transactions! Like with `UnconfirmedSpentCoins`, we'll have to wait until enough confirmations have occured until we can spend any Coin that we receive. ::: Ok, I think I understand how wallets work. But what are `CoinInfos`? `CoinInfos` are convenient structs that hold the information about TransactionOutputs necessary for turning them into TransactionInputs. You'll see them as either keys or values in all of the wallet's mappings. #### Implement: ```go! // HandleTransactions handles the transactions of a new block. // It updates the wallet's fields when applicable. func (w *Wallet) HandleTransactions(txs []*block.Transaction) ``` ##### Overview: * Simply put, `HandleTransactions` moves coins (via coinInfos) between our various mappings. This function looks at all of the transactions in a block and sees if any of them involve the wallet's owner. * What fields of `Wallet` should we update? #### Implement: ```go! // RequestTransaction allows the wallet to send a transaction to the node, // which will propagate the transaction along the P2P network. func (w *Wallet) RequestTransaction(amount uint32, fee uint32, recipientPK []byte) *block.Transaction ``` #### Overview * What should we check before sending a transaction? * What fields of `Wallet` should we update? * Make sure that you actually send your finalized transaction to the `TransactionRequests` channel. Otherwise, the node won't be able to broadcast it! * Lastly, update your balance. We temporarily reduce our balance by the total of the inputs when we have a pending transaction. This means we'll have to wait until we've seen our transaction in the Chain (with enough confirmations) to get our change back! ##### Helpful functions: * `func (txo *TransactionOutput) MakeSignature(id id.ID) (string, error)` * `func (id *SimpleID) GetPublicKeyString() string` * While we did not provide our implementations of `generateTransactionInputs` and `generateTransactionOutputs`, we did leave you the function headers as a guide to how you might want to fill in and use these helpers. ### (3) node.go Nodes are the workhouses of cryptocurrencies like Bitcoin. They send information to their peers, run miners, and generally do a lot of validation. Our node should take advantage of non-blocking **goroutines** to delegate work to our miner/wallet/blockchain and continue on with its duties. That way, the nodes won't have to wait for the miner/wallet/blockchain to finish before we can continue. Head back to [Lab 1](https://hackmd.io/@KOnWTzqNQeG_fcTmpWZdTw/H1NKYBHuyl) for a refresher on goroutines. **Here are `Node` fields that you have to be aware of for this project:** :::info * `Config`: the node's configuration. You'll want to know whether this node has a miner * `Blockchain`, `Wallet`, and `Miner`: self-explanatory * `SeenTransactions`: the transactions that our node has either (1) heard about from other nodes or (2) broadcast itself * `SeenBlocks`: same as `SeenTransactions`, but for blocks * `PeerDb`: the database of peers that the Node is currently connected to. ::: #### Implement: ```go! // BroadcastTransaction broadcasts transactions created by the wallet // to other peers in the network. func (n *Node) BroadcastTransaction(tx *block.Transaction) ``` ##### Overview: * Our wallet has just requested that we broadcast one of its transactions to our peers, who will then broadcast to their peers, etc... * What field(s) of `Node` should we update? * If we have a miner, it should handle the tx in the `TXPool` somehow, since it can now include this transaction in one of its own blocks. * We should send this transaction to every peer in our `PeerDb`. Make sure to wrap your RPC call in a goroutine! ##### Helpful functions: * `func (m *Miner) HandleTransaction(t *block.Transaction)` * `func (a *Address) ForwardTransactionRPC(request *pro.Transaction) (*pro.Empty, error)`: this function allows us to forward a transaction to other nodes. #### Implement: ```go! // HandleMinerBlock handles a block // that was just made by the miner. It does this // by sending the block to the chain so that it can be // added, to the wallet, and to the network to be // broadcast. func (n *Node) HandleMinerBlock(b *block.Block) ``` ##### Overview: * Woo! Our miner has succesfully mined a block! * What field(s) of `Node` should we update? * What function can we use to update the blockchain? * If we have a wallet, how can we update its state of coins? * We need to broadcast this block to all the peers in our network. ##### Helpful functions: * `func (a *Address) ForwardBlockRPC(request *pro.Block) (*pro.Empty, error)`: this function allows us to forward a block to other nodes. --- ## Testing This assignment is autograded, and you are able to run our test suite as many time as you like. In addition, you should write your own tests when things aren't working! We have provided several helper functions in `test/mocking_utils.go` and `test/testing_utils.go` and some starter tests as well. If you have written your own tests, you can `cd` into `test` and run `go test`. This will let you know which tests are failing, and why. It will likely be more convenient to **run individual tests**, which you can do using the GoLand UI. ## Debugging Since many parts of this project make use of concurrency, you may find it a bit tricky to debug. Luckily, the GoLand debugger has support for debugging goroutines. You can read all about it [here](https://blog.jetbrains.com/go/2020/03/03/how-to-find-goroutines-during-debugging/). ## Install 1. Clone the [stencil repo](https://classroom.github.com/a/t0X7NUuh). 2. In your local Coin directory, run `go get ./...` to install the project's dependencies. 3. Get after it! Good luck :smiley: ## HandIn 1. Log into [Gradescope](https://www.gradescope.com/). 2. Submit your code using **GitHub**. ## Grading This assignment carries a total of **100 points**. This will be determined by passing the following test functions: ### Miner | Test Function | Points | |:--------------------------------- |:------:| | `TestCalculateNonce` | 5 | | `TestCalculateNonceContext` | 5 | | `TestGenerateCoinbaseTransaction` | 5 | | `TestMine` | 15 | | **Total** | **30** | ### Wallet | Test Function | Points | |:--------------------------------- |:-------:| | `TestHandleTransactions` | 15 | | `TestBasicTransactionRequest` | 10 | | `TestMultipleTransactionRequests` | 15 | | `TestRequestTransactionFails` | 10 | | **Total** | **50** | ### Node | Test Function | Points | |:-------------------------- |:------:| | `TestBroadcastTransaction` | 10 | | `TestHandleMinerBlock` | 10 | | **Total** | **20** |

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully