// Validate the new blocks in mem pool and store them in db func validateBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) bool { // Validate the genesis block if b.Header.DBHeight == 0 { h, _ := common.CreateHash(b) if h.String() != common.GENESIS_DIR_BLOCK_HASH { // panic for milestone 1 panic("\nGenesis block hash expected: " + common.GENESIS_DIR_BLOCK_HASH + "\nGenesis block hash found: " + h.String() + "\n") //procLog.Errorf("Genesis dir block is not as expected: " + h.String()) } } fMemPool.RLock() defer fMemPool.RUnlock() for _, dbEntry := range b.DBEntries { switch dbEntry.ChainID.String() { case ecchain.ChainID.String(): if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok { return false } case achain.ChainID.String(): if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok { return false } else { // validate signature of the previous dir block aBlkMsg, _ := msg.(*wire.MsgABlock) if !validateDBSignature(aBlkMsg.ABlk, dchain) { return false } } case fchain.ChainID.String(): if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok { return false } default: if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok { return false } else { eBlkMsg, _ := msg.(*wire.MsgEBlock) // validate every entry in EBlock for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries { if _, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; !foundInMemPool { if !bytes.Equal(ebEntry.Bytes()[:31], common.ZERO_HASH[:31]) { // continue if the entry arleady exists in db entry, _ := db.FetchEntryByHash(ebEntry) if entry == nil { return false } } } } } } } return true }
// DirBlockLocatorFromHash returns a block locator for the passed block hash. // See BlockLocator for details on the algotirhm used to create a block locator. // // In addition to the general algorithm referenced above, there are a couple of // special cases which are handled: // // - If the genesis hash is passed, there are no previous hashes to add and // therefore the block locator will only consist of the genesis hash // - If the passed hash is not currently known, the block locator will only // consist of the passed hash func DirBlockLocatorFromHash(hash *wire.ShaHash) blockchain.BlockLocator { // The locator contains the requested hash at the very least. locator := make(blockchain.BlockLocator, 0, wire.MaxBlockLocatorsPerMsg) locator = append(locator, hash) h, _ := common.HexToHash(common.GENESIS_DIR_BLOCK_HASH) genesisHash := wire.FactomHashToShaHash(h) // Nothing more to do if a locator for the genesis hash was requested. if genesisHash.IsEqual(hash) { return locator } // Attempt to find the height of the block that corresponds to the // passed hash, and if it's on a side chain, also find the height at // which it forks from the main chain. blockHeight := int64(-1) // Generate the block locators according to the algorithm described in // in the BlockLocator comment and make sure to leave room for the // final genesis hash. dblock, _ := db.FetchDBlockByHash(hash.ToFactomHash()) if dblock != nil { blockHeight = int64(dblock.Header.DBHeight) } increment := int64(1) for len(locator) < wire.MaxBlockLocatorsPerMsg-1 { // Once there are 10 locators, exponentially increase the // distance between each block locator. if len(locator) > 10 { increment *= 2 } blockHeight -= increment if blockHeight < 1 { break } blk, _ := db.FetchDBlockByHeight(uint32(blockHeight)) if blk == nil { continue } else if blk.DBHash == nil { blk.DBHash, _ = common.CreateHash(blk) } locator = append(locator, wire.FactomHashToShaHash(blk.DBHash)) } // Append the appropriate genesis block. locator = append(locator, genesisHash) return locator }
// Seals the current open block, store it in db and create the next open block func newDirectoryBlock(chain *common.DChain) *common.DirectoryBlock { procLog.Debug("**** new Dir Block") // acquire the last block block := chain.NextBlock if devNet { block.Header.NetworkID = common.NETWORK_ID_TEST } else { block.Header.NetworkID = common.NETWORK_ID_EB } // Create the block add a new block for new coming entries chain.BlockMutex.Lock() block.Header.BlockCount = uint32(len(block.DBEntries)) // Calculate Merkle Root for FBlock and store it in header if block.Header.BodyMR == nil { block.Header.BodyMR, _ = block.BuildBodyMR() // Factoid1 block not in the right place... } block.IsSealed = true chain.AddDBlockToDChain(block) chain.NextDBHeight++ chain.NextBlock, _ = common.CreateDBlock(chain, block, 10) chain.BlockMutex.Unlock() block.DBHash, _ = common.CreateHash(block) block.BuildKeyMerkleRoot() //Store the block in db db.ProcessDBlockBatch(block) // Initialize the dirBlockInfo obj in db db.InsertDirBlockInfo(common.NewDirBlockInfoFromDBlock(block)) anchor.UpdateDirBlockInfoMap(common.NewDirBlockInfoFromDBlock(block)) procLog.Info("DirectoryBlock: block" + strconv.FormatUint(uint64(block.Header.DBHeight), 10) + " created for directory block chain: " + chain.ChainID.String()) // To be improved in milestone 2 SignDirectoryBlock() return block }
// Validate a dir block func validateDBlock(c *common.DChain, b *common.DirectoryBlock) (merkleRoot *common.Hash, dbHash *common.Hash, err error) { bodyMR, err := b.BuildBodyMR() if err != nil { return nil, nil, err } if !b.Header.BodyMR.IsSameAs(bodyMR) { return nil, nil, errors.New("Invalid body MR for dir block: " + string(b.Header.DBHeight)) } for _, dbEntry := range b.DBEntries { switch dbEntry.ChainID.String() { case ecchain.ChainID.String(): err := validateCBlockByMR(dbEntry.KeyMR) if err != nil { return nil, nil, err } case achain.ChainID.String(): err := validateABlockByMR(dbEntry.KeyMR) if err != nil { return nil, nil, err } case wire.FChainID.String(): err := validateFBlockByMR(dbEntry.KeyMR) if err != nil { return nil, nil, err } default: err := validateEBlockByMR(dbEntry.ChainID, dbEntry.KeyMR) if err != nil { return nil, nil, err } } } b.DBHash, _ = common.CreateHash(b) b.BuildKeyMerkleRoot() return b.KeyMR, b.DBHash, nil }
// HaveBlockInDB returns whether or not the chain instance has the block represented // by the passed hash. This includes checking the various places a block can // be like part of the main chain, on a side chain, or in the orphan pool. // // This function is NOT safe for concurrent access. func HaveBlockInDB(hash *common.Hash) (bool, error) { //util.Trace(spew.Sdump(hash)) if hash == nil || dchain.Blocks == nil || len(dchain.Blocks) == 0 { return false, nil } // double check the block ids for i := 0; i < len(dchain.Blocks); i = i + 1 { if dchain.Blocks[i] == nil { continue } if dchain.Blocks[i].DBHash == nil { dchain.Blocks[i].DBHash, _ = common.CreateHash(dchain.Blocks[i]) } if dchain.Blocks[i].DBHash.IsSameAs(hash) { return true, nil } } return false, nil }
// Validate the new blocks in mem pool and store them in db // Need to make a batch insert in db in milestone 2 func storeBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) error { fMemPool.RLock() defer fMemPool.RUnlock() for _, dbEntry := range b.DBEntries { switch dbEntry.ChainID.String() { case ecchain.ChainID.String(): ecBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgECBlock) err := db.ProcessECBlockBatch(ecBlkMsg.ECBlock) if err != nil { return err } // needs to be improved?? initializeECreditMap(ecBlkMsg.ECBlock) // for debugging exportECBlock(ecBlkMsg.ECBlock) case achain.ChainID.String(): aBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgABlock) err := db.ProcessABlockBatch(aBlkMsg.ABlk) if err != nil { return err } // for debugging exportABlock(aBlkMsg.ABlk) case fchain.ChainID.String(): fBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgFBlock) err := db.ProcessFBlockBatch(fBlkMsg.SC) if err != nil { return err } // Initialize the Factoid State err = common.FactoidState.AddTransactionBlock(fBlkMsg.SC) FactoshisPerCredit = fBlkMsg.SC.GetExchRate() if err != nil { return err } // for debugging exportFctBlock(fBlkMsg.SC) default: // handle Entry Block eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock) // store entry in db first for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries { if msg, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; foundInMemPool { err := db.InsertEntry(msg.(*wire.MsgEntry).Entry) if err != nil { return err } } } // Store Entry Block in db err := db.ProcessEBlockBatch(eBlkMsg.EBlk) if err != nil { return err } // create a chain when it's the first block of the entry chain if eBlkMsg.EBlk.Header.EBSequence == 0 { chain := new(common.EChain) chain.ChainID = eBlkMsg.EBlk.Header.ChainID chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0]) if chain.FirstEntry == nil { return errors.New("First entry not found for chain:" + eBlkMsg.EBlk.Header.ChainID.String()) } db.InsertChain(chain) chainIDMap[chain.ChainID.String()] = chain } // for debugging exportEBlock(eBlkMsg.EBlk) } } dbhash, dbHeight, _ := db.FetchBlockHeightCache() //fmt.Printf("last block height is %d, to-be-saved block height is %d\n", dbHeight, b.Header.DBHeight) // Store the dir block err := db.ProcessDBlockBatch(b) if err != nil { return err } lastDirBlockTimestamp = b.Header.Timestamp // Update dir block height cache in db commonHash, _ := common.CreateHash(b) db.UpdateBlockHeightCache(b.Header.DBHeight, commonHash) // for debugging exportDBlock(b) // this means, there's syncup breakage happened, and let's renew syncup. if uint32(dbHeight) < b.Header.DBHeight-1 { startHash, _ := wire.NewShaHash(dbhash.Bytes()) stopHash, _ := wire.NewShaHash(commonHash.Bytes()) outMsgQueue <- &wire.MsgInt_ReSyncup{ StartHash: startHash, StopHash: stopHash, } } return nil }
// Validate the new blocks in mem pool and store them in db // Need to make a batch insert in db in milestone 2 func storeBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) error { for _, dbEntry := range b.DBEntries { switch dbEntry.ChainID.String() { case ecchain.ChainID.String(): ecBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgECBlock) err := db.ProcessECBlockBatch(ecBlkMsg.ECBlock) if err != nil { return err } // needs to be improved?? initializeECreditMap(ecBlkMsg.ECBlock) // for debugging exportECBlock(ecBlkMsg.ECBlock) case achain.ChainID.String(): aBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgABlock) err := db.ProcessABlockBatch(aBlkMsg.ABlk) if err != nil { return err } // for debugging exportABlock(aBlkMsg.ABlk) case fchain.ChainID.String(): fBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgFBlock) err := db.ProcessFBlockBatch(fBlkMsg.SC) if err != nil { return err } // Initialize the Factoid State err = common.FactoidState.AddTransactionBlock(fBlkMsg.SC) FactoshisPerCredit = fBlkMsg.SC.GetExchRate() if err != nil { return err } // for debugging exportFctBlock(fBlkMsg.SC) default: // handle Entry Block eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock) // store entry in db first for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries { if msg, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; foundInMemPool { err := db.InsertEntry(msg.(*wire.MsgEntry).Entry) if err != nil { return err } } } // Store Entry Block in db err := db.ProcessEBlockBatch(eBlkMsg.EBlk) if err != nil { return err } // create a chain when it's the first block of the entry chain if eBlkMsg.EBlk.Header.EBSequence == 0 { chain := new(common.EChain) chain.ChainID = eBlkMsg.EBlk.Header.ChainID chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0]) if chain.FirstEntry == nil { return errors.New("First entry not found for chain:" + eBlkMsg.EBlk.Header.ChainID.String()) } db.InsertChain(chain) chainIDMap[chain.ChainID.String()] = chain } // for debugging exportEBlock(eBlkMsg.EBlk) } } // Store the dir block err := db.ProcessDBlockBatch(b) if err != nil { return err } // Update dir block height cache in db commonHash, _ := common.CreateHash(b) db.UpdateBlockHeightCache(b.Header.DBHeight, commonHash) // for debugging exportDBlock(b) return nil }