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; }
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; }