From 09bc520f7b7cc8a09f9d45e1481e2d716a895d74 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 12 May 2015 21:27:04 +0200 Subject: [PATCH 01/14] Known state: store tags on stack as unions. --- libevmasm/CommonSubexpressionEliminator.cpp | 9 +- libevmasm/ControlFlowGraph.cpp | 51 ++++++------ libevmasm/ControlFlowGraph.h | 4 - libevmasm/ExpressionClasses.cpp | 10 +++ libevmasm/ExpressionClasses.h | 6 +- libevmasm/KnownState.cpp | 92 +++++++++++++++------ libevmasm/KnownState.h | 19 +++-- test/libsolidity/SolidityOptimizer.cpp | 43 ++++++++++ 8 files changed, 168 insertions(+), 66 deletions(-) diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index e369c9dbc..7564fcd99 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -153,7 +153,9 @@ AssemblyItems CSECodeGenerator::generateCode( assertThrow(!m_classPositions[targetItem.second].empty(), OptimizerException, ""); if (m_classPositions[targetItem.second].count(targetItem.first)) continue; - SourceLocation const& location = m_expressionClasses.representative(targetItem.second).item->getLocation(); + SourceLocation location; + if (m_expressionClasses.representative(targetItem.second).item) + location = m_expressionClasses.representative(targetItem.second).item->getLocation(); int position = classElementPosition(targetItem.second); if (position < targetItem.first) // it is already at its target, we need another copy @@ -197,7 +199,9 @@ void CSECodeGenerator::addDependencies(Id _c) addDependencies(argument); m_neededBy.insert(make_pair(argument, _c)); } - if (expr.item->type() == Operation && ( + if ( + expr.item && + expr.item->type() == Operation && ( expr.item->instruction() == Instruction::SLOAD || expr.item->instruction() == Instruction::MLOAD || expr.item->instruction() == Instruction::SHA3 @@ -288,6 +292,7 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) OptimizerException, "Sequence constrained operation requested out of sequence." ); + assertThrow(expr.item, OptimizerException, "Non-generated expression without item."); vector const& arguments = expr.arguments; for (Id arg: boost::adaptors::reverse(arguments)) generateClassElement(arg); diff --git a/libevmasm/ControlFlowGraph.cpp b/libevmasm/ControlFlowGraph.cpp index cc68b2af8..3566bdb17 100644 --- a/libevmasm/ControlFlowGraph.cpp +++ b/libevmasm/ControlFlowGraph.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -217,7 +218,6 @@ void ControlFlowGraph::gatherKnowledge() // @todo actually we know that memory is filled with zeros at the beginning, // we could make use of that. KnownStatePointer emptyState = make_shared(); - ExpressionClasses& expr = emptyState->expressionClasses(); bool unknownJumpEncountered = false; vector> workQueue({make_pair(BlockId::initial(), emptyState->copy())}); @@ -238,8 +238,6 @@ void ControlFlowGraph::gatherKnowledge() } block.startState = state->copy(); - //@todo we might know the return address for the first pass, but not anymore for the second, - // -> store knowledge about tags as a union. // Feed all items except for the final jump yet because it will erase the target tag. unsigned pc = block.begin; @@ -254,22 +252,29 @@ void ControlFlowGraph::gatherKnowledge() assertThrow(block.begin <= pc && pc == block.end - 1, OptimizerException, ""); //@todo in the case of JUMPI, add knowledge about the condition to the state // (for both values of the condition) - BlockId nextBlock = expressionClassToBlockId( - state->stackElement(state->stackHeight(), SourceLocation()), - expr + set tags = state->tagsInExpression( + state->stackElement(state->stackHeight(), SourceLocation()) ); state->feedItem(m_items.at(pc++)); - if (nextBlock) - workQueue.push_back(make_pair(nextBlock, state->copy())); - else if (!unknownJumpEncountered) + + if (tags.empty() || std::any_of(tags.begin(), tags.end(), [&](u256 const& _tag) + { + return !m_blocks.count(BlockId(_tag)); + })) { - // We do not know where this jump goes, so we have to reset the states of all - // JUMPDESTs. - unknownJumpEncountered = true; - for (auto const& it: m_blocks) - if (it.second.begin < it.second.end && m_items[it.second.begin].type() == Tag) - workQueue.push_back(make_pair(it.first, emptyState->copy())); + if (!unknownJumpEncountered) + { + // We do not know the target of this jump, so we have to reset the states of all + // JUMPDESTs. + unknownJumpEncountered = true; + for (auto const& it: m_blocks) + if (it.second.begin < it.second.end && m_items[it.second.begin].type() == Tag) + workQueue.push_back(make_pair(it.first, emptyState->copy())); + } } + else + for (auto tag: tags) + workQueue.push_back(make_pair(BlockId(tag), state->copy())); } else if (block.begin <= pc && pc < block.end) state->feedItem(m_items.at(pc++)); @@ -329,7 +334,11 @@ BasicBlocks ControlFlowGraph::rebuildCode() if (previousHandedOver && !pushes[blockId] && m_items[block.begin].type() == Tag) ++block.begin; if (block.begin < block.end) + { blocks.push_back(block); + blocks.back().startState->clearTagUnions(); + blocks.back().endState->clearTagUnions(); + } previousHandedOver = (block.endType == BasicBlock::EndType::HANDOVER); } } @@ -337,18 +346,6 @@ BasicBlocks ControlFlowGraph::rebuildCode() return blocks; } -BlockId ControlFlowGraph::expressionClassToBlockId( - ExpressionClasses::Id _id, - ExpressionClasses& _exprClasses -) -{ - ExpressionClasses::Expression expr = _exprClasses.representative(_id); - if (expr.item && expr.item->type() == PushTag) - return BlockId(expr.item->data()); - else - return BlockId::invalid(); -} - BlockId ControlFlowGraph::generateNewId() { BlockId id = BlockId(++m_lastUsedId); diff --git a/libevmasm/ControlFlowGraph.h b/libevmasm/ControlFlowGraph.h index 3366dc45f..4480ba491 100644 --- a/libevmasm/ControlFlowGraph.h +++ b/libevmasm/ControlFlowGraph.h @@ -108,10 +108,6 @@ private: void setPrevLinks(); BasicBlocks rebuildCode(); - /// @returns the corresponding BlockId if _id is a pushed jump tag, - /// and an invalid BlockId otherwise. - BlockId expressionClassToBlockId(ExpressionClasses::Id _id, ExpressionClasses& _exprClasses); - BlockId generateNewId(); unsigned m_lastUsedId = 0; diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp index cfbeba7fa..81adc0dbb 100644 --- a/libevmasm/ExpressionClasses.cpp +++ b/libevmasm/ExpressionClasses.cpp @@ -82,6 +82,16 @@ ExpressionClasses::Id ExpressionClasses::find( return exp.id; } +ExpressionClasses::Id ExpressionClasses::newClass(SourceLocation const& _location) +{ + Expression exp; + exp.id = m_representatives.size(); + exp.item = storeItem(AssemblyItem(UndefinedItem, (u256(1) << 255) + exp.id, _location)); + m_representatives.push_back(exp); + m_expressions.insert(exp); + return exp.id; +} + bool ExpressionClasses::knownToBeDifferent(ExpressionClasses::Id _a, ExpressionClasses::Id _b) { // Try to simplify "_a - _b" and return true iff the value is a non-zero constant. diff --git a/libevmasm/ExpressionClasses.h b/libevmasm/ExpressionClasses.h index c83520300..dd94092e8 100644 --- a/libevmasm/ExpressionClasses.h +++ b/libevmasm/ExpressionClasses.h @@ -52,7 +52,8 @@ public: Id id; AssemblyItem const* item = nullptr; Ids arguments; - unsigned sequenceNumber; ///< Storage modification sequence, only used for SLOAD/SSTORE instructions. + /// Storage modification sequence, only used for storage and memory operations. + unsigned sequenceNumber = 0; /// Behaves as if this was a tuple of (item->type(), item->data(), arguments, sequenceNumber). bool operator<(Expression const& _other) const; }; @@ -73,6 +74,9 @@ public: /// @returns the number of classes. Id size() const { return m_representatives.size(); } + /// @returns the id of a new class which is different to all other classes. + Id newClass(SourceLocation const& _location); + /// @returns true if the values of the given classes are known to be different (on every input). /// @note that this function might still return false for some different inputs. bool knownToBeDifferent(Id _a, Id _b); diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index 5a70a74fb..b84e656aa 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -162,29 +162,41 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool /// Helper function for KnownState::reduceToCommonKnowledge, removes everything from /// _this which is not in or not equal to the value in _other. -template void intersect( - _Mapping& _this, - _Mapping const& _other, - function<_KeyType(_KeyType)> const& _keyTrans = [](_KeyType _k) { return _k; } -) +template void intersect(_Mapping& _this, _Mapping const& _other) { for (auto it = _this.begin(); it != _this.end();) - if (_other.count(_keyTrans(it->first)) && _other.at(_keyTrans(it->first)) == it->second) + if (_other.count(it->first) && _other.at(it->first) == it->second) ++it; else it = _this.erase(it); } -template void intersect(_Mapping& _this, _Mapping const& _other) -{ - intersect<_Mapping, ExpressionClasses::Id>(_this, _other, [](ExpressionClasses::Id _k) { return _k; }); -} - void KnownState::reduceToCommonKnowledge(KnownState const& _other) { int stackDiff = m_stackHeight - _other.m_stackHeight; - function stackKeyTransform = [=](int _key) -> int { return _key - stackDiff; }; - intersect(m_stackElements, _other.m_stackElements, stackKeyTransform); + for (auto it = m_stackElements.begin(); it != m_stackElements.end();) + if (_other.m_stackElements.count(it->first - stackDiff)) + { + Id other = _other.m_stackElements.at(it->first - stackDiff); + if (it->second == other) + ++it; + else + { + set theseTags = tagsInExpression(it->second); + set otherTags = tagsInExpression(other); + if (!theseTags.empty() && !otherTags.empty()) + { + theseTags.insert(otherTags.begin(), otherTags.end()); + it->second = tagUnion(theseTags); + ++it; + } + else + it = m_stackElements.erase(it); + } + } + else + it = m_stackElements.erase(it); + // Use the smaller stack height. Essential to terminate in case of loops. if (m_stackHeight > _other.m_stackHeight) { @@ -201,10 +213,15 @@ void KnownState::reduceToCommonKnowledge(KnownState const& _other) bool KnownState::operator==(const KnownState& _other) const { - return m_storageContent == _other.m_storageContent && - m_memoryContent == _other.m_memoryContent && - m_stackHeight == _other.m_stackHeight && - m_stackElements == _other.m_stackElements; + if (m_storageContent != _other.m_storageContent || m_memoryContent != _other.m_memoryContent) + return false; + int stackDiff = m_stackHeight - _other.m_stackHeight; + auto thisIt = m_stackElements.cbegin(); + auto otherIt = _other.m_stackElements.cbegin(); + for (; thisIt != m_stackElements.cend() && otherIt != _other.m_stackElements.cend(); ++thisIt, ++otherIt) + if (thisIt->first - stackDiff != otherIt->first || thisIt->second != otherIt->second) + return false; + return (thisIt == m_stackElements.cend() && otherIt == _other.m_stackElements.cend()); } ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation const& _location) @@ -212,18 +229,17 @@ ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation if (m_stackElements.count(_stackHeight)) return m_stackElements.at(_stackHeight); // Stack element not found (not assigned yet), create new unknown equivalence class. - //@todo check that we do not infer incorrect equivalences when the stack is cleared partially - //in between. - return m_stackElements[_stackHeight] = initialStackElement(_stackHeight, _location); + return m_stackElements[_stackHeight] = + m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, _location)); } -ExpressionClasses::Id KnownState::initialStackElement( - int _stackHeight, - SourceLocation const& _location -) +void KnownState::clearTagUnions() { - // This is a special assembly item that refers to elements pre-existing on the initial stack. - return m_expressionClasses->find(AssemblyItem(UndefinedItem, u256(_stackHeight), _location)); + for (auto it = m_stackElements.begin(); it != m_stackElements.end();) + if (m_tagUnions.left.count(it->second)) + it = m_stackElements.erase(it); + else + ++it; } void KnownState::setStackElement(int _stackHeight, Id _class) @@ -352,3 +368,27 @@ KnownState::Id KnownState::applySha3( return m_knownSha3Hashes[arguments] = v; } +set KnownState::tagsInExpression(KnownState::Id _expressionId) +{ + if (m_tagUnions.left.count(_expressionId)) + return m_tagUnions.left.at(_expressionId); + // Might be a tag, then return the set of itself. + ExpressionClasses::Expression expr = m_expressionClasses->representative(_expressionId); + if (expr.item && expr.item->type() == PushTag) + return set({expr.item->data()}); + else + return set(); +} + +KnownState::Id KnownState::tagUnion(set _tags) +{ + if (m_tagUnions.right.count(_tags)) + return m_tagUnions.right.at(_tags); + else + { + Id id = m_expressionClasses->newClass(SourceLocation()); + m_tagUnions.right.insert(make_pair(_tags, id)); + return id; + } +} + diff --git a/libevmasm/KnownState.h b/libevmasm/KnownState.h index f7a3dd675..3505df74f 100644 --- a/libevmasm/KnownState.h +++ b/libevmasm/KnownState.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -107,15 +108,16 @@ public: /// @returns true if the knowledge about the state of both objects is (known to be) equal. bool operator==(KnownState const& _other) const; - ///@todo the sequence numbers in two copies of this class should never be the same. - /// might be doable using two-dimensional sequence numbers, where the first value is incremented - /// for each copy - /// Retrieves the current equivalence class fo the given stack element (or generates a new /// one if it does not exist yet). Id stackElement(int _stackHeight, SourceLocation const& _location); - /// @returns the equivalence class id of the special initial stack element at the given height. - Id initialStackElement(int _stackHeight, SourceLocation const& _location); + + /// @returns its set of tags if the given expression class is a known tag union; returns a set + /// containing the tag if it is a PushTag expression and the empty set otherwise. + std::set tagsInExpression(Id _expressionId); + /// During analysis, different tags on the stack are partially treated as the same class. + /// This removes such classes not to confuse later analyzers. + void clearTagUnions(); int stackHeight() const { return m_stackHeight; } std::map const& stackElements() const { return m_stackElements; } @@ -142,6 +144,9 @@ private: /// Finds or creates a new expression that applies the sha3 hash function to the contents in memory. Id applySha3(Id _start, Id _length, SourceLocation const& _location); + /// @returns a new or already used Id representing the given set of tags. + Id tagUnion(std::set _tags); + /// Current stack height, can be negative. int m_stackHeight = 0; /// Current stack layout, mapping stack height -> equivalence class @@ -157,6 +162,8 @@ private: std::map, Id> m_knownSha3Hashes; /// Structure containing the classes of equivalent expressions. std::shared_ptr m_expressionClasses; + /// Container for unions of tags stored on the stack. + boost::bimap> m_tagUnions; }; } diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index efc9316b0..ce43887e1 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -315,6 +315,49 @@ BOOST_AUTO_TEST_CASE(retain_information_in_branches) BOOST_CHECK_EQUAL(1, numSHA3s); } +BOOST_AUTO_TEST_CASE(store_tags_as_unions) +{ + // This calls the same function from two sources and both calls have a certain sha3 on + // the stack at the same position. + // Without storing tags as unions, the return from the shared function would not know where to + // jump and thus all jumpdests are forced to clear their state and we do not know about the + // sha3 anymore. + // Note that, for now, this only works if the functions have the same number of return + // parameters since otherwise, the return jump addresses are at different stack positions + // which triggers the "unknown jump target" situation. + char const* sourceCode = R"( + contract test { + bytes32 data; + function f(uint x, bytes32 y) external returns (uint r_a, bytes32 r_d) { + r_d = sha3(y); + shared(y); + r_d = sha3(y); + r_a = 5; + } + function g(uint x, bytes32 y) external returns (uint r_a, bytes32 r_d) { + r_d = sha3(y); + shared(y); + r_d = bytes32(uint(sha3(y)) + 2); + r_a = 7; + } + function shared(bytes32 y) internal { + data = sha3(y); + } + } + )"; + compileBothVersions(sourceCode); + compareVersions("f()", 7, "abc"); + + m_optimize = true; + bytes optimizedBytecode = compileAndRun(sourceCode, 0, "test"); + size_t numSHA3s = 0; + eth::eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) { + if (_instr == eth::Instruction::SHA3) + numSHA3s++; + }); + BOOST_CHECK_EQUAL(2, numSHA3s); +} + BOOST_AUTO_TEST_CASE(cse_intermediate_swap) { eth::KnownState state; From dfdc1a44e9dc820f9931e9d17c0070386cfee0d7 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 13 May 2015 19:13:03 +0200 Subject: [PATCH 02/14] Fixed indentation. --- libevmasm/CommonSubexpressionEliminator.cpp | 4 +--- libevmasm/KnownState.cpp | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index 7564fcd99..9f6f9dd63 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -199,9 +199,7 @@ void CSECodeGenerator::addDependencies(Id _c) addDependencies(argument); m_neededBy.insert(make_pair(argument, _c)); } - if ( - expr.item && - expr.item->type() == Operation && ( + if (expr.item && expr.item->type() == Operation && ( expr.item->instruction() == Instruction::SLOAD || expr.item->instruction() == Instruction::MLOAD || expr.item->instruction() == Instruction::SHA3 diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index b84e656aa..0aac9cedb 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -230,7 +230,7 @@ ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation return m_stackElements.at(_stackHeight); // Stack element not found (not assigned yet), create new unknown equivalence class. return m_stackElements[_stackHeight] = - m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, _location)); + m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, _location)); } void KnownState::clearTagUnions() From 1958a7a46942f9543589467a863fcb50277f8a49 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 14 May 2015 20:55:57 +0200 Subject: [PATCH 03/14] Skip second nonce check on import --- libethereum/BlockChain.cpp | 2 +- libethereum/State.cpp | 8 ++++---- libethereum/State.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 7c03bc24f..712a1e1ba 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -639,7 +639,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import } try { - State canary(_db, *this, bi.hash()); + State canary(_db, *this, bi.hash(), ImportRequirements::DontHave); } catch (...) { diff --git a/libethereum/State.cpp b/libethereum/State.cpp index f5739aadb..1a73177d5 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -114,7 +114,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("end of normal construction.", true); } -State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h): +State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h, ImportRequirements::value _ir): m_db(_db), m_state(&m_db), m_blockReward(c_blockReward) @@ -136,18 +136,18 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h): // 1. Start at parent's end state (state root). BlockInfo bip; bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + sync(_bc, bi.parentHash, bip, _ir); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; - enact(&b, _bc); + enact(&b, _bc, _ir); } else { // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi); + sync(_bc, _h, bi, _ir); } } diff --git a/libethereum/State.h b/libethereum/State.h index a11812c6f..d9fc9d2b5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -118,7 +118,7 @@ public: explicit State(OverlayDB const& _db, BaseState _bs = BaseState::PreExisting, Address _coinbaseAddress = Address()); /// Construct state object from arbitrary point in blockchain. - State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash); + State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash, ImportRequirements::value _ir = ImportRequirements::Default); /// Copy state object. State(State const& _s); From 38bf18de816a6d62fcfae5c656b72633eeaa66cb Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 14 May 2015 21:59:36 +0200 Subject: [PATCH 04/14] fix in chain uncle tests --- test/libethereum/blockchain.cpp | 35 ++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 824eafe26..191b94cc3 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -204,6 +204,20 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blObj["transactions"] = writeTransactionsToJson(txList); BlockInfo current_BlockHeader = state.info(); + + RLPStream uncleStream; + uncleStream.appendList(vBiUncles.size()); + for (unsigned i = 0; i < vBiUncles.size(); ++i) + { + RLPStream uncleRlp; + vBiUncles[i].streamRLP(uncleRlp, WithNonce); + uncleStream.appendRaw(uncleRlp.out()); + } + + // update unclehash in case of invalid uncles + current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + updatePoW(current_BlockHeader); + if (blObj.count("blockHeader")) overwriteBlockHeader(current_BlockHeader, blObj); @@ -223,15 +237,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) txStream.appendRaw(txrlp.out()); } - RLPStream uncleStream; - uncleStream.appendList(vBiUncles.size()); - for (unsigned i = 0; i < vBiUncles.size(); ++i) - { - RLPStream uncleRlp; - vBiUncles[i].streamRLP(uncleRlp, WithNonce); - uncleStream.appendRaw(uncleRlp.out()); - } - RLPStream block2 = createFullBlockFromHeader(current_BlockHeader, txStream.out(), uncleStream.out()); blObj["rlp"] = toHex(block2.out(), 2, HexPrefix::Add); @@ -497,14 +502,20 @@ mArray importUncles(mObject const& blObj, vector& vBiUncles, vector Date: Thu, 14 May 2015 22:56:19 +0200 Subject: [PATCH 05/14] update gas Pricer tests --- test/libethereum/gaspricer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index 577d217e8..68a55ab42 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -115,26 +115,26 @@ BOOST_AUTO_TEST_CASE(basicGasPricer_notxs) BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_LowestPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Lowest, 15731292650, 10000000000000); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Lowest, 15731282021, 10000000000000); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_LowPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Low, 15731292650, 15734152261884); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Low, 15731282021, 15734152261884); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_MediumPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Medium, 15731292650, 20000000000000); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Medium, 15731282021, 20000000000000); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_HighPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::High, 15731292650, 24265847738115); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::High, 15731282021, 24265847738115); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_HighestPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Highest, 15731292650, 30000000000000); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Highest, 15731282021, 30000000000000); } BOOST_AUTO_TEST_SUITE_END() From 32f57c6c25911022bbeced63d0a51047f9042099 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 15 May 2015 11:46:32 +0200 Subject: [PATCH 06/14] Disable test. --- test/libsolidity/SolidityOptimizer.cpp | 27 ++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index ce43887e1..e8cc2d5b5 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -884,18 +884,21 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_noninterfering_store_in_between BOOST_CHECK_EQUAL(1, count(output.begin(), output.end(), AssemblyItem(Instruction::SHA3))); } -BOOST_AUTO_TEST_CASE(cse_with_initially_known_stack) -{ - eth::KnownState state = createInitialState(AssemblyItems{ - u256(0x12), - u256(0x20), - Instruction::ADD - }); - AssemblyItems input{ - u256(0x12 + 0x20) - }; - checkCSE(input, AssemblyItems{Instruction::DUP1}, state); -} +// ****************************** +// DISABLED DUE TO FAILURE ON OSX +// ****************************** +//BOOST_AUTO_TEST_CASE(cse_with_initially_known_stack) +//{ +// eth::KnownState state = createInitialState(AssemblyItems{ +// u256(0x12), +// u256(0x20), +// Instruction::ADD +// }); +// AssemblyItems input{ +// u256(0x12 + 0x20) +// }; +// checkCSE(input, AssemblyItems{Instruction::DUP1}, state); +//} BOOST_AUTO_TEST_CASE(cse_equality_on_initially_known_stack) { From 9357e47a8392fc227cde74ba9c95e3c058c869eb Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 15 May 2015 11:50:21 +0200 Subject: [PATCH 07/14] Update gas limit modulation. --- libethcore/BlockInfo.cpp | 5 ++++- libwhisper/WhisperPeer.cpp | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb64593af..e70b16753 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -228,7 +228,10 @@ u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const return c_genesisGasLimit; else // target minimum of 3141592 - return max(max(c_minGasLimit, 3141592), _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + if (_parent.gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + else + return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 9bef25140..5ac538171 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -68,8 +68,7 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) { unsigned n = 0; for (auto i: _r) - if (n++) - host()->inject(Envelope(i), this); + host()->inject(Envelope(i), this); break; } default: From bc7e909eabdf5a860bf19b5b5633be6ac5d50dcb Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 15 May 2015 12:15:55 +0200 Subject: [PATCH 08/14] reverse unrelated code --- libwhisper/WhisperPeer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 5ac538171..9bef25140 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -68,7 +68,8 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) { unsigned n = 0; for (auto i: _r) - host()->inject(Envelope(i), this); + if (n++) + host()->inject(Envelope(i), this); break; } default: From ca7df0afa3b3a4869bfec1839dbf947ee241fe46 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 15 May 2015 13:25:44 +0200 Subject: [PATCH 09/14] Store copied assembly items in test. Fixes OSX issues. --- test/libsolidity/SolidityOptimizer.cpp | 29 ++++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index e8cc2d5b5..744fc48ae 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -97,7 +97,7 @@ public: { eth::KnownState state; for (auto const& item: addDummyLocations(_input)) - state.feedItem(item); + state.feedItem(item, true); return state; } @@ -884,21 +884,18 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_noninterfering_store_in_between BOOST_CHECK_EQUAL(1, count(output.begin(), output.end(), AssemblyItem(Instruction::SHA3))); } -// ****************************** -// DISABLED DUE TO FAILURE ON OSX -// ****************************** -//BOOST_AUTO_TEST_CASE(cse_with_initially_known_stack) -//{ -// eth::KnownState state = createInitialState(AssemblyItems{ -// u256(0x12), -// u256(0x20), -// Instruction::ADD -// }); -// AssemblyItems input{ -// u256(0x12 + 0x20) -// }; -// checkCSE(input, AssemblyItems{Instruction::DUP1}, state); -//} +BOOST_AUTO_TEST_CASE(cse_with_initially_known_stack) +{ + eth::KnownState state = createInitialState(AssemblyItems{ + u256(0x12), + u256(0x20), + Instruction::ADD + }); + AssemblyItems input{ + u256(0x12 + 0x20) + }; + checkCSE(input, AssemblyItems{Instruction::DUP1}, state); +} BOOST_AUTO_TEST_CASE(cse_equality_on_initially_known_stack) { From b4912db1c6263e53e0fdc5614740f03ba5e2a099 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 15 May 2015 15:27:31 +0200 Subject: [PATCH 10/14] Succint interfaces. --- libsolidity/InterfaceHandler.cpp | 6 +++--- libsolidity/InterfaceHandler.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index a49c4dc3f..85026ac12 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -101,7 +101,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinitio event["inputs"] = params; abi.append(event); } - return std::unique_ptr(new std::string(m_writer.write(abi))); + return std::unique_ptr(new std::string(Json::FastWriter().write(abi))); } unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition const& _contractDef) @@ -153,7 +153,7 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefi } doc["methods"] = methods; - return std::unique_ptr(new std::string(m_writer.write(doc))); + return std::unique_ptr(new std::string(Json::FastWriter().write(doc))); } std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef) @@ -217,7 +217,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin } doc["methods"] = methods; - return std::unique_ptr(new std::string(m_writer.write(doc))); + return std::unique_ptr(new std::string(Json::FastWriter().write(doc))); } /* -- private -- */ diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index 6aa3f72d6..405181890 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -108,8 +108,6 @@ private: std::string const& _tag, CommentOwner _owner); - Json::StyledWriter m_writer; - // internal state DocTagType m_lastTag; std::string m_notice; From eeceeea3d440fd07a0c5a7f1fc4b1124ef9401df Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 15 May 2015 15:36:14 +0200 Subject: [PATCH 11/14] Hex/decimal cleanup for assembly output. --- libevmasm/Assembly.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 1011392b9..6f38b0f42 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -121,13 +121,13 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con _out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString(); break; case Push: - _out << " PUSH " << i.data(); + _out << " PUSH " << hex << i.data(); break; case PushString: _out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; break; case PushTag: - _out << " PUSH [tag" << i.data() << "]"; + _out << " PUSH [tag" << dec << i.data() << "]"; break; case PushSub: _out << " PUSH [$" << h256(i.data()).abridged() << "]"; @@ -139,7 +139,7 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con _out << " PUSHSIZE"; break; case Tag: - _out << "tag" << i.data() << ": " << endl << _prefix << " JUMPDEST"; + _out << "tag" << dec << i.data() << ": " << endl << _prefix << " JUMPDEST"; break; case PushData: _out << " PUSH [" << hex << (unsigned)i.data() << "]"; @@ -208,7 +208,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes break; case PushTag: collection.append( - createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); + createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); break; case PushSub: collection.append( @@ -223,19 +223,13 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes createJsonValue("PUSHSIZE", i.getLocation().start, i.getLocation().end)); break; case Tag: - { collection.append( createJsonValue("tag", i.getLocation().start, i.getLocation().end, string(i.data()))); collection.append( createJsonValue("JUMDEST", i.getLocation().start, i.getLocation().end)); - } break; case PushData: - { - Json::Value pushData; - pushData["name"] = "PUSH hex"; - collection.append(createJsonValue("PUSH hex", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); - } + collection.append(createJsonValue("PUSH data", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); From 65bcb451d4e186274d566e391d4a91da097bd315 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 15 May 2015 17:00:08 +0200 Subject: [PATCH 12/14] Function hashes for JSON compiler. --- solc/jsonCompiler.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index 6f3834af4..d47903fca 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -50,6 +50,14 @@ string formatError(Exception const& _exception, string const& _name, CompilerSta return Json::FastWriter().write(output); } +Json::Value functionHashes(ContractDefinition const& _contract) +{ + Json::Value functionHashes(Json::objectValue); + for (auto const& it: _contract.getInterfaceFunctions()) + functionHashes[it.second->externalSignature()] = toHex(it.first.ref()); + return functionHashes; +} + string compile(string _input, bool _optimize) { StringMap sources; @@ -100,6 +108,7 @@ string compile(string _input, bool _optimize) contractData["interface"] = compiler.getInterface(contractName); contractData["bytecode"] = toHex(compiler.getBytecode(contractName)); contractData["opcodes"] = eth::disassemble(compiler.getBytecode(contractName)); + contractData["functionHashes"] = functionHashes(compiler.getContractDefinition(contractName)); ostringstream unused; contractData["assembly"] = compiler.streamAssembly(unused, contractName, sources, true); output["contracts"][contractName] = contractData; From 01aced01890f0e5ba29c0ebe6d9f3069cd2a173f Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 15 May 2015 17:36:20 +0200 Subject: [PATCH 13/14] fixed gas calculation --- mix/MixClient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index cac208ba4..e3ed2eead 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -220,7 +220,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c d.address = _t.receiveAddress(); d.sender = _t.sender(); d.value = _t.value(); - d.gasUsed = er.gasUsed + er.gasRefunded; + d.gasUsed = er.gasUsed + er.gasRefunded + c_callStipend; if (_t.isCreation()) d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); if (!_call) @@ -234,7 +234,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c er =_state.execute(lastHashes, t); if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); - d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit; + d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; // collect watches h256Set changed; Guard l(x_filtersWatches); From 135513f18a1851bc18a2d4f01ecf76d376abc2e9 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 15 May 2015 17:56:44 +0200 Subject: [PATCH 14/14] globalreg address --- mix/qml/DeploymentDialog.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 1fbde3ac9..81092ec76 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -15,7 +15,7 @@ Dialog { id: modalDeploymentDialog modality: Qt.ApplicationModal width: 735 - height: 400 + height: 450 visible: false property int ownedRegistrarDeployGas: 1179075 // TODO: Use sol library to calculate gas requirement for each tr. property int ownedRegistrarSetSubRegistrarGas: 50000 @@ -293,15 +293,15 @@ Dialog { DefaultLabel { text: qsTr("Root Registrar address:") - visible: false //still use it for now in dev env. + visible: true //still use it for now in dev env. } DefaultTextField { Layout.preferredWidth: 350 id: registrarAddr - text: "ab69f864e49fc4294d18355c4bafb0b91b5e629b" - visible: false + text: "c6d9d2cd449a754c494264e1809c50e34d64562b" + visible: true } DefaultLabel