or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
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.
Syncing
xxxxxxxxxx
Chain
Released: February 5th, 11:59pm EST
Due: February 25th, 11:59pm EST
Introduction
Chain is an example storage system (a blockchain) for a cryptocurrency. Chain is modeled after Bitcoin's storage system, though heavily simplified. The goal of this project is to give you a taste of the many working components of a blockchain.
Components
Chain consists of several main components. Here's a quick overview:
Gear-Up!
Here's a gear-up video to get you started!
Assignment
For this assignment, you will implement the functions listed below. We recommend that you tackle them in the following order:
StoreBlockRecord
GetBlockRecord
WriteBlock
WriteUndoBlock
StoreBlock
UndoCoins
HandeBlock
To see how difficult we think each function is, check out our grading breakdown.
(1) blockinfodatabase.go
Protocol Buffers:
Why do we have local structs if we're using protobufs?
Good question. Normally, when using protobufs, you would probably NOT create redundant local structs. After all, if you have a well-defined message format, why would you rewrite the same format? The answers is that these redundant local structs are easier to work with. That means less headaches for you.
BlockRecords:
Implement:
As suggested by this function's name, the purpose of
StoreBlockRecord
is to store block records in the BlockInfoDatabase.In order to do this, we'll need to 1) encode the
BlockRecord
as a protobuf, 2) convert the protobuf to the correct format and type (byte[]
) so that it can be inserted into the database, and 3), put the block record into the database.Helpful functions:
func EncodeBlockRecord(br *BlockRecord) *pro.BlockRecord
func Marshal(m Message) ([]byte, error)
. See documentation here.func (db *DB) Put(key, value []byte, wo *opt.WriteOptions) error
. See documentation here.Implement:
This function retrieves block records from the database, and returns the block record.
In order to do this, we'll basically do the reverse of what we did in
StoreBlockRecord
. Specifically, we'll 1) retrieve the block record from the database, 2) Convert thebyte[]
returned by the database to a protobuf, and 3) convert the protobuf back into aBlockRecord
.Helpful functions:
func DecodeBlockRecord(pbr *pro.BlockRecord) *BlockRecord
func Unmarshal(b []byte, m Message) error
. See documentation here.func (db *DB) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error)
. See documentation here and be sure to account for the corresponding I/O errors.(2) chainwriter.go
So what's an UndoBlock?
Implement:
Note: These two functions are nearly identical. Think about which ChainWriter fields you're modifying.
Hints:
cw.CurrentBlockFileNumber
by one.dataDirectory/fileName_fileNumber.<file extension>
ChainWriter
fields as appropriateHelpful functions:
writeToDisk(fileName, serializedBlock)
(3) coindatabase.go:
Cache vs Database
Understanding Reverting a Block
Implement:
Hints
Helpful functions:
makeCoinLocator(txi *block.TransactionInput)
coinDB.removeCoinFromDB(txHash string, cl CoinLocator)
coinDB.FlushMainCache()
coinDB.createCoinRecord(tx *block.Transaction, active bool)
coinDB.putRecordInDB(txHash string, cr *CoinRecord)
Helpful functions:
coinDB.removeCoinFromRecord(cr *CoinRecord, outputIndex uint32)
Delete(key []byte, wo *opt.WriteOptions)
coinDB.getCoinRecordFromDB(txHash string)
coinDB.addCoinsToRecord(cr *CoinRecord, ub chainwriter.UndoBlock)
coinDB.putRecordInDB(txHash string, cr *CoinRecord)
(4) blockchain.go
Implement
Helpful functions:
blockchain.go
that we've crafted to make your life easier. Make sure you understand what each one is doing!Additional notes:
unsafeHashes[0]
is the least recent hash. This means that when updatingunsafeHashes
, we pop from the front (but should we always pop?) and push to the back of the slice. The helper functiongetForkedBlocks
handlesunsafeHashes
as such. If you decide to keep track of unsafe hashes differently,getForkedBlocks
will not behave as expected. In that case, feel free to updategetForkedBlocks
!unsafeHashes
andmaxHashes = 6
as a heuristic for how many blocks back we need to check to find the origin of a fork. While in real life there is an infinitesimal chance that a Bitcoin fork requires a node to search back beyond 6 blocks, it's still possible! Such an event would (unfortunately) break our implementation.UndoCoins()
) is somewhat complicated and long. If you're stuck, collaborate with your peers or come to TA hours!Extra credit opportunity! (15pts)
HandleBlock
is the child of a block that hasn't been stored yet, you are not required to handle it. Such a block is called an Orphan Block. See this article.block1
andblock2
, whereblock2
's parent isblock1
. Normally, we'd callHandleBlock
onblock1
first. However, under some conditions, we may receiveblock2
first.block2
will be invalid until we seeblock1
.Testing
This assignment is autograded, and you are able to run our test suite as many times as you like on Gradesceope.
In addition, you should write your own tests when things aren't working! We have provided several helper functions in
test/utils.go
.To test your project with the tests you've written,
cd
intotest
and rungo 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.Note: Running the autograder directly on the stencil will cause a system panic, since the application relies on the dereferencing of things like block records (which will be null if you have yet to implement anything). We have configured it such that you will still see the error message in cases like this, but it may not be as useful as those that were written by the staff.
Install
go get ./...
to install the project's dependencies.- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →HandIn
Grading
This assignment carries a total of 155 points. Following the project deadline, a TA will schedule an interactive grading session with you. During this session, you will demonstrate the functionality of your program and respond to questions about your submission. Attendance and participation in this grading session are valued at 15 points. The remaining 140 points of your grade will be determined by passing the following test functions:
BlockChain
TestHandleAppendingBlock
TestHandleInvalidBlock
TestHandle50Blocks
TestHandleForkingBlock
TestHandle2Forks
BlockInfoDatabase
TestGetSameRecord
TestGetDifferentRecords
ChainWriter
TestReadBlock
TestReadUndoBlock
TestRead100Blocks
TestStoreOrphanBlock
TestStoreBlock
TestWriteBlock
TestWriteBlockSwitchesFiles
TestWriteUndoBlock
TestWriteUndoBlockSwitchesFiles
CoinDatabase
TestGetCoin
TestUndoCoins
TestUpdateSpentCoinsInCache
TestUpdateSpentCoinsNotInCache
TestValidateValidBlock
TestValidateInvalidBlock
TestCacheFlushedWhenFull
TestCoinsStoredInCacheAndDB