arnaucube
arnaucube/bcPublic Self-hosted repository
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}