Exemple #1
0
// 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
}
Exemple #2
0
// ProcessDBlockBatche inserts the DBlock and update all it's dbentries in DB
func (db *LevelDb) ProcessDBlockBatch(dblock *common.DirectoryBlock) error {

	if dblock != nil {
		if db.lbatch == nil {
			db.lbatch = new(leveldb.Batch)
		}

		defer db.lbatch.Reset()

		binaryDblock, err := dblock.MarshalBinary()
		if err != nil {
			return err
		}

		if dblock.DBHash == nil {
			dblock.DBHash = common.Sha(binaryDblock)
		}

		if dblock.KeyMR == nil {
			dblock.BuildKeyMerkleRoot()
		}

		// Insert the binary directory block
		var key []byte = []byte{byte(TBL_DB)}
		key = append(key, dblock.DBHash.Bytes()...)
		db.lbatch.Put(key, binaryDblock)

		// Insert block height cross reference
		var dbNumkey []byte = []byte{byte(TBL_DB_NUM)}
		var buf bytes.Buffer
		binary.Write(&buf, binary.BigEndian, dblock.Header.DBHeight)
		dbNumkey = append(dbNumkey, buf.Bytes()...)
		db.lbatch.Put(dbNumkey, dblock.DBHash.Bytes())

		// Insert the directory block merkle root cross reference
		key = []byte{byte(TBL_DB_MR)}
		key = append(key, dblock.KeyMR.Bytes()...)
		binaryDBHash, _ := dblock.DBHash.MarshalBinary()
		db.lbatch.Put(key, binaryDBHash)

		// Update the chain head reference
		key = []byte{byte(TBL_CHAIN_HEAD)}
		key = append(key, common.D_CHAINID...)
		db.lbatch.Put(key, dblock.KeyMR.Bytes())

		err = db.lDb.Write(db.lbatch, db.wo)
		if err != nil {
			return err
		}

		// Update DirBlock Height cache
		db.lastDirBlkHeight = int64(dblock.Header.DBHeight)
		db.lastDirBlkSha, _ = wire.NewShaHash(dblock.DBHash.Bytes())
		db.lastDirBlkShaCached = true

	}
	return nil
}
Exemple #3
0
// handleABlockMsg is invoked when a peer receives a entry credit block message.
func (p *peer) handleABlockMsg(msg *wire.MsgABlock, buf []byte) {
	binary, _ := msg.ABlk.MarshalBinary()
	commonHash := common.Sha(binary)
	hash, _ := wire.NewShaHash(commonHash.Bytes())

	iv := wire.NewInvVect(wire.InvTypeFactomAdminBlock, hash)
	p.AddKnownInventory(iv)
	inMsgQueue <- msg
}
Exemple #4
0
// handleFactoidMsg
func (p *peer) handleFactoidMsg(msg *wire.MsgFactoidTX, buf []byte) {
	binary, _ := msg.Transaction.MarshalBinary()
	commonHash := common.Sha(binary)
	hash, _ := wire.NewShaHash(commonHash.Bytes())

	iv := wire.NewInvVect(wire.InvTypeTx, hash)
	p.AddKnownInventory(iv)

	inMsgQueue <- msg
}
Exemple #5
0
// pushGetEntryDataMsg takes the passed EBlock
// and return all the corresponding EBEntries
func (p *peer) pushGetEntryDataMsg(eblock *common.EBlock) {
	binary, _ := eblock.MarshalBinary()
	commonHash := common.Sha(binary)
	hash, _ := wire.NewShaHash(commonHash.Bytes())

	iv := wire.NewInvVect(wire.InvTypeFactomEntry, hash)
	gdmsg := wire.NewMsgGetEntryData()
	gdmsg.AddInvVect(iv)
	if len(gdmsg.InvList) > 0 {
		p.QueueMessage(gdmsg, nil)
	}
}
Exemple #6
0
// handleEBlockMsg is invoked when a peer receives an entry block bitcoin message.
func (p *peer) handleEBlockMsg(msg *wire.MsgEBlock, buf []byte) {
	binary, _ := msg.EBlk.MarshalBinary()
	commonHash := common.Sha(binary)
	hash, _ := wire.NewShaHash(commonHash.Bytes())

	iv := wire.NewInvVect(wire.InvTypeFactomEntryBlock, hash)
	p.AddKnownInventory(iv)

	p.pushGetEntryDataMsg(msg.EBlk)

	inMsgQueue <- msg

}
Exemple #7
0
// handleDirBlockMsg is invoked when a peer receives a dir block message.
func (p *peer) handleDirBlockMsg(msg *wire.MsgDirBlock, buf []byte) {
	binary, _ := msg.DBlk.MarshalBinary()
	commonHash := common.Sha(binary)
	hash, _ := wire.NewShaHash(commonHash.Bytes())

	iv := wire.NewInvVect(wire.InvTypeFactomDirBlock, hash)
	p.AddKnownInventory(iv)

	p.pushGetNonDirDataMsg(msg.DBlk)

	inMsgQueue <- msg

	delete(p.requestedBlocks, *hash)
	delete(p.server.blockManager.requestedBlocks, *hash)
}
Exemple #8
0
// BenchmarkMruInventoryList performs basic benchmarks on the most recently
// used inventory handling.
func BenchmarkMruInventoryList(b *testing.B) {
	// Create a bunch of fake inventory vectors to use in benchmarking
	// the mru inventory code.
	b.StopTimer()
	numInvVects := 100000
	invVects := make([]*wire.InvVect, 0, numInvVects)
	for i := 0; i < numInvVects; i++ {
		hashBytes := make([]byte, wire.HashSize)
		rand.Read(hashBytes)
		hash, _ := wire.NewShaHash(hashBytes)
		iv := wire.NewInvVect(wire.InvTypeBlock, hash)
		invVects = append(invVects, iv)
	}
	b.StartTimer()

	// Benchmark the add plus evicition code.
	limit := 20000
	mruInvMap := NewMruInventoryMap(uint(limit))
	for i := 0; i < b.N; i++ {
		mruInvMap.Add(invVects[i%numInvVects])
	}
}
Exemple #9
0
// 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
}
Exemple #10
0
// build blocks from all process lists
func buildBlocks() error {

	// Allocate the first three dbentries for Admin block, ECBlock and Factoid block
	dchain.AddDBEntry(&common.DBEntry{}) // AdminBlock
	dchain.AddDBEntry(&common.DBEntry{}) // ECBlock
	dchain.AddDBEntry(&common.DBEntry{}) // factoid

	if plMgr != nil && plMgr.MyProcessList.IsValid() {
		buildFromProcessList(plMgr.MyProcessList)
	}

	// Entry Credit Chain
	ecBlock := newEntryCreditBlock(ecchain)
	dchain.AddECBlockToDBEntry(ecBlock)
	exportECBlock(ecBlock)

	// Admin chain
	aBlock := newAdminBlock(achain)

	dchain.AddABlockToDBEntry(aBlock)
	exportABlock(aBlock)

	// Factoid chain
	fBlock := newFactoidBlock(fchain)

	dchain.AddFBlockToDBEntry(fBlock)
	exportFctBlock(fBlock)

	// sort the echains by chain id
	var keys []string
	for k := range chainIDMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// Entry Chains
	for _, k := range keys {
		chain := chainIDMap[k]
		eblock := newEntryBlock(chain)
		if eblock != nil {
			dchain.AddEBlockToDBEntry(eblock)
		}
		exportEBlock(eblock)
	}

	// Directory Block chain
	procLog.Debug("in buildBlocks")
	dbBlock := newDirectoryBlock(dchain)

	// Generate the inventory vector and relay it.
	binary, _ := dbBlock.MarshalBinary()
	commonHash := common.Sha(binary)
	hash, _ := wire.NewShaHash(commonHash.Bytes())
	outMsgQueue <- (&wire.MsgInt_DirBlock{hash})

	// Update dir block height cache in db
	db.UpdateBlockHeightCache(dbBlock.Header.DBHeight, commonHash)
	db.UpdateNextBlockHeightCache(dchain.NextDBHeight)

	exportDBlock(dbBlock)

	// re-initialize the process lit manager
	initProcessListMgr()

	// Initialize timer for the new dblock
	if nodeMode == common.SERVER_NODE {
		timer := &BlockTimer{
			nextDBlockHeight: dchain.NextDBHeight,
			inCtlMsgQueue:    inCtlMsgQueue,
		}
		go timer.StartBlockTimer()
	}

	// place an anchor into btc
	placeAnchor(dbBlock)

	return nil
}
Exemple #11
0
// processRevealEntry validates the MsgRevealEntry and adds it to processlist
func processRevealEntry(msg *wire.MsgRevealEntry) error {
	e := msg.Entry
	bin, _ := e.MarshalBinary()
	h, _ := wire.NewShaHash(e.Hash().Bytes())

	// Check if the chain id is valid
	if e.ChainID.IsSameAs(zeroHash) || e.ChainID.IsSameAs(dchain.ChainID) || e.ChainID.IsSameAs(achain.ChainID) ||
		e.ChainID.IsSameAs(ecchain.ChainID) || e.ChainID.IsSameAs(fchain.ChainID) {
		return fmt.Errorf("This entry chain is not supported: %s", e.ChainID.String())
	}

	if c, ok := commitEntryMap[e.Hash().String()]; ok {
		if chainIDMap[e.ChainID.String()] == nil {
			fMemPool.addOrphanMsg(msg, h)
			return fmt.Errorf("This chain is not supported: %s",
				msg.Entry.ChainID.String())
		}

		// Calculate the entry credits required for the entry
		cred, err := util.EntryCost(bin)
		if err != nil {
			return err
		}

		if c.Credits < cred {
			fMemPool.addOrphanMsg(msg, h)
			return fmt.Errorf("Credit needs to paid first before an entry is revealed: %s", e.Hash().String())
		}

		// Add the msg to the Mem pool
		fMemPool.addMsg(msg, h)

		// Add to MyPL if Server Node
		if nodeMode == common.SERVER_NODE {
			if plMgr.IsMyPListExceedingLimit() {
				procLog.Warning("Exceeding MyProcessList size limit!")
				return fMemPool.addOrphanMsg(msg, h)
			}

			ack, err := plMgr.AddMyProcessListItem(msg, h,
				wire.ACK_REVEAL_ENTRY)
			if err != nil {
				return err
			} else {
				// Broadcast the ack to the network if no errors
				outMsgQueue <- ack
			}
		}

		delete(commitEntryMap, e.Hash().String())
		return nil
	} else if c, ok := commitChainMap[e.Hash().String()]; ok { //Reveal chain ---------------------------
		if chainIDMap[e.ChainID.String()] != nil {
			fMemPool.addOrphanMsg(msg, h)
			return fmt.Errorf("This chain is not supported: %s",
				msg.Entry.ChainID.String())
		}

		// add new chain to chainIDMap
		newChain := common.NewEChain()
		newChain.ChainID = e.ChainID
		newChain.FirstEntry = e
		chainIDMap[e.ChainID.String()] = newChain

		// Calculate the entry credits required for the entry
		cred, err := util.EntryCost(bin)
		if err != nil {
			return err
		}

		// 10 credit is additional for the chain creation
		if c.Credits < cred+10 {
			fMemPool.addOrphanMsg(msg, h)
			return fmt.Errorf("Credit needs to paid first before an entry is revealed: %s", e.Hash().String())
		}

		//validate chain id for the first entry
		expectedChainID := common.NewChainID(e)
		if !expectedChainID.IsSameAs(e.ChainID) {
			return fmt.Errorf("Invalid ChainID for entry: %s", e.Hash().String())
		}

		//validate chainid hash in the commitChain
		chainIDHash := common.DoubleSha(e.ChainID.Bytes())
		if !bytes.Equal(c.ChainIDHash.Bytes()[:], chainIDHash[:]) {
			return fmt.Errorf("RevealChain's chainid hash does not match with CommitChain: %s", e.Hash().String())
		}

		//validate Weld in the commitChain
		weld := common.DoubleSha(append(c.EntryHash.Bytes(), e.ChainID.Bytes()...))
		if !bytes.Equal(c.Weld.Bytes()[:], weld[:]) {
			return fmt.Errorf("RevealChain's weld does not match with CommitChain: %s", e.Hash().String())
		}

		// Add the msg to the Mem pool
		fMemPool.addMsg(msg, h)

		// Add to MyPL if Server Node
		if nodeMode == common.SERVER_NODE {
			if plMgr.IsMyPListExceedingLimit() {
				procLog.Warning("Exceeding MyProcessList size limit!")
				return fMemPool.addOrphanMsg(msg, h)
			}
			ack, err := plMgr.AddMyProcessListItem(msg, h,
				wire.ACK_REVEAL_CHAIN)
			if err != nil {
				return err
			} else {
				// Broadcast the ack to the network if no errors
				outMsgQueue <- ack
			}
		}

		delete(commitChainMap, e.Hash().String())
		return nil
	} else {
		return fmt.Errorf("No commit for entry")
	}

	return nil
}