예제 #1
0
bool State::sync(BlockChain const& _bc, h256 _block)
{
	bool ret = false;
	// BLOCK
	BlockInfo bi;
	try
	{
		auto b = _bc.block(_block);
		bi.populate(b);
		bi.verifyInternals(_bc.block(_block));
	}
	catch (...)
	{
		// TODO: Slightly nicer handling? :-)
		cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
		exit(1);
	}

	if (bi == m_currentBlock)
	{
		// We mined the last block.
		// Our state is good - we just need to move on to next.
		m_previousBlock = m_currentBlock;
		resetCurrent();
		m_currentNumber++;
		ret = true;
	}
	else if (bi == m_previousBlock)
	{
		// No change since last sync.
		// Carry on as we were.
	}
	else
	{
		// New blocks available, or we've switched to a different branch. All change.
		// Find most recent state dump and replay what's left.
		// (Most recent state dump might end up being genesis.)

		std::vector<h256> chain;
		while (bi.stateRoot != BlockInfo::genesis().hash && m_db.lookup(bi.stateRoot).empty())	// while we don't have the state root of the latest block...
		{
			chain.push_back(bi.hash);				// push back for later replay.
			bi.populate(_bc.block(bi.parentHash));	// move to parent.
		}

		m_previousBlock = bi;
		resetCurrent();

		// Iterate through in reverse, playing back each of the blocks.
		for (auto it = chain.rbegin(); it != chain.rend(); ++it)
			playback(_bc.block(*it), true);

		m_currentNumber = _bc.details(_block).number + 1;
		resetCurrent();
		ret = true;
	}
	return ret;
}
예제 #2
0
State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
	m_db(_db),
	m_state(&m_db),
	m_blockReward(c_blockReward)
{
	// TODO THINK: is this necessary?
	m_state.init();

	auto b = _bc.block(_h);
	BlockInfo bi;
	BlockInfo bip;
	if (_h)
		bi.populate(b);
	if (bi && bi.number)
		bip.populate(_bc.block(bi.parentHash));
	if (!_h || !bip)
		return;
	m_ourAddress = bi.coinbaseAddress;

	sync(_bc, bi.parentHash, bip);
	enact(&b, _bc);
}
예제 #3
0
u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc)
{
	// Check family:
	BlockInfo biParent(_bc.block(_bi.parentHash));
	_bi.verifyParent(biParent);
	BlockInfo biGrandParent;
	if (biParent.number)
		biGrandParent.populate(_bc.block(biParent.parentHash));
	sync(_bc, _bi.parentHash);
	resetCurrent();
	m_previousBlock = biParent;
	return enact(_block, _bc);
}
예제 #4
0
void BlockChain::import(bytes const& _block)
{
	try
	{
		// VERIFY: populates from the block and checks the block is internally coherent.
		BlockInfo bi(&_block);
		bi.verifyInternals(&_block);

		auto newHash = eth::sha3(_block);

		// Check block doesn't already exist first!
		if (m_details.count(newHash))
			return;

		// Work out its number as the parent's number + 1
		auto it = m_details.find(bi.parentHash);
		if (it == m_details.end())
			// We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on.
			return;

		// Check family:
		BlockInfo biParent(block(bi.parentHash));
		bi.verifyParent(biParent);

		// Check transactions are valid and that they result in a state equivalent to our state_root.
		State s(bi.coinbaseAddress);
		s.sync(*this, bi.parentHash);

		// Get total difficulty increase and update state, checking it.
		BlockInfo biGrandParent;
		if (it->second.number)
			biGrandParent.populate(block(it->second.parent));
		u256 td = it->second.totalDifficulty + s.playback(&_block, bi, biParent, biGrandParent);

		// All ok - insert into DB
		m_details[newHash] = BlockDetails{(uint)it->second.number + 1, bi.parentHash, td};
		m_details[bi.parentHash].children.push_back(newHash);
		m_db->Put(m_writeOptions, ldb::Slice(toBigEndianString(newHash)), (ldb::Slice)ref(_block));

		// This might be the new last block...
		if (td > m_details[m_lastBlockHash].totalDifficulty)
			m_lastBlockHash = newHash;
	}
	catch (...)
	{
		// Exit silently on exception(?)
		return;
	}
}
예제 #5
0
PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& _h, ImportRequirements::value _ir)
{
	PopulationStatistics ret { 0.0, 0.0 };

	if (!_bc.isKnown(_h))
	{
		// Might be worth throwing here.
		cwarn << "Invalid block given for state population: " << _h;
		return ret;
	}

	auto b = _bc.block(_h);
	BlockInfo bi(b);
	if (bi.number)
	{
		// Non-genesis:

		// 1. Start at parent's end state (state root).
		BlockInfo bip;
		bip.populate(_bc.block(bi.parentHash));
		sync(_bc, bi.parentHash, bip, _ir);

		// 2. Enact the block's transactions onto this state.
		m_ourAddress = bi.coinbaseAddress;
		Timer t;
		auto vb = BlockChain::verifyBlock(b);
		ret.verify = t.elapsed();
		t.restart();
		enact(vb, _bc, _ir);
		ret.enact = t.elapsed();
	}
	else
	{
		// Genesis required:
		// We know there are no transactions, so just populate directly.
		m_state.init();
		sync(_bc, _h, bi, _ir);
	}

	return ret;
}
예제 #6
0
bool Block::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi)
{
	bool ret = false;
	// BLOCK
	BlockInfo bi = _bi ? _bi : _bc.info(_block);
#if ETH_PARANOIA
	if (!bi)
		while (1)
		{
			try
			{
				auto b = _bc.block(_block);
				bi.populate(b);
				break;
			}
			catch (Exception const& _e)
			{
				// TODO: Slightly nicer handling? :-)
				cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
				cerr << diagnostic_information(_e) << endl;
			}
			catch (std::exception const& _e)
			{
				// TODO: Slightly nicer handling? :-)
				cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
				cerr << _e.what() << endl;
			}
		}
#endif
	if (bi == m_currentBlock)
	{
		// We mined the last block.
		// Our state is good - we just need to move on to next.
		m_previousBlock = m_currentBlock;
		resetCurrent();
		ret = true;
	}
	else if (bi == m_previousBlock)
	{
		// No change since last sync.
		// Carry on as we were.
	}
	else
	{
		// New blocks available, or we've switched to a different branch. All change.
		// Find most recent state dump and replay what's left.
		// (Most recent state dump might end up being genesis.)

		if (m_state.db().lookup(bi.stateRoot()).empty())	// TODO: API in State for this?
		{
			cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database.";
			cwarn << "Database corrupt: contains block without stateRoot:" << bi;
			cwarn << "Try rescuing the database by running: eth --rescue";
			BOOST_THROW_EXCEPTION(InvalidStateRoot() << errinfo_target(bi.stateRoot()));
		}
		m_previousBlock = bi;
		resetCurrent();
		ret = true;
	}
#if ALLOW_REBUILD
	else
	{
예제 #7
0
void BlockChain::import(bytes const& _block, Overlay const& _db)
{
	// VERIFY: populates from the block and checks the block is internally coherent.
	BlockInfo bi(&_block);
	bi.verifyInternals(&_block);

	auto newHash = eth::sha3(_block);

	// Check block doesn't already exist first!
	if (details(newHash))
	{
		clog(BlockChainChat) << newHash << ": Not new.";
		throw AlreadyHaveBlock();
	}

	// Work out its number as the parent's number + 1
	auto pd = details(bi.parentHash);
	if (!pd)
	{
		clog(BlockChainChat) << newHash << ": Unknown parent " << bi.parentHash;
		// We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on.
		throw UnknownParent();
	}

	clog(BlockChainNote) << "Attempting import of " << newHash << "...";

	u256 td;
	try
	{
		// Check family:
		BlockInfo biParent(block(bi.parentHash));
		bi.verifyParent(biParent);

		// Check transactions are valid and that they result in a state equivalent to our state_root.
		State s(bi.coinbaseAddress, _db);
		s.sync(*this, bi.parentHash);

		// Get total difficulty increase and update state, checking it.
		BlockInfo biGrandParent;
		if (pd.number)
			biGrandParent.populate(block(pd.parent));
		auto tdIncrease = s.playback(&_block, bi, biParent, biGrandParent, true);
		td = pd.totalDifficulty + tdIncrease;

#if !NDEBUG
		checkConsistency();
#endif
		// All ok - insert into DB
		m_details[newHash] = BlockDetails((uint)pd.number + 1, td, bi.parentHash, {});
		m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&newHash, 32), (ldb::Slice)eth::ref(m_details[newHash].rlp()));

		m_details[bi.parentHash].children.push_back(newHash);
		m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&bi.parentHash, 32), (ldb::Slice)eth::ref(m_details[bi.parentHash].rlp()));

		m_db->Put(m_writeOptions, ldb::Slice((char const*)&newHash, 32), (ldb::Slice)ref(_block));

