Login Register






How to make a cryptocurrency, part 2: Your first blockchain system filter_list
Author
Message
How to make a cryptocurrency, part 2: Your first blockchain system #1
How to make a cryptocurrency, part 2: Your first blockchain system


[Image: 62726.png]


It took me a while to decide not to shove everything in one thread, but here I am.  In this tutorial, we're going start to make a simple blockchain implementation.  In the next tutorial(s), we'll tun it into a full cryptocurrency. I expect that you have read and fully understand part 1, if not, then go do so, I'll wait. (https://sinister.li/Thread-How-to-make-a...blockchain)

Getting started:

Alright, we're going to have a simple one-node system, which we'll later expand to a multiple node currency or some other blockchain application.  I'm going to write this in Go, it's a language I really like (and really have issues with), but remember that you should know C and an ASM before higher languages.  Eventually, we'll add networking with multiple nodes, and node-discovery.  

Here's the directory structure that I chose:
Code:
BlockCoin/ ├──── client/ |     └── main.go └──── node/       └── main.go

In this thread we'll only be focusing on the node/main.go file.

Let's get to the code:
Alright, let's get to the code.  
Let's start with how every Go program starts:
Code:
package main import (        "fmt" ) /* Dear Rob Pike,        Go is a decent language, but for the sake of us 'Gophers', please use a better form of error handling Please don't kill me,        Ender */ func Handle(err error) {        if err != nil {                panic(err)        } } func main() { }

I'll just give you the import list right now:
Code:
import (        "bytes"        "crypto/sha256"        "encoding/binary"        "fmt"        "math/big"        "time" )

Ok, now let's add some basic stuff... The block struct, the blockchain type, and the targetBits const:
Code:
const targetBits = 21 //Max of 256, the lower the harder.  21 is both a prime number, and a triangular number! type Block struct {        Timestamp uint32 // Current timestamp        Data      []byte        PrevHash  []byte // The hash of the last block        BlockHash []byte // The hash of this block        Nonce     uint32 // The nonce } type Blockchain []*Block

Alright, now we want to be able to simply mine blocks with one function call in main(), so let's write our main function to do that:
Code:
func main() {        chain := NewBlockchain()        chain.AddBlock("Here is some test data.")        chain.AddBlock("Later, we'll use transaction data instead") }

Alright, so now we have a good idea of how we want the interface to work.  Let's start by writing the NewBlockchain() function:
Code:
/* An unneeded function that creates a new blockchain with a Genesis block.   I have no idea why I did this */ func NewBlockchain() Blockchain {        return Blockchain{ GenesisBlock() } }

Yeah... I'm generally against unnecessary functions, but I did it like this anyway...

Let's make the GenisisBlock() function:
Code:
//Creates a new Genesis block func GenesisBlock() *Block {        return NewBlock( "GENISIS", []byte{} ) //creates a new block containing the data "GENISIS" }

It's good practice to comment your functions.

This is where we actually start getting into the details.  NewBlock() is going to fill a Block struct with the data "GENISIS", an empty PrevHash, and it'll generate the rest of the data.  First it should fill the block with what data we have, then call a function MineBlock() to get the other data, set the nonce in the block to the nonce returned, and return the block.  I'm gonna start adding spoilers here so you can try on your own and check your work against mine:
Spoiler:
//Creates a new block
func NewBlock(data string, prevHash []byte) *Block {
       block := &Block{ uint32(time.Now().Unix()), []byte(data), prevHash, []byte{}, 0 }
       hash, nonce := MineBlock(block)
       block.BlockHash = hash
       block.Nonce = nonce
       return block
}


I wish SL had syntax highlighting and tab support, but then again, SL isn't a text editor...
Alright, now for the big one, let's implement the mining function MineBlock()
I'm going to show you this comment, and I want you to try it yourself after reading it:
Code:
/*        MineBlock(block *Block) ([]byte, uint32) -- Mines a block.        ----------------------------------------------------------        Alright, let's go through the algorithm here:                First, we create a new bigInt with a value of 1, then we left-shift that by 256 minus the target bits.                The reason for this, is that we can't have the target be larger than 256 bits, or it will be larger than the SHA256 hash.                We then convert targetBits to a byte slice, and put it in targetBitsArray. After this, we join all the block data into a 2d byte array,                then we begin the mining process.                In mining, we start the nonce at 0, then move up. We hash the data, then check if the hash is less than the target.                If not, we increment the nonce, and repeat the same process all over again. Once the hash is less than the target, we return the hash and                nonce. */

