diff --git a/core/Block.go b/core/Block.go index 9946f48..09c4c13 100644 --- a/core/Block.go +++ b/core/Block.go @@ -17,8 +17,8 @@ type Block struct { // JSONBlock representation type JSONBlock struct { Timestamp time.Time `json:"timestamp"` - Hash string `json:"hash"` PreviousHash string `json:"previous_hash"` + Hash string `json:"hash"` Data []Transaction `json:"data"` Proof int `json:"nonce"` } @@ -33,6 +33,7 @@ func (block *Block) AsJSON() JSONBlock { return JSONBlock{Timestamp: block.Timestamp, Hash: block.Hash(), PreviousHash: block.PreviousHash, Data: block.Data, Proof: block.Proof} } +// FromJSON casts a `JSONBlock` to a regular `Block` struct func (block *JSONBlock) FromJSON() Block { return Block{Timestamp: block.Timestamp, PreviousHash: block.PreviousHash, Data: block.Data, Proof: block.Proof} } diff --git a/core/Blockchain.go b/core/Blockchain.go index ea3b430..f8f689e 100644 --- a/core/Blockchain.go +++ b/core/Blockchain.go @@ -29,12 +29,12 @@ func (bc *Blockchain) MineBlock() Block { bc.Blocks = append(bc.Blocks, block) bc.PendingTransactions = []Transaction{} + bc.NotifyPeers() log.Print("Block Added: ", block.Hash()) return block } block.Proof++ } - } // NewBlockchain creates a new Blockchain @@ -91,7 +91,7 @@ func contains(s []string, e string) bool { } // IsValid checks, if the chain has any faulty blocks -func (bc *Blockchain) IsValid() bool { +func (bc Blockchain) IsValid() bool { for i := 1; i < len(bc.Blocks); i++ { if bc.Blocks[i-1].Hash() != bc.Blocks[i].PreviousHash { return false @@ -101,6 +101,14 @@ func (bc *Blockchain) IsValid() bool { return true } +// NotifyPeers requests an update to all peers +func (bc *Blockchain) NotifyPeers() { + for _, peer := range bc.Peers { + http.Get("http://" + peer + "/update") + } +} + +// Update compares the length of the own chain to the blocklength of every known peer, and updates the chain accordingly func (bc *Blockchain) Update() bool { var hasBeenReplaced = false @@ -112,15 +120,8 @@ func (bc *Blockchain) Update() bool { var receivedBlockchain JSONBlockchain err = decoder.Decode(&receivedBlockchain) if err == nil { - if receivedBlockchain.Blockcount > bc.AsJSON().Blockcount { - - newBlocks := make([]Block, 0) - for _, block := range receivedBlockchain.Blocks { - newBlocks = append(newBlocks, block.FromJSON()) - } - - bc.Blocks = newBlocks - + if receivedBlockchain.Blockcount > bc.AsJSON().Blockcount && receivedBlockchain.FromJSON().IsValid() { + bc.replaceChain(receivedBlockchain.FromJSON()) log.Println("Blockchain has been updated by " + peer) hasBeenReplaced = true } @@ -129,6 +130,16 @@ func (bc *Blockchain) Update() bool { return hasBeenReplaced } +func (bc *Blockchain) replaceChain(newChain Blockchain) { + newBlocks := make([]Block, 0) + for _, block := range newChain.Blocks { + newBlocks = append(newBlocks, block) + } + + bc.Blocks = newBlocks + bc.NotifyPeers() +} + // JSONBlockchain is needed, because the hash of each block is calculated dynamically, and therefore is not stored in the `Block` struct type JSONBlockchain struct { Blocks []JSONBlock @@ -148,3 +159,13 @@ func (bc *Blockchain) AsJSON() JSONBlockchain { return jsonChain } + +// FromJSON casts a `JSONBlockchain` to a regular `Blockchain` struct +func (bc *JSONBlockchain) FromJSON() Blockchain { + chain := Blockchain{PendingTransactions: bc.PendingTransactions, Peers: bc.Peers} + for _, block := range bc.Blocks { + chain.Blocks = append(chain.Blocks, block.FromJSON()) + } + + return chain +}