bc/peer/blockchainlib/blockchain.go
peer/blockchainlib/blockchain.goRaw
1package blockchainlib
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "io/ioutil"
8 "net/http"
9 "time"
10
11 "github.com/fatih/color"
12)
13
14type Block struct {
15 Hash string `json:"hash"`
16 Height int64 `json:"height"`
17 Date time.Time `json:"date"`
18 PreviousHash string `json:"previoushash"`
19 NextHash string `json:"nexthash"`
20 Data []string `json:"data"`
21 Emitter string `json:"emitter"` //the ID of the peer that has emmited the block
22}
23
24type Blockchain struct {
25 GenesisBlock string `json:"genesisblock"`
26 LastUpdate time.Time `json:"lastupdate"`
27 Blocks []Block `json:"blocks"`
28}
29
30//var blockchain Blockchain
31
32func (bc *Blockchain) GetBlockByHash(hash string) (Block, error) {
33 for _, block := range bc.Blocks {
34 if block.Hash == hash {
35 return block, nil
36 }
37 }
38 var b Block
39 return b, errors.New("Block Hash not found")
40}
41
42func (bc *Blockchain) CreateBlock(data string) Block {
43 var b Block
44 b.Height = int64(len(bc.Blocks))
45 if len(bc.Blocks) == 0 {
46 b.Height = 0
47 } else {
48 b.PreviousHash = bc.Blocks[len(bc.Blocks)-1].Hash
49 }
50 b.Date = time.Now()
51 b.Data = append(b.Data, data)
52 //b.Emitter = runningPeer.ID
53
54 b.Hash = HashBlock(b)
55 return b
56}
57
58func (bc *Blockchain) BlockExists(block Block) bool {
59 for _, b := range bc.Blocks {
60 if b.Hash == block.Hash {
61 return true
62 }
63 }
64 return false
65}
66
67func (bc *Blockchain) AddBlock(block Block) error {
68 if bc.BlockExists(block) {
69 return errors.New("[Error adding Block]: Block already exists in the Blockchain")
70 }
71 if len(bc.Blocks) > 0 {
72 bc.Blocks[len(bc.Blocks)-1].NextHash = block.Hash
73 } else {
74 bc.GenesisBlock = block.Hash
75 }
76 bc.Blocks = append(bc.Blocks, block)
77
78 bc.SaveToDisk()
79
80 return nil
81}
82
83func (bc *Blockchain) ReconstructBlockchainFromBlock(urlAPI string, h string) {
84 color.Yellow("reconstructing the blockchain from last block in memory")
85 var block Block
86 var err error
87
88 block, err = bc.GetBlockByHash(h)
89 check(err)
90
91 if h == "" {
92 //no genesis block yet
93 color.Green(urlAPI + "/blocks/genesis")
94 res, err := http.Get(urlAPI + "/blocks/genesis")
95 check(err)
96 body, err := ioutil.ReadAll(res.Body)
97 check(err)
98 err = json.Unmarshal(body, &block)
99 check(err)
100 color.Yellow("[New Block]: " + block.Hash)
101 err = bc.AddBlock(block)
102 check(err)
103 } else {
104 block.NextHash = h
105 }
106
107 for block.NextHash != "" && block.Hash != "" {
108 res, err := http.Get(urlAPI + "/blocks/next/" + block.Hash)
109 check(err)
110 body, err := ioutil.ReadAll(res.Body)
111 check(err)
112 err = json.Unmarshal(body, &block)
113 check(err)
114 if block.Hash != "" {
115 color.Yellow("[New Block]: " + block.Hash)
116 err = bc.AddBlock(block)
117 check(err)
118 }
119 }
120 bc.Print()
121}
122
123func (bc *Blockchain) Print() {
124 color.Green("Printing Blockchain stored in memory")
125 color.Green("Genesis Block: " + bc.GenesisBlock)
126 for _, b := range bc.Blocks {
127 color.Green("Block height:")
128 fmt.Println(b.Height)
129 color.Green("Hash: " + b.Hash)
130 color.Green("Date: " + b.Date.String())
131 color.Green("---")
132 }
133}
134
135func (bc *Blockchain) ReadFromDisk() error {
136 file, err := ioutil.ReadFile("blockchain.data")
137 if err != nil {
138 return err
139 }
140 content := string(file)
141 json.Unmarshal([]byte(content), &bc)
142 return nil
143}
144
145func (bc *Blockchain) SaveToDisk() error {
146 bytesBlockchain, err := json.Marshal(bc)
147 if err != nil {
148 return err
149 }
150 err = ioutil.WriteFile("blockchain.data", bytesBlockchain, 0644)
151 if err != nil {
152 return err
153 }
154 return nil
155}