Check each of the last nBytes bytes are '\x00'. Check that the next byte (from the end) is divisible by 1<
b0.ValidHash() should return false, but if we set b0.Proof = 56231 then b0.ValidHash() should be true. Another example, with this setup, b1 is valid and has exactly 19 zero bits at the end of its hash:
b0 := Initial(19)
b0.SetProof(87745)
b1 := b0.Next("hash example 1234")
b1.SetProof(1407891) But if we did this, the block it not valid. It has only 18 zero bits at the end of its hash:
b1.SetProof(346082) Mining Now that we have the basic structure for blocks, we need to do some mining. Put this functionality in
blockchain/mining.go. The process of mining a block is conceptually easy: check proof-of-work values until you find one that would make block.ValidHash() true. Once you have found it, set block.Proof and block.Hash to make the block valid. (The provided .SetProof does the last step.) A function mineSequential is provided that loops over proof values starting a 0 until a valid one is found. You don't need this, but it completely avoids the need for the work queue, and may be convenient for testing the more complex implementation we're about to create… 4/7
A mining task will be a range of possible proof-of-work values: we want to check those value and return any one of them that makes the block's hash valid. Mining Tasks We will use our work queue for this. We will need a struct that implements the Worker interface, i.e. has a
.Run() method. We can also use the struct for any other information needed to do the mining we want done. The .Run() call should return a MiningResult struct that includes (at least) a .Proof (proof-of-work value, if found) and .Found (indicating if the search was successful). Once you have that, you can use it in block.MineRange(start, end, workers, chunks). This should check proof values for this block, from start to end (inclusive). The calculation should be done in parallel by the given number of workers, and dividing the work into chunks approximately-equal parts. This must be done using the work queue created above. If that is implemented correctly, it should be fairly easy to do this work in parallel, and to stop checking proof values (soon) after a valid proof is found. A note on handling types and interfaces: the work queue will insist you return an interface{} value from
.Run(). To actually use the result, it will have to be treated as a MiningResult. You will need a “type assertion” to get that to work. Example Blocks Here is an example of valid hashes being mined, and the proof values I get:
b0 := Initial(7)
b0.Mine(1)
fmt.Println(b0.Proof, hex.EncodeToString(b0.Hash))
b1 := b0.Next("this is an interesting message")
b1.Mine(1)
fmt.Println(b1.Proof, hex.EncodeToString(b1.Hash))
b2 := b1.Next("this is not interesting")
b2.Mine(1)
fmt.Println(b2.Proof, hex.EncodeToString(b2.Hash))
This outputs:
385 379bf2fb1a558872f09442a45e300e72f00f03f2c6f4dd29971f67ea4f3d5300
20 4a1c722d8021346fa2f440d7f0bbaa585e632f68fd20fed812fc944613b92500
40 ba2f9bf0f9ec629db726f1a5fe7312eb76270459e3f5bfdc4e213df9e47cd380
There are other valid proof values for these blocks, but these are the ones my code finds (and the numerically-smallest). Changing to difficulty 20 in the above code, it outputs:
1209938 19e2d3b3f0e2ebda3891979d76f957a5d51e1ba0b43f4296d8fb37c470600000
989099 a42b7e319ee2dee845f1eb842c31dac60a94c04432319638ec1b9f989d000000
1017262 6c589f7a3d2df217fdb39cd969006bc8651a0a3251ffb50470cbc9a0e4d00000
Valid Blockchains 5/7
In blockchain.go, we will finally put our blocks together into a blockchain, so we can have a chain and verify the validity of each block. A simple struct for a blockchain is provided. Complete a method .Add that appends a new block to the chain. The method .IsValid will check a few aspects of the blockchain to make sure it is valid. The whole point: this is computationally efficient, but creating the blockchain (with proofs) was hard. Tests The provided blockchain_test.go doesn't actually contain any tests, but it should. Write some tests that check the core functionality of the Block. Your tests should ensure that at least some of the functionality described above is correct. There is no requirement for complete code coverage or testing every single thing mentioned. You should write at least three or four tests (depending on the complexity of each test, of course) and cover a reasonable variety of the requirements for the assignment. At least some tests should be on examples not directly from the assignment description. You can assume that the testify/assert package (https://godoc.org/github.com/stretchr/testify/assert) is available when we're marking. You can install it like:
go get github.com/stretchr/testify/assert
Summary All of the functions provided in the code skeleton should be complete with arguments and return values as specified. We will expect them to be there when testing your implementation. Pieces provided that shouldn't be changed:
blockchain.Block, ….MiningResult, ….Blockchain
blockchain.Block.SetProof, ….Mine
These structs/functions/methods as in the provided code skeleton should be completed to work as described above:
work_queue.Create
work_queue.WorkQueue
work_queue.WorkQueue.Enqueue, ….Shutdown
blockchain.Initial
blockchain.Block.Next, ….CalcHash, ….ValidHash, ….MineRange
blockchain.Blockchain.Add
Some tests in blockchain_test.go. Where there are stub implementations in the provided hints, you aren't required to use them, as long as the functions listed here work as specified. Blockchains Revisited There is a lingering question here: is this a “good” blockchain implementation? 6/7
The answer is clear: no. You are dangerously bad at cryptography (https://web.archive.org/web/20190710233618/https://www.happybearsoftware.com/you-are- dangerously-bad-at-cryptography.html) , and so am I. But, it does contain and illustrate some of the core ideas. .