arnaucube
arnaucube/blockchainIDsystemPublic Self-hosted repository
blockchainIDsystem/peer/blockchain.go
peer/blockchain.goRaw
  1package main
  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         []Address `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
 30var 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(address Address) 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, address)
 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 blockchain.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 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 = blockchain.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 = blockchain.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 = blockchain.addBlock(block)
117			check(err)
118		}
119	}
120	blockchain.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(blockchain)
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}