Ok, you've tried it?  I'm going to go through this one step by step:
Spoiler:
I think you've figured this part out:
Code:
func MineBlock(block *Block) ([]byte, uint32) {

Now for the creation of the target:
Code:
       target := big.NewInt(1)        target.Lsh(target, uint(256-targetBits)) //The SHA256 hash should take 256 bits of memory, we left-shift by the size of target        targetBitsArray := ToBytes(targetBits)

Getting everything into a slice:
Code:
       data := bytes.Join(                [][]byte{                        ToBytes(block.Timestamp),                        block.Data,                        block.PrevHash,                        targetBitsArray,                        ToBytes(uint32(block.Nonce)),                },                []byte{},        )

Variable declarations:
Code:
       var hashInt big.Int        var hash [32]byte        var nonce uint32

Setting of the nonce, hashing the data, and setting hashInt to that:
Code:
       nonce = 0        hash = sha256.Sum256(data)        hashInt.SetBytes(hash[:]) //we need it as a slice, so we have [:]

Time to print a mining message, and jump into the main mining loop:
Code:
       fmt.Printf("Mining block containing '%s'\n", block.Data)        for hashInt.Cmp(target) != -1 {                nonce++                block.Nonce = nonce                data := bytes.Join(                        [][]byte{                                ToBytes(block.Timestamp),                                block.Data,                                block.PrevHash,                                targetBitsArray,                                ToBytes(uint32(block.Nonce)),                        },                        []byte{},                )                hash = sha256.Sum256(data)                hashInt.SetBytes(hash[:])        }

Now... There's a bug in the piece of code above.  I want you to find it, although it is a tough one, and you probably won't think of it unless you have some experience with C or another lower-level lang...
I'll leave it here in a spoiler, but I highly recommend that you try to figure it out.

Spoiler: bug
It is possible for the nonce to overflow, since it is limited by the max uint32 size.  I'm going to leave it up to you to solve it.  Wink


Alright, let's let the miner know that he's making money, and then let's return the hash (as a slice), and the nonce:
Code:
       fmt.Println("Mined!")        return hash[:], nonce }

If you did this yourself and are reading through this, you probably noticed that I used a function ToBytes()...
Here's the code for that:
Code:
//Converts a uint32 to a byte array func ToBytes(num uint32) []byte {        bs := make([]byte, 4)        binary.LittleEndian.PutUint32(bs, num)        return bs }

My whole MineBlock() function looks like this, yours should be somewhat different though:
Code:
func MineBlock(block *Block) ([]byte, uint32) {        target := big.NewInt(1)        target.Lsh(target, uint(256-targetBits)) //The SHA256 hash should take 256 bits of memory, we left-shift by the size of target        targetBitsArray := ToBytes(targetBits)        data := bytes.Join(                [][]byte{                        ToBytes(block.Timestamp),                        block.Data,                        block.PrevHash,                        targetBitsArray,                        ToBytes(uint32(block.Nonce)),                },                []byte{},        )        var hashInt big.Int        var hash [32]byte        var nonce uint32        nonce = 0        hash = sha256.Sum256(data)        hashInt.SetBytes(hash[:]) //we need it as a slice, so we have [:]        fmt.Printf("Mining block containing '%s'\n", block.Data)        for hashInt.Cmp(target) != -1 {                nonce++                block.Nonce = nonce                data := bytes.Join(                        [][]byte{                                ToBytes(block.Timestamp),                                block.Data,                                block.PrevHash,                                targetBitsArray,                                ToBytes(uint32(block.Nonce)),                        },                        []byte{},                )                hash = sha256.Sum256(data)                hashInt.SetBytes(hash[:])        }        fmt.Println("Mined!")        return hash[:], nonce }

Note that it's a bit redundant, that'll be for you to fix.


Now, all we need is the AddBlock() function.
It should just get the hash of the last block, and use that to call NewBlock().
You should figure this one out yourself, but I'll still leave my code here.
Spoiler:
Did I mention to do it yourself first?

Spoiler:
Code:
func (bc Blockchain) AddBlock(data string) {        previousBlock := bc[ len(bc)-1 ]        newBlock := NewBlock(data, previousBlock.BlockHash)        bc = append(bc, newBlock) }



Conclusion:

You should now know how to implement a basic blockchain.  I suggest that you try to make something like a token/ticket system, or an entire cryptocurrency from this.  Or even just try to get it networked across multiple nodes.
Anyway, I'll be making more of these in the future, so keep an eye out for them.
Everything here is licensed under a modified Beerware license.  I basically switched 'beer' for 'drink', and that's about it: (I'm a minor, so there's that)
Code:
/* * ---------------------------------------------------------------------------- * "ENDER'S DRINK-WARE LICENSE": * Ender wrote these files. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a drink in return. * ---------------------------------------------------------------------------- */

Also thanks to Ciisco for helping me debug this

Don't forget to post below with questions or comments!
(This post was last modified: 07-22-2019, 09:01 AM by Blink.)


(11-02-2018, 02:51 AM)Skullmeat Wrote: Ok, there no real practical reason for doing this, but that's never stopped me.

[+] 3 users Like Blink's post
Reply

RE: How to make a cryptocurrency, part 2: Your first blockchain system #2
Well written @"Ender" , I was so glad when you told me you were going to be working on such an interesting topic in Go, and it was an honor to be able to help out! I recommend everyone who has read the thread to try to fill in some of the hidden code @"Ender" has included. Overall excellent tutorial!
{Ciisco}

[+] 1 user Likes Ciisco's post
Reply

RE: How to make a cryptocurrency, part 2: Your first blockchain system #3
(03-18-2018, 04:23 AM)Ciisco Wrote: Well written @"Ender" , I was so glad when you told me you were going to be working on such an interesting topic in Go, and it was an honor to be able to help out! I recommend everyone who has read the thread to try to fill in some of the hidden code @"Ender"  has included.  Overall excellent tutorial!

Thanks!
I love how you said "hidden code", funny way of putting it. You guys should also try to fix the bug that I mentioned.


(11-02-2018, 02:51 AM)Skullmeat Wrote: Ok, there no real practical reason for doing this, but that's never stopped me.

[+] 1 user Likes Blink's post
Reply

RE: How to make a cryptocurrency, part 2: Your first blockchain system #4
Thank you a ton for this man!

Reply

RE: How to make a cryptocurrency, part 2: Your first blockchain system #5
What an excellent, well written guide. Very educational, thanks!

Reply