func sanityCheck(hash *common.Hash) (*common.DirBlockInfo, error) { dirBlockInfo := dirBlockInfoMap[hash.String()] if dirBlockInfo == nil { s := fmt.Sprintf("Anchor Error: hash %s does not exist in dirBlockInfoMap.\n", hash.String()) anchorLog.Error(s) return nil, errors.New(s) } if dirBlockInfo.BTCConfirmed { s := fmt.Sprintf("Anchor Warning: hash %s has already been confirmed in btc block chain.\n", hash.String()) anchorLog.Error(s) return nil, errors.New(s) } //The re-anchoring is allowed now. //if !common.NewHash().IsSameAs(dirBlockInfo.BTCTxHash) { //s := fmt.Sprintf("Anchor Warning: hash %s has already been anchored but not confirmed. btc tx hash is %s\n", hash.String(), dirBlockInfo.BTCTxHash.String()) //anchorLog.Error(s) //return nil, errors.New(s) //} if dclient == nil || wclient == nil { s := fmt.Sprintf("\n\n$$$ WARNING: rpc clients and/or wallet are not initiated successfully. No anchoring for now.\n") anchorLog.Warning(s) return nil, errors.New(s) } if len(balances) == 0 { anchorLog.Warning("len(balances) == 0, start rescan UTXO *** ") updateUTXO() } if len(balances) == 0 { s := fmt.Sprintf("\n\n$$$ WARNING: No balance in your wallet. No anchoring for now.\n") anchorLog.Warning(s) return nil, errors.New(s) } return dirBlockInfo, 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)) blk, _ := db.FetchDBlockByHash(hash) if blk != nil { fmt.Println("HaveBlockInDB. true. ", hash.BTCString()) return true, nil } return false, nil /* 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 */ }
// SendRawTransactionToBTC is the main function used to anchor factom // dir block hash to bitcoin blockchain func SendRawTransactionToBTC(hash *common.Hash, blockHeight uint32) (*wire.ShaHash, error) { anchorLog.Debug("SendRawTransactionToBTC: hash=", hash.String(), ", dir block height=", blockHeight) //strconv.FormatUint(blockHeight, 10)) dirBlockInfo, err := sanityCheck(hash) if err != nil { return nil, err } return doTransaction(hash, blockHeight, dirBlockInfo) }
// UpdateBlockHeightCache updates the dir block height cache in db func (db *LevelDb) UpdateBlockHeightCache(dirBlkHeigh uint32, dirBlkHash *common.Hash) error { // Update DirBlock Height cache db.lastDirBlkHeight = int64(dirBlkHeigh) db.lastDirBlkSha, _ = wire.NewShaHash(dirBlkHash.Bytes()) db.lastDirBlkShaCached = true return nil }
// Validate Admin Block by merkle root func validateABlockByMR(mr *common.Hash) error { b, _ := db.FetchABlockByHash(mr) if b == nil { return errors.New("Admin block not found in db for merkle root: " + mr.String()) } return nil }
// Validate Entry Credit Block by merkle root func validateCBlockByMR(mr *common.Hash) error { cb, _ := db.FetchECBlockByHash(mr) if cb == nil { return errors.New("Entry Credit block not found in db for merkle root: " + mr.String()) } return nil }
// FetchEntry gets an entry by hash from the database. func (db *LevelDb) FetchEntryByHash(entrySha *common.Hash) (entry *common.Entry, err error) { var key []byte = []byte{byte(TBL_ENTRY)} key = append(key, entrySha.Bytes()...) db.dbLock.RLock() data, err := db.lDb.Get(key, db.ro) db.dbLock.RUnlock() if data != nil { entry = new(common.Entry) _, err := entry.UnmarshalBinaryData(data) if err != nil { return nil, err } } return entry, nil }
// FetchECBlockByHash gets an Entry Credit block by hash from the database. func (db *LevelDb) FetchECBlockByHash(ecBlockHash *common.Hash) (ecBlock *common.ECBlock, err error) { db.dbLock.Lock() defer db.dbLock.Unlock() var key []byte = []byte{byte(TBL_CB)} key = append(key, ecBlockHash.Bytes()...) data, err := db.lDb.Get(key, db.ro) if data != nil { ecBlock = common.NewECBlock() _, err := ecBlock.UnmarshalBinaryData(data) if err != nil { return nil, err } } return ecBlock, nil }
// FetchFBlockByHash gets an factoid block by hash from the database. func (db *LevelDb) FetchFBlockByHash(hash *common.Hash) (FBlock block.IFBlock, err error) { db.dbLock.Lock() defer db.dbLock.Unlock() var key []byte = []byte{byte(TBL_SC)} key = append(key, hash.Bytes()...) data, err := db.lDb.Get(key, db.ro) if data != nil { FBlock = new(block.FBlock) _, err := FBlock.UnmarshalBinaryData(data) if err != nil { return nil, err } } return FBlock, nil }
// FetchABlockByHash gets an admin block by hash from the database. func (db *LevelDb) FetchABlockByHash(aBlockHash *common.Hash) (aBlock *common.AdminBlock, err error) { var key = []byte{byte(TBL_AB)} key = append(key, aBlockHash.Bytes()...) var data []byte db.dbLock.RLock() data, err = db.lDb.Get(key, db.ro) db.dbLock.RUnlock() if data != nil { aBlock = new(common.AdminBlock) _, err := aBlock.UnmarshalBinaryData(data) if err != nil { return nil, err } } return aBlock, nil }
// FetchDirBlockInfoByHash gets an DirBlockInfo obj func (db *LevelDb) FetchDirBlockInfoByHash(dbHash *common.Hash) (dirBlockInfo *common.DirBlockInfo, err error) { db.dbLock.Lock() defer db.dbLock.Unlock() var key []byte = []byte{byte(TBL_DB_INFO)} key = append(key, dbHash.Bytes()...) data, err := db.lDb.Get(key, db.ro) if data != nil { dirBlockInfo = new(common.DirBlockInfo) _, err := dirBlockInfo.UnmarshalBinaryData(data) if err != nil { return nil, err } } return dirBlockInfo, nil }
// FetchEBHashByMR gets an entry by hash from the database. func (db *LevelDb) FetchEBHashByMR(eBMR *common.Hash) (*common.Hash, error) { var key []byte = []byte{byte(TBL_EB_MR)} key = append(key, eBMR.Bytes()...) db.dbLock.RLock() data, err := db.lDb.Get(key, db.ro) db.dbLock.RUnlock() if err != nil { return nil, err } eBlockHash := common.NewHash() _, err = eBlockHash.UnmarshalBinaryData(data) if err != nil { return nil, err } return eBlockHash, nil }
// FetchDBHashByMR gets a DBHash by MR from the database. func (db *LevelDb) FetchDBHashByMR(dBMR *common.Hash) (*common.Hash, error) { db.dbLock.Lock() defer db.dbLock.Unlock() var key []byte = []byte{byte(TBL_DB_MR)} key = append(key, dBMR.Bytes()...) data, err := db.lDb.Get(key, db.ro) if err != nil { return nil, err } dBlockHash := common.NewHash() _, err = dBlockHash.UnmarshalBinaryData(data) if err != nil { return nil, err } return dBlockHash, nil }
// FetchEntryBlock gets an entry by hash from the database. func (db *LevelDb) FetchEBlockByHash(eBlockHash *common.Hash) (*common.EBlock, error) { var key []byte = []byte{byte(TBL_EB)} key = append(key, eBlockHash.Bytes()...) db.dbLock.RLock() data, err := db.lDb.Get(key, db.ro) db.dbLock.RUnlock() if err != nil { return nil, err } eBlock := common.NewEBlock() if data != nil { _, err := eBlock.UnmarshalBinaryData(data) if err != nil { return nil, err } } return eBlock, nil }
// FetchDBlockByHash gets an entry by hash from the database. func (db *LevelDb) FetchDBlockByHash(dBlockHash *common.Hash) (*common.DirectoryBlock, error) { var key = []byte{byte(TBL_DB)} key = append(key, dBlockHash.Bytes()...) db.dbLock.RLock() data, _ := db.lDb.Get(key, db.ro) db.dbLock.RUnlock() dBlock := common.NewDBlock() if data == nil { return nil, errors.New("DBlock not found for Hash: " + dBlockHash.String()) } _, err := dBlock.UnmarshalBinaryData(data) if err != nil { return nil, err } dBlock.DBHash = dBlockHash return dBlock, nil }
// FetchChainByHash gets a chain by chainID func (db *LevelDb) FetchChainByHash(chainID *common.Hash) (*common.EChain, error) { var key []byte = []byte{byte(TBL_CHAIN_HASH)} key = append(key, chainID.Bytes()...) db.dbLock.RLock() data, err := db.lDb.Get(key, db.ro) db.dbLock.RUnlock() if err != nil { return nil, err } chain := common.NewEChain() if data != nil { _, err := chain.UnmarshalBinaryData(data) if err != nil { return nil, err } } return chain, nil }
func doTransaction(hash *common.Hash, blockHeight uint64, dirBlockInfo *common.DirBlockInfo) (*wire.ShaHash, error) { b := balances[0] i := copy(balances, balances[1:]) balances[i] = b msgtx, err := createRawTransaction(b, hash.Bytes(), blockHeight) if err != nil { return nil, fmt.Errorf("cannot create Raw Transaction: %s", err) } shaHash, err := sendRawTransaction(msgtx) if err != nil { return nil, fmt.Errorf("cannot send Raw Transaction: %s", err) } // for test purpose if dirBlockInfo != nil { dirBlockInfo.BTCTxHash = toHash(shaHash) } return shaHash, nil }
func doTransaction(hash *common.Hash, blockHeight uint32, dirBlockInfo *common.DirBlockInfo) (*wire.ShaHash, error) { b := balances[0] balances = balances[1:] anchorLog.Info("new balances.len=", len(balances)) msgtx, err := createRawTransaction(b, hash.Bytes(), blockHeight) if err != nil { return nil, fmt.Errorf("cannot create Raw Transaction: %s", err) } shaHash, err := sendRawTransaction(msgtx) if err != nil { return nil, fmt.Errorf("cannot send Raw Transaction: %s", err) } if dirBlockInfo != nil { dirBlockInfo.BTCTxHash = toHash(shaHash) } return shaHash, nil }
// FetchAllEBlocksByChain gets all of the blocks by chain id func (db *LevelDb) FetchAllEBlocksByChain(chainID *common.Hash) (eBlocks *[]common.EBlock, err error) { db.dbLock.RLock() defer db.dbLock.RUnlock() var fromkey []byte = []byte{byte(TBL_EB_CHAIN_NUM)} // Table Name (1 bytes) fromkey = append(fromkey, chainID.Bytes()...) // Chain Type (32 bytes) var tokey []byte = addOneToByteArray(fromkey) eBlockSlice := make([]common.EBlock, 0, 10) iter := db.lDb.NewIterator(&util.Range{Start: fromkey, Limit: tokey}, db.ro) for iter.Next() { eBlockHash := common.NewHash() _, err := eBlockHash.UnmarshalBinaryData(iter.Value()) if err != nil { return nil, err } var key []byte = []byte{byte(TBL_EB)} key = append(key, eBlockHash.Bytes()...) data, err := db.lDb.Get(key, db.ro) if err != nil { return nil, err } eBlock := common.NewEBlock() if data != nil { _, err := eBlock.UnmarshalBinaryData(data) if err != nil { return nil, err } eBlockSlice = append(eBlockSlice, *eBlock) } } iter.Release() err = iter.Error() return &eBlockSlice, nil }
// Validate Entry Block by merkle root func validateEBlockByMR(cid *common.Hash, mr *common.Hash) error { eb, err := db.FetchEBlockByMR(mr) if err != nil { return err } if eb == nil { return errors.New("Entry block not found in db for merkle root: " + mr.String()) } keyMR, err := eb.KeyMR() if err != nil { return err } if !mr.IsSameAs(keyMR) { return errors.New("Entry block's merkle root does not match with: " + mr.String()) } for _, ebEntry := range eb.Body.EBEntries { if !bytes.Equal(ebEntry.Bytes()[:31], common.ZERO_HASH[:31]) { entry, _ := db.FetchEntryByHash(ebEntry) if entry == nil { return errors.New("Entry not found in db for entry hash: " + ebEntry.String()) } } // Else ... we could do a bit more validation of the minute markers. } return nil }
// FetchECBlockByHash gets an Entry Credit block by hash from the database. func (db *LevelDb) FetchECBlockByHash(ecBlockHash *common.Hash) (ecBlock *common.ECBlock, err error) { var key = []byte{byte(TBL_CB)} key = append(key, ecBlockHash.Bytes()...) var data []byte db.dbLock.RLock() data, err = db.lDb.Get(key, db.ro) db.dbLock.RUnlock() if err != nil { return nil, err } //fmt.Println("FetchECBlockByHash: key=", hex.EncodeToString(key), ", data=", string(data)) if data != nil { ecBlock = common.NewECBlock() _, err := ecBlock.UnmarshalBinaryData(data) if err != nil { return nil, err } } //fmt.Println("FetchECBlockByHash: ecBlock=", spew.Sdump(ecBlock)) return ecBlock, nil }
// FetchHeadMRByChainID gets a MR of the highest block from the database. func (db *LevelDb) FetchHeadMRByChainID(chainID *common.Hash) (blkMR *common.Hash, err error) { if chainID == nil { return nil, nil } var key = []byte{byte(TBL_CHAIN_HEAD)} key = append(key, chainID.Bytes()...) db.dbLock.RLock() data, err := db.lDb.Get(key, db.ro) db.dbLock.RUnlock() if err != nil { return nil, err } blkMR = common.NewHash() _, err = blkMR.UnmarshalBinaryData(data) if err != nil { return nil, err } return blkMR, nil }
func sanityCheck(hash *common.Hash) (*common.DirBlockInfo, error) { dirBlockInfo := dirBlockInfoMap[hash.String()] if dirBlockInfo == nil { s := fmt.Sprintf("Anchor Error: hash %s does not exist in dirBlockInfoMap.\n", hash.String()) anchorLog.Error(s) return nil, errors.New(s) } if dirBlockInfo.BTCConfirmed { s := fmt.Sprintf("Anchor Warning: hash %s has already been confirmed in btc block chain.\n", hash.String()) anchorLog.Error(s) return nil, errors.New(s) } if !common.NewHash().IsSameAs(dirBlockInfo.BTCTxHash) { s := fmt.Sprintf("Anchor Warning: hash %s has already been anchored but not confirmed. btc tx hash is %s\n", hash.String(), dirBlockInfo.BTCTxHash.String()) anchorLog.Error(s) return nil, errors.New(s) } if dclient == nil || wclient == nil || balances == nil { s := fmt.Sprintf("\n\n$$$ WARNING: rpc clients and/or wallet are not initiated successfully. No anchoring for now.\n") anchorLog.Warning(s) return nil, errors.New(s) } return dirBlockInfo, nil }
// Validate FBlock by merkle root func validateFBlockByMR(mr *common.Hash) error { b, _ := db.FetchFBlockByHash(mr) if b == nil { return errors.New("Factoid block not found in db for merkle root: \n" + mr.String()) } // check that we used the KeyMR to store the block... if !bytes.Equal(b.GetKeyMR().Bytes(), mr.Bytes()) { return fmt.Errorf("Factoid block match failure: block %d \n%s\n%s", b.GetDBHeight(), "Key in the database: "+mr.String(), "Hash of the blk found: "+b.GetKeyMR().String()) } return nil }
// Convert wire.ShaHash into factom.common.Hash func (hash *ShaHash) ToFactomHash() *common.Hash { commonhash := new(common.Hash) commonhash.SetBytes(hash.Bytes()) return commonhash }
func toHash(txHash *wire.ShaHash) *common.Hash { h := new(common.Hash) h.SetBytes(txHash.Bytes()) return h }
// Convert factom.common.hash into a wire.ShaHash func FactomHashToShaHash(ftmHash *common.Hash) *ShaHash { h, _ := NewShaHash(ftmHash.Bytes()) return h }
func getPrePaidChainKey(entryHash *common.Hash, chainIDHash *common.Hash) string { return chainIDHash.String() + entryHash.String() }
// 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 }