// FetchBlockHeightBySha returns the block height for the given hash. This is // part of the database.Db interface implementation. func (db *LevelDb) FetchBlockHeightBySha(sha *wire.ShaHash) (int64, error) { dblk, _ := db.FetchDBlockByHash(sha.ToFactomHash()) var height int64 = -1 if dblk != nil { height = int64(dblk.Header.DBHeight) } return height, nil }
// 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 }
// PushGetDirBlocksMsg sends a getdirblocks message for the provided block locator // and stop hash. It will ignore back-to-back duplicate requests. func (p *peer) PushGetDirBlocksMsg(locator blockchain.BlockLocator, stopHash *wire.ShaHash) error { // Extract the begin hash from the block locator, if one was specified, // to use for filtering duplicate getblocks requests. // request. var beginHash *wire.ShaHash if len(locator) > 0 { beginHash = locator[0] } // Filter duplicate getdirblocks requests. if p.prevGetBlocksStop != nil && p.prevGetBlocksBegin != nil && beginHash != nil && stopHash.IsEqual(p.prevGetBlocksStop) && beginHash.IsEqual(p.prevGetBlocksBegin) { peerLog.Tracef("Filtering duplicate [getdirblocks] with begin "+ "hash %v, stop hash %v", beginHash, stopHash) return nil } // Construct the getblocks request and queue it to be sent. msg := wire.NewMsgGetDirBlocks(stopHash) for _, hash := range locator { err := msg.AddBlockLocatorHash(hash) if err != nil { return err } } p.QueueMessage(msg, nil) // Update the previous getblocks request information for filtering // duplicates. p.prevGetBlocksBegin = beginHash p.prevGetBlocksStop = stopHash return nil }
func shaSpentTxToKey(sha *wire.ShaHash) []byte { shaB := sha.Bytes() shaB = append(shaB, "sx"...) return shaB }
func shaBlkToKey(sha *wire.ShaHash) []byte { shaB := sha.Bytes() return shaB }
// pushDirBlockMsg sends a dir block message for the provided block hash to the // connected peer. An error is returned if the block hash is not known. func (p *peer) pushDirBlockMsg(sha *wire.ShaHash, doneChan, waitChan chan struct{}) error { commonhash := new(common.Hash) commonhash.SetBytes(sha.Bytes()) blk, err := db.FetchDBlockByHash(commonhash) if err != nil { peerLog.Tracef("Unable to fetch requested dir block sha %v: %v", sha, err) if doneChan != nil { doneChan <- struct{}{} } return err } // Once we have fetched data wait for any previous operation to finish. if waitChan != nil { <-waitChan } // We only send the channel for this message if we aren't sending(sha) // an inv straight after. var dc chan struct{} sendInv := p.continueHash != nil && p.continueHash.IsEqual(sha) if !sendInv { dc = doneChan } msg := wire.NewMsgDirBlock() msg.DBlk = blk p.QueueMessage(msg, dc) //blk.MsgBlock(), dc) // When the peer requests the final block that was advertised in // response to a getblocks message which requested more blocks than // would fit into a single message, send it a new inventory message // to trigger it to issue another getblocks message for the next // batch of inventory. if p.continueHash != nil && p.continueHash.IsEqual(sha) { peerLog.Debug("continueHash: " + spew.Sdump(sha)) // Sleep for 5 seconds for the peer to catch up time.Sleep(5 * time.Second) // // Note: Rather than the latest block height, we should pass // the last block height of this batch of wire.MaxBlockLocatorsPerMsg // to signal this is the end of the batch and // to trigger a client to send a new GetDirBlocks message // //hash, _, err := db.FetchBlockHeightCache() //if err == nil { invMsg := wire.NewMsgDirInvSizeHint(1) iv := wire.NewInvVect(wire.InvTypeFactomDirBlock, sha) //hash) invMsg.AddInvVect(iv) p.QueueMessage(invMsg, doneChan) p.continueHash = nil //} else if doneChan != nil { if doneChan != nil { doneChan <- struct{}{} } } return nil }