aboutsummaryrefslogtreecommitdiff
path: root/pkg/blockchain/blockchain.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/blockchain/blockchain.go')
-rw-r--r--pkg/blockchain/blockchain.go66
1 files changed, 65 insertions, 1 deletions
diff --git a/pkg/blockchain/blockchain.go b/pkg/blockchain/blockchain.go
index c456be1..7b92b1a 100644
--- a/pkg/blockchain/blockchain.go
+++ b/pkg/blockchain/blockchain.go
@@ -6,6 +6,7 @@ import (
"Chain/pkg/blockchain/chainwriter"
"Chain/pkg/blockchain/coindatabase"
"Chain/pkg/utils"
+ "math"
)
// BlockChain is the main type of this project.
@@ -86,7 +87,70 @@ func GenesisBlock(config *Config) *block.Block {
// (4) Handles a fork, if necessary.
// (5) Updates the BlockChain's fields.
func (bc *BlockChain) HandleBlock(b *block.Block) {
- //TODO
+ appends := bc.appendsToActiveChain(b)
+ blockHash := b.Hash()
+
+ // 1. Validate Block
+ if appends && !bc.CoinDB.ValidateBlock(b.Transactions) {
+ return
+ }
+
+ // 2. Make Undo Block
+ ub := bc.makeUndoBlock(b.Transactions)
+
+ // 3. Store Block in CoinDatabase
+ bc.CoinDB.StoreBlock(b.Transactions, appends)
+
+ // 4. Get BlockRecord for previous Block
+ previousBr := bc.BlockInfoDB.GetBlockRecord(b.Header.PreviousHash)
+
+ // 5. Store UndoBlock and Block to Disk
+ height := previousBr.Height + 1
+ br := bc.ChainWriter.StoreBlock(b, ub, height)
+
+ // 6. Store BlockRecord to BlockInfoDatabase
+ bc.BlockInfoDB.StoreBlockRecord(blockHash, br)
+
+ if appends {
+ // 7. Handle appending Block
+ bc.Length++
+ bc.LastBlock = b
+ bc.LastHash = blockHash
+ if len(bc.UnsafeHashes) >= 6 {
+ bc.UnsafeHashes = bc.UnsafeHashes[1:]
+ }
+ bc.UnsafeHashes = append(bc.UnsafeHashes, blockHash)
+ } else if height > bc.Length {
+ // 8. Handle fork
+ bc.handleFork(b, blockHash, height)
+ }
+}
+
+// handleFork updates the BlockChain when a fork occurs. First, it
+// finds the Blocks the BlockChain must revert. Once found, it uses
+// those Blocks to update the CoinDatabase. Lastly, it updates the
+// BlockChain's fields to reflect the fork.
+func (bc *BlockChain) handleFork(b *block.Block, blockHash string, height uint32) {
+ bc.Length = height
+ forkedBlocks := bc.getForkedBlocks(blockHash)
+ var forkedUnsafeHashes []string
+ min := int(math.Min(float64(6), float64(len(forkedBlocks))))
+ for i := 0; i < min; i++ {
+ forkedHash := forkedBlocks[i].Hash()
+ forkedUnsafeHashes = append(forkedUnsafeHashes, forkedHash)
+ }
+ // likely have to add unsafe hashes
+ bc.UnsafeHashes = forkedUnsafeHashes
+ blocks, undoBlocks := bc.getBlocksAndUndoBlocks(len(forkedBlocks) - 1)
+ bc.CoinDB.UndoCoins(blocks, undoBlocks)
+ for _, bl := range forkedBlocks {
+ if !bc.CoinDB.ValidateBlock(bl.Transactions) {
+ utils.Debug.Printf("Validation failed for forked block {%v}", b.Hash())
+ }
+ bc.CoinDB.StoreBlock(bl.Transactions, true)
+ }
+ bc.LastBlock = b
+ bc.LastHash = b.Hash()
}
// makeUndoBlock returns an UndoBlock given a slice of Transaction.