Building a Blockchain in Go PT: IV - Transactions
Tags: tutorial, blockchain, go
Published: 2021-04-15 16:58:08



>You can find the code [here](https://replit.com/@nheingit/GolangBlockChain-4#main.go)

Hello everyone!

Last I left off I was adding the ability  to print out the chain that we have stored in the database. I would like to start approaching something that people would find a bit more recognizable as a blockchain. That would be crypto! Many people that aren't in the thick of things would tell you that bitcoin and blockchain are the same thing. So to take a step into the mainstream I would like to add wallets.

Wallets have many moving parts to them, so we are looking at one piece of the puzzle specifically. That will be transactions.

# Building Transactions

A wallet module is a bit complicated. I thought transactions would be a good place to start. In order to have transactions, we need to have a transaction struct. We also need a way to generate some "coins". This allows us to actually insert something into the transaction. As I talked about earlier in the series, bitcoin "miners" get fees for doing the expensive work of blockchain mining. We can start there.

### The `Transaction` struct

So to start things out, as in our previous chapters, we will make a new file in our **Blockchain** folder called _transaction.go_

```go
//transaction.go
type Transaction struct {
	ID      []byte
	Inputs  []TxInput
	Outputs []TxOutput
}
```
Looks pretty straightforward right? A transaction should have a unique ID to differentiate itself from the many other transactions. It goes TO someone, and it comes FROM someone. That means we need  `Inputs` and `Outputs` fields.

Don't get too ahead of yourself though, you'll notice those aren't primitive data types. We are gonna have to make those inputs and outputs ourselves. Let's see what that looks like.

```go
type TxOutput struct {
	Value int
	//Value would be representative of the amount of coins in a transaction
	PubKey string
	//The Pubkey is needed to "unlock" any coins within an Output. This indicated that YOU are the one that sent it.
	//You are indentifiable by your PubKey
	//PubKey in this iteration will be very straightforward, however in an actual application this is a more complex algorithm
}
//TxInput is representative of a reference to a previous TxOutput
type TxInput struct {
	ID []byte
	//ID will find the Transaction that a specific output is inside of
	Out int
	//Out will be the index of the specific output we found within a transaction.
	//For example if a transaction has 4 outputs, we can use this "Out" field to specify which output we are looking for
	Sig string
	//This would be a script that adds data to an outputs' PubKey
	//however for this tutorial the Sig will be indentical to the PubKey.
}
```
With that piece finished we can get onto initializing our first transaction.

### Coinbase Transaction
Not THAT [coinbase](https://www.coinbase.com/). The first transaction in a block is called a Coinbase. Our first transaction will be when a new block is "mined" as it were. So upon our `Genesis` call, we will want to add some coins inside of the block to be rewarded to whoever is fortunate enough to crack the code. Similar to our `Blocks`, we don't have any previous transactions to point back to. This means we will need to set an empty `TxInput` for our first transaction. 

The following function should incorporate everything I just mentioned above.

```go
//transaction.go

func CoinbaseTx(toAddress, data string) *Transaction {
	if data == "" {
		data = fmt.Sprintf("Coins to %s", toAddress)
	}
	//Since this is the "first" transaction of the block, it has no previous output to reference.
	//This means that we initialize it with no ID, and it's OutputIndex is -1
	txIn := TxInput{[]byte{}, -1, data}

	txOut := TxOutput{reward, toAddress}

	tx := Transaction{nil, []TxInput{txIn}, []TxOutput{txOut}}

	return &tx

}
```

You may get a warning because you are referencing `reward` which is undefined currently. Go to the top of your file, and initialize a constant global variable named `reward` with a value of 100.
>`const reward = 100`

Great! We have the goody egg on standby.

### Utility functions.

I won't go over these too much as I believe they explain themselves quite nicely. 
>You are **reading** the code right?


`SetID` will encode and hash our `Transactions` `ID` field.  We then use the `CanUnlock` and `CanBeUnlocked` methods to check that the `Sig` and the `PubKey` are correct. The last one is checking a transaction to see if it was a coinbase transaction.

```go
//transaction.go

func (tx *Transaction) SetID() {
	var encoded bytes.Buffer
	var hash [32]byte

	encoder := gob.NewEncoder(&encoded)
	err := encoder.Encode(tx)
	Handle(err)

	hash = sha256.Sum256(encoded.Bytes())
	tx.ID = hash[:]

}

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

func (tx *Transaction) IsCoinbase() bool {
	//This checks a transaction and will only return true if it is a newly minted "coin"
	return len(tx.Inputs) == 1 && len(tx.Inputs[0].ID) == 0 && tx.Inputs[0].Out == -1
}
```

I think that is everything we need for transaction for now.

Let's go add it to our `Blocks`!


# Implementing Transactions

We are done with our _transaction.go_ file for now. Let us move over to our _block.go_ file. 
Since we now have transactions, this will replace our `Data` field in our `Block` struct.
```go
//block.go
type Block struct {
	Hash     []byte
	Transactions []*Transaction
	PrevHash []byte
	Nonce    int
}
```
With that done you will notice your entire project becomes inundated with errors. 

Do not worry, we will be working through our refactoring, and hopefully when we're done everything will compile!

### Updating Methods
In our `CreateBlock` method, we will want to change the `Data string` in our parameters. Instead we will put in `txs []*Transaction`. 

```go
//block.go
func CreateBlock(txs []*Transaction, prevHash []byte) *Block {
	block := &Block{[]byte{}, txs, prevHash, 0}
	pow := NewProofOfWork(block)
	nonce, hash := pow.Run()

	block.Hash = hash[:]
	block.Nonce = nonce

	return block
}
```


With that out of the way, we  meander our way to the `Genesis` function. We need to add an empty `Transaction` to our `Genesis` block.
```go
//block.go
func Genesis(coinbase *Transaction) *Block {
	return CreateBlock([]*Transaction{coinbase}, []byte{})
}
```
### Data Hashing

The last thing we have to do is build a method that takes all of the transactions existing in a block and hashes them.
```go
//block.go
func (b *Block) HashTransactions() []byte {
	var txHashes [][]byte
	var txHash [32]byte

	for _, tx := range b.Transactions {
		txHashes = append(txHashes, tx.ID)
	}
	txHash = sha256.Sum256(bytes.Join(txHashes, []byte))

	return txHash[:]
}
```
That should be all of the changes we need to make in our _block.go_ file for the time being. 

Time to hop over to _proof.go_!

# Proof of Work Changes

This one should be super quick, we just need to change the `InitData` method. Since it calls to `Block.Data` which no longer exists. However, this is where our previous function comes in handy. Since this method is expecting everything to be in bytes, we can call our new function. Our refactored `InitData` method should look like this.

```go
//proof.go
func (pow *ProofOfWork) InitData(nonce int) []byte {
	data := bytes.Join(
		[][]byte{
			pow.Block.PrevHash,
			pow.Block.HashTransactions(), // THIS IS THE LINE WE CHANGED
			toHex(int64(nonce)),
			toHex(int64(Difference)),
		},
		[]byte{},
	)
	return data
}
```
Great job! We're all done here.


We can now move onto our last file in the **blockchain** folder, which is _blockchain.go_.

# Blockchain Changes
Alrighty, back to the fun stuff we were doing with the database before!

Moving forward, we need to add a few more global constants at the top of our _blockchain.go_ file. We want to add a `dbFile`, and `genesisData`. so right under our imports we want to initialize our constants like so:
```go
//blockchain.go
const (
	dbPath = "./tmp/blocks"
	
	// This can be used to verify that the blockchain exists
	dbFile = "./tmp/blocks/MANIFEST" 
	
	// This is arbitrary data for our genesis block
	genesisData = "First Transaction from Genesis" 
)
```

You may have noticed when you finished part III, that whenever you ran the code, in the **/tmp/blocks** folder that it creates a Manifest file. This is what we are setting the `dbFIle` to. 

It allows us  to check if a blockchain already exists or not.

The `genesisData` is simply some data to provide our genesis block so it won't be empty.

We will need to Breakup our `InitBlockChain` function so we can more easily reference our transactions using the cli later. Currently there a large if/else block, that essentially checks  if we've already got a database, and responds conditionally.

We will break this up into an `InitBlockChain` and `ContinueBlockChain` function. We can break this function cleanly at the if/else junction. The logic that is inside each portion will be placed into its own function. The only caveat is we will need to duplicate the extra code that is required to make database transactions.

Before I show you what each function looks like, I would like to add a quick utility that we can use to check if the blockchain exists already.
```go
//blockchain.go

//DBexists checks to see if we've initialized a database
func DBexists(db) bool {
	if _, err := os.Stat(db); os.IsNotExist(err) {
		return false
	}
	return true
}
```
With this we can pass the `dbFile` constant to the function, and it will give us a Boolean value in return.

Alrighty, back to the splitting of our `initBlockChain` function. As stated before, we will split the if/else logic into its own function. One will handle if the database exists, and one will handle if it doesn't exist.

The main difference being, if the database/blockchain does not exist, we need to add the `CoinbaseTx`. 

We  want to get some transaction action goin' on!

Enough explanation, SHOW ME THE CODE!

```go
//blockchain.go
func InitBlockChain(address string) *BlockChain {
	var lastHash []byte

	if DBexists(dbFile) {
		fmt.Println("blockchain already exists")
		runtime.Goexit()
	}

	opts := badger.DefaultOptions(dbPath)
	db, err := badger.Open(opts)
	Handle(err)

	err = db.Update(func(txn *badger.Txn) error {
		
		cbtx := CoinbaseTx(address, genesisData)
		genesis := Genesis(cbtx)
		fmt.Println("Genesis Created")
		err = txn.Set(genesis.Hash, genesis.Serialize())
		Handle(err)
		err = txn.Set([]byte("lh"), genesis.Hash)

		lastHash = genesis.Hash

		return err

	})
```

So that's the first one. 

Here's the `ContinueBlockChain` function.

```go
//blockchain.go

//I Know we don't reference address anywhere in here. Keep it anyway.
func ContinueBlockChain(address string) *BlockChain {
	if DBexists(dbFile) == false {
		fmt.Println("No blockchain found, please create one first")
		runtime.Goexit()
	}

	var lastHash []byte

	opts := badger.DefaultOptions(dbPath)
	db, err := badger.Open(opts)
	Handle(err)

	err = db.Update(func(txn *badger.Txn) error {
		item, err := txn.Get([]byte("lh"))
		Handle(err)
		err = item.Value(func (val []byte) error {
			lastHash = val
			return nil
		})
		handle(err)
		return err
	})
	Handle(err)

	chain := BlockChain{lastHash, db}
	return &chain
}
```

The main difference, is now the `InitBlockChain` has a parameter that we can pass an argument to. This argument will be the address of the person that mined the block.
Now that we have done that, we will be able to get to the good stuff.

# Adding Transactions

So with those two functions split up we will have a way to implement the CLI to check the balance of an account as well as being able to send coins from one account to another.

You may have noticed that while an `TxOutput` is representative of some action between two addresses, `TxInput` is merely a reference to a previous `TxOutput`.

This may not be immeaditely apparent, but because of this we are able to figure out the balance of an account. This is because we can check for all of the outputs that an account has linked to it, and then check all of the inputs. Whichever outputs do not have an input pointing to it will be spendable.

Let me say that again. Transactions that have outputs, but no inputs pointing to them are spendable. We will call these Unspent Transactions.

Let's build that out.

### Finding Unspent Transactions
>Remember when I said I wouldn't be teaching you go?
This may be one of those moments where you have to pause and read some other material for a bit if you aren't quite familiar with everything yet.
>
>However, I will send you along with some relevant resources. 
>
>I use this site all the time. Many people think you go through it once and that's it. That couldn't be farther from the truth. I encourage you do run through this one multiple times and refer back to it often. 
>
>Here it is  https://gobyexample.com/
>
>This is a good place to start for [maps](https://gobyexample.com/maps).
>
>Here is a resource for [labesl](https://medium.com/golangspec/labels-in-go-4ffd81932339) as well. 

```go
//blockchain.go
func (chain *BlockChain) FindUnspentTransactions(address string) []Transaction {
	var unspentTxs []Transaction

	spentTXNs := make(map[string][]int)

	iter := chain.Iterator()

	for {
		block := iter.Next()

		for _, tx := range block.Transactions {
			txID := hex.EncodeToString(tx.ID)

		Outputs:
			for outIdx, out := range tx.Outputs {
				if spentTXNs[txID] != nil {
					for _, spentOut := range spentTXNs[txID] {
						if spentOut == outIdx {
							continue Outputs
						}
					}
				}
				if out.CanBeUnlocked(address){
					unspentTxs = append(unspentTxs, *tx)
				}
			}
			if tx.IsCoinbase() == false {
				for _, in := range tx.Inputs {
					if in.CanUnlock(address) {
						inTxID := hex.EncodeToString(in.ID)
						spentTXNs[inTxID] = append(spentTXNs[inTxID], in.Out)
					}
			}
		}
		if len(block.PrevHash) == 0 {
			break
		}
	}
	return unspentTxs

}

```
This is a lot to unpack!

We can break this function down into a few parts.

We need to loop through our entire chain, and we can do that like we did before using the `chain.Iterator().Next()`  method.

* We want to loop through each blocks `Transactions`.

* As we loop through the `Transactions`, we also want to take a look at all of the `Outputs`  that each one has. 

* If at anypoint during this we find a `txID` we know this `Output` has been spent. 

* At this point we hit the `continue Outputs` line and continue to our next conditional.

* We now loop through the outputs that are available for spending. 
>We know they are spendable because they have no inputs associated with them

Now we can check if these `Outputs` can be unlocked. 

Using our `CanBeUnlocked` method, we just need to pass in the address. 

If that returns true we can add it to our `unspentTxs` variable that we declared at the top of the method.

With all of that is done; we can move on to the next portion of the method.

>Keep in mind that we are still looping through each blocks transactions at this point. 

Now we check if the Transaction is a coinbase transaction. 

If it isn't, we can look through all of the Inputs.

If an input has a matching address, we can add the Input's ID to the `spentTXNs` map that we were checking our outputs against above.

At the end, return all of the unspent transactions that we gathered for the particular address.

Congradulations! We're all done here.

### Finding Unspent Transaction Outputs

Luckily that above function is the most complicated thing we will be dealing with. Now that we have a way to find all of the unspent transactions, we can narrow it down a bit and look for the unspent outputs.

```go
//blockchain.go
func (chain *BlockChain) FindUTXO(address string) []TxOutput {
	var UTXOs []TxOutput
	unspentTransactions := chain.FindUnspentTransactions(address)
	for _, tx := range unspentTransactions {
		for _, out := range tx.Outputs {
			if CanBeUnlocked(address) {
				UTXOs = append(UTXOs, out
			}
		}
	}

	return UTXOs
}
```

Loop through all of the unspent transactions and see if we can unlock the outputs. 

Add them all to an array and return that array of `TxOutput`s

### Finding Unspent Transaction Outputs That Are Spendable
Now to the fun bit! we have narrowed down our search into the thing we actually care about. Spending money! 

Currently the only way to make a transaction is to be a coinbase transaction which defeats the purpose of the whole "blockchain" thing we have goin' on. What point is there in having money if you can only make more by mining it? 

We should be able to spread the wealth. In order to do that we need to find all of the spendable outputs. Just because there is an output that hasn't been spent, doesn't mean that ANYONE can spend it. Only the person with the key has those honors.

The following will be a function that takes an account's address, and the amount that we would like to spend. It returns a tuple that contains the amount we can spend, and a map of the aggregated outputs that can make that happen.
```go
//blockchain.go
func (chain *BlockChain) FindSpendableOutputs(address string, amount int) (int, map[string][]int) {
	unspentOuts := make(map[string][]int)
	unspentTxs := chain.FindUnspentTransactions(address)
	accumulated := 0

Work:
	for _, tx := range unspentTxs {
		txID := hex.EncodeToString(tx.ID)
		for outIdx, out := range tx.Outputs {
			if out.CanBeUnlocked(address) && accumulated < amount {
				accumulated += out.Value
				unspentOuts[txID] = append(unspentOuts[txID], outIdx)

				if accumulated >= amount {
					break Work
				}
			}
		}
	}
	return accumulated, unspentOuts
}
```

Alrighty, with that done we can make the last change in our _blockchain.go_ file.


Our `AddBlock` method is still using `data` as a paramter, and passes it down to `createBlock` as an argument. We need to change both of those to be transactions. The new function will be shown below. Try not to just copy/paste everything. Look for what changed and why! Understanding the flow of data in your program is critical.

```go
//blockchain.go
//DATA STRING ---> TRANSACTIONS []*TRANSACTION
func (chain *BlockChain) AddBlock(transactions []*Transaction) {
	var lastHash []byte

	err := chain.Database.View(func(txn *badger.Txn) error {
		item, err := txn.Get([]byte("lh"))
		Handle(err)
		err = item.Value(func(val []byte) error {
			lastHash = val
			return nil
		})
		Handle(err)
		return err
	})
	Handle(err)

	newBlock := CreateBlock(transactions, lastHash) //THIS LINE CHANGED
	err = chain.Database.Update(func(transaction *badger.Txn) error {
		err := transaction.Set(newBlock.Hash, newBlock.Serialize())
		Handle(err)
		err = transaction.Set([]byte("lh"), newBlock.Hash)

		chain.LastHash = newBlock.Hash
		return err
	})
	Handle(err)
}
```

We can now save our blockchain file with no more errors and move onto the rest of our program.

# Spending Coins!
With all of our data running smoothly through our blockchain, we can go back to our _transaction.go_ file and add our last function before moving onto our CLI.

We need this function to do a few things:
1. Find Spendable Outputs
2. Check if we have enough money to send the amount that we are asking
3. If we do, make inputs that point to the outputs we are spending
4. If there is any leftover money, make new outputs from the difference.
5. Initialize a new transaction with all the new inputs and outputs we made
6. Set a new ID, and return it.

Let's get typing!
```go
//transaction.go
func NewTransaction(from, to string, amount int, chain *BlockChain) *Transaction {
	var inputs []TxInput
	var outputs []TxOutput
	
	//STEP 1
	acc, validOutputs := chain.FindSpendableOutputs(from, amount)
	
	//STEP 2
	if acc < amount {
		log.Panic("Error: Not enough funds!")
	}
	
	//STEP 3
	for txid, outs := range validOutputs {
		txID, err := hex.DecodeString(txid)
		Handle(err)

		for _, out := range outs {
			input := TxInput{txID, out, from}
			inputs = append(inputs, input)
		}
	}
	
	outputs = append(outputs, TxOutput{amount, to})
	
	//STEP 4
	if acc > amount {
		outputs = append(outputs, TxOutput{acc - amount, from})
	}
	
	//STEP 5
	tx := Transaction{nil, inputs, outputs}
	//STEP 6
	tx.SetID()

	return &tx
}
```
Awesome! That's all we need to complete the _transaction.go_ file.

# Updating The CLI
Okay, so we're all done with the heavy lifting, now we just have some updating of functions.

Moving to _main.go_

Let's start by simplifying our lives a bit.

We're going to remove the blockchain field within our `CommandLine` struct.

It should now look like this:
```go
type CommandLine struct {}
```

Now to update our `printUsage` method. 

We will no longer support the `addBlock` method. We can delete that whole function.

Afterwards we will want to add 3 more functions.

1. getbalance
2. createblockchain
3. send
 
 That means we need to tell our users how this cli operates. The new `printUsage` should look like:
 ```go
 //main.go
 func (cli \*CommandLine) printUsage() {

 fmt.Println("Usage: ")

 fmt.Println("getbalance -address ADDRESS - get balance for ADDRESS")

 fmt.Println("createblockchain -address ADDRESS creates a blockchain and rewards the mining fee")

 fmt.Println("printchain - Prints the blocks in the chain")

 fmt.Println("send -from FROM -to TO -amount AMOUNT - Send amount of coins from one address to another")

}
```

After this go to `printChain` and remove the line that was displaying the `data` field of the block, as `data` no longer exists.

Now to create the new methods that we outlined in our `printUsage` method.

first `createBlockChain`:
 
 ```go
 //main.go
 
 func (cli *CommandLine) createBlockChain(address string) {
	newChain := blockchain.InitBlockChain(address)
	newChain.Database.Close()
	fmt.Println("Finished creating chain")
}

```

WIth that out of the way we can move to `getBalance`

```go
//main.go
func (cli *CommandLine) getBalance(address string) {
	chain := blockchain.ContinueBlockChain(address)
	defer chain.Database.Close()

	balance := 0
	UTXOs := chain.FindUTXO(address)

	for _, out := range UTXOs {
		balance += out.Value
	}

	fmt.Printf("Balance of %s: %d\n", address, balance)
}
```

Fantastic, moving through at a blazing pace! Time to send money!
```go
//main.go

func (cli *CommandLine) send(from, to string, amount int) {
	chain := blockchain.ContinueBlockChain(from)
	defer chain.Database.Close()

	tx := blockchain.NewTransaction(from, to, amount, chain)

	chain.AddBlock([]*blockchain.Transaction{tx})
	fmt.Println("Success!")
}
```


Now we have to update all of our CLI flags and strings inside the `run` method. Feel free to copy paste this bit honestly. It was very painful to write out.

```go
//main.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)

	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)
		}
	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)
	}
}
```

The very last thing to do is remove the database portion of the `main` command!

The new one should look like this:

```go
func main() {
	defer os.Exit(0)
	cli := CommandLine{}
	cli.run()
```
Now we're all done!  

I won't hold your hand through how to use this as I'm sure with the wonderful usage flags we made you'll be able to figure it out. The only thing to be aware of is if you have an existing chain in your **tmp/blocks** folder you will need to delete that before using this new fancy stuff as we can only have one chain at a time currently.

Please leave any questions you may have in the comments and I'll try my best to help you out!

Until next time!