#if !NDEBUG
		checkConsistency();
#endif
	}
	catch (...)
	{
		clog(BlockChainNote) << "   Malformed block.";
		throw;
	}

//	cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children.";

	// This might be the new last block...
	if (td > m_details[m_lastBlockHash].totalDifficulty)
	{
		m_lastBlockHash = newHash;
		m_detailsDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
		clog(BlockChainNote) << "   Imported and best. Has" << details(bi.parentHash).children.size() << "siblings.";
	}
	else
	{
		clog(BlockChainNote) << "   Imported but not best (oTD:" << m_details[m_lastBlockHash].totalDifficulty << ", TD:" << td << ")";
	}
}
예제 #8
0
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
{
	// Check if we already know this block.
	h256 h = BlockInfo::headerHash(_block);

	cblockq << "Queuing block" << h.abridged() << "for import...";

	UpgradableGuard l(m_lock);

	if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h))
	{
		// Already know about this one.
		cblockq << "Already known.";
		return ImportResult::AlreadyKnown;
	}

	// VERIFY: populates from the block and checks the block is internally coherent.
	BlockInfo bi;

#if ETH_CATCH
	try
#endif
	{
		bi.populate(_block);
		bi.verifyInternals(_block);
	}
#if ETH_CATCH
	catch (Exception const& _e)
	{
		cwarn << "Ignoring malformed block: " << diagnostic_information(_e);
		return false;
		return ImportResult::Malformed;
	}
