Esempio n. 1
0
GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
{
	GasConsumption gas;
	switch (_item.type())
	{
	case Push:
	case PushTag:
	case PushData:
	case PushString:
	case PushSub:
	case PushSubSize:
	case PushProgramSize:
	case PushLibraryAddress:
		gas = runGas(Instruction::PUSH1);
		break;
	case Tag:
		gas = runGas(Instruction::JUMPDEST);
		break;
	case Operation:
	{
		ExpressionClasses& classes = m_state->expressionClasses();
		gas = runGas(_item.instruction());
		switch (_item.instruction())
		{
		case Instruction::SSTORE:
		{
			ExpressionClasses::Id slot = m_state->relativeStackElement(0);
			ExpressionClasses::Id value = m_state->relativeStackElement(-1);
			if (classes.knownZero(value) || (
				m_state->storageContent().count(slot) &&
				classes.knownNonZero(m_state->storageContent().at(slot))
			))
				gas += GasCosts::sstoreResetGas; //@todo take refunds into account
			else
				gas += GasCosts::sstoreSetGas;
			break;
		}
		case Instruction::SLOAD:
			gas += GasCosts::sloadGas;
			break;
		case Instruction::RETURN:
			gas += memoryGas(0, -1);
			break;
		case Instruction::MLOAD:
		case Instruction::MSTORE:
			gas += memoryGas(classes.find(Instruction::ADD, {
				m_state->relativeStackElement(0),
				classes.find(AssemblyItem(32))
			}));
			break;
		case Instruction::MSTORE8:
			gas += memoryGas(classes.find(Instruction::ADD, {
				m_state->relativeStackElement(0),
				classes.find(AssemblyItem(1))
			}));
			break;
		case Instruction::SHA3:
			gas = GasCosts::sha3Gas;
			gas += wordGas(GasCosts::sha3WordGas, m_state->relativeStackElement(-1));
			gas += memoryGas(0, -1);
			break;
		case Instruction::CALLDATACOPY:
		case Instruction::CODECOPY:
			gas += memoryGas(0, -2);
			gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-2));
			break;
		case Instruction::EXTCODECOPY:
			gas += memoryGas(-1, -3);
			gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-3));
			break;
		case Instruction::LOG0:
		case Instruction::LOG1:
		case Instruction::LOG2:
		case Instruction::LOG3:
		case Instruction::LOG4:
		{
			unsigned n = unsigned(_item.instruction()) - unsigned(Instruction::LOG0);
			gas = GasCosts::logGas + GasCosts::logTopicGas * n;
			gas += memoryGas(0, -1);
			if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
				gas += GasCosts::logDataGas * (*value);
			else
				gas = GasConsumption::infinite();
			break;
		}
		case Instruction::CALL:
		case Instruction::CALLCODE:
		case Instruction::DELEGATECALL:
		{
			gas = GasCosts::callGas;
			if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0)))
				gas += (*value);
			else
				gas = GasConsumption::infinite();
			if (_item.instruction() == Instruction::CALL)
				gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
			int valueSize = _item.instruction() == Instruction::DELEGATECALL ? 0 : 1;
			if (!classes.knownZero(m_state->relativeStackElement(-1 - valueSize)))
				gas += GasCosts::callValueTransferGas;
			gas += memoryGas(-2 - valueSize, -3 - valueSize);
			gas += memoryGas(-4 - valueSize, -5 - valueSize);
			break;
		}
		case Instruction::CREATE:
			gas = GasCosts::createGas;
			gas += memoryGas(-1, -2);
			break;
		case Instruction::EXP:
			gas = GasCosts::expGas;
			if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
				gas += GasCosts::expByteGas * (32 - (h256(*value).firstBitSet() / 8));
			else
				gas += GasCosts::expByteGas * 32;
			break;
		default:
			break;
		}
		break;
	}
	default:
		gas = GasConsumption::infinite();
		break;
	}

	m_state->feedItem(_item);
	return gas;
}
Esempio n. 2
0
KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool _copyItem)
{
	StoreOperation op;
	if (_item.type() == Tag)
	{
		// can be ignored
	}
	else if (_item.type() != Operation)
	{
		assertThrow(_item.deposit() == 1, InvalidDeposit, "");
		if (_item.pushedValue())
			// only available after assembly stage, should not be used for optimisation
			setStackElement(++m_stackHeight, m_expressionClasses->find(*_item.pushedValue()));
		else
			setStackElement(++m_stackHeight, m_expressionClasses->find(_item, {}, _copyItem));
	}
	else
	{
		Instruction instruction = _item.instruction();
		InstructionInfo info = instructionInfo(instruction);
		if (SemanticInformation::isDupInstruction(_item))
			setStackElement(
				m_stackHeight + 1,
				stackElement(
					m_stackHeight - int(instruction) + int(Instruction::DUP1),
					_item.getLocation()
				)
			);
		else if (SemanticInformation::isSwapInstruction(_item))
			swapStackElements(
				m_stackHeight,
				m_stackHeight - 1 - int(instruction) + int(Instruction::SWAP1),
				_item.getLocation()
			);
		else if (instruction != Instruction::POP)
		{
			vector<Id> arguments(info.args);
			for (int i = 0; i < info.args; ++i)
				arguments[i] = stackElement(m_stackHeight - i, _item.getLocation());

			if (_item.instruction() == Instruction::SSTORE)
				op = storeInStorage(arguments[0], arguments[1], _item.getLocation());
			else if (_item.instruction() == Instruction::SLOAD)
				setStackElement(
					m_stackHeight + _item.deposit(),
					loadFromStorage(arguments[0], _item.getLocation())
				);
			else if (_item.instruction() == Instruction::MSTORE)
				op = storeInMemory(arguments[0], arguments[1], _item.getLocation());
			else if (_item.instruction() == Instruction::MLOAD)
				setStackElement(
					m_stackHeight + _item.deposit(),
					loadFromMemory(arguments[0], _item.getLocation())
				);
			else if (_item.instruction() == Instruction::SHA3)
				setStackElement(
					m_stackHeight + _item.deposit(),
					applySha3(arguments.at(0), arguments.at(1), _item.getLocation())
				);
			else
			{
				if (SemanticInformation::invalidatesMemory(_item.instruction()))
					resetMemory();
				if (SemanticInformation::invalidatesStorage(_item.instruction()))
					resetStorage();
				assertThrow(info.ret <= 1, InvalidDeposit, "");
				if (info.ret == 1)
					setStackElement(
						m_stackHeight + _item.deposit(),
						m_expressionClasses->find(_item, arguments, _copyItem)
					);
			}
		}
		m_stackElements.erase(
			m_stackElements.upper_bound(m_stackHeight + _item.deposit()),
			m_stackElements.end()
		);
		m_stackHeight += _item.deposit();
	}
	return op;
}