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}
122func (bc *Blockchain) ReconstructBlockchainFromBlockRESTversion(urlAPI string, h string) {
123 color.Yellow("reconstructing the blockchain from last block in memory")
124 var block Block
125 var err error
126
127 block, err = bc.GetBlockByHash(h)
128 check(err)
129
130 if h == "" {
131 //no genesis block yet
132 color.Green(urlAPI + "/blocks/genesis")
133 res, err := http.Get(urlAPI + "/blocks/genesis")
134 check(err)
135 body, err := ioutil.ReadAll(res.Body)
136 check(err)
137 err = json.Unmarshal(body, &block)
138 check(err)
139 color.Yellow("[New Block]: " + block.Hash)
140 err = bc.AddBlock(block)
141 check(err)
142 } else {
143 block.NextHash = h
144 }
145
146 for block.NextHash != "" && block.Hash != "" {
147 res, err := http.Get(urlAPI + "/blocks/next/" + block.Hash)
148 check(err)
149 body, err := ioutil.ReadAll(res.Body)
150 check(err)
151 err = json.Unmarshal(body, &block)
152 check(err)
153 if block.Hash != "" {
154 color.Yellow("[New Block]: " + block.Hash)
155 err = bc.AddBlock(block)
156 check(err)
157 }
158 }
159 bc.Print()
160}
161
162func (bc *Blockchain) Print() {
163 color.Green("Printing Blockchain stored in memory")
164 color.Green("Genesis Block: " + bc.GenesisBlock)
165 for _, b := range bc.Blocks {
166 color.Green("Block height:")
167 fmt.Println(b.Height)
168 color.Green("Hash: " + b.Hash)
169 color.Green("Date: " + b.Date.String())
170 color.Green("---")
171 }
172}
173
174func (bc *Blockchain) ReadFromDisk() error {
175 file, err := ioutil.ReadFile("blockchain.data")
176 if err != nil {
177 return err
178 }
179 content := string(file)
180 json.Unmarshal([]byte(content), &bc)
181 return nil
182}
183
184func (bc *Blockchain) SaveToDisk() error {
185 bytesBlockchain, err := json.Marshal(bc)
186 if err != nil {
187 return err
188 }
189 err = ioutil.WriteFile("blockchain.data", bytesBlockchain, 0644)
190 if err != nil {
191 return err
192 }
193 return nil
194}