#endif

	// Check block doesn't already exist first!
	if (_bc.details(h))
	{
		cblockq << "Already known in chain.";
		return ImportResult::AlreadyInChain;
	}

	UpgradeGuard ul(l);

	// Check it's not in the future
	if (bi.timestamp > (u256)time(0))
	{
		m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes()));
		cblockq << "OK - queued for future.";
		return ImportResult::FutureTime;
	}
	else
	{
		// We now know it.
		if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
		{
			// We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
			cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged();
			m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
			m_unknownSet.insert(h);

			return ImportResult::UnknownParent;
		}
		else
		{
			// If valid, append to blocks.
			cblockq << "OK - ready for chain insertion.";
			m_ready.push_back(_block.toBytes());
			m_readySet.insert(h);

			noteReadyWithoutWriteGuard(h);
			return ImportResult::Success;
		}
	}
}
예제 #9
0
bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
{
	bool ret = false;
	// BLOCK
	BlockInfo bi = _bi;
	if (!bi)
		while (1)
		{
			try
			{
				auto b = _bc.block(_block);
				bi.populate(b);
	//			bi.verifyInternals(_bc.block(_block));	// Unneeded - we already verify on import into the blockchain.
				break;
			}
			catch (Exception const& _e)
			{
				// TODO: Slightly nicer handling? :-)
				cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
				cerr << diagnostic_information(_e) << endl;
			}
			catch (std::exception const& _e)
			{
				// TODO: Slightly nicer handling? :-)
				cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
				cerr << _e.what() << endl;
			}
		}
	if (bi == m_currentBlock)
	{
		// We mined the last block.
		// Our state is good - we just need to move on to next.
		m_previousBlock = m_currentBlock;
		resetCurrent();
		ret = true;
	}
	else if (bi == m_previousBlock)
	{
		// No change since last sync.
		// Carry on as we were.
	}
	else
	{
		// New blocks available, or we've switched to a different branch. All change.
		// Find most recent state dump and replay what's left.
		// (Most recent state dump might end up being genesis.)

		std::vector<h256> chain;
		while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty())	// while we don't have the state root of the latest block...
		{
			chain.push_back(bi.hash);				// push back for later replay.
			bi.populate(_bc.block(bi.parentHash));	// move to parent.
		}

		m_previousBlock = bi;
		resetCurrent();

		// Iterate through in reverse, playing back each of the blocks.
		try
		{
			for (auto it = chain.rbegin(); it != chain.rend(); ++it)
			{
				auto b = _bc.block(*it);
				enact(&b, _bc);
				cleanup(true);
			}
		}
		catch (...)
		{
			// TODO: Slightly nicer handling? :-)
			cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
			cerr << boost::current_exception_diagnostic_information() << endl;
			exit(1);
		}

		resetCurrent();
		ret = true;
	}
	return ret;
}
예제 #10
0
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs)
{
    clog(BlockQueueTraceChannel) << std::this_thread::get_id();
    // Check if we already know this block.
    h256 h = BlockInfo::headerHash(_block);

    clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import...";

    UpgradableGuard l(m_lock);

    if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h))
    {
        // Already know about this one.
        clog(BlockQueueTraceChannel) << "Already known.";
        return ImportResult::AlreadyKnown;
    }

    // VERIFY: populates from the block and checks the block is internally coherent.
    BlockInfo bi;

    try
    {
        // TODO: quick verify
        bi.populate(_block);
        bi.verifyInternals(_block);
    }
    catch (Exception const& _e)
    {
        cwarn << "Ignoring malformed block: " << diagnostic_information(_e);
        return ImportResult::Malformed;
    }

    clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash;

    // Check block doesn't already exist first!
    if (_bc.isKnown(h))
    {
        cblockq << "Already known in chain.";
        return ImportResult::AlreadyInChain;
    }

    UpgradeGuard ul(l);
    DEV_INVARIANT_CHECK;

    // Check it's not in the future
    (void)_isOurs;
    if (bi.timestamp > (u256)time(0)/* && !_isOurs*/)
    {
        m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes())));
        char buf[24];
        time_t bit = (unsigned)bi.timestamp;
        if (strftime(buf, 24, "%X", localtime(&bit)) == 0)
            buf[0] = '\0'; // empty if case strftime fails
        clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf;
        m_unknownSize += _block.size();
        m_unknownCount++;
        m_difficulty += bi.difficulty;
        bool unknown =  !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash);
        return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown;
    }
    else
    {
        // We now know it.
        if (m_knownBad.count(bi.parentHash))
        {
            m_knownBad.insert(bi.hash());
            updateBad_WITH_LOCK(bi.hash());
            // bad parent; this is bad too, note it as such
            return ImportResult::BadChain;
        }
        else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
        {
            // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
            clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash;
            m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
            m_unknownSet.insert(h);
            m_unknownSize += _block.size();
            m_difficulty += bi.difficulty;
            m_unknownCount++;

            return ImportResult::UnknownParent;
        }
        else
        {
            // If valid, append to blocks.
            clog(BlockQueueTraceChannel) << "OK - ready for chain insertion.";
            DEV_GUARDED(m_verification)
            m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() });
            m_moreToVerify.notify_one();
            m_readySet.insert(h);
            m_knownSize += _block.size();
            m_difficulty += bi.difficulty;
            m_knownCount++;

            noteReady_WITH_LOCK(h);

            return ImportResult::Success;
        }
    }
}