Introduce
In the previous section, we learned the basics of Transaction & DB State. If you haven’t seen it yet, you can check it out.
Github: https://github.com/lequocbinh04/the-simple-blockchain
Continue the story
Tuesday evening, March 26.
On a chilly evening while John was happily stressing out with his favorite game, John accidentally typed rm -rf /.
, everything on the computer has disappeared cleanly, including genesis.json
and state.json
have also been discolored.
John, a senior developer, is extremely angry and yells at the parents of his computer, but he doesn’t panic when he doesn’t have a backup for his computer, because he already has something better: a note the entire transaction. Now his job is to do the transactions again and his db will be restored.
He was very interested in this option, so he decided to develop his MVP database: For each bar activity (e.g. payment of water bill), it must be recorded inside the database. data of the blockchain.
Each customer recorded in the DB is an Account data type:
1 2 | <span class="token keyword">type</span> Account <span class="token builtin">string</span> |
Each Transaction (TX – data change in DB) will have 4 attributes: from, to, value and data. The data attribute is a value that is the data of that tx (e.g. “reward” represents the transaction that is a reward to John for inventing TBB and increasing the initial total supply of TBB).
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">type</span> Tx <span class="token keyword">struct</span> <span class="token punctuation">{</span> From Account <span class="token string">`json:"from"`</span> To Account <span class="token string">`json:"to"`</span> Value <span class="token builtin">uint</span> <span class="token string">`json:"value"`</span> Data <span class="token builtin">string</span> <span class="token string">`json:"data"`</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> t Tx <span class="token punctuation">)</span> <span class="token function">IsReward</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token builtin">bool</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> t <span class="token punctuation">.</span> Data <span class="token operator">==</span> <span class="token string">"reward"</span> <span class="token punctuation">}</span> |
Genesis DB is still a json file:
1 2 3 4 5 6 7 8 | <span class="token punctuation">{</span> <span class="token string">"genesis_time"</span> <span class="token punctuation">:</span> <span class="token string">"2019-03-18T00:00:00.000000000Z"</span> <span class="token punctuation">,</span> <span class="token string">"chain_id"</span> <span class="token punctuation">:</span> <span class="token string">"the-blockchain-bar-ledger"</span> <span class="token punctuation">,</span> <span class="token string">"balances"</span> <span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"john"</span> <span class="token punctuation">:</span> <span class="token number">1000000</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
And every transaction, formerly written on paper, he now writes in the file tx.db (one json file each line is the details of tx)
1 2 3 4 5 6 | <span class="token punctuation">{</span> <span class="token string">"from"</span> <span class="token punctuation">:</span> <span class="token string">"john"</span> <span class="token punctuation">,</span> <span class="token string">"to"</span> <span class="token punctuation">:</span> <span class="token string">"john"</span> <span class="token punctuation">,</span> <span class="token string">"value"</span> <span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">,</span> <span class="token string">"data"</span> <span class="token punctuation">:</span> <span class="token string">""</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token string">"from"</span> <span class="token punctuation">:</span> <span class="token string">"john"</span> <span class="token punctuation">,</span> <span class="token string">"to"</span> <span class="token punctuation">:</span> <span class="token string">"john"</span> <span class="token punctuation">,</span> <span class="token string">"value"</span> <span class="token punctuation">:</span> <span class="token number">700</span> <span class="token punctuation">,</span> <span class="token string">"data"</span> <span class="token punctuation">:</span> <span class="token string">"reward"</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token string">"from"</span> <span class="token punctuation">:</span> <span class="token string">"john"</span> <span class="token punctuation">,</span> <span class="token string">"to"</span> <span class="token punctuation">:</span> <span class="token string">"jack"</span> <span class="token punctuation">,</span> <span class="token string">"value"</span> <span class="token punctuation">:</span> <span class="token number">2000</span> <span class="token punctuation">,</span> <span class="token string">"data"</span> <span class="token punctuation">:</span> <span class="token string">""</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token string">"from"</span> <span class="token punctuation">:</span> <span class="token string">"john"</span> <span class="token punctuation">,</span> <span class="token string">"to"</span> <span class="token punctuation">:</span> <span class="token string">"john"</span> <span class="token punctuation">,</span> <span class="token string">"value"</span> <span class="token punctuation">:</span> <span class="token number">100</span> <span class="token punctuation">,</span> <span class="token string">"data"</span> <span class="token punctuation">:</span> <span class="token string">"reward"</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token string">"from"</span> <span class="token punctuation">:</span> <span class="token string">"jack"</span> <span class="token punctuation">,</span> <span class="token string">"to"</span> <span class="token punctuation">:</span> <span class="token string">"john"</span> <span class="token punctuation">,</span> <span class="token string">"value"</span> <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">,</span> <span class="token string">"data"</span> <span class="token punctuation">:</span> <span class="token string">""</span> <span class="token punctuation">}</span> |
And the most important part, containing the entire business login will be State
1 2 3 4 5 6 | <span class="token keyword">type</span> State <span class="token keyword">struct</span> <span class="token punctuation">{</span> Balances <span class="token keyword">map</span> <span class="token punctuation">[</span> Account <span class="token punctuation">]</span> <span class="token builtin">uint</span> txMempool <span class="token punctuation">[</span> <span class="token punctuation">]</span> Tx dbFile <span class="token operator">*</span> os <span class="token punctuation">.</span> File <span class="token punctuation">}</span> |
State
will save all user balances, transaction history, who transfers TBB tokens to whom. State
starts by reading init data from genesis.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">func</span> <span class="token function">NewStateFromDisk</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">(</span> <span class="token operator">*</span> State <span class="token punctuation">,</span> <span class="token builtin">error</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// get current working directory</span> cwd <span class="token punctuation">,</span> err <span class="token operator">:=</span> os <span class="token punctuation">.</span> <span class="token function">Getwd</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">,</span> err <span class="token punctuation">}</span> genFilePath <span class="token operator">:=</span> filepath <span class="token punctuation">.</span> <span class="token function">Join</span> <span class="token punctuation">(</span> cwd <span class="token punctuation">,</span> <span class="token string">"database"</span> <span class="token punctuation">,</span> <span class="token string">"genesis.json"</span> <span class="token punctuation">)</span> gen <span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">loadGenesis</span> <span class="token punctuation">(</span> genFilePath <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">,</span> err <span class="token punctuation">}</span> balances <span class="token operator">:=</span> <span class="token function">make</span> <span class="token punctuation">(</span> <span class="token keyword">map</span> <span class="token punctuation">[</span> Account <span class="token punctuation">]</span> <span class="token builtin">uint</span> <span class="token punctuation">)</span> <span class="token keyword">for</span> account <span class="token punctuation">,</span> balance <span class="token operator">:=</span> <span class="token keyword">range</span> gen <span class="token punctuation">.</span> Balances <span class="token punctuation">{</span> balances <span class="token punctuation">[</span> account <span class="token punctuation">]</span> <span class="token operator">=</span> balance <span class="token punctuation">}</span> |
After successfully loading the user’s initial balance from genesis.json
we will sequentially execute the entire transaction in tx.db
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | txDbFilePath <span class="token operator">:=</span> filepath <span class="token punctuation">.</span> <span class="token function">Join</span> <span class="token punctuation">(</span> cwd <span class="token punctuation">,</span> <span class="token string">"database"</span> <span class="token punctuation">,</span> <span class="token string">"tx.db"</span> <span class="token punctuation">)</span> f <span class="token punctuation">,</span> err <span class="token operator">:=</span> os <span class="token punctuation">.</span> <span class="token function">OpenFile</span> <span class="token punctuation">(</span> txDbFilePath <span class="token punctuation">,</span> os <span class="token punctuation">.</span> O_APPEND <span class="token operator">|</span> os <span class="token punctuation">.</span> O_RDWR <span class="token punctuation">,</span> <span class="token number">0600</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">,</span> err <span class="token punctuation">}</span> scanner <span class="token operator">:=</span> bufio <span class="token punctuation">.</span> <span class="token function">NewScanner</span> <span class="token punctuation">(</span> f <span class="token punctuation">)</span> state <span class="token operator">:=</span> <span class="token operator">&</span> State <span class="token punctuation">{</span> balances <span class="token punctuation">,</span> <span class="token function">make</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> Tx <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> f <span class="token punctuation">}</span> <span class="token comment">// Iterate over each the tx.db file's line</span> <span class="token keyword">for</span> scanner <span class="token punctuation">.</span> <span class="token function">Scan</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> err <span class="token operator">:=</span> scanner <span class="token punctuation">.</span> <span class="token function">Err</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">,</span> err <span class="token punctuation">}</span> <span class="token comment">// Convert JSON encoded TX into an object (struct)</span> <span class="token keyword">var</span> tx Tx json <span class="token punctuation">.</span> <span class="token function">Unmarshal</span> <span class="token punctuation">(</span> scanner <span class="token punctuation">.</span> <span class="token function">Bytes</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token operator">&</span> tx <span class="token punctuation">)</span> <span class="token comment">// Rebuild the state (user balances),</span> <span class="token comment">// as a series of events</span> <span class="token keyword">if</span> err <span class="token operator">:=</span> state <span class="token punctuation">.</span> <span class="token function">apply</span> <span class="token punctuation">(</span> tx <span class="token punctuation">)</span> <span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">,</span> err <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> state <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span> |
State component is responsible for:
- Add a new transaction to Mempool
- Transaction validation (check user balance)
- Change state
- Persist state to file
- Recalculate the entire transaction starting from genesis
Add a new transaction to Mempool :
1 2 3 4 5 6 7 8 | <span class="token keyword">func</span> <span class="token punctuation">(</span> s <span class="token operator">*</span> State <span class="token punctuation">)</span> <span class="token function">Add</span> <span class="token punctuation">(</span> tx Tx <span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> err <span class="token operator">:=</span> s <span class="token punctuation">.</span> <span class="token function">apply</span> <span class="token punctuation">(</span> tx <span class="token punctuation">)</span> <span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> err <span class="token punctuation">}</span> s <span class="token punctuation">.</span> txMempool <span class="token operator">=</span> <span class="token function">append</span> <span class="token punctuation">(</span> s <span class="token punctuation">.</span> txMempool <span class="token punctuation">,</span> tx <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span> |
Persist state to file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token keyword">func</span> <span class="token punctuation">(</span> s <span class="token operator">*</span> State <span class="token punctuation">)</span> <span class="token function">Persist</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> <span class="token comment">// Make a copy of mempool because the s.txMempool will be modified</span> <span class="token comment">// in the loop below</span> mempool <span class="token operator">:=</span> <span class="token function">make</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> Tx <span class="token punctuation">,</span> <span class="token function">len</span> <span class="token punctuation">(</span> s <span class="token punctuation">.</span> txMempool <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token function">copy</span> <span class="token punctuation">(</span> mempool <span class="token punctuation">,</span> s <span class="token punctuation">.</span> txMempool <span class="token punctuation">)</span> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span> <span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token function">len</span> <span class="token punctuation">(</span> mempool <span class="token punctuation">)</span> <span class="token punctuation">;</span> i <span class="token operator">++</span> <span class="token punctuation">{</span> txJson <span class="token punctuation">,</span> err <span class="token operator">:=</span> json <span class="token punctuation">.</span> <span class="token function">Marshal</span> <span class="token punctuation">(</span> mempool <span class="token punctuation">[</span> i <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> err <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token boolean">_</span> <span class="token punctuation">,</span> err <span class="token operator">=</span> s <span class="token punctuation">.</span> dbFile <span class="token punctuation">.</span> <span class="token function">Write</span> <span class="token punctuation">(</span> <span class="token function">append</span> <span class="token punctuation">(</span> txJson <span class="token punctuation">,</span> <span class="token string">'n'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> err <span class="token punctuation">}</span> <span class="token comment">// Remove the TX written to a file from the mempool</span> s <span class="token punctuation">.</span> txMempool <span class="token operator">=</span> s <span class="token punctuation">.</span> txMempool <span class="token punctuation">[</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span> |
Transaction validation (check user balance)
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">func</span> <span class="token punctuation">(</span> s <span class="token operator">*</span> State <span class="token punctuation">)</span> <span class="token function">apply</span> <span class="token punctuation">(</span> tx Tx <span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> tx <span class="token punctuation">.</span> <span class="token function">IsReward</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> s <span class="token punctuation">.</span> Balances <span class="token punctuation">[</span> tx <span class="token punctuation">.</span> To <span class="token punctuation">]</span> <span class="token operator">+=</span> tx <span class="token punctuation">.</span> Value <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> tx <span class="token punctuation">.</span> Value <span class="token operator">></span> s <span class="token punctuation">.</span> Balances <span class="token punctuation">[</span> tx <span class="token punctuation">.</span> From <span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> fmt <span class="token punctuation">.</span> <span class="token function">Errorf</span> <span class="token punctuation">(</span> <span class="token string">"insufficient balance"</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> s <span class="token punctuation">.</span> Balances <span class="token punctuation">[</span> tx <span class="token punctuation">.</span> From <span class="token punctuation">]</span> <span class="token operator">-=</span> tx <span class="token punctuation">.</span> Value s <span class="token punctuation">.</span> Balances <span class="token punctuation">[</span> tx <span class="token punctuation">.</span> To <span class="token punctuation">]</span> <span class="token operator">+=</span> tx <span class="token punctuation">.</span> Value <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span> |
Build a Command-Line-Interface (CLI)
Tuesday evening, March 26
John wanted a way to make it easier to add transactions to the DB and easily retrieve user balances on the system. Since go can build binary files, John decided to build a CLI for easy manipulation.
The easy way to build a CLI with go is to use the library github.com/spf13/cobra
. Next he creates a new file cmd/tbb/main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"github.com/spf13/cobra"</span> <span class="token string">"os"</span> <span class="token string">"fmt"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> tbbCmd <span class="token operator">=</span> <span class="token operator">&</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> Use <span class="token punctuation">:</span> <span class="token string">"tbb"</span> <span class="token punctuation">,</span> Short <span class="token punctuation">:</span> <span class="token string">"The Blockchain Bar CLI"</span> <span class="token punctuation">,</span> Run <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> cmd <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">,</span> args <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">string</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> err <span class="token operator">:=</span> tbbCmd <span class="token punctuation">.</span> <span class="token function">Execute</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprintln</span> <span class="token punctuation">(</span> os <span class="token punctuation">.</span> Stderr <span class="token punctuation">,</span> err <span class="token punctuation">)</span> os <span class="token punctuation">.</span> <span class="token function">Exit</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
He then proceeded to install the CLI
1 2 | go <span class="token function">install</span> ./cmd/tbb/ <span class="token punctuation">..</span> . |
1 2 3 4 | go: finding github.com/spf13/cobra v1.0.0 go: downloading github.com/spf13/cobra v1.0.0 go: extracting github.com/spf13/cobra v1.0.0 |
Go will automatically install it in $GOPATH/bin
and you can run the tbb
command directly in the terminal, but of course there won’t be anything at the moment since the run function in the main.go
file is empty.
First John will make version for it, in the same directory as main.go
we create version.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token string">"github.com/spf13/cobra"</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> Major <span class="token operator">=</span> <span class="token string">"0"</span> <span class="token keyword">const</span> Minor <span class="token operator">=</span> <span class="token string">"1"</span> <span class="token keyword">const</span> Fix <span class="token operator">=</span> <span class="token string">"0"</span> <span class="token keyword">const</span> Verbal <span class="token operator">=</span> <span class="token string">"TX Add && Balances List"</span> <span class="token keyword">var</span> versionCmd <span class="token operator">=</span> <span class="token operator">&</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> Use <span class="token punctuation">:</span> <span class="token string">"version"</span> <span class="token punctuation">,</span> Short <span class="token punctuation">:</span> <span class="token string">"Describes version."</span> <span class="token punctuation">,</span> Run <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> cmd <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">,</span> args <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">string</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Printf</span> <span class="token punctuation">(</span> <span class="token string">"Version: %s.%s.%s-beta %s"</span> <span class="token punctuation">,</span> Major <span class="token punctuation">,</span> Minor <span class="token punctuation">,</span> Fix <span class="token punctuation">,</span> Verbal <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> |
Compile and run
1 2 3 | go <span class="token function">install</span> ./cmd/tbb/ <span class="token punctuation">..</span> . tbb version |
1 2 | <span class="token operator">></span> Version: <span class="token number">0.1</span> .0-beta TX Add <span class="token operator">&&</span> Balances List |
Nude!
Similarly he created the file balances.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">func</span> <span class="token function">balancesCmd</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> <span class="token keyword">var</span> balancesCmd <span class="token operator">=</span> <span class="token operator">&</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> Use <span class="token punctuation">:</span> <span class="token string">"balances"</span> <span class="token punctuation">,</span> Short <span class="token punctuation">:</span> <span class="token string">"Interact with balances (list...)."</span> <span class="token punctuation">,</span> PreRunE <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> cmd <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">,</span> args <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">string</span> <span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">incorrectUsageErr</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> Run <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> cmd <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">,</span> args <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">string</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> balancesCmd <span class="token punctuation">.</span> <span class="token function">AddCommand</span> <span class="token punctuation">(</span> balancesListCmd <span class="token punctuation">)</span> <span class="token keyword">return</span> balancesCmd <span class="token punctuation">}</span> |
The balance
command will print the user’s balance to the screen
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token keyword">var</span> balancesListCmd <span class="token operator">=</span> <span class="token operator">&</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> Use <span class="token punctuation">:</span> <span class="token string">"list"</span> <span class="token punctuation">,</span> Short <span class="token punctuation">:</span> <span class="token string">"Lists all balances."</span> <span class="token punctuation">,</span> Run <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> cmd <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">,</span> args <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">string</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> state <span class="token punctuation">,</span> err <span class="token operator">:=</span> database <span class="token punctuation">.</span> <span class="token function">NewStateFromDisk</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprintln</span> <span class="token punctuation">(</span> os <span class="token punctuation">.</span> Stderr <span class="token punctuation">,</span> err <span class="token punctuation">)</span> os <span class="token punctuation">.</span> <span class="token function">Exit</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">defer</span> state <span class="token punctuation">.</span> <span class="token function">Close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> fmt <span class="token punctuation">.</span> <span class="token function">Println</span> <span class="token punctuation">(</span> <span class="token string">"Accounts balances:"</span> <span class="token punctuation">)</span> fmt <span class="token punctuation">.</span> <span class="token function">Println</span> <span class="token punctuation">(</span> <span class="token string">"__________________"</span> <span class="token punctuation">)</span> fmt <span class="token punctuation">.</span> <span class="token function">Println</span> <span class="token punctuation">(</span> <span class="token string">""</span> <span class="token punctuation">)</span> <span class="token keyword">for</span> account <span class="token punctuation">,</span> balance <span class="token operator">:=</span> <span class="token keyword">range</span> state <span class="token punctuation">.</span> Balances <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Println</span> <span class="token punctuation">(</span> fmt <span class="token punctuation">.</span> <span class="token function">Sprintf</span> <span class="token punctuation">(</span> <span class="token string">"%s: %d"</span> <span class="token punctuation">,</span> account <span class="token punctuation">,</span> balance <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> |
Next John tests the balance
. command
1 2 3 4 | go <span class="token function">install</span> ./cmd/tbb/ <span class="token punctuation">..</span> . tbb balances list |
1 2 | <span class="token operator">></span> john: <span class="token number">1000000</span> |
Delicious! Next John will do the command to interact with the transaction, he creates the file ./cmd/tbb/tx.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">func</span> <span class="token function">txCmd</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> <span class="token keyword">var</span> txsCmd <span class="token operator">=</span> <span class="token operator">&</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> Use <span class="token punctuation">:</span> <span class="token string">"tx"</span> <span class="token punctuation">,</span> Short <span class="token punctuation">:</span> <span class="token string">"Interact with txs (add...)."</span> <span class="token punctuation">,</span> PreRunE <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> cmd <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">,</span> args <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">string</span> <span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">incorrectUsageErr</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> Run <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> cmd <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">,</span> args <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">string</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> txsCmd <span class="token punctuation">.</span> <span class="token function">AddCommand</span> <span class="token punctuation">(</span> <span class="token function">txAddCmd</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> txsCmd <span class="token punctuation">}</span> |
tbb tx add
to add a new tx to the db
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <span class="token keyword">func</span> <span class="token function">txAddCmd</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> <span class="token keyword">var</span> cmd <span class="token operator">=</span> <span class="token operator">&</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">{</span> Use <span class="token punctuation">:</span> <span class="token string">"add"</span> <span class="token punctuation">,</span> Short <span class="token punctuation">:</span> <span class="token string">"Adds new TX to database."</span> <span class="token punctuation">,</span> Run <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> cmd <span class="token operator">*</span> cobra <span class="token punctuation">.</span> Command <span class="token punctuation">,</span> args <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">string</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> from <span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> cmd <span class="token punctuation">.</span> <span class="token function">Flags</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">GetString</span> <span class="token punctuation">(</span> flagFrom <span class="token punctuation">)</span> to <span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> cmd <span class="token punctuation">.</span> <span class="token function">Flags</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">GetString</span> <span class="token punctuation">(</span> flagTo <span class="token punctuation">)</span> value <span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> cmd <span class="token punctuation">.</span> <span class="token function">Flags</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">GetUint</span> <span class="token punctuation">(</span> flagValue <span class="token punctuation">)</span> data <span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> cmd <span class="token punctuation">.</span> <span class="token function">Flags</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">GetString</span> <span class="token punctuation">(</span> flagData <span class="token punctuation">)</span> fromAcc <span class="token operator">:=</span> database <span class="token punctuation">.</span> <span class="token function">NewAccount</span> <span class="token punctuation">(</span> from <span class="token punctuation">)</span> toAcc <span class="token operator">:=</span> database <span class="token punctuation">.</span> <span class="token function">NewAccount</span> <span class="token punctuation">(</span> to <span class="token punctuation">)</span> tx <span class="token operator">:=</span> database <span class="token punctuation">.</span> <span class="token function">NewTx</span> <span class="token punctuation">(</span> fromAcc <span class="token punctuation">,</span> toAcc <span class="token punctuation">,</span> value <span class="token punctuation">,</span> data <span class="token punctuation">)</span> state <span class="token punctuation">,</span> err <span class="token operator">:=</span> database <span class="token punctuation">.</span> <span class="token function">NewStateFromDisk</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprintln</span> <span class="token punctuation">(</span> os <span class="token punctuation">.</span> Stderr <span class="token punctuation">,</span> err <span class="token punctuation">)</span> os <span class="token punctuation">.</span> <span class="token function">Exit</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// defer means, at the end of this function execution,</span> <span class="token comment">// execute the following statement</span> <span class="token comment">// (close DB file with all TXs)</span> <span class="token keyword">defer</span> state <span class="token punctuation">.</span> <span class="token function">Close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// Add the TX to an in-memory array (pool)</span> err <span class="token operator">=</span> state <span class="token punctuation">.</span> <span class="token function">Add</span> <span class="token punctuation">(</span> tx <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprintln</span> <span class="token punctuation">(</span> os <span class="token punctuation">.</span> Stderr <span class="token punctuation">,</span> err <span class="token punctuation">)</span> os <span class="token punctuation">.</span> <span class="token function">Exit</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// Flush the mempool TXs to disk</span> err <span class="token operator">=</span> state <span class="token punctuation">.</span> <span class="token function">Persist</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> fmt <span class="token punctuation">.</span> <span class="token function">Fprintln</span> <span class="token punctuation">(</span> os <span class="token punctuation">.</span> Stderr <span class="token punctuation">,</span> err <span class="token punctuation">)</span> os <span class="token punctuation">.</span> <span class="token function">Exit</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> fmt <span class="token punctuation">.</span> <span class="token function">Println</span> <span class="token punctuation">(</span> <span class="token string">"TX successfully added to the ledger."</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> |
The command tbb tx add
will have 3 required flags --from
, --to
and --value
. CLI is complete!
John in turn added the tx he wrote on the paper
1 2 3 4 5 6 | tbb tx <span class="token function">add</span> --from <span class="token operator">=</span> john --to <span class="token operator">=</span> john --value <span class="token operator">=</span> <span class="token number">3</span> tbb tx <span class="token function">add</span> --from <span class="token operator">=</span> john --to <span class="token operator">=</span> john --value <span class="token operator">=</span> <span class="token number">700</span> --data <span class="token operator">=</span> reward tbb tx <span class="token function">add</span> --from <span class="token operator">=</span> john --to <span class="token operator">=</span> jack --value <span class="token operator">=</span> <span class="token number">2000</span> tbb tx <span class="token function">add</span> --from <span class="token operator">=</span> john --to <span class="token operator">=</span> john --value <span class="token operator">=</span> <span class="token number">100</span> --data <span class="token operator">=</span> reward tbb tx <span class="token function">add</span> --from <span class="token operator">=</span> jack --to <span class="token operator">=</span> john --value <span class="token operator">=</span> <span class="token number">1</span> |
Get balance
1 2 | tbb balances list |
1 2 3 4 5 | <span class="token operator">></span> Accounts balances: __________________ john: <span class="token number">998801</span> jack: <span class="token number">1999</span> |
The data has been written successfully!
Mempool
The mempool in this series is designed by the author in a very very simple way, for educational purposes. To know more about mempool in real projects, you can find out for yourself at the code of go-ethereum
summary
[🔑] Block chain is a database.
The total token supply, user initial balance, and blockchain settings will be located in the Genesis file. The balance, the initial state of the blockchain recorded in the genesis file is never changed.
Changes to the database are called transactions (Transaction | TX). Transactions are events for actions in the system