diff options
Diffstat (limited to 'pkg/blockchain/blockchain.go')
-rw-r--r-- | pkg/blockchain/blockchain.go | 66 |
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. |