You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
4.3 KiB

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