Skip to content

Commit 8f93046

Browse files
authored
Merge pull request #14 from tdadadavid/feat/blockchain_db
Feat: add chain utils
2 parents 4c68d5f + 5e0a460 commit 8f93046

File tree

6 files changed

+109
-23
lines changed

6 files changed

+109
-23
lines changed

cmd/block_functions.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@ func init() {
1313
blockChain = chain.New(context.Background(), "/data/blocks")
1414
}
1515

16-
func printChain() {
17-
blockChain.PrettyPrint()
18-
}
19-
2016
func addBlock(data string) {
2117
blockChain.AddBlock(data)
2218
}
2319

24-
func printLastBlockOnChain() {
20+
func printBlock(hash string) {
21+
blockChain.PrintBlock(hash)
22+
}
23+
24+
func printChain(_ string) {
25+
blockChain.PrintChain()
26+
}
27+
28+
func printLastBlockOnChain(_ string) {
2529
b, _ := blockChain.FindLast()
2630
fmt.Printf("Block {%v}\n", b)
2731
}

cmd/print_blockchain.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,33 @@ var printCmd = &cobra.Command{
1414
Short: "View the chain",
1515
Long: "🥽 into the chain",
1616
Example: "block print <chain|block>",
17-
Args: cobra.ExactArgs(1),
17+
Args: cobra.MaximumNArgs(3),
1818
Run: func(cmd *cobra.Command, args []string) {
1919
input := strings.ToLower(args[0])
20+
value := ""
21+
if len(args) > 1 {
22+
value = strings.ToLower(args[1])
23+
}
2024

2125
if input == "" {
2226
logger.Error("empty or wrong input passed", slog.String("got", input))
2327
os.Exit(100)
2428
}
2529

26-
if CommandToHandlers[input] == nil {
27-
fmt.Println("Not implemented")
30+
command, ok := CommandToHandlers[input]
31+
if !ok {
32+
fmt.Println("not implemented")
33+
return
2834
}
29-
30-
command := CommandToHandlers[input]
31-
command()
35+
command(value)
3236
},
3337
}
3438

3539
func init() {
3640
rootCmd.AddCommand(printCmd)
3741

42+
CommandToHandlers["b"] = printBlock
3843
CommandToHandlers["bc"] = printChain
3944
CommandToHandlers["last"] = printLastBlockOnChain
45+
4046
}

cmd/root.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import (
88
"github.com/spf13/cobra"
99
)
1010

11-
var CommandToHandlers = map[string]func(){}
11+
12+
var CommandToHandlers = map[string]func(string){}
1213

1314
var (
1415
logger *slog.Logger

pkg/block/block.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ func New(data string, prevBlkHash string, height int32) (block Block) {
6666
return block
6767
}
6868

69+
6970
// NewGenesisBlock creates the first block on the chain known as the 'GENESIS_BLOCK'
7071
//
7172
// Note:
@@ -101,6 +102,13 @@ func (b *Block) GetPrevBlockHash() string {
101102
return b.PrevBlockHash
102103
}
103104

105+
// String returns a string representation of a Block
106+
// This implements the Stringer interface to enable us printing like this fmt.Println(&block)
107+
func (b *Block) String() string {
108+
return fmt.Sprintf("{Hash: %q, PrevBlockHash: %q, Height: %d, Timestamp: %d, Transactions: %q, Nonce: %d}",
109+
b.Hash, b.PrevBlockHash, b.Height, b.Timestamp, b.Transactions, b.Nonce)
110+
}
111+
104112
// Serialize converts the Block in binary data stored in the storage
105113
//
106114
// Process:

pkg/chain/chain.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package chain
22

33
import (
44
"context"
5-
"encoding/json"
65
"fmt"
76

87
"github.com/dgraph-io/badger/v4"
@@ -98,15 +97,37 @@ func (c *Chain) AddBlock(data string) {
9897
c.currentHash = newBlock.GetHash()
9998
}
10099

101-
// PrettyPrint this formats the chain into a readable json format for easy debugging
102-
func (c *Chain) PrettyPrint() {
103-
json, err := json.MarshalIndent(c, "Blockchain ", "")
104-
if err != nil {
105-
fmt.Printf("error marshalling block: %s", err)
100+
// GetAllBlocks retrieves all blocks from the chain store
101+
//
102+
// Process:
103+
// - It first creates an iterator object for the loop process
104+
// - while there is a block on the chain it gets it and appends it to a slice of blocks
105+
// - Reverse the blocks to get them in chronological order (oldest first)
106+
//
107+
// Returns:
108+
// - `blocks []*block.Block`: a slice of blocks for this chain
109+
// - `err error`: an error object
110+
func (c *Chain) GetAllBlocks() (blocks []*block.Block, err error) {
111+
iter := c.iter()
112+
113+
for iter.HasNext(c.chainCtx) {
114+
block := iter.Next(c.chainCtx)
115+
if block == nil {
116+
err = fmt.Errorf("failed to get block %s", c.currentHash)
117+
return blocks, err
118+
}
119+
blocks = append(blocks, block)
106120
}
107-
fmt.Println(string(json))
121+
122+
// Reverse the blocks to get them in chronological order (oldest first)
123+
for i, j := 0, len(blocks)-1; i < j; i, j = i+1, j-1 {
124+
blocks[i], blocks[j] = blocks[j], blocks[i]
125+
}
126+
127+
return blocks, err
108128
}
109129

130+
110131
// iter add a block to the chain
111132
//
112133
// Process:
@@ -121,7 +142,4 @@ func (c *Chain) iter() ChainIterator {
121142
}
122143
}
123144

124-
// Utility functions
125-
func (c *Chain) FindLast() (block.Block, error) {
126-
return c.store.FindLast(c.chainCtx)
127-
}
145+

pkg/chain/chain_utils.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package chain
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/tdadadavid/block/pkg/block"
9+
)
10+
11+
12+
func (c *Chain) FindLast() (block.Block, error) {
13+
return c.store.FindLast(c.chainCtx)
14+
}
15+
16+
func (c *Chain) PrintBlock(hash string) {
17+
block, err := c.store.FindByHash(context.Background(), hash)
18+
if err != nil {
19+
fmt.Printf("err printing block")
20+
}
21+
fmt.Println(block)
22+
}
23+
24+
// PrintChain prints the blockchain in a formatted way
25+
func (c *Chain) PrintChain() {
26+
var builder strings.Builder
27+
builder.WriteString("Blockchain {\n")
28+
builder.WriteString(fmt.Sprintf(" currentHash: %q\n", c.currentHash))
29+
30+
// Get blocks from the store
31+
blocks, err := c.GetAllBlocks()
32+
if err != nil {
33+
fmt.Printf("Blockchain {\n currentHash: %q\n blocks: [Error fetching blocks: %v]\n}",
34+
c.currentHash, err)
35+
}
36+
37+
builder.WriteString(" blocks: [\n")
38+
for i, block := range blocks {
39+
builder.WriteString(fmt.Sprintf(" %s", block.String()))
40+
if i < len(blocks)-1 {
41+
builder.WriteString(",")
42+
}
43+
builder.WriteString("\n")
44+
}
45+
builder.WriteString(" ]\n")
46+
builder.WriteString("}")
47+
48+
fmt.Println(builder.String())
49+
}

0 commit comments

Comments
 (0)