Building a Blockchain in Go Pt V - Wallets
Tags: blockchain, go, tutorial
Published: 2021-04-26 22:00:37

Hello Readers!



You may have guessed that we will be building a wallet module. You would be correct.

> code can be found [here](https://replit.com/@nheingit/GolangBlockChain-5)

# What is a Wallet?

Excellent question! 

In the real world a wallet may hold your money, along with maybe your credit/debit cards or ID. However in the blockchain world your [wallet](https://en.wikipedia.org/wiki/Cryptocurrency_wallet) does not hold any money at all. It holds all of your private keys. You went over [transactions](https://dev.to/nheindev/building-a-blockchain-in-go-pt-iv-transactions-1612), in the previous post and used a pseudo-key to see if you were eligible to spend the money in the block that the key unlocked. This is the functionality of what keys do in the blockchain.

If you were to come up with a diagram, it would look a little something like this. 

Wallet makes private key -> key unlocks block -> block releases money.

So a wallet holds keys. 

That's great, but....

# What is a Key?

Excellent question! 

Wow, you sure do have a lot of those. Good thing I anticiapted you being such a smart cookie.

As you remember from the last section, a key will unlock the data that is representative of your money.

The thing about this "key", is there is actually two of them. They are tied together, there is a public key, and a private key.

![Hydra heads multiplying](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tk9q6wi29zjqbxyuk1x2.gif)

You have a private key, and this is the one that you wallet holds. You don't want to share this with anyone, as anyone that has your private key can access all of the money that belongs to you.

You also have a public key which is tied to your private key. This key may be used by anyone, and when someone sends money to you, they use your public key to lock the funds up.

If I were to use an analogy, it would be slapping your own personal branded padlock on something. Everyone knows its your padlock, and everyone knows that only your private key will unlock it. Anyone can take your padlock and lock funds up that they want to send to you.

![Lock it down, playing piano](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/402rb1vn779qu45sv9er.gif)

So in recap, you have the two keys. Your wallet generates both of them, and they are tied together. Your wallet keeps your private key a secret from everyone, while simultaneously sharing your public key with anyone who wants it.

Public keys let people lock funds up under your name. 

Private keys let you unlock said funds.

> Keep in mind that this is not a perfect analogy, and depending on the form of encryption you are using, these roles may be reversed. Just remember that either can lock, and whichever one locked it, the other one can unlock.

It is this mechanic where the phrase, "not your keys, not your coins" comes from.

If you are on an exchange that abstracts this wallet idea from you as a user, they are holding your keys. While this is not typically an issue, it is certainly a potential one. Many people who join blockchain technology for the decentralization and security aspect will not stomach such vulnerability.

Hopefully you now know a bit more about wallets and keys and why they are important. However, I am talking encryption here and I would be doing you a disservice to not talk about the underlying algorithms that make your keys safe from ne'er-do-wells.


A wallet has an address that is unique to itself, and is the address that people will see and use when sending you money. 

This mental model is pretty simple to visualize.
![Wallet Mental Model](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44932i22qva36vdkcbt1.png)

However, how we generate these keys and derive the address from them is a bit more complicated. This will become apparent as we start to build out the wallet. 

BUT FIRST!
# House Cleaning
As per usual, there is a bit of refactoring to do before we go further.

I think it's time you boot up ye-olde code editor to follow along!

### Cli Cleanup

I like my _main.go_ files to be a bit cleaner than what it looks like currently. I'm going to abstract all of this CLI business to its own folder and have it be its own package.

You will want to create a **cli** folder in your root directory, and inside of it make a _cli.go_ file.

![Folder Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ioopw98bznvoekidj71j.png)

We are going to move everything that is not inside our `main` function over to cli.go. The only thing to change here is you need to make the `run()` command start with a capital R to indicate to the go complier that it is a public method and can be called as such.

```go
//cli.go
func (cli *CommandLine) Run(){
// Big fat function here
}
```

That should leave your main.go file looking like this:
```go
//main.go
package main

import (
	"os"

	"github.com/nheingit/learnGo/cli"
)

func main() {
	defer os.Exit(0)

	cmd := cli.CommandLine{}

	cmd.Run()
}

```

Everything else should be in the _cli.go_ file, with a `package cli` up top to declare a new package for importing. With that done we can now move on to our transactions, since our wallet will be dealing with those.

### Transaction Cleanup
Most of your transaction implementation and logic will be left alone. I would like to pull out the Input and Output, along with their methods. You can place these in a new file _tx.go_
```go
//tx.go

package blockchain

type TxOutput struct {
	Value int
	
	PubKey string
}

//Important to note that each output is Indivisible.
//You cannot "make change" with any output.
//If the Value is 10, in order to give someone 5, we need to make two five coin outputs.

type TxInput struct {
	ID []byte
	Out int
	Sig string
	
}

func (in *TxInput) CanUnlock(data string) bool {
	return in.Sig == data
}

func (out *TxOutput) CanBeUnlocked(data string) bool {
	return out.PubKey == data
}

```

That should be everything for cleanup! Good job.
![SpongeBob Dusting Hands off](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xcrpte6by548fuj5vot7.gif)

# Wallet Building
First off, you will want to navigate over to your **Blockchain** folder and add a **wallet** folder. Inisde **wallet** You should make  _util.go_ and  _wallet.go_  files.

### Wallet.go
> Important to note that this will be a new package

As with any go file, we need to start with our package, and import statement. I will also go ahead and include the global variable we will be using. You won't really understand it at this point. That's okay, don't worry!

```go
//wallet.go
package wallet

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"log"

	"golang.org/x/crypto/ripemd160"
)

const (
	checksumLength = 4
	//hexadecimal representation of 0
	version = byte(0x00)
)

```

After our boilerplate, we will be creating.......You guessed it! A struct.

```go
//wallet.go
type Wallet struct {
	//ecdsa = eliptical curve digital signiture algorithm
	PrivateKey ecdsa.PrivateKey
	PublicKey  []byte
}
```
Now here you can see a data type that most of you will not recognize. `ecdsa.Privatekey` is a data type that has quite a bit going on behind the scenes. So much going on that I didn't want to just refer you to some other content. 

Here's a 5 minute video explaining public/private keys, and the underlying logic.

{% youtube Ry-bZHZs1Ks %}

Something not mentioned in the video is what the heck ECDSA stands for.

Elipitic Curve Digial Signature Algorithm. 



With that overhead out of the way, let us continue onto generating the keys.

```go
//wallet.go
func NewKeyPair() (ecdsa.PrivateKey, []byte) {
	curve := elliptic.P256()

	private, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		log.Panic(err)
	}

	pub := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...)

	return *private, pub
}
```


Fun Fact: This algorithm can generate potentially 10^77 number of keys. For a reference of how big that number is; it is currently estimated that there are approximately 10^80 number of atoms in the observable universe

![Mind Blown](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rolikw4phteo3pje8q06.gif)


We have a wallet, and some keys. This is where the magic happens. We now need to create a wallet address that uses our public key (created from our private key), and does a bunch of stuff to it, and then gives us an address where people can send us money!

Before you get into that, move over to your _util.go_ file for a moment to add some utility functions.

## Utility Functions
All you need to do here is add the encode and decode function for base58 algorithms.

```go
//util.go
package wallet

import (
	"log"

	"github.com/mr-tron/base58"
)

func base58Encode(input []byte) []byte {
	encode := base58.Encode(input)

	return []byte(encode)
}

func base58Decode(input []byte) []byte {
	decode, err := base58.Decode(string(input[:]))
	if err != nil {
		log.Panic(err)
	}
	return decode
}
```
The only thing funny in here is we do a bit of type casting to ensure that we recieve bytes, and return bytes. The `base.58Decode()` method expects us to give it a string. 

This portion is necessary because the base58 encode will give us a wallet address that is more readable. 

It ensures that we get a shorter output, and one that doesn't have the trouble of characters like: 0, O, l, I
> (zero, capital O, capital i, lowercase L) 

While we will typically be copy/pasting any wallet addresses, it is nice to be able to read them and type in if necessary.

To generate this wallet address, our key is going to go through a number of processes.  Here is a diagram of the pipeline our publickey will run through

![Blockchain key diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9opy2rf7o7g7nhx15g2.png)


Now that may be a lot to take in, so I'll break it down step-by-step for you here:
1. Take our public key (in bytes)
3. Run a SHA256 hash on it, then run a RipeMD160 hash on that hash. This is called our PublicHash
4. take our Publish Hash and append our Version (the global variable from earlier) to it. This is called the Versioned Hash
5. Run SHA256 on our Versioned Hash twice. Then take the first 4 bytes of that output. This is called the Checksum
6. Then we will add our Checksum to the end of our original Versioned Hash. We can call this FinalHash
7. Lastly, we will base58Encode our FinalHash. This is our wallet address!

Now that was quite a lot. You have to make sure your keys stay secure! Doing that while also giving people a public wallet address is a bit tricky, but this manages to do that.

Let me walk you through all of those steps, and make sure we have the functionality to do all of them.

#### Step 1
> Take our public key (in bytes)

You have your public key available already with the `NewKeyPair()` function.
#### Step 2
>Run a SHA256 hash on it, then run a RipeMD160 hash on that hash. This is called our PublicHash

We will make a function to do this.
```go
//wallet.go
func PublicKeyHash(publicKey []byte) []byte {
	hashedPublicKey := sha256.Sum256(publicKey)

	hasher := ripemd160.New()
	_, err := hasher.Write(hashedPublicKey[:])
	if err != nil {
		log.Panic(err)
	}
	publicRipeMd := hasher.Sum(nil)

	return publicRipeMd
}
```
#### Step 3
> take our Publish Hash and append our Version (the global variable from earlier) to it. This is called the Versioned Hash

This is achievable through simply calling an `append()` method on our hash, so this is doable already.
#### Step 4
> Run SHA256 on our Versioned Hash twice. Then take the first 4 bytes of that output. This is called the Checksum

We can make a Checksum function:
```go
//wallet.go
func Checksum(ripeMdHash []byte) []byte {
	firstHash := sha256.Sum256(ripeMdHash)
	secondHash := sha256.Sum256(firstHash[:])

	return secondHash[:checksumLength]
}
```

#### Step 5
>  Then we will add our Checksum to the end of our original Versioned Hash. We can call this FinalHash

Same as step 3, we will be able to append this to our hash, no function necessary here.

#### Step 6
> Lastly, we will base58Encode our FinalHash. This is our wallet address!

We just built out our utility function for this. It looks like we're ready to go. 

All that's left is to put it all together!

```go
//wallet.go
func (w *Wallet) Address() []byte {
	// Step 1/2
	pubHash := PublicKeyHash(w.PublicKey)
	//Step 3
	versionedHash := append([]byte{version}, pubHash...)
	//Step 4
	checksum := Checksum(versionedHash)
	//Step 5
	finalHash := append(versionedHash, checksum...)
	//Step 6
	address := base58Encode(finalHash)
	return address
}

```

The next thing will be a way to initialize a wallet. We can call this `MakeWallet()`

```go
//wallet.go
func MakeWallet() *Wallet {
	privateKey, publicKey := NewKeyPair()
	wallet := Wallet{privateKey, publicKey}
	return &wallet
}
```

That's everything for the _wallet.go_ file!


# Wallet(s)
Now that we have everything in place for a singular wallet, it would be a good idea to pluralize the functionality.

Start by making a _wallets.go_ file

The purpose of our _wallets.go_ file is to add persistence to our wallets, and to incorporate the CLI functions that we will be calling.

We won't be using badger for the persistence of this. We want to keep the blockchain logic and the wallet logic seperate. 

Here's how the begining of your file should look:
```go
//wallets.go
package wallet

import(
    "bytes"
  	"crypto/elliptic"
  	"encoding/gob"
  	"fmt"
  	"io/ioutil"
  	"log"
  	"os")

const walletFile = "./tmp/wallets.data"
```

Then we can add the `Wallets` struct.
```go
//wallets.go
type Wallets struct {
  Wallets map[string]*Wallet
}
```
Now we will need a way to save and load our wallets, using the global file we made at the top.

This will need to use the encoder and ioutil libaries, in addition to the elliptic libary. This is because we need to encode our wallets on the same elliptic curve that we used originally.

Here's the save file method:
```go
//wallets.go
func (ws *Wallets) SaveFile() {
  var content bytes.Buffer

  gob.Register(elliptic.P256())

  encoder := gob.NewEncoder(&content)
  err := encoder.Encode(ws)
  if err != nil {
    log.Panic(err)
  }

  err = ioutil.WriteFile(walletFile, content.Bytes(), 0644)
  if err != nil {
    log.Panic(err)
  }
}
```

Then the load will be pretty much the same thing, but opposite, in that we're using the decoder instead of the encoder

```go
//wallets.go
func (ws *Wallets) LoadFile() error {
  if _, err := os.Stat(walletFile); os.IsNotExist(err) {
    return err
  }

  var wallets Wallets

  fileContent, err := ioutil.ReadFile(walletFile)

  gob.Register(elliptic.P256())
  decoder := gob.NewDecoder(bytes.NewReader(fileContent))
  err = decoder.Decode(&wallets)
  if err != nil {
    return err
  }

  ws.Wallets = wallets.Wallets

  return nil
}
```
Now we need a way to create a wallet. This will create a wallet using the `MakeWallet()` method that we created earlier, and then adding it to the list of wallets.

```go
//wallets.go
func CreateWallets() (*Wallets, error) {
  wallets := Wallets{}
  wallets.Wallets = make(map[string]*Wallet)
  err := wallets.LoadFile()

  return &wallets, err
}
```

Now we don't want to create a new `Wallets{}` struct every time, so we will add a way to append to our `Wallets{}` struct.

```go
//wallets.go
func (ws *Wallets) AddWallet() string {
  wallet := MakeWallet()
  address := fmt.Sprintf("%s", wallet.Address())

  ws.Wallets[address] = wallet

  return address
}
```
The last things we need is a way to look up a wallet by its address, and a way to list ALL of the wallets' addresses.

Here's the former:
```go
//wallets.go
func (ws Wallets) GetWallet(address string) Wallet {
  return *ws.Wallets[address]
}
```

and the latter:
```go
//wallets.go
func (ws *Wallets) GetAllAddresses() []string {
  var addresses []string

  for address := range ws.Wallets {
    addresses = append(addresses, address)
  }
  return addresses
}
```
That's everything we need for our _wallets.go_ file. Now we can add the functionality to our cli.


# CLI Implementation
First you will want to add your wallet package into your imports:
You will need to adjust yours based off of whatever you initialized in your _go.mod_ file. This is mine.
```go
//cli.go
import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime"
	"strconv"

	"github.com/nheingit/learnGo/blockchain"
	"github.com/nheingit/learnGo/blockchain/wallet" // This is the new one

)

```
Then we can update the `printUsage` method to add our new commands
```go
//cli.go
func (cli *CommandLine) printUsage() {
	// ...
	// ...
	// Rest of commands above
	fmt.Println("createwallet - Creates a new wallet")
	fmt.Println("listaddresses - Lists the addresses in the wallet file")
}
```
Then to add the two methods that our CLI will call.

First up the `listAddresses()` method
```go
//cli.go
func(cli *CommandLine) listAddresses() {
	wallets, _ := wallet.CreateWallets()
	addresses := wallets.GetAllAddresses()

	for _, address := range addresses {
		fmt.Println(address)
	}

}
```
Second, the `createWallet()` method.

```go
//cli.go
func(cli *CommandLine) createWallet() {
	wallets, _ := wallet.CreateWallets()
	address := wallets.AddWallet()
	wallets.SaveFile()

	fmt.Printf("New address is: %s\n", address)

}

```

Next roadblock is our `Run()` method. We will need to add the flags, the switch statements, and then the if statements.

I'm going to dump the entire method out right here, and comment where you need to look, as I think doing these one at a time would be much too long for not much reason.

```go
//cli.go
func (cli *CommandLine) Run() {
	cli.validateArgs()

	getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError)
	createBlockchainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError)
	sendCmd := flag.NewFlagSet("send", flag.ExitOnError)
	printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError)
	createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError) // this Cmd is new
	listAddressesCmd := flag.NewFlagSet("listaddresses", flag.ExitOnError) // this Cmd is new

	getBalanceAddress := getBalanceCmd.String("address", "", "The address to get balance for")
	createBlockchainAddress := createBlockchainCmd.String("address", "", "The address to send genesis block reward to")
	sendFrom := sendCmd.String("from", "", "Source wallet address")
	sendTo := sendCmd.String("to", "", "Destination wallet address")
	sendAmount := sendCmd.Int("amount", 0, "Amount to send")

	switch os.Args[1] {
	case "getbalance":
		err := getBalanceCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	case "createblockchain":
		err := createBlockchainCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	case "printchain":
		err := printChainCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	case "send":
		err := sendCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	case "listaddresses": // this case statement is new
		err := listAddressesCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	case "createwallet": // this case statement is new
		err := createWalletCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	default:
		cli.printUsage()
		runtime.Goexit()
	}

	if getBalanceCmd.Parsed() {
		if *getBalanceAddress == "" {
			getBalanceCmd.Usage()
			runtime.Goexit()
		}
		cli.getBalance(*getBalanceAddress)
	}

	if createBlockchainCmd.Parsed() {
		if *createBlockchainAddress == "" {
			createBlockchainCmd.Usage()
			runtime.Goexit()
		}
		cli.createBlockChain(*createBlockchainAddress)
	}

	if printChainCmd.Parsed() {
		cli.printChain()
	}

	if sendCmd.Parsed() {
		if *sendFrom == "" || *sendTo == "" || *sendAmount <= 0 {
			sendCmd.Usage()
			runtime.Goexit()
		}

		cli.send(*sendFrom, *sendTo, *sendAmount)
	}
	if listAddressesCmd.Parsed() { // this if statement is new
		cli.listAddresses()
	}
	if createWalletCmd.Parsed(){ // this if statement is new
		cli.createWallet()
	}
}
```

With this change, you should now be able to boot up the command line  with `go run main.go`
and be greeted with this:
```
Usage: 
getbalance -address ADDRESS - get balance for ADDRESS

createblockchain -address ADDRESS creates a blockchain and rewards the mining fee

printchain - Prints the blocks in the chain

send -from FROM -to TO -amount AMOUNT - Send amount of coins from one address to another

createwallet - Creates a new wallet

listaddresses - Lists the addresses in the wallet file
```
You can use `go run main.go createwallet` and get an output that looks something like this:
```
New address is: 1HMHzfY8RsNaH2JG5cNLLrZk6UBGnFEmnV
```

then finally `go run main.go listaddresses` after running `createwallet` a few times, will look something like this:
```
1HSJhCX9y6YhyPffG8vMXphfYZABJ3aaK9
15kR566wYiNDf8dCsJG91JfrVgCiQqTsFC
1M76k9VZdhvmxMong4yZQ9SqZBVZiQLnfS
1NTBAtCZjiWCXorNP45S19gyzVtdwYzV6T
```
That's everything for this portion!

You are done building!

You may have noticed that the interaction between our wallets and our transactions aren't integrated. Currently the wallet address is just an arbitrary string. In the next module we will incorporate the two, and add in the signature functionality of the wallets. 

As always I hope you learned a thing or two, and I hope to see you in the next module!