예제 #1
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);
}
예제 #2
0
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
{
	// m_currentBlock is assumed to be prepopulated and reset.

#if !ETH_RELEASE
	BlockInfo bi(_block, _checkNonce);
	assert(m_previousBlock.hash == bi.parentHash);
	assert(m_currentBlock.parentHash == bi.parentHash);
	assert(rootHash() == m_previousBlock.stateRoot);
#endif

	if (m_currentBlock.parentHash != m_previousBlock.hash)
		BOOST_THROW_EXCEPTION(InvalidParentHash());

	// Populate m_currentBlock with the correct values.
	m_currentBlock.populate(_block, _checkNonce);
	m_currentBlock.verifyInternals(_block);

//	cnote << "playback begins:" << m_state.root();
//	cnote << m_state;

	MemoryDB tm;
	GenericTrieDB<MemoryDB> transactionsTrie(&tm);
	transactionsTrie.init();

	MemoryDB rm;
	GenericTrieDB<MemoryDB> receiptsTrie(&rm);
	receiptsTrie.init();

	LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number);

	// All ok with the block generally. Play back the transactions now...
	unsigned i = 0;
	for (auto const& tr: RLP(_block)[1])
	{
		RLPStream k;
		k << i;

		transactionsTrie.insert(&k.out(), tr.data());
		execute(lh, tr.data());

		RLPStream receiptrlp;
		m_receipts.back().streamRLP(receiptrlp);
		receiptsTrie.insert(&k.out(), &receiptrlp.out());
		++i;
	}

	if (transactionsTrie.root() != m_currentBlock.transactionsRoot)
	{
		cwarn << "Bad transactions state root!";
		BOOST_THROW_EXCEPTION(InvalidTransactionsStateRoot());
	}

	if (receiptsTrie.root() != m_currentBlock.receiptsRoot)
	{
		cwarn << "Bad receipts state root.";
		cwarn << "Block:" << toHex(_block);
		cwarn << "Block RLP:" << RLP(_block);
		cwarn << "Calculated: " << receiptsTrie.root();
		for (unsigned j = 0; j < i; ++j)
		{
			RLPStream k;
			k << j;
			auto b = asBytes(receiptsTrie.at(&k.out()));
			cwarn << j << ": ";
			cwarn << "RLP: " << RLP(b);
			cwarn << "Hex: " << toHex(b);
			cwarn << TransactionReceipt(&b);
		}
		cwarn << "Recorded: " << m_currentBlock.receiptsRoot;
		auto rs = _bc.receipts(m_currentBlock.hash);
		for (unsigned j = 0; j < rs.receipts.size(); ++j)
		{
			auto b = rs.receipts[j].rlp();
			cwarn << j << ": ";
			cwarn << "RLP: " << RLP(b);
			cwarn << "Hex: " << toHex(b);
			cwarn << rs.receipts[j];
		}
		BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
	}

	if (m_currentBlock.logBloom != logBloom())
	{
		cwarn << "Bad log bloom!";
		BOOST_THROW_EXCEPTION(InvalidLogBloom());
	}

	// Initialise total difficulty calculation.
	u256 tdIncrease = m_currentBlock.difficulty;

	// Check uncles & apply their rewards to state.
	set<h256> nonces = { m_currentBlock.nonce };
	Addresses rewarded;
	set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
	for (auto const& i: RLP(_block)[2])
	{
		if (knownUncles.count(sha3(i.data())))
			BOOST_THROW_EXCEPTION(UncleInChain(knownUncles, sha3(i.data()) ));

		BlockInfo uncle = BlockInfo::fromHeader(i.data());
		if (nonces.count(uncle.nonce))
			BOOST_THROW_EXCEPTION(DuplicateUncleNonce());

		BlockInfo uncleParent(_bc.block(uncle.parentHash));
		if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
			BOOST_THROW_EXCEPTION(UncleTooOld());
		uncle.verifyParent(uncleParent);

		nonces.insert(uncle.nonce);
		tdIncrease += uncle.difficulty;
		rewarded.push_back(uncle.coinbaseAddress);
	}
	applyRewards(rewarded);

	// Commit all cached state changes to the state trie.
	commit();

	// Hash the state trie and check against the state_root hash in m_currentBlock.
	if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash())
	{
		cwarn << "Bad state root!";
		cnote << "Given to be:" << m_currentBlock.stateRoot;
		cnote << TrieDB<Address, OverlayDB>(&m_db, m_currentBlock.stateRoot);
		cnote << "Calculated to be:" << rootHash();
		cnote << m_state;
		cnote << *this;
		// Rollback the trie.
		m_db.rollback();
		BOOST_THROW_EXCEPTION(InvalidStateRoot());
	}

	if (m_currentBlock.gasUsed != gasUsed())
	{
		// Rollback the trie.
		m_db.rollback();
		BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed)));
	}

	return tdIncrease;
}
예제 #3
0
u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit)
{
	if (m_currentBlock.parentHash != m_previousBlock.hash)
		throw InvalidParentHash();

//	cnote << "playback begins:" << m_state.root();
//	cnote << m_state;

	// All ok with the block generally. Play back the transactions now...
	for (auto const& i: RLP(_block)[1])
		execute(i.data());

	// Initialise total difficulty calculation.
	u256 tdIncrease = m_currentBlock.difficulty;

	// Check uncles & apply their rewards to state.
	// TODO: Check for uniqueness of uncles.
	Addresses rewarded;
	for (auto const& i: RLP(_block)[2])
	{
		BlockInfo uncle = BlockInfo::fromHeader(i.data());
		if (m_previousBlock.parentHash != uncle.parentHash)
			throw InvalidUncle();
		if (_grandParent)
			uncle.verifyParent(_grandParent);
		tdIncrease += uncle.difficulty;
		rewarded.push_back(uncle.coinbaseAddress);
	}
	applyRewards(rewarded);

	// Commit all cached state changes to the state trie.
	commit();

	// Hash the state trie and check against the state_root hash in m_currentBlock.
	if (m_currentBlock.stateRoot != rootHash())
	{
		cwarn << "Bad state root!";
		cnote << "Given to be:" << m_currentBlock.stateRoot;
		cnote << TrieDB<Address, Overlay>(&m_db, m_currentBlock.stateRoot);
		cnote << "Calculated to be:" << rootHash();
		cnote << m_state;
		cnote << *this;
		// Rollback the trie.
		m_db.rollback();
		throw InvalidStateRoot();
	}

	if (_fullCommit)
	{
		// Commit the new trie to disk.
		m_db.commit();

		m_previousBlock = m_currentBlock;
		resetCurrent();
	}
	else
	{
		m_db.rollback();
		resetCurrent();
	}

	return tdIncrease;
}