From 39c5cc45d49b9f23116164164109ed4c45329154 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 26 May 2015 14:56:18 +0200 Subject: [PATCH 01/52] fix #2012 --- eth/main.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index a57928e72..4ac462d64 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -628,7 +628,7 @@ int main(int argc, char** argv) nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), netPrefs, &nodesState); - + auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); @@ -693,15 +693,18 @@ int main(int argc, char** argv) } if (keyManager.exists()) - while (masterPassword.empty()) - { - masterPassword = getPassword("Please enter your MASTER password: "); - if (!keyManager.load(masterPassword)) + if (!masterPassword.empty()) + keyManager.load(masterPassword); + else + while (masterPassword.empty()) { - cout << "Password invalid. Try again." << endl; - masterPassword.clear(); + masterPassword = getPassword("Please enter your MASTER password: "); + if (!keyManager.load(masterPassword)) + { + cout << "Password invalid. Try again." << endl; + masterPassword.clear(); + } } - } else { while (masterPassword.empty()) From ba6efaf40813e8d575adc8624caafdb0488ce63e Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 28 May 2015 14:43:46 +0200 Subject: [PATCH 02/52] Allow duplicate code removal for loops. --- libevmasm/Assembly.cpp | 10 ++-- libevmasm/BlockDeduplicator.cpp | 75 +++++++++++++++++++------- libevmasm/BlockDeduplicator.h | 16 ++++-- libsolidity/ArrayUtils.cpp | 14 ++++- test/libsolidity/SolidityOptimizer.cpp | 32 +++++++++++ 5 files changed, 116 insertions(+), 31 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 5cf3b787a..8c6591885 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -307,6 +307,11 @@ Assembly& Assembly::optimise(bool _enable) count = 0; copt << "Performing optimisation..."; + // This only modifies PushTags, we have to run again to actually remove code. + BlockDeduplicator dedup(m_items); + if (dedup.deduplicate()) + count++; + { ControlFlowGraph cfg(m_items); AssemblyItems optimisedItems; @@ -349,11 +354,6 @@ Assembly& Assembly::optimise(bool _enable) m_items = move(optimisedItems); count++; } - - // This only modifies PushTags, we have to run again to actually remove code. - BlockDeduplicator dedup(m_items); - if (dedup.deduplicate()) - count++; } } diff --git a/libevmasm/BlockDeduplicator.cpp b/libevmasm/BlockDeduplicator.cpp index eadbe1b40..d930ea22b 100644 --- a/libevmasm/BlockDeduplicator.cpp +++ b/libevmasm/BlockDeduplicator.cpp @@ -35,13 +35,33 @@ bool BlockDeduplicator::deduplicate() { // Compares indices based on the suffix that starts there, ignoring tags and stopping at // opcodes that stop the control flow. + + // Virtual tag that signifies "the current block" and which is used to optimise loops. + // We abort if this virtual tag actually exists. + AssemblyItem pushSelf(PushTag, u256(-4)); + if ( + std::count(m_items.cbegin(), m_items.cend(), pushSelf.tag()) || + std::count(m_items.cbegin(), m_items.cend(), pushSelf.pushTag()) + ) + return false; + function comparator = [&](size_t _i, size_t _j) { if (_i == _j) return false; - BlockIterator first(m_items.begin() + _i, m_items.end()); - BlockIterator second(m_items.begin() + _j, m_items.end()); + // To compare recursive loops, we have to already unify PushTag opcodes of the + // block's own tag. + AssemblyItem pushFirstTag(pushSelf); + AssemblyItem pushSecondTag(pushSelf); + + if (_i < m_items.size() && m_items.at(_i).type() == Tag) + pushFirstTag = m_items.at(_i).pushTag(); + if (_j < m_items.size() && m_items.at(_j).type() == Tag) + pushSecondTag = m_items.at(_j).pushTag(); + + BlockIterator first(m_items.begin() + _i, m_items.end(), &pushFirstTag, &pushSelf); + BlockIterator second(m_items.begin() + _j, m_items.end(), &pushSecondTag, &pushSelf); BlockIterator end(m_items.end(), m_items.end()); if (first != end && (*first).type() == Tag) @@ -52,27 +72,34 @@ bool BlockDeduplicator::deduplicate() return std::lexicographical_compare(first, end, second, end); }; - set> blocksSeen(comparator); - map tagReplacement; - for (size_t i = 0; i < m_items.size(); ++i) + size_t iterations = 0; + for (; ; ++iterations) { - if (m_items.at(i).type() != Tag) - continue; - auto it = blocksSeen.find(i); - if (it == blocksSeen.end()) - blocksSeen.insert(i); - else - tagReplacement[m_items.at(i).data()] = m_items.at(*it).data(); - } - - bool ret = false; - for (AssemblyItem& item: m_items) - if (item.type() == PushTag && tagReplacement.count(item.data())) + //@todo this should probably be optimized. + set> blocksSeen(comparator); + map tagReplacement; + for (size_t i = 0; i < m_items.size(); ++i) { - ret = true; - item.setData(tagReplacement.at(item.data())); + if (m_items.at(i).type() != Tag) + continue; + auto it = blocksSeen.find(i); + if (it == blocksSeen.end()) + blocksSeen.insert(i); + else + tagReplacement[m_items.at(i).data()] = m_items.at(*it).data(); } - return ret; + + bool changed = false; + for (AssemblyItem& item: m_items) + if (item.type() == PushTag && tagReplacement.count(item.data())) + { + changed = true; + item.setData(tagReplacement.at(item.data())); + } + if (!changed) + break; + } + return iterations > 0; } BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++() @@ -89,3 +116,11 @@ BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++() } return *this; } + +AssemblyItem const& BlockDeduplicator::BlockIterator::operator*() const +{ + if (replaceItem && replaceWith && *it == *replaceItem) + return *replaceWith; + else + return *it; +} diff --git a/libevmasm/BlockDeduplicator.h b/libevmasm/BlockDeduplicator.h index 8a82a1ed7..c48835fd4 100644 --- a/libevmasm/BlockDeduplicator.h +++ b/libevmasm/BlockDeduplicator.h @@ -47,19 +47,27 @@ public: bool deduplicate(); private: - /// Iterator that skips tags skips to the end if (all branches of) the control + /// Iterator that skips tags and skips to the end if (all branches of) the control /// flow does not continue to the next instruction. + /// If the arguments are supplied to the constructor, replaces items on the fly. struct BlockIterator: std::iterator { public: - BlockIterator(AssemblyItems::const_iterator _it, AssemblyItems::const_iterator _end): - it(_it), end(_end) { } + BlockIterator( + AssemblyItems::const_iterator _it, + AssemblyItems::const_iterator _end, + AssemblyItem const* _replaceItem = nullptr, + AssemblyItem const* _replaceWith = nullptr + ): + it(_it), end(_end), replaceItem(_replaceItem), replaceWith(_replaceWith) {} BlockIterator& operator++(); bool operator==(BlockIterator const& _other) const { return it == _other.it; } bool operator!=(BlockIterator const& _other) const { return it != _other.it; } - AssemblyItem const& operator*() const { return *it; } + AssemblyItem const& operator*() const; AssemblyItems::const_iterator it; AssemblyItems::const_iterator end; + AssemblyItem const* replaceItem; + AssemblyItem const* replaceWith; }; AssemblyItems& m_items; diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index 448e4da2a..397b098c4 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -364,7 +364,13 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const return; } // stack: end_pos pos - eth::AssemblyItem loopStart = m_context.newTag(); + + // jump to and return from the loop to allow for duplicate code removal + eth::AssemblyItem returnTag = m_context.pushNewTag(); + m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1; + + // stack: end_pos pos + eth::AssemblyItem loopStart = m_context.appendJumpToNew(); m_context << loopStart; // check for loop condition m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 @@ -380,7 +386,11 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const m_context.appendJumpTo(loopStart); // cleanup m_context << zeroLoopEnd; - m_context << eth::Instruction::POP; + m_context << eth::Instruction::POP << eth::Instruction::SWAP1; + // "return" + m_context << eth::Instruction::JUMP; + + m_context << returnTag; solAssert(m_context.getStackHeight() == stackHeightStart - 1, ""); } diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 744fc48ae..827d8833a 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -1004,6 +1004,38 @@ BOOST_AUTO_TEST_CASE(block_deduplicator) BOOST_CHECK_EQUAL(pushTags.size(), 2); } +BOOST_AUTO_TEST_CASE(block_deduplicator_loops) +{ + AssemblyItems input{ + u256(0), + eth::Instruction::SLOAD, + AssemblyItem(PushTag, 1), + AssemblyItem(PushTag, 2), + eth::Instruction::JUMPI, + eth::Instruction::JUMP, + AssemblyItem(Tag, 1), + u256(5), + u256(6), + eth::Instruction::SSTORE, + AssemblyItem(PushTag, 1), + eth::Instruction::JUMP, + AssemblyItem(Tag, 2), + u256(5), + u256(6), + eth::Instruction::SSTORE, + AssemblyItem(PushTag, 2), + eth::Instruction::JUMP, + }; + BlockDeduplicator dedup(input); + dedup.deduplicate(); + + set pushTags; + for (AssemblyItem const& item: input) + if (item.type() == PushTag) + pushTags.insert(item.data()); + BOOST_CHECK_EQUAL(pushTags.size(), 1); +} + BOOST_AUTO_TEST_SUITE_END() } From b6f9d51cd622253352eec72517851dda5e6f8e4f Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 28 May 2015 16:20:50 +0200 Subject: [PATCH 03/52] Re-introduce string type. --- libsolidity/AST.cpp | 2 ++ libsolidity/ExpressionCompiler.cpp | 3 ++ libsolidity/Token.h | 2 +- libsolidity/Types.cpp | 20 +++++++---- libsolidity/Types.h | 22 +++++++++---- mix/CodeModel.cpp | 4 ++- mix/SolidityType.h | 1 + test/libsolidity/SolidityABIJSON.cpp | 27 +++++++++++++++ .../SolidityNameAndTypeResolution.cpp | 33 +++++++++++++++++++ 9 files changed, 100 insertions(+), 14 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 14884254e..248abfdb9 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -890,6 +890,8 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) ArrayType const& type = dynamic_cast(*m_base->getType()); if (!m_index) BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); + if (type.isString()) + BOOST_THROW_EXCEPTION(createTypeError("Index access for string is not possible.")); m_index->expectType(IntegerType(256)); if (type.isByteArray()) m_type = make_shared(1); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 2e513b7fc..5a9782858 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -824,7 +824,10 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) if (arrayType.getLocation() == ArrayType::Location::Storage) { if (arrayType.isByteArray()) + { + solAssert(!arrayType.isString(), "Index access to string is not allowed."); setLValue(_indexAccess); + } else setLValueToStorageItem(_indexAccess); } diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 8a373da34..bce16ed17 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -286,6 +286,7 @@ namespace solidity K(Bytes32, "bytes32", 0) \ K(Bytes, "bytes", 0) \ K(Byte, "byte", 0) \ + K(String, "string", 0) \ K(Address, "address", 0) \ K(Bool, "bool", 0) \ K(Real, "real", 0) \ @@ -312,7 +313,6 @@ namespace solidity K(Match, "match", 0) \ K(Of, "of", 0) \ K(Relocatable, "relocatable", 0) \ - T(String, "string", 0) \ K(Switch, "switch", 0) \ K(Throw, "throw", 0) \ K(Try, "try", 0) \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7577b83a1..0e9ea9876 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -145,6 +145,8 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) return make_shared(); else if (_typeToken == Token::Bytes) return make_shared(ArrayType::Location::Storage); + else if (_typeToken == Token::String) + return make_shared(ArrayType::Location::Storage, true); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); @@ -663,7 +665,7 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const // let us not allow assignment to memory arrays for now if (convertTo.getLocation() != Location::Storage) return false; - if (convertTo.isByteArray() != isByteArray()) + if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString()) return false; if (!getBaseType()->isImplicitlyConvertibleTo(*convertTo.getBaseType())) return false; @@ -684,8 +686,12 @@ bool ArrayType::operator==(Type const& _other) const if (_other.getCategory() != getCategory()) return false; ArrayType const& other = dynamic_cast(_other); - if (other.m_location != m_location || other.isByteArray() != isByteArray() || - other.isDynamicallySized() != isDynamicallySized()) + if ( + other.m_location != m_location || + other.isByteArray() != isByteArray() || + other.isString() != isString() || + other.isDynamicallySized() != isDynamicallySized() + ) return false; return isDynamicallySized() || getLength() == other.getLength(); } @@ -736,7 +742,9 @@ unsigned ArrayType::getSizeOnStack() const string ArrayType::toString() const { - if (isByteArray()) + if (isString()) + return "string"; + else if (isByteArray()) return "bytes"; string ret = getBaseType()->toString() + "["; if (!isDynamicallySized()) @@ -746,7 +754,7 @@ string ArrayType::toString() const TypePointer ArrayType::externalType() const { - if (m_isByteArray) + if (m_arrayKind != ArrayKind::Ordinary) return shared_from_this(); if (!m_baseType->externalType()) return TypePointer(); @@ -762,7 +770,7 @@ TypePointer ArrayType::externalType() const shared_ptr ArrayType::copyForLocation(ArrayType::Location _location) const { auto copy = make_shared(_location); - copy->m_isByteArray = m_isByteArray; + copy->m_arrayKind = m_arrayKind; if (m_baseType->getCategory() == Type::Category::Array) copy->m_baseType = dynamic_cast(*m_baseType).copyForLocation(_location); else diff --git a/libsolidity/Types.h b/libsolidity/Types.h index a69df964c..65f6e4474 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -367,10 +367,10 @@ public: virtual Category getCategory() const override { return Category::Array; } - /// Constructor for a byte array ("bytes") - explicit ArrayType(Location _location): + /// Constructor for a byte array ("bytes") and string. + explicit ArrayType(Location _location, bool _isString = false): m_location(_location), - m_isByteArray(true), + m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes), m_baseType(std::make_shared(1)) {} /// Constructor for a dynamically sized array type ("type[]") @@ -394,11 +394,17 @@ public: virtual u256 getStorageSize() const override; virtual unsigned getSizeOnStack() const override; virtual std::string toString() const override; - virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; } + virtual MemberList const& getMembers() const override + { + return isString() ? EmptyMemberList : s_arrayTypeMemberList; + } virtual TypePointer externalType() const override; Location getLocation() const { return m_location; } - bool isByteArray() const { return m_isByteArray; } + /// @returns true if this is a byte array or a string + bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; } + /// @returns true if this is a string + bool isString() const { return m_arrayKind == ArrayKind::String; } TypePointer const& getBaseType() const { solAssert(!!m_baseType, ""); return m_baseType;} u256 const& getLength() const { return m_length; } @@ -407,8 +413,12 @@ public: std::shared_ptr copyForLocation(Location _location) const; private: + /// String is interpreted as a subtype of Bytes. + enum class ArrayKind { Ordinary, Bytes, String }; + Location m_location; - bool m_isByteArray = false; ///< Byte arrays ("bytes") have different semantics from ordinary arrays. + ///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays. + ArrayKind m_arrayKind = ArrayKind::Ordinary; TypePointer m_baseType; bool m_hasDynamicLength = true; u256 m_length; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 2b4e332c0..bfa4dada9 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -507,7 +507,9 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) case Type::Category::Array: { ArrayType const* array = dynamic_cast(_type); - if (array->isByteArray()) + if (array->isString()) + r.type = SolidityType::Type::String; + else if (array->isByteArray()) r.type = SolidityType::Type::Bytes; else { diff --git a/mix/SolidityType.h b/mix/SolidityType.h index accdb14b4..75f47e7fa 100644 --- a/mix/SolidityType.h +++ b/mix/SolidityType.h @@ -45,6 +45,7 @@ struct SolidityType Bool, Address, Bytes, + String, Enum, Struct }; diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index f9bf78d0a..f7390dc93 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -568,6 +568,33 @@ BOOST_AUTO_TEST_CASE(return_param_in_abi) checkInterface(sourceCode, interface); } +BOOST_AUTO_TEST_CASE(strings_and_arrays) +{ + // bug #1801 + char const* sourceCode = R"( + contract test { + function f(string a, bytes b, uint[] c) external {} + } + )"; + + char const* interface = R"( + [ + { + "constant" : false, + "name": "f", + "inputs": [ + { "name": "a", "type": "string" }, + { "name": "b", "type": "bytes" }, + { "name": "c", "type": "uint256[]" } + ], + "outputs": [], + "type" : "function" + } + ] + )"; + checkInterface(sourceCode, interface); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index c52bbf9de..48404aaac 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1783,6 +1783,39 @@ BOOST_AUTO_TEST_CASE(uninitialized_var) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(string) +{ + char const* sourceCode = R"( + contract C { + string s; + function f(string x) external { s = x; } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); +} + +BOOST_AUTO_TEST_CASE(string_index) +{ + char const* sourceCode = R"( + contract C { + string s; + function f() { var a = s[2]; } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(string_length) +{ + char const* sourceCode = R"( + contract C { + string s; + function f() { var a = s.length; } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From df3313046b1129aee39a62a6a50169c87f3071f4 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 28 May 2015 17:05:52 +0200 Subject: [PATCH 04/52] - add validation for input parameters. - ui bug fix. --- mix/qml.qrc | 1 + mix/qml/QIntTypeView.qml | 7 +++ mix/qml/TransactionDialog.qml | 23 ++++++- mix/qml/js/InputValidator.js | 112 ++++++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 mix/qml/js/InputValidator.js diff --git a/mix/qml.qrc b/mix/qml.qrc index c47a7254f..784404270 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -63,5 +63,6 @@ qml/js/Printer.js qml/js/ansi2html.js qml/js/NetworkDeployment.js + qml/js/InputValidator.js diff --git a/mix/qml/QIntTypeView.qml b/mix/qml/QIntTypeView.qml index a3c67aafc..c42e65654 100644 --- a/mix/qml/QIntTypeView.qml +++ b/mix/qml/QIntTypeView.qml @@ -21,8 +21,15 @@ Item clip: true selectByMouse: true text: value + anchors.fill: parent font.pointSize: dbgStyle.general.basicFontSize color: dbgStyle.general.basicColor + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: textinput.forceActiveFocus() + } } } } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index e7fe22e51..a4c896d3f 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -6,6 +6,7 @@ import QtQuick.Window 2.0 import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper +import "js/InputValidator.js" as InputValidator import "." Dialog { @@ -503,10 +504,22 @@ Dialog { anchors.right: parent.right; Button { + text: qsTr("OK"); onClicked: { - close(); - accepted(); + var invalid = InputValidator.validate(paramsModel, paramValues); + if (invalid.length === 0) + { + close(); + accepted(); + } + else + { + errorDialog.text = qsTr("some parameters are invalid:\n"); + for (var k in invalid) + errorDialog.text += invalid[k].message + "\n"; + errorDialog.open(); + } } } @@ -514,6 +527,12 @@ Dialog { text: qsTr("Cancel"); onClicked: close(); } + + MessageDialog { + id: errorDialog + standardButtons: StandardButton.Ok + icon: StandardIcon.Critical + } } } } diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js new file mode 100644 index 000000000..6e94dec6e --- /dev/null +++ b/mix/qml/js/InputValidator.js @@ -0,0 +1,112 @@ +var nbRegEx = new RegExp('^[0-9]+$'); +function validate(model, values) +{ + var inError = []; + for (var k in model) + { + if (values[model[k].name]) + { + var type = model[k].type.name; + var res; + if (type.indexOf("int") !== -1) + res = validateInt(type, values[model[k].name]); + else if (type.indexOf("bytes") !== -1) + res = validateBytes(type, values[model[k].name]); + else if (type.indexOf("bool") !== -1) + res = validateBool(type, values[model[k].name]); + else if (type.indexOf("address") !== -1) + res = validateAddress(type, values[model[k].name]); + else + res = validateAddress(type, values[model[k].name]); //we suppose that this is a ctr type. + if (!res.valid) + inError.push({ type: type, value: values, message: res.message }); + } + } + return inError; +} + +function validateInt(_type, _value) +{ + var ret = { valid: true, message: "" } + if (_value.indexOf("-") === 0) + { + _value = _value.substring(1); + if (_type.indexOf("uint") === -1) + { + ret.valid = false; + ret.message = "uint type cannot represent negative number"; + return false; + } + } + ret.valid = nbRegEx.test(_value); + if (!ret.valid) + ret.message = _value + " does not represent " + _type + " type."; + else + { + var t = _type.replace("uint", "").replace("int", ""); + var max = parseInt(t) / 4; + if (_value.length > max) + { + ret.valid = false; + ret.message = _type + " should not contains more than " + max + " digits"; + } + } + return ret; +} + +function validateAddress(_type, _value) +{ + var ret = { valid: true, message: "" } + if (_value.indexOf("<") === 0 && _value.indexOf(">") === _value.length - 1) + { + var v = _value.split(' - '); + console.log(JSON.stringify(v)); + if (v.length !== 2 || !nbRegEx.test(v[1].replace(">", ""))) // + { + ret.valid = false; + ret.message = _value + " is not a valid token for address type."; + } + } + else if (_value.indexOf("0x") !== 0) + { + ret.valid = false + ret.message = "Address type should start with 0x."; + } + else + { + _value = _value.substring(2); + if (_value.length !== 40) + { + ret.valid = false + ret.message = "Address type should contain 40 characters."; + } + } + return ret; +} + +function validateBytes(_type, _value) +{ + var ret = { valid: true, message: "" } + if (_value.length > parseInt(_type.replace("bytes", "")) ) + { + ret.valid = false; + ret.message = _type + " should not contains more than " + _type.replace("bytes", "") + " characters"; + } + return ret; +} + +function validateBool(_type, _value) +{ + var ret = { valid: true, message: "" } + if (_value !== "1" && _value !== "0") + { + ret.valid = false; + ret.message = _value + " is not in the correct bool format"; + } + return ret; +} + +function validateEnum(_type, _value) +{ +} + From 1482599e521d1406611969eceeb6e8c593a84544 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 29 May 2015 16:28:30 +0200 Subject: [PATCH 05/52] - Check uint, int input from c++. - Check address also by contract name. --- mix/QBigInt.cpp | 35 +++++++++++++++++++++++++++++++++++ mix/QBigInt.h | 3 +++ mix/qml/TransactionDialog.qml | 2 +- mix/qml/js/InputValidator.js | 29 +++++++++++++++++++++-------- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/mix/QBigInt.cpp b/mix/QBigInt.cpp index 21d32a9c3..ee29cea43 100644 --- a/mix/QBigInt.cpp +++ b/mix/QBigInt.cpp @@ -57,3 +57,38 @@ QBigInt* QBigInt::divide(QBigInt* const& _value) const BigIntVariant toDivide = _value->internalValue(); return new QBigInt(boost::apply_visitor(mix::divide(), m_internalValue, toDivide)); } + +QVariantMap QBigInt::checkAgainst(QString const& _type) const +{ + QVariantMap ret; + QString type = _type; + QString capacity = type.replace("uint", "").replace("int", ""); + if (capacity.isEmpty()) + capacity = "256"; + bigint range = 256^(capacity.toInt() / 8); + bigint value = boost::get(this->internalValue()); + ret.insert("valid", true); + if (_type.startsWith("uint") && value > range - 1) + { + ret.insert("minValue", "0"); + std::ostringstream s; + s << range - 1; + ret.insert("maxValue", QString::fromStdString(s.str())); + if (value > range) + ret["valid"] = false; + } + else if (_type.startsWith("int")) + { + range = range / 2; + std::ostringstream s; + s << -range; + ret.insert("minValue", QString::fromStdString(s.str())); + s.str(""); + s.clear(); + s << range - 1; + ret.insert("maxValue", QString::fromStdString(s.str())); + if (-range > value || value > range - 1) + ret["valid"] = false; + } + return ret; +} diff --git a/mix/QBigInt.h b/mix/QBigInt.h index b549a16db..ccf487d2a 100644 --- a/mix/QBigInt.h +++ b/mix/QBigInt.h @@ -84,6 +84,7 @@ public: Q_INVOKABLE QString value() const; /// Set the value of the BigInteger used. Will use u256 type. Invokable from QML. Q_INVOKABLE void setValue(QString const& _value) { m_internalValue = dev::jsToU256(_value.toStdString()); } + Q_INVOKABLE void setBigInt(QString const& _value) { m_internalValue = bigint(_value.toStdString()); } /// Subtract by @a _value. Invokable from QML. Q_INVOKABLE QBigInt* subtract(QBigInt* const& _value) const; /// Add @a _value to the current big integer. Invokable from QML. @@ -92,6 +93,8 @@ public: Q_INVOKABLE QBigInt* multiply(QBigInt* const& _value) const; /// divide by @a _value. Invokable from QML. Q_INVOKABLE QBigInt* divide(QBigInt* const& _value) const; + /// check if the current value satisfy the given type + Q_INVOKABLE QVariantMap checkAgainst(QString const& _type) const; protected: BigIntVariant m_internalValue; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index a4c896d3f..df5ad781b 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -515,7 +515,7 @@ Dialog { } else { - errorDialog.text = qsTr("some parameters are invalid:\n"); + errorDialog.text = qsTr("Some parameters are invalid:\n"); for (var k in invalid) errorDialog.text += invalid[k].message + "\n"; errorDialog.open(); diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js index 6e94dec6e..37185b898 100644 --- a/mix/qml/js/InputValidator.js +++ b/mix/qml/js/InputValidator.js @@ -1,3 +1,5 @@ +Qt.include("QEtherHelper.js") + var nbRegEx = new RegExp('^[0-9]+$'); function validate(model, values) { @@ -8,7 +10,9 @@ function validate(model, values) { var type = model[k].type.name; var res; - if (type.indexOf("int") !== -1) + if (isContractType(type)) + res = validateAddress(type, values[model[k].name]); + else if (type.indexOf("int") !== -1) res = validateInt(type, values[model[k].name]); else if (type.indexOf("bytes") !== -1) res = validateBytes(type, values[model[k].name]); @@ -17,7 +21,7 @@ function validate(model, values) else if (type.indexOf("address") !== -1) res = validateAddress(type, values[model[k].name]); else - res = validateAddress(type, values[model[k].name]); //we suppose that this is a ctr type. + res.valid = true; if (!res.valid) inError.push({ type: type, value: values, message: res.message }); } @@ -25,6 +29,16 @@ function validate(model, values) return inError; } +function isContractType(_type) +{ + for (var k in Object.keys(codeModel.contracts)) + { + if ("contract " + Object.keys(codeModel.contracts)[k] === _type) + return true; + } + return false; +} + function validateInt(_type, _value) { var ret = { valid: true, message: "" } @@ -35,7 +49,6 @@ function validateInt(_type, _value) { ret.valid = false; ret.message = "uint type cannot represent negative number"; - return false; } } ret.valid = nbRegEx.test(_value); @@ -43,12 +56,13 @@ function validateInt(_type, _value) ret.message = _value + " does not represent " + _type + " type."; else { - var t = _type.replace("uint", "").replace("int", ""); - var max = parseInt(t) / 4; - if (_value.length > max) + var bigInt = createBigInt(_value); + bigInt.setBigInt(_value); + var result = bigInt.checkAgainst(_type); + if (!result.valid) { ret.valid = false; - ret.message = _type + " should not contains more than " + max + " digits"; + ret.message = _type + " should be between " + result.minValue + " and " + result.maxValue; } } return ret; @@ -60,7 +74,6 @@ function validateAddress(_type, _value) if (_value.indexOf("<") === 0 && _value.indexOf(">") === _value.length - 1) { var v = _value.split(' - '); - console.log(JSON.stringify(v)); if (v.length !== 2 || !nbRegEx.test(v[1].replace(">", ""))) // { ret.valid = false; From 74c46b8298a9c69327441c8fd4596f2d2566f6c6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 29 May 2015 16:34:34 +0200 Subject: [PATCH 06/52] rollback --- eth/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/eth/main.cpp b/eth/main.cpp index 645465234..b7bdee78b 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -628,7 +628,6 @@ int main(int argc, char** argv) nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), netPrefs, &nodesState); - auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); From 05c47db94769bac8afe7f18171c9c6a04f275f4a Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 29 May 2015 16:39:07 +0200 Subject: [PATCH 07/52] rollback --- eth/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/eth/main.cpp b/eth/main.cpp index b7bdee78b..645465234 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -628,6 +628,7 @@ int main(int argc, char** argv) nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), netPrefs, &nodesState); + auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); From fcc6d2f62172eb6aa547b76653328522a0cc35c5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 12:38:25 +0800 Subject: [PATCH 08/52] Possible MSVC workaround. --- libethereum/BlockQueue.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 4a7a61a31..c2bd35afc 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -102,6 +102,7 @@ void BlockQueue::verifierBody() RLP r(&res.second); for (auto const& uncle: r[2]) + { try { BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); @@ -125,6 +126,7 @@ void BlockQueue::verifierBody() badBlockHeader(uncle.data(), _e.what()); throw; } + } } catch (...) { From ec0074c225ecce21ed73cee2df87af95fae216af Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Jun 2015 09:48:19 +0200 Subject: [PATCH 09/52] add ability to test uncle as brother --- test/libethereum/blockchain.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 4e98b4036..0ea8b95a8 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -547,6 +547,10 @@ mArray importUncles(mObject const& blObj, vector& vBiUncles, vector Date: Mon, 1 Jun 2015 09:50:39 +0200 Subject: [PATCH 10/52] add uncle is brother test --- .../BlockTestsFiller/bcUncleTestFiller.json | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json index aeb372f67..761bce316 100644 --- a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json @@ -85,6 +85,108 @@ ] }, + "UncleIsBrother" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + { + "overwriteAndRedoPoW" : "parentHashIsBlocksParent", + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "acde5374fce5edbc8e2a8697c15331677e6ebf0b", + "difficulty" : "131072", + "extraData" : "0x", + "gasLimit" : "4141592", + "gasUsed" : "150000", + "hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04", + "mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770", + "nonce" : "18a524c1790fa83b", + "number" : "2", + "parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd", + "timestamp" : "142813170", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } + ] + } + ] + }, + "uncleHeaderWithGeneration0" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", From be62f618372e41005dfe4612f102b1aeb1935939 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 19 May 2015 16:55:43 +0200 Subject: [PATCH 11/52] Test for issue #1977 Test that reproduces issue #1977 and will fail on ArchLinux with Boost version: 1.58.0-1 gcc version: 4.9.2-4 --- test/libevm/vm.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 7b589d238..9f790501d 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -438,6 +438,15 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) BOOST_AUTO_TEST_SUITE(VMTests) +// test that reproduces issue https://github.com/ethereum/cpp-ethereum/issues/1977 +BOOST_AUTO_TEST_CASE(u256_overflow_test) +{ + dev::u256 a = 14; + dev::bigint b = dev::bigint("115792089237316195423570985008687907853269984665640564039457584007913129639948"); + // to fix cast `a` to dev::bigint + BOOST_CHECK(a < b); +} + BOOST_AUTO_TEST_CASE(vmtests) { dev::test::executeTests("vmtests", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests); From a61e4a70a33fde189e50bab45a67d7c5b40bbdc6 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Jun 2015 10:40:17 +0200 Subject: [PATCH 12/52] Move the u256 test to external_dependencies tests --- test/CMakeLists.txt | 1 + .../external_dependencies/CMakeLists.txt | 5 +++ .../external_dependencies/boost.cpp | 37 +++++++++++++++++++ test/libevm/vm.cpp | 9 ----- 4 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 test/libdevcore/external_dependencies/CMakeLists.txt create mode 100644 test/libdevcore/external_dependencies/boost.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 39a235c58..0812a278a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,6 +19,7 @@ endmacro() add_subdirectory(fuzzTesting) add_subdirectory(libdevcore) +add_subdirectory(libdevcore/external_dependencies) add_subdirectory(libdevcrypto) add_subdirectory(libethcore) add_subdirectory(libethereum) diff --git a/test/libdevcore/external_dependencies/CMakeLists.txt b/test/libdevcore/external_dependencies/CMakeLists.txt new file mode 100644 index 000000000..3ceda13b0 --- /dev/null +++ b/test/libdevcore/external_dependencies/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_policy(SET CMP0015 NEW) + +aux_source_directory(. SRCS) + +add_sources(${SRCS}) diff --git a/test/libdevcore/external_dependencies/boost.cpp b/test/libdevcore/external_dependencies/boost.cpp new file mode 100644 index 000000000..5212c260b --- /dev/null +++ b/test/libdevcore/external_dependencies/boost.cpp @@ -0,0 +1,37 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file boost.cpp + * @author Lefteris Karapetsas + * @date 205 + * Tests for external dependencies: Boost + */ + +#include +#include + +BOOST_AUTO_TEST_SUITE(ExtDepBoost) + +// test that reproduces issue https://github.com/ethereum/cpp-ethereum/issues/1977 +BOOST_AUTO_TEST_CASE(u256_overflow_test) +{ + dev::u256 a = 14; + dev::bigint b = dev::bigint("115792089237316195423570985008687907853269984665640564039457584007913129639948"); + // to fix cast `a` to dev::bigint + BOOST_CHECK(a < b); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 9f790501d..7b589d238 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -438,15 +438,6 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) BOOST_AUTO_TEST_SUITE(VMTests) -// test that reproduces issue https://github.com/ethereum/cpp-ethereum/issues/1977 -BOOST_AUTO_TEST_CASE(u256_overflow_test) -{ - dev::u256 a = 14; - dev::bigint b = dev::bigint("115792089237316195423570985008687907853269984665640564039457584007913129639948"); - // to fix cast `a` to dev::bigint - BOOST_CHECK(a < b); -} - BOOST_AUTO_TEST_CASE(vmtests) { dev::test::executeTests("vmtests", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests); From 2c89b071d0515d7335048f71de17625ef03db25b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Jun 2015 11:09:38 +0200 Subject: [PATCH 13/52] Move external-dependencies test out of lifdevcore --- test/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../external_dependencies => external-dependencies}/boost.cpp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename test/{libdevcore/external_dependencies => external-dependencies}/CMakeLists.txt (100%) rename test/{libdevcore/external_dependencies => external-dependencies}/boost.cpp (98%) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0812a278a..d39a5cca1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,13 +19,13 @@ endmacro() add_subdirectory(fuzzTesting) add_subdirectory(libdevcore) -add_subdirectory(libdevcore/external_dependencies) add_subdirectory(libdevcrypto) add_subdirectory(libethcore) add_subdirectory(libethereum) add_subdirectory(libevm) add_subdirectory(libnatspec) add_subdirectory(libp2p) +add_subdirectory(external-dependencies) if (JSCONSOLE) add_subdirectory(libjsengine) diff --git a/test/libdevcore/external_dependencies/CMakeLists.txt b/test/external-dependencies/CMakeLists.txt similarity index 100% rename from test/libdevcore/external_dependencies/CMakeLists.txt rename to test/external-dependencies/CMakeLists.txt diff --git a/test/libdevcore/external_dependencies/boost.cpp b/test/external-dependencies/boost.cpp similarity index 98% rename from test/libdevcore/external_dependencies/boost.cpp rename to test/external-dependencies/boost.cpp index 5212c260b..91bf384b1 100644 --- a/test/libdevcore/external_dependencies/boost.cpp +++ b/test/external-dependencies/boost.cpp @@ -16,7 +16,7 @@ */ /** @file boost.cpp * @author Lefteris Karapetsas - * @date 205 + * @date 2015 * Tests for external dependencies: Boost */ From a706397875f37bafd85e3d280ed02f341197cde2 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 1 Jun 2015 12:01:01 +0200 Subject: [PATCH 14/52] MSVS compiler error and warnings fixed --- libp2p/UDP.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index a455b5057..b032c9e73 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -65,8 +65,8 @@ protected: */ struct RLPXDatagramFace: public UDPDatagram { - static uint32_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } - static uint32_t secondsSinceEpoch() { return std::chrono::duration_cast((std::chrono::system_clock::now()).time_since_epoch()).count(); } + static uint32_t futureFromEpoch(std::chrono::seconds _sec) { return static_cast(std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count()); } + static uint32_t secondsSinceEpoch() { return static_cast(std::chrono::duration_cast((std::chrono::system_clock::now()).time_since_epoch()).count()); } static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp); virtual uint8_t packetType() = 0; @@ -115,7 +115,7 @@ class UDPSocket: UDPSocketFace, public std::enable_shared_from_this Date: Fri, 15 May 2015 12:23:13 +0200 Subject: [PATCH 15/52] added error jump instead of STOP instraction in case of exception --- libevmasm/Assembly.cpp | 28 +++- libevmasm/Assembly.h | 6 +- libevmasm/AssemblyItem.h | 2 +- libevmasm/ControlFlowGraph.cpp | 8 +- libsolidity/ArrayUtils.cpp | 8 +- libsolidity/Compiler.cpp | 3 +- libsolidity/CompilerContext.h | 2 + libsolidity/ExpressionCompiler.cpp | 7 +- test/libsolidity/SolidityCompiler.cpp | 192 ---------------------- test/libsolidity/SolidityEndToEndTest.cpp | 1 + 10 files changed, 43 insertions(+), 214 deletions(-) delete mode 100644 test/libsolidity/SolidityCompiler.cpp diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 5cf3b787a..f492260af 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -127,7 +127,10 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con _out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; break; case PushTag: - _out << " PUSH [tag" << dec << i.data() << "]"; + if (i.data() == 0) + _out << " PUSH [ErrorTag]"; + else + _out << " PUSH [tag" << dec << i.data() << "]"; break; case PushSub: _out << " PUSH [$" << h256(i.data()).abridged() << "]"; @@ -207,6 +210,10 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes createJsonValue("PUSH tag", i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: + if (i.data() == 0) + collection.append( + createJsonValue("PUSH [ErrorTag]", i.getLocation().start, i.getLocation().end, "")); + collection.append( createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); break; @@ -226,7 +233,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes collection.append( createJsonValue("tag", i.getLocation().start, i.getLocation().end, string(i.data()))); collection.append( - createJsonValue("JUMDEST", i.getLocation().start, i.getLocation().end)); + createJsonValue("JUMPDEST", i.getLocation().start, i.getLocation().end)); break; case PushData: collection.append(createJsonValue("PUSH data", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); @@ -387,6 +394,11 @@ bytes Assembly::assemble() const // m_data must not change from here on for (AssemblyItem const& i: m_items) + { + // store position of the invalid jump destination + if (i.type() != Tag && tagPos[0] == 0) + tagPos[0] = ret.size(); + switch (i.type()) { case Operation: @@ -448,17 +460,23 @@ bytes Assembly::assemble() const } case Tag: tagPos[(unsigned)i.data()] = ret.size(); + assertThrow(i.data() != 0, AssemblyException, ""); ret.push_back((byte)Instruction::JUMPDEST); break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); } - + } for (auto const& i: tagRef) { bytesRef r(ret.data() + i.first, bytesPerTag); - //@todo in the failure case, we could use the position of the invalid jumpdest - toBigEndian(i.second < tagPos.size() ? tagPos[i.second] : (1 << (8 * bytesPerTag)) - 1, r); + auto tag = i.second; + if (tag >= tagPos.size()) + tag = 0; + if (tag == 0) + assertThrow(tagPos[tag] != 0, AssemblyException, ""); + + toBigEndian(tagPos[tag], r); } if (!m_data.empty()) diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index b4850f7d0..4550eb6e7 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -67,6 +67,8 @@ public: AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; } + AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); } + template Assembly& operator<<(T const& _d) { append(_d); return *this; } AssemblyItems const& getItems() const { return m_items; } AssemblyItem const& back() const { return m_items.back(); } @@ -97,7 +99,6 @@ public: const StringMap &_sourceCodes = StringMap(), bool _inJsonFormat = false ) const; - protected: std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } @@ -109,7 +110,8 @@ private: Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const; protected: - unsigned m_usedTags = 0; + // 0 is reserved for exception + unsigned m_usedTags = 1; AssemblyItems m_items; mutable std::map m_data; std::vector m_subs; diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 7d8f3d9a4..9eca0a7d1 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -65,7 +65,7 @@ public: /// @returns the instruction of this item (only valid if type() == Operation) Instruction instruction() const { return Instruction(byte(m_data)); } - /// @returns true iff the type and data of the items are equal. + /// @returns true if the type and data of the items are equal. bool operator==(AssemblyItem const& _other) const { return m_type == _other.m_type && m_data == _other.m_data; } bool operator!=(AssemblyItem const& _other) const { return !operator==(_other); } /// Less-than operator compatible with operator==. diff --git a/libevmasm/ControlFlowGraph.cpp b/libevmasm/ControlFlowGraph.cpp index 3566bdb17..41a53aa82 100644 --- a/libevmasm/ControlFlowGraph.cpp +++ b/libevmasm/ControlFlowGraph.cpp @@ -226,7 +226,10 @@ void ControlFlowGraph::gatherKnowledge() //@todo we might have to do something like incrementing the sequence number for each JUMPDEST assertThrow(!!workQueue.back().first, OptimizerException, ""); if (!m_blocks.count(workQueue.back().first)) + { + workQueue.pop_back(); continue; // too bad, we do not know the tag, probably an invalid jump + } BasicBlock& block = m_blocks.at(workQueue.back().first); KnownStatePointer state = workQueue.back().second; workQueue.pop_back(); @@ -257,10 +260,7 @@ void ControlFlowGraph::gatherKnowledge() ); state->feedItem(m_items.at(pc++)); - if (tags.empty() || std::any_of(tags.begin(), tags.end(), [&](u256 const& _tag) - { - return !m_blocks.count(BlockId(_tag)); - })) + if (tags.empty()) { if (!unknownJumpEncountered) { diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index 448e4da2a..f59385d97 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -455,12 +455,10 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const m_context << eth::Instruction::DUP2 << load; // stack: // check out-of-bounds access - m_context << eth::Instruction::DUP2 << eth::Instruction::LT; - eth::AssemblyItem legalAccess = m_context.appendConditionalJump(); - // out-of-bounds access throws exception (just STOP for now) - m_context << eth::Instruction::STOP; + m_context << eth::Instruction::DUP2 << eth::Instruction::LT << eth::Instruction::ISZERO; + // out-of-bounds access throws exception + m_context.appendConditionalJumpTo(m_context.errorTag()); - m_context << legalAccess; // stack: m_context << eth::Instruction::SWAP1; if (_arrayType.isDynamicallySized()) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 5e24aaaa2..261473404 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -193,8 +193,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) appendReturnValuePacker(FunctionType(*fallback).getReturnParameterTypes()); } else - m_context << eth::Instruction::STOP; // function not found - + m_context.appendConditionalJumpTo(m_context.errorTag()); // function not found for (auto const& it: interfaceFunctions) { FunctionTypePointer const& functionType = it.second; diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 7bc29de1a..dbf3dcd4f 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -98,6 +98,8 @@ public: eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); } /// Appends a JUMP to a tag already on the stack CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary); + /// Appends a JUMP to an "ErrorTag" + eth::AssemblyItem errorTag() { return m_asm.errorTag(); } /// Appends a JUMP to a specific tag CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } /// Appends pushing of a new tag and @returns the new tag. diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 2e513b7fc..a9f0ba3ef 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1102,9 +1102,10 @@ void ExpressionCompiler::appendExternalFunctionCall( ) m_context << eth::Instruction::CALLCODE; else - m_context << eth::Instruction::CALL; - auto tag = m_context.appendConditionalJump(); - m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0. + { + m_context << eth::Instruction::CALL << eth::Instruction::ISZERO; + auto tag = m_context.appendConditionalJumpTo(m_context.errorTag());// if CALL leaves 0. + } if (_functionType.valueSet()) m_context << eth::Instruction::POP; if (_functionType.gasSet()) diff --git a/test/libsolidity/SolidityCompiler.cpp b/test/libsolidity/SolidityCompiler.cpp deleted file mode 100644 index dda7847ed..000000000 --- a/test/libsolidity/SolidityCompiler.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** - * @author Christian - * @date 2014 - * Unit tests for the solidity compiler. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -using namespace dev::eth; - -namespace dev -{ -namespace solidity -{ -namespace test -{ - -namespace -{ - -bytes compileContract(const string& _sourceCode) -{ - Parser parser; - ASTPointer sourceUnit; - BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared(CharStream(_sourceCode)))); - NameAndTypeResolver resolver({}); - resolver.registerDeclarations(*sourceUnit); - for (ASTPointer const& node: sourceUnit->getNodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - { - BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); - } - for (ASTPointer const& node: sourceUnit->getNodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - { - BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract)); - } - for (ASTPointer const& node: sourceUnit->getNodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - { - Compiler compiler; - compiler.compileContract(*contract, map{}); - - // debug - //compiler.streamAssembly(cout); - return compiler.getAssembledBytecode(); - } - BOOST_FAIL("No contract found in source."); - return bytes(); -} - -/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation. -/// This is necessary since the compiler will add boilerplate add the beginning that is not -/// tested here. -void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset) -{ - BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size()); - auto checkStart = _compiledCode.begin() + _offset; - BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(), - _expectation.begin(), _expectation.end()); -} - -} // end anonymous namespace - -BOOST_AUTO_TEST_SUITE(SolidityCompiler) - -BOOST_AUTO_TEST_CASE(smoke_test) -{ - char const* sourceCode = "contract test {\n" - " function f() { var x = 2; }\n" - "}\n"; - bytes code = compileContract(sourceCode); - - unsigned boilerplateSize = 73; - bytes expectation({byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x0, // initialize local variable x - byte(Instruction::PUSH1), 0x2, - byte(Instruction::SWAP1), - byte(Instruction::POP), - byte(Instruction::JUMPDEST), - byte(Instruction::POP), - byte(Instruction::JUMP)}); - checkCodePresentAt(code, expectation, boilerplateSize); -} - -BOOST_AUTO_TEST_CASE(ifStatement) -{ - char const* sourceCode = "contract test {\n" - " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" - "}\n"; - bytes code = compileContract(sourceCode); - unsigned shift = 60; - unsigned boilerplateSize = 73; - bytes expectation({ - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x0, - byte(Instruction::DUP1), - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), byte(0x0f + shift), // "false" target - byte(Instruction::JUMPI), - // "if" body - byte(Instruction::PUSH1), 0x4d, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x21 + shift), - byte(Instruction::JUMP), - // new check "else if" condition - byte(Instruction::JUMPDEST), - byte(Instruction::DUP1), - byte(Instruction::ISZERO), - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), byte(0x1c + shift), - byte(Instruction::JUMPI), - // "else if" body - byte(Instruction::PUSH1), 0x4e, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x20 + shift), - byte(Instruction::JUMP), - // "else" body - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x4f, - byte(Instruction::POP), - }); - checkCodePresentAt(code, expectation, boilerplateSize); -} - -BOOST_AUTO_TEST_CASE(loops) -{ - char const* sourceCode = "contract test {\n" - " function f() { while(true){1;break;2;continue;3;return;4;} }" - "}\n"; - bytes code = compileContract(sourceCode); - unsigned shift = 60; - unsigned boilerplateSize = 73; - bytes expectation({byte(Instruction::JUMPDEST), - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x1, - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), byte(0x21 + shift), - byte(Instruction::JUMPI), - byte(Instruction::PUSH1), 0x1, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x21 + shift), - byte(Instruction::JUMP), // break - byte(Instruction::PUSH1), 0x2, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x2 + shift), - byte(Instruction::JUMP), // continue - byte(Instruction::PUSH1), 0x3, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x22 + shift), - byte(Instruction::JUMP), // return - byte(Instruction::PUSH1), 0x4, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x2 + shift), - byte(Instruction::JUMP), - byte(Instruction::JUMPDEST), - byte(Instruction::JUMPDEST), - byte(Instruction::JUMP)}); - - checkCodePresentAt(code, expectation, boilerplateSize); -} - -BOOST_AUTO_TEST_SUITE_END() - -} -} -} // end namespaces diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 503615a5a..f8d20d70f 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1784,6 +1784,7 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses) } )"; compileAndRun(sourceCode, 20); + auto res = callContractFunction("getBalance()"); BOOST_REQUIRE(callContractFunction("getBalance()") == encodeArgs(u256(20 - 5), u256(5))); } From fb564b222ddc581bfbfb73c4f02f646b3d937979 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 19 May 2015 12:58:12 +0200 Subject: [PATCH 16/52] fixed mistake because of conflict resolving --- libsolidity/ExpressionCompiler.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index a9f0ba3ef..063af7ce6 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1102,10 +1102,11 @@ void ExpressionCompiler::appendExternalFunctionCall( ) m_context << eth::Instruction::CALLCODE; else - { - m_context << eth::Instruction::CALL << eth::Instruction::ISZERO; - auto tag = m_context.appendConditionalJumpTo(m_context.errorTag());// if CALL leaves 0. - } + m_context << eth::Instruction::CALL; + + m_context << eth::Instruction::ISZERO; + auto tag = m_context.appendConditionalJumpTo(m_context.errorTag());// if CALL leaves 0. + if (_functionType.valueSet()) m_context << eth::Instruction::POP; if (_functionType.gasSet()) From 74549bd60fff00dc0b01d4ba9e8ab7af43c7078b Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 19 May 2015 14:55:12 +0200 Subject: [PATCH 17/52] added test to check evm exception --- test/libsolidity/SolidityEndToEndTest.cpp | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f8d20d70f..faa5dad4d 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4111,6 +4111,30 @@ BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) BOOST_CHECK(callContractFunction("deleteIt()") == encodeArgs(0)); } +BOOST_AUTO_TEST_CASE(evm_exceptions) +{ + char const* sourceCode = R"( + contract A { + uint[3] arr; + bool public test = false; + function getElement(uint i) returns (uint) + { + return arr[i]; + } + function testIt() returns (bool) + { + uint i = this.getElement(5); + test = true; + return true; + } + } + )"; + compileAndRun(sourceCode, 0, "A"); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(false)); + BOOST_CHECK(callContractFunction("testIt()") == encodeArgs()); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(false)); +} + BOOST_AUTO_TEST_SUITE_END() } From d89589febc52aa7a85a013dfefb0f52eb5da93bd Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 19 May 2015 15:44:58 +0200 Subject: [PATCH 18/52] style fixes --- libevmasm/Assembly.h | 2 +- libsolidity/CompilerContext.h | 2 +- libsolidity/ExpressionCompiler.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 4550eb6e7..3c82125a1 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -67,7 +67,7 @@ public: AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; } - AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); } + AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); } template Assembly& operator<<(T const& _d) { append(_d); return *this; } AssemblyItems const& getItems() const { return m_items; } diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index dbf3dcd4f..573e0b576 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -98,7 +98,7 @@ public: eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); } /// Appends a JUMP to a tag already on the stack CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary); - /// Appends a JUMP to an "ErrorTag" + /// Returns an "ErrorTag" eth::AssemblyItem errorTag() { return m_asm.errorTag(); } /// Appends a JUMP to a specific tag CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 063af7ce6..c8aece85a 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1104,8 +1104,9 @@ void ExpressionCompiler::appendExternalFunctionCall( else m_context << eth::Instruction::CALL; + //Propagate error condition (if CALL pushes 0 on stack). m_context << eth::Instruction::ISZERO; - auto tag = m_context.appendConditionalJumpTo(m_context.errorTag());// if CALL leaves 0. + auto tag = m_context.appendConditionalJumpTo(m_context.errorTag()); if (_functionType.valueSet()) m_context << eth::Instruction::POP; From 77e1d116ca21fff8983fa67810f7c07806e95251 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 21 May 2015 12:10:26 +0200 Subject: [PATCH 19/52] one more test to test the call of non-existed function Conflicts: test/libsolidity/SolidityEndToEndTest.cpp --- libsolidity/ExpressionCompiler.cpp | 2 +- test/libsolidity/SolidityEndToEndTest.cpp | 28 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index c8aece85a..ae8bcaeee 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1106,7 +1106,7 @@ void ExpressionCompiler::appendExternalFunctionCall( //Propagate error condition (if CALL pushes 0 on stack). m_context << eth::Instruction::ISZERO; - auto tag = m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalJumpTo(m_context.errorTag()); if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index faa5dad4d..839ad7928 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4111,7 +4111,7 @@ BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) BOOST_CHECK(callContractFunction("deleteIt()") == encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(evm_exceptions) +BOOST_AUTO_TEST_CASE(evm_exceptions_out_of_band_access) { char const* sourceCode = R"( contract A { @@ -4135,6 +4135,32 @@ BOOST_AUTO_TEST_CASE(evm_exceptions) BOOST_CHECK(callContractFunction("test()") == encodeArgs(false)); } +BOOST_AUTO_TEST_CASE(evm_exceptions_when_calling_non_existing_function) +{ + char const* sourceCode = R"( + contract A { + uint public test = 0; + function badFunction() returns (uint) + { + this.call("123"); + test = 1; + return 2; + } + function testIt() returns (bool) + { + this.badFunction(); + test = 2; + return true; + } + } + )"; + compileAndRun(sourceCode, 0, "A"); + + BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); + BOOST_CHECK(callContractFunction("testIt()") == encodeArgs()); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); +} + BOOST_AUTO_TEST_SUITE_END() } From 52fad1282c64f003c7d60244d21f368f0a269013 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 20 May 2015 13:15:01 +0200 Subject: [PATCH 20/52] corrected asm-json output --- libevmasm/Assembly.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index f492260af..dabf646c1 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -213,9 +213,9 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes if (i.data() == 0) collection.append( createJsonValue("PUSH [ErrorTag]", i.getLocation().start, i.getLocation().end, "")); - - collection.append( - createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); + else + collection.append( + createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); break; case PushSub: collection.append( From 4b0e0d86914d5d52e620524c4d8cc952397983cf Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 21 May 2015 13:02:24 +0200 Subject: [PATCH 21/52] test for exception in constructor --- test/libsolidity/SolidityEndToEndTest.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 839ad7928..76952c676 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4161,6 +4161,23 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_when_calling_non_existing_function) BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); } +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor) +{ + char const* sourceCode = R"( + contract A { + uint public test = 0; + function A() + { + this.call("123"); + test = 1; + } + } + )"; + compileAndRun(sourceCode, 0, "A"); + + BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); +} + BOOST_AUTO_TEST_SUITE_END() } From 803bea66544d5d2c0f7ee112566dbfb054e5d52f Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 21 May 2015 13:45:32 +0200 Subject: [PATCH 22/52] test for constructor (out of band exception) --- test/libsolidity/SolidityEndToEndTest.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 76952c676..c150a488c 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4161,7 +4161,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_when_calling_non_existing_function) BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor) +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) { char const* sourceCode = R"( contract A { @@ -4169,7 +4169,25 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor) function A() { this.call("123"); - test = 1; + ++test; + } + } + )"; + compileAndRun(sourceCode, 0, "A"); + + BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); +} + +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_band) +{ + char const* sourceCode = R"( + contract A { + uint public test = 0; + uint[3] arr; + function A() + { + test = arr[5]; + ++test; } } )"; From 5996d912a2efeaceeeecba382e49d2e884f47d44 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 22 May 2015 14:07:05 +0200 Subject: [PATCH 23/52] remove line for debugging --- test/libsolidity/SolidityEndToEndTest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index c150a488c..e4c5b47f1 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1784,7 +1784,6 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses) } )"; compileAndRun(sourceCode, 20); - auto res = callContractFunction("getBalance()"); BOOST_REQUIRE(callContractFunction("getBalance()") == encodeArgs(u256(20 - 5), u256(5))); } From 7ef2c7dc4424ac6858b43f9be04ab6f3dfd5b597 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 22 May 2015 17:48:38 +0200 Subject: [PATCH 24/52] modified the test --- test/libsolidity/SolidityEndToEndTest.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index e4c5b47f1..538174ab5 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4164,24 +4164,32 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) { char const* sourceCode = R"( contract A { - uint public test = 0; function A() { this.call("123"); + + } + } + contract B { + uint public test = 1; + function testIt() + { + A a; ++test; } } )"; - compileAndRun(sourceCode, 0, "A"); + compileAndRun(sourceCode, 0, "B"); - BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); + BOOST_CHECK(callContractFunction("testIt()") == encodeArgs()); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(2)); } BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_band) { char const* sourceCode = R"( contract A { - uint public test = 0; + uint public test = 1; uint[3] arr; function A() { From a723fb7e813e098ea50fa1f9ba7e62d35db01c8a Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 26 May 2015 15:05:58 +0200 Subject: [PATCH 25/52] special handle of send --- libsolidity/ExpressionCompiler.cpp | 18 +++++++++++++----- libsolidity/ExpressionCompiler.h | 3 ++- test/libsolidity/SolidityEndToEndTest.cpp | 1 - 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index ae8bcaeee..e8ac8ff8b 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -534,7 +534,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) true, true ), - {} + {}, + true ); break; case Location::Suicide: @@ -1034,8 +1035,8 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, - vector> const& _arguments -) + vector> const& _arguments, + bool isSend) { solAssert(_functionType.takesArbitraryParameters() || _arguments.size() == _functionType.getParameterTypes().size(), ""); @@ -1105,8 +1106,15 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << eth::Instruction::CALL; //Propagate error condition (if CALL pushes 0 on stack). - m_context << eth::Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + if (!isSend) + { + m_context << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(m_context.errorTag()); + } else + { + auto tag = m_context.appendConditionalJump(); + m_context << eth::Instruction::STOP << tag; + } if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 954e32c84..6f47762b9 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -100,7 +100,8 @@ private: /// Appends code to call a function of the given type with the given arguments. void appendExternalFunctionCall( FunctionType const& _functionType, - std::vector> const& _arguments + std::vector> const& _arguments, + bool isSend = false ); /// Appends code that evaluates the given arguments and moves the result to memory encoded as /// specified by the ABI. The memory offset is expected to be on the stack and is updated by diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 538174ab5..efebbb2f0 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4167,7 +4167,6 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) function A() { this.call("123"); - } } contract B { From 0d55798adf4757eb26393555f0b8c2ae12de8ed7 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 28 May 2015 14:48:37 +0200 Subject: [PATCH 26/52] removed exception when function is not found --- libsolidity/Compiler.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 18 ++++--------- libsolidity/ExpressionCompiler.h | 6 +---- test/libsolidity/SolidityEndToEndTest.cpp | 32 ++--------------------- 4 files changed, 9 insertions(+), 49 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 261473404..93d786bed 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -193,7 +193,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) appendReturnValuePacker(FunctionType(*fallback).getReturnParameterTypes()); } else - m_context.appendConditionalJumpTo(m_context.errorTag()); // function not found + m_context << eth::Instruction::STOP; // function not found for (auto const& it: interfaceFunctions) { FunctionTypePointer const& functionType = it.second; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index e8ac8ff8b..d618c6311 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -534,8 +534,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) true, true ), - {}, - true + {} ); break; case Location::Suicide: @@ -1035,8 +1034,8 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, - vector> const& _arguments, - bool isSend) + vector> const& _arguments + ) { solAssert(_functionType.takesArbitraryParameters() || _arguments.size() == _functionType.getParameterTypes().size(), ""); @@ -1106,15 +1105,8 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << eth::Instruction::CALL; //Propagate error condition (if CALL pushes 0 on stack). - if (!isSend) - { - m_context << eth::Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); - } else - { - auto tag = m_context.appendConditionalJump(); - m_context << eth::Instruction::STOP << tag; - } + auto tag = m_context.appendConditionalJump(); + m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.// } if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 6f47762b9..174e16d8d 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -98,11 +98,7 @@ private: void appendHighBitsCleanup(IntegerType const& _typeOnStack); /// Appends code to call a function of the given type with the given arguments. - void appendExternalFunctionCall( - FunctionType const& _functionType, - std::vector> const& _arguments, - bool isSend = false - ); + void appendExternalFunctionCall(FunctionType const& _functionType, std::vector> const& _arguments); /// Appends code that evaluates the given arguments and moves the result to memory encoded as /// specified by the ABI. The memory offset is expected to be on the stack and is updated by /// this call. If @a _padToWordBoundaries is set to false, all values are concatenated without diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index efebbb2f0..d2faaae08 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4080,7 +4080,6 @@ BOOST_AUTO_TEST_CASE(struct_delete_member) } )"; compileAndRun(sourceCode, 0, "test"); - auto res = callContractFunction("deleteMember()"); BOOST_CHECK(callContractFunction("deleteMember()") == encodeArgs(0)); } @@ -4106,7 +4105,6 @@ BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) } )"; compileAndRun(sourceCode, 0, "test"); - auto res = callContractFunction("deleteIt()"); BOOST_CHECK(callContractFunction("deleteIt()") == encodeArgs(0)); } @@ -4134,32 +4132,6 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_out_of_band_access) BOOST_CHECK(callContractFunction("test()") == encodeArgs(false)); } -BOOST_AUTO_TEST_CASE(evm_exceptions_when_calling_non_existing_function) -{ - char const* sourceCode = R"( - contract A { - uint public test = 0; - function badFunction() returns (uint) - { - this.call("123"); - test = 1; - return 2; - } - function testIt() returns (bool) - { - this.badFunction(); - test = 2; - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "A"); - - BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); - BOOST_CHECK(callContractFunction("testIt()") == encodeArgs()); - BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); -} - BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) { char const* sourceCode = R"( @@ -4184,7 +4156,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) BOOST_CHECK(callContractFunction("test()") == encodeArgs(2)); } -BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_band) +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) { char const* sourceCode = R"( contract A { @@ -4199,7 +4171,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_band) )"; compileAndRun(sourceCode, 0, "A"); - BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); + //BOOST_CHECK(m_output.empty()); todo } BOOST_AUTO_TEST_SUITE_END() From e8148a444f6f9d5906f0f0f9f9853dc4ea054259 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 29 May 2015 15:39:42 +0200 Subject: [PATCH 27/52] style fixes in test/libsolidity/solidityExecutionFramework.h fixed the test --- test/libsolidity/SolidityEndToEndTest.cpp | 4 +- test/libsolidity/solidityExecutionFramework.h | 281 ++++++++++-------- 2 files changed, 150 insertions(+), 135 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d2faaae08..ef7b5c2a4 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4169,9 +4169,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) } } )"; - compileAndRun(sourceCode, 0, "A"); - - //BOOST_CHECK(m_output.empty()); todo + BOOST_CHECK(execute(sourceCode, 0, "A").empty()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index fa25fb12c..2c70415eb 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -40,142 +40,159 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } - - bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - m_compiler.reset(false, m_addStandardSources); - m_compiler.addSource("", _sourceCode); - ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); - - bytes code = m_compiler.getBytecode(_contractName); - sendMessage(code, true, _value); - BOOST_REQUIRE(!m_output.empty()); - return m_output; - } - - template - bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, - Args const&... _arguments) - { - FixedHash<4> hash(dev::sha3(_sig)); - sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); - return m_output; - } - - template - bytes const& callContractFunction(std::string _sig, Args const&... _arguments) - { - return callContractFunctionWithValue(_sig, 0, _arguments...); - } - - template - void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) - { - bytes solidityResult = callContractFunction(_sig, _arguments...); - bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); - BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." - "\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult)); - } - - template - void testSolidityAgainstCppOnRange(std::string _sig, CppFunction const& _cppFunction, - u256 const& _rangeStart, u256 const& _rangeEnd) - { - for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) - { - bytes solidityResult = callContractFunction(_sig, argument); - bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); - BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." - "\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult) + - "\nArgument: " + toHex(encode(argument))); - } - } - - static bytes encode(bool _value) { return encode(byte(_value)); } - static bytes encode(int _value) { return encode(u256(_value)); } - static bytes encode(char const* _value) { return encode(std::string(_value)); } - static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } - static bytes encode(u256 const& _value) { return toBigEndian(_value); } - static bytes encode(h256 const& _value) { return _value.asBytes(); } - static bytes encode(bytes const& _value, bool _padLeft = true) - { - bytes padding = bytes((32 - _value.size() % 32) % 32, 0); - return _padLeft ? padding + _value : _value + padding; - } - static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } - - template - static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) - { - return encode(_firstArg) + encodeArgs(_followingArgs...); - } - static bytes encodeArgs() - { - return bytes(); - } + ExecutionFramework() { g_logVerbosity = 0; } + + bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", _sourceCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); + + bytes code = m_compiler.getBytecode(_contractName); + sendMessage(code, true, _value); + return m_output; + } + + bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + execute(_sourceCode, _value, _contractName); + BOOST_REQUIRE(!m_output.empty()); + return m_output; + } + + template + bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) + { + FixedHash<4> hash(dev::sha3(_sig)); + sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); + return m_output; + } + + template + bytes const& callContractFunction(std::string _sig, Args const&... _arguments) + { + return callContractFunctionWithValue(_sig, 0, _arguments...); + } + + template + void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) + { + bytes solidityResult = callContractFunction(_sig, _arguments...); + bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, "Computed values do not match.\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult)); + } + + template + void testSolidityAgainstCppOnRange( + std::string _sig, + CppFunction const& _cppFunction, + u256 const& _rangeStart, + u256 const& _rangeEnd + ) + { + for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + { + bytes solidityResult = callContractFunction(_sig, argument); + bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult) + + "\nArgument: " + + toHex(encode(argument)) + ); + } + } + + static bytes encode(bool _value) { return encode(byte(_value)); } + static bytes encode(int _value) { return encode(u256(_value)); } + static bytes encode(char const* _value) { return encode(std::string(_value)); } + static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } + static bytes encode(u256 const& _value) { return toBigEndian(_value); } + static bytes encode(h256 const& _value) { return _value.asBytes(); } + static bytes encode(bytes const& _value, bool _padLeft = true) + { + bytes padding = bytes((32 - _value.size() % 32) % 32, 0); + return _padLeft ? padding + _value : _value + padding; + } + static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + + template + static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) + { + return encode(_firstArg) + encodeArgs(_followingArgs...); + } + static bytes encodeArgs() + { + return bytes(); + } private: - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - _cppFunction(_arguments...); - return bytes(); - } - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - return encode(_cppFunction(_arguments...)); - } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + _cppFunction(_arguments...); + return bytes(); + } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + return encode(_cppFunction(_arguments...)); + } protected: - void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) - { - m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, eth::LastHashes(), 0); - eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) - : eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); - bytes transactionRLP = t.rlp(); - try - { - // this will throw since the transaction is invalid, but it should nevertheless store the transaction - executive.initialize(&transactionRLP); - executive.execute(); - } - catch (...) {} - if (_isCreation) - { - BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); - m_contractAddress = executive.newAddress(); - BOOST_REQUIRE(m_contractAddress); - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - } - else - { - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); - } - BOOST_REQUIRE(executive.go()); - m_state.noteSending(m_sender); - executive.finalize(); - m_gasUsed = executive.gasUsed(); - m_output = executive.out().toVector(); - m_logs = executive.logs(); - } - - bool m_optimize = false; - bool m_addStandardSources = false; - dev::solidity::CompilerStack m_compiler; - Address m_sender; - Address m_contractAddress; - eth::State m_state; - u256 const m_gasPrice = 100 * eth::szabo; - u256 const m_gas = 100000000; - bytes m_output; - eth::LogEntries m_logs; - u256 m_gasUsed; + void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) + { + m_state.addBalance(m_sender, _value); // just in case + eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::Transaction t = _isCreation ? eth::Transaction( + _value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec() + ) : eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); + + bytes transactionRLP = t.rlp(); + try + { + // this will throw since the transaction is invalid, but it should nevertheless store the transaction + executive.initialize(&transactionRLP); + executive.execute(); + } + catch (...) {} + if (_isCreation) + { + BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); + m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + } + else + { + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + } + BOOST_REQUIRE(executive.go()); + m_state.noteSending(m_sender); + executive.finalize(); + m_gasUsed = executive.gasUsed(); + m_output = executive.out().toVector(); + m_logs = executive.logs(); + } + + bool m_optimize = false; + bool m_addStandardSources = false; + dev::solidity::CompilerStack m_compiler; + Address m_sender; + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 100000000; + bytes m_output; + eth::LogEntries m_logs; + u256 m_gasUsed; }; } From 7512689becc4e623a1e576350abd0c191b57242d Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 29 May 2015 18:38:57 +0200 Subject: [PATCH 28/52] style fixes --- libsolidity/ExpressionCompiler.cpp | 4 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- test/libsolidity/solidityExecutionFramework.h | 284 +++++++++--------- 3 files changed, 144 insertions(+), 146 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index d618c6311..6a246f441 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1035,7 +1035,7 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, vector> const& _arguments - ) +) { solAssert(_functionType.takesArbitraryParameters() || _arguments.size() == _functionType.getParameterTypes().size(), ""); @@ -1106,7 +1106,7 @@ void ExpressionCompiler::appendExternalFunctionCall( //Propagate error condition (if CALL pushes 0 on stack). auto tag = m_context.appendConditionalJump(); - m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.// } + m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0. if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index ef7b5c2a4..db115b104 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4145,7 +4145,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) uint public test = 1; function testIt() { - A a; + A a = new A(); ++test; } } diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 2c70415eb..879667fde 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -40,159 +40,157 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } - - bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - m_compiler.reset(false, m_addStandardSources); - m_compiler.addSource("", _sourceCode); - ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); - - bytes code = m_compiler.getBytecode(_contractName); - sendMessage(code, true, _value); - return m_output; - } - - bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - execute(_sourceCode, _value, _contractName); - BOOST_REQUIRE(!m_output.empty()); - return m_output; - } - - template - bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) - { - FixedHash<4> hash(dev::sha3(_sig)); - sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); - return m_output; - } - - template - bytes const& callContractFunction(std::string _sig, Args const&... _arguments) - { - return callContractFunctionWithValue(_sig, 0, _arguments...); - } - - template - void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) - { - bytes solidityResult = callContractFunction(_sig, _arguments...); - bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); - BOOST_CHECK_MESSAGE( - solidityResult == cppResult, "Computed values do not match.\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult)); - } - - template - void testSolidityAgainstCppOnRange( - std::string _sig, - CppFunction const& _cppFunction, - u256 const& _rangeStart, - u256 const& _rangeEnd - ) - { - for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + ExecutionFramework() { g_logVerbosity = 0; } + + bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { - bytes solidityResult = callContractFunction(_sig, argument); - bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); - BOOST_CHECK_MESSAGE( - solidityResult == cppResult, - "Computed values do not match.\nSolidity: " + - toHex(solidityResult) + - "\nC++: " + - toHex(cppResult) + - "\nArgument: " + - toHex(encode(argument)) - ); + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", _sourceCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); + bytes code = m_compiler.getBytecode(_contractName); + sendMessage(code, true, _value); + return m_output; } - } - - static bytes encode(bool _value) { return encode(byte(_value)); } - static bytes encode(int _value) { return encode(u256(_value)); } - static bytes encode(char const* _value) { return encode(std::string(_value)); } - static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } - static bytes encode(u256 const& _value) { return toBigEndian(_value); } - static bytes encode(h256 const& _value) { return _value.asBytes(); } - static bytes encode(bytes const& _value, bool _padLeft = true) - { - bytes padding = bytes((32 - _value.size() % 32) % 32, 0); - return _padLeft ? padding + _value : _value + padding; - } - static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } - - template - static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) - { - return encode(_firstArg) + encodeArgs(_followingArgs...); - } - static bytes encodeArgs() - { - return bytes(); - } -private: - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - _cppFunction(_arguments...); - return bytes(); - } - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - return encode(_cppFunction(_arguments...)); - } + bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + execute(_sourceCode, _value, _contractName); + BOOST_REQUIRE(!m_output.empty()); + return m_output; + } -protected: - void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) - { - m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, eth::LastHashes(), 0); - eth::Transaction t = _isCreation ? eth::Transaction( - _value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec() - ) : eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); - - bytes transactionRLP = t.rlp(); - try + template + bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) { - // this will throw since the transaction is invalid, but it should nevertheless store the transaction - executive.initialize(&transactionRLP); - executive.execute(); + FixedHash<4> hash(dev::sha3(_sig)); + sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); + return m_output; } - catch (...) {} - if (_isCreation) + + template + bytes const& callContractFunction(std::string _sig, Args const&... _arguments) { - BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); - m_contractAddress = executive.newAddress(); - BOOST_REQUIRE(m_contractAddress); - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + return callContractFunctionWithValue(_sig, 0, _arguments...); } - else + + template + void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) { - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + bytes solidityResult = callContractFunction(_sig, _arguments...); + bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult)); } - BOOST_REQUIRE(executive.go()); - m_state.noteSending(m_sender); - executive.finalize(); - m_gasUsed = executive.gasUsed(); - m_output = executive.out().toVector(); - m_logs = executive.logs(); - } - - bool m_optimize = false; - bool m_addStandardSources = false; - dev::solidity::CompilerStack m_compiler; - Address m_sender; - Address m_contractAddress; - eth::State m_state; - u256 const m_gasPrice = 100 * eth::szabo; - u256 const m_gas = 100000000; - bytes m_output; - eth::LogEntries m_logs; - u256 m_gasUsed; + + template + void testSolidityAgainstCppOnRange(std::string _sig, CppFunction const& _cppFunction, u256 const& _rangeStart, u256 const& _rangeEnd) + { + for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + { + bytes solidityResult = callContractFunction(_sig, argument); + bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult) + + "\nArgument: " + + toHex(encode(argument)) + ); + } + } + + static bytes encode(bool _value) { return encode(byte(_value)); } + static bytes encode(int _value) { return encode(u256(_value)); } + static bytes encode(char const* _value) { return encode(std::string(_value)); } + static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } + static bytes encode(u256 const& _value) { return toBigEndian(_value); } + static bytes encode(h256 const& _value) { return _value.asBytes(); } + static bytes encode(bytes const& _value, bool _padLeft = true) + { + bytes padding = bytes((32 - _value.size() % 32) % 32, 0); + return _padLeft ? padding + _value : _value + padding; + } + static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + + template + static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) + { + return encode(_firstArg) + encodeArgs(_followingArgs...); + } + static bytes encodeArgs() + { + return bytes(); + } + +private: + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + _cppFunction(_arguments...); + return bytes(); + } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + return encode(_cppFunction(_arguments...)); + } + +protected: + void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) + { + m_state.addBalance(m_sender, _value); // just in case + eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::Transaction t = + _isCreation ? + eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : + eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); + bytes transactionRLP = t.rlp(); + try + { + // this will throw since the transaction is invalid, but it should nevertheless store the transaction + executive.initialize(&transactionRLP); + executive.execute(); + } + catch (...) {} + if (_isCreation) + { + BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); + m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + } + else + { + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + } + BOOST_REQUIRE(executive.go()); + m_state.noteSending(m_sender); + executive.finalize(); + m_gasUsed = executive.gasUsed(); + m_output = executive.out().toVector(); + m_logs = executive.logs(); + } + + bool m_optimize = false; + bool m_addStandardSources = false; + dev::solidity::CompilerStack m_compiler; + Address m_sender; + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 100000000; + bytes m_output; + eth::LogEntries m_logs; + u256 m_gasUsed; }; } From 8ece3534ad0d8369dd12e6f75b31a6872698ea93 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 1 Jun 2015 13:25:02 +0200 Subject: [PATCH 29/52] Gas estimates for JSON compiler. --- solc/jsonCompiler.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index d47903fca..7bde3e47c 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,61 @@ Json::Value functionHashes(ContractDefinition const& _contract) return functionHashes; } +Json::Value gasToJson(GasEstimator::GasConsumption const& _gas) +{ + if (_gas.isInfinite || _gas.value > std::numeric_limits::max()) + return Json::Value(Json::nullValue); + else + return Json::Value(Json::LargestUInt(_gas.value)); +} + +Json::Value estimateGas(CompilerStack const& _compiler, string const& _contract) +{ + Json::Value gasEstimates(Json::objectValue); + using Gas = GasEstimator::GasConsumption; + if (!_compiler.getAssemblyItems(_contract) && !_compiler.getRuntimeAssemblyItems(_contract)) + return gasEstimates; + if (eth::AssemblyItems const* items = _compiler.getAssemblyItems(_contract)) + { + Gas gas = GasEstimator::functionalEstimation(*items); + u256 bytecodeSize(_compiler.getRuntimeBytecode(_contract).size()); + Json::Value creationGas(Json::arrayValue); + creationGas[0] = gasToJson(gas); + creationGas[1] = gasToJson(bytecodeSize * eth::c_createDataGas); + gasEstimates["creation"] = creationGas; + } + if (eth::AssemblyItems const* items = _compiler.getRuntimeAssemblyItems(_contract)) + { + ContractDefinition const& contract = _compiler.getContractDefinition(_contract); + Json::Value externalFunctions(Json::objectValue); + for (auto it: contract.getInterfaceFunctions()) + { + string sig = it.second->externalSignature(); + externalFunctions[sig] = gasToJson(GasEstimator::functionalEstimation(*items, sig)); + } + gasEstimates["external"] = externalFunctions; + Json::Value internalFunctions(Json::objectValue); + for (auto const& it: contract.getDefinedFunctions()) + { + if (it->isPartOfExternalInterface() || it->isConstructor()) + continue; + size_t entry = _compiler.getFunctionEntryPoint(_contract, *it); + GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite(); + if (entry > 0) + gas = GasEstimator::functionalEstimation(*items, entry, *it); + FunctionType type(*it); + string sig = it->getName() + "("; + auto end = type.getParameterTypes().end(); + for (auto it = type.getParameterTypes().begin(); it != end; ++it) + sig += (*it)->toString() + (it + 1 == end ? "" : ","); + sig += ")"; + internalFunctions[sig] = gasToJson(gas); + } + gasEstimates["internal"] = internalFunctions; + } + return gasEstimates; +} + string compile(string _input, bool _optimize) { StringMap sources; @@ -109,6 +165,7 @@ string compile(string _input, bool _optimize) contractData["bytecode"] = toHex(compiler.getBytecode(contractName)); contractData["opcodes"] = eth::disassemble(compiler.getBytecode(contractName)); contractData["functionHashes"] = functionHashes(compiler.getContractDefinition(contractName)); + contractData["gasEstimates"] = estimateGas(compiler, contractName); ostringstream unused; contractData["assembly"] = compiler.streamAssembly(unused, contractName, sources, true); output["contracts"][contractName] = contractData; From 2d076b8954bcf9e9aa1c6262d88f6b0dc6d70e1b Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 1 Jun 2015 13:03:29 +0200 Subject: [PATCH 30/52] corrected intends in solidityExecutionFramwork.h --- test/libsolidity/solidityExecutionFramework.h | 294 +++++++++--------- 1 file changed, 147 insertions(+), 147 deletions(-) diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 879667fde..29f3c4710 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -40,157 +40,157 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } - - bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - m_compiler.reset(false, m_addStandardSources); - m_compiler.addSource("", _sourceCode); - ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); - bytes code = m_compiler.getBytecode(_contractName); - sendMessage(code, true, _value); - return m_output; - } - - bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - execute(_sourceCode, _value, _contractName); - BOOST_REQUIRE(!m_output.empty()); - return m_output; - } - - template - bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) - { - FixedHash<4> hash(dev::sha3(_sig)); - sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); - return m_output; - } - - template - bytes const& callContractFunction(std::string _sig, Args const&... _arguments) - { - return callContractFunctionWithValue(_sig, 0, _arguments...); - } - - template - void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) - { - bytes solidityResult = callContractFunction(_sig, _arguments...); - bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); - BOOST_CHECK_MESSAGE( - solidityResult == cppResult, - "Computed values do not match.\nSolidity: " + - toHex(solidityResult) + - "\nC++: " + - toHex(cppResult)); - } - - template - void testSolidityAgainstCppOnRange(std::string _sig, CppFunction const& _cppFunction, u256 const& _rangeStart, u256 const& _rangeEnd) - { - for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) - { - bytes solidityResult = callContractFunction(_sig, argument); - bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); - BOOST_CHECK_MESSAGE( - solidityResult == cppResult, - "Computed values do not match.\nSolidity: " + - toHex(solidityResult) + - "\nC++: " + - toHex(cppResult) + - "\nArgument: " + - toHex(encode(argument)) - ); - } - } - - static bytes encode(bool _value) { return encode(byte(_value)); } - static bytes encode(int _value) { return encode(u256(_value)); } - static bytes encode(char const* _value) { return encode(std::string(_value)); } - static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } - static bytes encode(u256 const& _value) { return toBigEndian(_value); } - static bytes encode(h256 const& _value) { return _value.asBytes(); } - static bytes encode(bytes const& _value, bool _padLeft = true) - { - bytes padding = bytes((32 - _value.size() % 32) % 32, 0); - return _padLeft ? padding + _value : _value + padding; - } - static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } - - template - static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) - { - return encode(_firstArg) + encodeArgs(_followingArgs...); - } - static bytes encodeArgs() - { - return bytes(); - } +ExecutionFramework() { g_logVerbosity = 0; } + + bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", _sourceCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); + bytes code = m_compiler.getBytecode(_contractName); + sendMessage(code, true, _value); + return m_output; + } + + bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + execute(_sourceCode, _value, _contractName); + BOOST_REQUIRE(!m_output.empty()); + return m_output; + } + + template + bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) + { + FixedHash<4> hash(dev::sha3(_sig)); + sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); + return m_output; + } + + template + bytes const& callContractFunction(std::string _sig, Args const&... _arguments) + { + return callContractFunctionWithValue(_sig, 0, _arguments...); + } + + template + void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) + { + bytes solidityResult = callContractFunction(_sig, _arguments...); + bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult)); + } + + template + void testSolidityAgainstCppOnRange(std::string _sig, CppFunction const& _cppFunction, u256 const& _rangeStart, u256 const& _rangeEnd) + { + for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + { + bytes solidityResult = callContractFunction(_sig, argument); + bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult) + + "\nArgument: " + + toHex(encode(argument)) + ); + } + } + + static bytes encode(bool _value) { return encode(byte(_value)); } + static bytes encode(int _value) { return encode(u256(_value)); } + static bytes encode(char const* _value) { return encode(std::string(_value)); } + static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } + static bytes encode(u256 const& _value) { return toBigEndian(_value); } + static bytes encode(h256 const& _value) { return _value.asBytes(); } + static bytes encode(bytes const& _value, bool _padLeft = true) + { + bytes padding = bytes((32 - _value.size() % 32) % 32, 0); + return _padLeft ? padding + _value : _value + padding; + } + static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + + template + static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) + { + return encode(_firstArg) + encodeArgs(_followingArgs...); + } + static bytes encodeArgs() + { + return bytes(); + } private: - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - _cppFunction(_arguments...); - return bytes(); - } - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - return encode(_cppFunction(_arguments...)); - } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + _cppFunction(_arguments...); + return bytes(); + } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + return encode(_cppFunction(_arguments...)); + } protected: - void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) - { - m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, eth::LastHashes(), 0); - eth::Transaction t = - _isCreation ? - eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : - eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); - bytes transactionRLP = t.rlp(); - try - { - // this will throw since the transaction is invalid, but it should nevertheless store the transaction - executive.initialize(&transactionRLP); - executive.execute(); - } - catch (...) {} - if (_isCreation) - { - BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); - m_contractAddress = executive.newAddress(); - BOOST_REQUIRE(m_contractAddress); - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - } - else - { - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); - } - BOOST_REQUIRE(executive.go()); - m_state.noteSending(m_sender); - executive.finalize(); - m_gasUsed = executive.gasUsed(); - m_output = executive.out().toVector(); - m_logs = executive.logs(); - } - - bool m_optimize = false; - bool m_addStandardSources = false; - dev::solidity::CompilerStack m_compiler; - Address m_sender; - Address m_contractAddress; - eth::State m_state; - u256 const m_gasPrice = 100 * eth::szabo; - u256 const m_gas = 100000000; - bytes m_output; - eth::LogEntries m_logs; - u256 m_gasUsed; + void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) + { + m_state.addBalance(m_sender, _value); // just in case + eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::Transaction t = + _isCreation ? + eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : + eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); + bytes transactionRLP = t.rlp(); + try + { + // this will throw since the transaction is invalid, but it should nevertheless store the transaction + executive.initialize(&transactionRLP); + executive.execute(); + } + catch (...) {} + if (_isCreation) + { + BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); + m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + } + else + { + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + } + BOOST_REQUIRE(executive.go()); + m_state.noteSending(m_sender); + executive.finalize(); + m_gasUsed = executive.gasUsed(); + m_output = executive.out().toVector(); + m_logs = executive.logs(); + } + + bool m_optimize = false; + bool m_addStandardSources = false; + dev::solidity::CompilerStack m_compiler; + Address m_sender; + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 100000000; + bytes m_output; + eth::LogEntries m_logs; + u256 m_gasUsed; }; } From 850c21eb3abf6c4e8ea701c0e9ed6065f14fdad6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 20:10:49 +0800 Subject: [PATCH 31/52] Avoid redownloading chain for non-breaking changes. --- libethereum/Client.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index e7d7a543b..96353ade2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -44,10 +44,11 @@ VersionChecker::VersionChecker(string const& _dbPath): try { auto protocolVersion = (unsigned)status[0]; + (void)protocolVersion; auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; m_action = - protocolVersion != eth::c_protocolVersion || databaseVersion != c_databaseVersion ? + databaseVersion != c_databaseVersion ? WithExisting::Kill : minorProtocolVersion != eth::c_minorProtocolVersion ? WithExisting::Verify From d1f19fe2d4fe75788669535af5e8aa40b791d89a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 20:11:59 +0800 Subject: [PATCH 32/52] Fix for windows. Better failure reporting on consensus issues. --- libethereum/Executive.cpp | 11 ++++++----- libethereum/Executive.h | 1 + libethereum/State.cpp | 33 ++++++++++++++++++++++++++++++++- libethereum/Transaction.cpp | 21 +++++++++++++++++++++ libethereum/Transaction.h | 3 +++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 09cdc6b04..8c77903ef 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -32,6 +32,7 @@ using namespace dev; using namespace dev::eth; const char* VMTraceChannel::name() { return "EVM"; } +const char* ExecutiveWarnChannel::name() { return WarnChannel::name(); } Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), @@ -63,7 +64,7 @@ void Executive::initialize(Transaction const& _transaction) u256 startGasUsed = m_s.gasUsed(); if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) { - clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); } @@ -71,7 +72,7 @@ void Executive::initialize(Transaction const& _transaction) // Check gas cost is enough. if (!m_t.checkPayment()) { - clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << m_t.gasRequired() << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Not enough gas to pay for the transaction: Require >" << m_t.gasRequired() << " Got" << m_t.gas(); m_excepted = TransactionException::OutOfGas; BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(m_t.gasRequired(), (bigint)m_t.gas())); } @@ -84,13 +85,13 @@ void Executive::initialize(Transaction const& _transaction) } catch (...) { - clog(StateDetail) << "Invalid Signature"; + clog(ExecutiveWarnChannel) << "Invalid Signature"; m_excepted = TransactionException::InvalidSignature; throw; } if (m_t.nonce() != nonceReq) { - clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); + clog(ExecutiveWarnChannel) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); m_excepted = TransactionException::InvalidNonce; BOOST_THROW_EXCEPTION(InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce())); } @@ -100,7 +101,7 @@ void Executive::initialize(Transaction const& _transaction) m_totalCost = m_t.value() + m_gasCost; if (m_s.balance(m_t.sender()) < m_totalCost) { - clog(StateDetail) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()); + clog(ExecutiveWarnChannel) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()); m_excepted = TransactionException::NotEnoughCash; BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(m_totalCost, (bigint)m_s.balance(m_t.sender()))); } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 949e2dc34..447f76eb9 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -36,6 +36,7 @@ class ExtVM; struct Manifest; struct VMTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 11; }; +struct ExecutiveWarnChannel: public LogChannel { static const char* name(); static const int verbosity = 6; }; /** * @brief Message-call/contract-creation executor; useful for executing transactions. diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 23405912c..20249f2eb 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -592,6 +592,24 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ss.str(); } +template +class LogOverride +{ +public: + LogOverride(bool _value): m_old(g_logOverride.count(&typeid(Channel)) ? (int)g_logOverride[&typeid(Channel)] : c_null) { g_logOverride[&typeid(Channel)] = _value; } + ~LogOverride() + { + if (m_old == c_null) + g_logOverride.erase(&typeid(Channel)); + else + g_logOverride[&typeid(Channel)] = (bool)m_old; + } + +private: + static const int c_null = -1; + int m_old; +}; + u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) { // m_currentBlock is assumed to be prepopulated and reset. @@ -624,7 +642,19 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement unsigned i = 0; for (auto const& tr: rlp[1]) { - execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + try { + LogOverride o(false); + execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + } + catch (...) + { + badBlock(_block, "Invalid transaction"); + cwarn << " Transaction Index:" << i; + LogOverride o(true); + execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + throw; + } + RLPStream receiptRLP; m_receipts.back().streamRLP(receiptRLP); receipts.push_back(receiptRLP.out()); @@ -1163,6 +1193,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); #endif + (void)_onOp; if (!e.execute()) #if ETH_VMTRACE e.go(e.simpleTrace()); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 975af53a5..b8d8d64c1 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -39,6 +39,27 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _e return _out; } +std::string badTransaction(bytesConstRef _tx, string const& _err) +{ + stringstream ret; + ret << "========================================================================" << endl; + ret << "== Software Failure " << (_err + string(max(0, 44 - _err.size()), ' ')) << " ==" << endl; + ret << "== Guru Meditation " << sha3(_tx).abridged() << " ==" << endl; + ret << "========================================================================" << endl; + ret << " Transaction: " << toHex(_tx) << endl; + ret << " Transaction RLP: "; + try { + ret << RLP(_tx); + } + catch (Exception& _e) + { + ret << "Invalid: " << _e.what(); + } + ret << endl; + + return ret.str(); +} + TransactionException dev::eth::toTransactionException(VMException const& _e) { if (!!dynamic_cast(&_e)) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 09d6cd54c..935b78c2a 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -235,5 +235,8 @@ inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) return _out; } +void badTransaction(bytesConstRef _tx, std::string const& _err); +inline void badTransaction(bytes const& _tx, std::string const& _err) { badTransaction(&_tx, _err); } + } } From 208d504314a11abda493d3b9672d1581c49c51c9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 20:13:49 +0800 Subject: [PATCH 33/52] Fixes #2052 --- libethereum/State.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 20249f2eb..b35ef98ce 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1193,10 +1193,12 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); #endif - (void)_onOp; if (!e.execute()) #if ETH_VMTRACE + { + (void)_onOp; e.go(e.simpleTrace()); + } #else e.go(_onOp); #endif From b325a5c3b2053a45a8c841001be03cfad743c9ea Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Jun 2015 15:43:55 +0200 Subject: [PATCH 34/52] Mutex guard m_fulls on eval() --- libethcore/EthashAux.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 06da22f98..4b546404a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -240,8 +240,9 @@ Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { - if (FullType dag = get()->m_fulls[_seedHash].lock()) - return dag->compute(_headerHash, _nonce); + DEV_GUARDED(get()->x_fulls) + if (FullType dag = get()->m_fulls[_seedHash].lock()) + return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { return Ethash::Result{ ~h256(), h256() }; From 1f8bd0fe680b1350a5a930f7c8a96089ab959e39 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 1 Jun 2015 17:34:11 +0300 Subject: [PATCH 35/52] BlockWeight: uncle POW issue --- test/libethereum/blockchain.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 0ea8b95a8..0ff7e57f3 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -214,9 +214,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) uncleStream.appendRaw(uncleRlp.out()); } - // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); - updatePoW(current_BlockHeader); + if (vBiUncles.size()) + { + // update unclehash in case of invalid uncles + current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + updatePoW(current_BlockHeader); + } if (blObj.count("blockHeader")) overwriteBlockHeader(current_BlockHeader, blObj); @@ -242,7 +245,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blObj["rlp"] = toHex(block2.out(), 2, HexPrefix::Add); if (sha3(RLP(state.blockData())[0].data()) != sha3(RLP(block2.out())[0].data())) - cnote << "block header mismatch\n"; + { + cnote << "block header mismatch state.blockData() vs updated state.info()\n"; + cerr << toHex(state.blockData()) << "vs" << toHex(block2.out()); + } if (sha3(RLP(state.blockData())[1].data()) != sha3(RLP(block2.out())[1].data())) cnote << "txs mismatch\n"; From 32458c0808ce6a6e396ab66281a5c22d58ef0929 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 1 Jun 2015 16:39:09 +0200 Subject: [PATCH 36/52] fixed CALL case. added exception --- libsolidity/ExpressionCompiler.cpp | 4 ++-- test/libsolidity/solidityExecutionFramework.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 6a246f441..ae8bcaeee 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1105,8 +1105,8 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << eth::Instruction::CALL; //Propagate error condition (if CALL pushes 0 on stack). - auto tag = m_context.appendConditionalJump(); - m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0. + m_context << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(m_context.errorTag()); if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 29f3c4710..ddbbb0161 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -40,7 +40,7 @@ namespace test class ExecutionFramework { public: -ExecutionFramework() { g_logVerbosity = 0; } + ExecutionFramework() { g_logVerbosity = 0; } bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { From 214542eb5e62cb6b909580bd6d98163c850ebe69 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 1 Jun 2015 16:48:13 +0200 Subject: [PATCH 37/52] renamed the test framwork function. --- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- test/libsolidity/solidityExecutionFramework.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index db115b104..9f6f27d7d 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4169,7 +4169,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) } } )"; - BOOST_CHECK(execute(sourceCode, 0, "A").empty()); + BOOST_CHECK(compileAndRunWthoutCheck(sourceCode, 0, "A").empty()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index ddbbb0161..c29257dd9 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -42,7 +42,7 @@ class ExecutionFramework public: ExecutionFramework() { g_logVerbosity = 0; } - bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + bytes const& compileAndRunWthoutCheck(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { m_compiler.reset(false, m_addStandardSources); m_compiler.addSource("", _sourceCode); @@ -54,7 +54,7 @@ public: bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { - execute(_sourceCode, _value, _contractName); + compileAndRunWthoutCheck(_sourceCode, _value, _contractName); BOOST_REQUIRE(!m_output.empty()); return m_output; } From 120611e9d4c6ac5b223f34ae8a7db84c995e1a07 Mon Sep 17 00:00:00 2001 From: winsvega Date: Thu, 21 May 2015 17:52:39 +0300 Subject: [PATCH 38/52] Random Code --- test/fuzzTesting/CMakeLists.txt | 7 +- test/fuzzTesting/createRandomStateTest.cpp | 57 +---------- test/fuzzTesting/fuzzHelper.cpp | 112 +++++++++++++++++++++ test/fuzzTesting/fuzzHelper.h | 75 ++++++++++++++ test/libethereum/blockchain.cpp | 9 +- 5 files changed, 205 insertions(+), 55 deletions(-) create mode 100644 test/fuzzTesting/fuzzHelper.cpp create mode 100644 test/fuzzTesting/fuzzHelper.h diff --git a/test/fuzzTesting/CMakeLists.txt b/test/fuzzTesting/CMakeLists.txt index b0b3b0776..371d6504d 100644 --- a/test/fuzzTesting/CMakeLists.txt +++ b/test/fuzzTesting/CMakeLists.txt @@ -9,10 +9,13 @@ include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") -add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp") -add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") +add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp") +add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp" ) add_executable(checkRandomStateTest "./checkRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp") +list(APPEND SRCS "./fuzzHelper.cpp") +add_sources(${SRCS}) + target_link_libraries(createRandomVMTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) target_link_libraries(createRandomVMTest ethereum) target_link_libraries(createRandomVMTest ethcore) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index e0cb35dd1..65bfa2cfa 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -37,6 +37,7 @@ #include #include #include +#include using namespace std; using namespace json_spirit; @@ -47,55 +48,7 @@ void doStateTests(json_spirit::mValue& _v); int main(int argc, char *argv[]) { g_logVerbosity = 0; - - // create random code - - boost::random::mt19937 gen; - - auto now = chrono::steady_clock::now().time_since_epoch(); - auto timeSinceEpoch = chrono::duration_cast(now).count(); - gen.seed(static_cast(timeSinceEpoch)); - // set min and max length of the random evm code - boost::random::uniform_int_distribution<> lengthOfCodeDist(8, 24); - boost::random::uniform_int_distribution<> reasonableInputValuesSize(0, 7); - boost::random::uniform_int_distribution<> opcodeDist(0, 255); - boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x40, 0x45); - boost::random::uniform_int_distribution<> uniformInt(0, 0x7fffffff); - boost::random::variate_generator > randGenInputValue(gen, reasonableInputValuesSize); - boost::random::variate_generator > randGenUniformInt(gen, uniformInt); - boost::random::variate_generator > randGen(gen, opcodeDist); - boost::random::variate_generator > randGenBlockInfoOpcode(gen, BlockInfoOpcodeDist); - - std::vector reasonableInputValues; - reasonableInputValues.push_back(0); - reasonableInputValues.push_back(1); - reasonableInputValues.push_back(50000); - reasonableInputValues.push_back(u256("0x10000000000000000000000000000000000000000")); - reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffff")); - reasonableInputValues.push_back(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe")); - reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); - reasonableInputValues.push_back(u256("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); - reasonableInputValues.push_back(randGenUniformInt()); - - int lengthOfCode = lengthOfCodeDist(gen); - string randomCode; - - for (int i = 0; i < lengthOfCode; ++i) - { - // pre-fill stack to avoid that most of the test fail with a stackunderflow - if (i < 8 && (randGen() < 192)) - { - randomCode += randGen() < 32 ? toHex(toCompactBigEndian((uint8_t)randGenBlockInfoOpcode())) : "7f" + toHex(reasonableInputValues[randGenInputValue()]); - continue; - } - - uint8_t opcode = randGen(); - // disregard all invalid commands, except of one (0x0c) - if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (randGen() > 250))) - randomCode += toHex(toCompactBigEndian(opcode)); - else - i--; - } + string randomCode = dev::test::RandomCode::generate(25); string const s = R"( { @@ -147,16 +100,16 @@ int main(int argc, char *argv[]) read_string(s, v); // insert new random code - v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + (randGen() > 128 ? "55" : "") + (randGen() > 128 ? "60005155" : ""); + v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; // insert new data in tx v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomCode; // insert new value in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = toString(randGenUniformInt()); + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = dev::test::RandomCode::randomUniInt(); // insert new gasLimit in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = "0x" + toHex(toCompactBigEndian((int)randGenUniformInt())); + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = dev::test::RandomCode::randomUniInt(); // fill test doStateTests(v); diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp new file mode 100644 index 000000000..5b3b0a7f0 --- /dev/null +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -0,0 +1,112 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file fuzzHelper.cpp + * @author Dimitry Khokhlov + * @date 2015 + */ + +#include "fuzzHelper.h" + +#include +#include +#include +#include + +namespace dev +{ +namespace test +{ + +boost::random::mt19937 RandomCode::gen; +boostIntDistrib RandomCode::opCodeDist = boostIntDistrib (0, 255); +boostIntDistrib RandomCode::opLengDist = boostIntDistrib (1, 32); +boostIntDistrib RandomCode::uniIntDist = boostIntDistrib (0, 0x7fffffff); + +boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist); +boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); +boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); + + +std::string RandomCode::rndByteSequence(int length) +{ + refreshSeed(); + std::string hash; + length = std::max(1, length); + for (auto i = 0; i < length; i++) + { + uint8_t byte = randOpCodeGen(); + hash += toCompactHex(byte); + } + return hash; +} + +std::string RandomCode::fillArguments(int num) +{ + std::string code; + for (auto i = 0; i < num; i++) + { + int length = randOpLengGen(); + int pushCode = 96 + length - 1; + code += toCompactHex(pushCode) + rndByteSequence(length); + } + return code; +} + +//generate smart random code +std::string RandomCode::generate(int maxOpNumber, CodeOptions options) +{ + refreshSeed(); + std::string code; + boostIntDistrib sizeDist (0, maxOpNumber); + boostIntGenerator rndSizeGen(gen, sizeDist); + int size = (int)rndSizeGen(); + for (auto i = 0; i < size; i++) + { + uint8_t opcode = randOpCodeGen(); + dev::eth::InstructionInfo info = dev::eth::instructionInfo((dev::eth::Instruction) opcode); + + if (info.name.find_first_of("INVALID_INSTRUCTION") > 0) + { + //Byte code is yet not implemented + if (options == CodeOptions::DontUseUndefinedOpCodes) + { + i--; + continue; + } + } + else + code += fillArguments(info.args); + code += toCompactHex(opcode); + } + return code; +} + +std::string RandomCode::randomUniInt() +{ + refreshSeed(); + return "0x" + toCompactHex((int)randUniIntGen()); +} + +void RandomCode::refreshSeed() +{ + auto now = std::chrono::steady_clock::now().time_since_epoch(); + auto timeSinceEpoch = std::chrono::duration_cast(now).count(); + gen.seed(static_cast(timeSinceEpoch)); +} + +} +} diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h new file mode 100644 index 000000000..c3e15a24f --- /dev/null +++ b/test/fuzzTesting/fuzzHelper.h @@ -0,0 +1,75 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file fuzzHelper.h + * @author Dimitry Khokhlov + * @date 2015 + */ + +#include +#include +#include + +#include +#include +#include + +#pragma once + +namespace dev +{ +namespace test +{ + +typedef boost::random::uniform_int_distribution<> boostIntDistrib; +typedef boost::random::variate_generator boostIntGenerator; + +enum class CodeOptions +{ + UseUndefinedOpCodes, + DontUseUndefinedOpCodes +}; + +class RandomCode +{ +public: + /// Generate random vm code + static std::string generate(int maxOpNumber = 1, CodeOptions options = CodeOptions::DontUseUndefinedOpCodes); + + /// Generate random byte string of a given length + static std::string rndByteSequence(int length = 1); + + /// Generate random uniForm Int with reasonable value 0..0x7fffffff + static std::string randomUniInt(); + +private: + static std::string fillArguments(int num); + static void refreshSeed(); + + static boost::random::mt19937 gen; ///< Random generator + static boostIntDistrib opCodeDist; ///< 0..255 opcodes + static boostIntDistrib opLengDist; ///< 1..32 byte string + static boostIntDistrib uniIntDist; ///< 0..0x7fffffff + + static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from + static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist + static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist +}; + + + +} +} diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 0ea8b95a8..a654712fe 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -19,7 +19,7 @@ * @date 2015 * block test functions. */ - +#include "test/fuzzTesting/fuzzHelper.h" #include #include #include @@ -811,4 +811,11 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) dev::test::userDefinedTest(dev::test::doBlockchainTests); } +BOOST_AUTO_TEST_CASE(rndCode) +{ + cerr << "Testing Random Code: "; + std::string code = dev::test::RandomCode::generate(10); + cerr << code; +} + BOOST_AUTO_TEST_SUITE_END() From 7788d4f6d9eacebbafcd740c2cb652233ef24bb3 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 22 May 2015 17:28:47 +0300 Subject: [PATCH 39/52] undo vmTest --- test/libethereum/blockchain.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index a654712fe..085a855d4 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -813,8 +813,16 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) BOOST_AUTO_TEST_CASE(rndCode) { + std::string code; cerr << "Testing Random Code: "; - std::string code = dev::test::RandomCode::generate(10); + try + { + code = dev::test::RandomCode::generate(10); + } + catch(...) + { + BOOST_ERROR("Exception thrown when generating random code!"); + } cerr << code; } From 3c6f053a79ab75370aface29579263583fc610d4 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 22 May 2015 21:04:12 +0300 Subject: [PATCH 40/52] Random Codes With Probability --- test/fuzzTesting/createRandomStateTest.cpp | 175 +++++++++++++++------ test/fuzzTesting/fuzzHelper.cpp | 16 +- test/fuzzTesting/fuzzHelper.h | 35 ++++- 3 files changed, 169 insertions(+), 57 deletions(-) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index 65bfa2cfa..f93cbfa6e 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -44,60 +44,139 @@ using namespace json_spirit; using namespace dev; void doStateTests(json_spirit::mValue& _v); +void doChristophAlgo(); +void doRandomCodeAlgo(); + +string const c_testExample = R"( +{ + "randomStatetest" : { + "env" : { + "currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5", + "currentDifficulty" : "5623894562375", + "currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0", + "code" : "0x6001600101600055", + "nonce" : "0", + "storage" : { + } + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "46", + "code" : "0x6000355415600957005b60203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "code" : "0x", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : { + "data" : "0x42", + "gasLimit" : "400000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000" + } + } +} +)"; int main(int argc, char *argv[]) +{ + //doChristophAlgo(); + doRandomCodeAlgo(); + return 0; +} + +void doChristophAlgo() { g_logVerbosity = 0; - string randomCode = dev::test::RandomCode::generate(25); - string const s = R"( + // create random code + boost::random::mt19937 gen; + auto now = chrono::steady_clock::now().time_since_epoch(); + auto timeSinceEpoch = chrono::duration_cast(now).count(); + gen.seed(static_cast(timeSinceEpoch)); + + // set min and max length of the random evm code + boost::random::uniform_int_distribution<> lengthOfCodeDist(8, 24); + boost::random::uniform_int_distribution<> reasonableInputValuesSize(0, 7); + boost::random::uniform_int_distribution<> opcodeDist(0, 255); + boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x40, 0x45); + boost::random::uniform_int_distribution<> uniformInt(0, 0x7fffffff); + boost::random::variate_generator > randGenInputValue(gen, reasonableInputValuesSize); + boost::random::variate_generator > randGenUniformInt(gen, uniformInt); + boost::random::variate_generator > randGen(gen, opcodeDist); + boost::random::variate_generator > randGenBlockInfoOpcode(gen, BlockInfoOpcodeDist); + + std::vector reasonableInputValues; + reasonableInputValues.push_back(0); + reasonableInputValues.push_back(1); + reasonableInputValues.push_back(50000); + reasonableInputValues.push_back(u256("0x10000000000000000000000000000000000000000")); + reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffff")); + reasonableInputValues.push_back(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe")); + reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + reasonableInputValues.push_back(u256("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); + reasonableInputValues.push_back(randGenUniformInt()); + + int lengthOfCode = lengthOfCodeDist(gen); + string randomCode; + for (int i = 0; i < lengthOfCode; ++i) { - "randomStatetest" : { - "env" : { - "currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5", - "currentDifficulty" : "5623894562375", - "currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "pre" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "0", - "code" : "0x6001600101600055", - "nonce" : "0", - "storage" : { - } - }, - "945304eb96065b2a98b57a48a06ae28d285a71b5" : { - "balance" : "46", - "code" : "0x6000355415600957005b60203560003555", - "nonce" : "0", - "storage" : { - } - }, - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "1000000000000000000", - "code" : "0x", - "nonce" : "0", - "storage" : { - } - } - }, - "transaction" : { - "data" : "0x42", - "gasLimit" : "400000", - "gasPrice" : "1", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "100000" - } + // pre-fill stack to avoid that most of the test fail with a stackunderflow + if (i < 8 && (randGen() < 192)) + { + randomCode += randGen() < 32 ? toHex(toCompactBigEndian((uint8_t)randGenBlockInfoOpcode())) : "7f" + toHex(reasonableInputValues[randGenInputValue()]); + continue; } + uint8_t opcode = randGen(); + // disregard all invalid commands, except of one (0x0c) + if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (randGen() > 250))) + randomCode += toHex(toCompactBigEndian(opcode)); + else + i--; } -)"; + mValue v; - read_string(s, v); + read_string(c_testExample, v); + // insert new random code + v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + (randGen() > 128 ? "55" : "") + (randGen() > 128 ? "60005155" : ""); + // insert new data in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomCode; + // insert new value in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = toString(randGenUniformInt()); + // insert new gasLimit in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = "0x" + toHex(toCompactBigEndian((int)randGenUniformInt())); + // fill test + doStateTests(v); + // stream to output for further handling by the bash script + cout << json_spirit::write_string(v, true); +} + +void doRandomCodeAlgo() +{ + g_logVerbosity = 0; + dev::test::RandomCodeOptions options; + options.setWeight(dev::eth::Instruction::STOP, 10); //default 50 + options.setWeight(dev::eth::Instruction::SSTORE, 70); + string randomCode = dev::test::RandomCode::generate(15); + + mValue v; + read_string(c_testExample, v); // insert new random code v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; @@ -116,10 +195,10 @@ int main(int argc, char *argv[]) // stream to output for further handling by the bash script cout << json_spirit::write_string(v, true); - - return 0; } + + void doStateTests(json_spirit::mValue& _v) { eth::VMFactory::setKind(eth::VMKind::Interpreter); @@ -159,3 +238,5 @@ void doStateTests(json_spirit::mValue& _v) } } + + diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 5b3b0a7f0..ba0e58575 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -40,7 +40,6 @@ boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist) boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); - std::string RandomCode::rndByteSequence(int length) { refreshSeed(); @@ -67,22 +66,28 @@ std::string RandomCode::fillArguments(int num) } //generate smart random code -std::string RandomCode::generate(int maxOpNumber, CodeOptions options) +std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) { refreshSeed(); std::string code; + + //random opCode amount boostIntDistrib sizeDist (0, maxOpNumber); boostIntGenerator rndSizeGen(gen, sizeDist); int size = (int)rndSizeGen(); + + boostWeightGenerator randOpCodeWeight (gen, options.opCodeProbability); + bool weightsDefined = options.opCodeProbability.probabilities().size() == 255; + for (auto i = 0; i < size; i++) { - uint8_t opcode = randOpCodeGen(); + uint8_t opcode = weightsDefined ? randOpCodeWeight() : randOpCodeGen(); dev::eth::InstructionInfo info = dev::eth::instructionInfo((dev::eth::Instruction) opcode); if (info.name.find_first_of("INVALID_INSTRUCTION") > 0) { //Byte code is yet not implemented - if (options == CodeOptions::DontUseUndefinedOpCodes) + if (options.useUndefinedOpCodes == false) { i--; continue; @@ -90,7 +95,8 @@ std::string RandomCode::generate(int maxOpNumber, CodeOptions options) } else code += fillArguments(info.args); - code += toCompactHex(opcode); + std::string byte = toCompactHex(opcode); + code += (byte == "") ? "00" : byte; } return code; } diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index c3e15a24f..29d3b19ea 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -26,6 +26,7 @@ #include #include #include +#include #pragma once @@ -35,19 +36,43 @@ namespace test { typedef boost::random::uniform_int_distribution<> boostIntDistrib; +typedef boost::random::discrete_distribution<> boostDescreteDistrib; + typedef boost::random::variate_generator boostIntGenerator; +typedef boost::random::variate_generator boostWeightGenerator; -enum class CodeOptions +struct RandomCodeOptions { - UseUndefinedOpCodes, - DontUseUndefinedOpCodes +public: + RandomCodeOptions() : useUndefinedOpCodes(false) { + //each op code with same weight-probability + for (auto i = 0; i < 255; i++) + mapWeights.insert(std::pair(i, 50)); + setWeights(); + } + void setWeight(dev::eth::Instruction opCode, int weight) + { + mapWeights.at((int)opCode) = weight; + setWeights(); + } + bool useUndefinedOpCodes; + boostDescreteDistrib opCodeProbability; +private: + void setWeights() + { + std::vector weights; + for (auto const& element: mapWeights) + weights.push_back(element.second); + opCodeProbability = boostDescreteDistrib(weights); + } + std::map mapWeights; }; class RandomCode { public: /// Generate random vm code - static std::string generate(int maxOpNumber = 1, CodeOptions options = CodeOptions::DontUseUndefinedOpCodes); + static std::string generate(int maxOpNumber = 1, RandomCodeOptions options = RandomCodeOptions()); /// Generate random byte string of a given length static std::string rndByteSequence(int length = 1); @@ -64,7 +89,7 @@ private: static boostIntDistrib opLengDist; ///< 1..32 byte string static boostIntDistrib uniIntDist; ///< 0..0x7fffffff - static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from + static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from uniIntDist static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist }; From b43c4f11456c0eea5fea3bf17fc6e57fb1f90c76 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 26 May 2015 16:27:22 +0300 Subject: [PATCH 41/52] Random test code --- test/TestHelper.cpp | 4 +++- test/TestHelper.h | 1 + test/fuzzTesting/createRandomStateTest.cpp | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 476d1ecf9..4836ce7f3 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -328,7 +328,7 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost) { // export output - m_TestObject["out"] = _output.size() > 4096 ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add); + m_TestObject["out"] = (_output.size() > 4096 && !Options::get().fulloutput) ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add); // export logs m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); @@ -760,6 +760,8 @@ Options::Options() else singleTestName = std::move(name1); } + else if (arg == "--fulloutput") + fulloutput = true; } } diff --git a/test/TestHelper.h b/test/TestHelper.h index fc6c77fad..8f0c73bf3 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -184,6 +184,7 @@ public: bool stats = false; ///< Execution time stats std::string statsOutFile; ///< Stats output file. "out" for standard output bool checkState = false;///< Throw error when checking test states + bool fulloutput = false;///< Replace large output to just it's length /// Test selection /// @{ diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index f93cbfa6e..e2c0600b6 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -173,7 +173,8 @@ void doRandomCodeAlgo() dev::test::RandomCodeOptions options; options.setWeight(dev::eth::Instruction::STOP, 10); //default 50 options.setWeight(dev::eth::Instruction::SSTORE, 70); - string randomCode = dev::test::RandomCode::generate(15); + string randomCode = dev::test::RandomCode::generate(10); + string randomData = dev::test::RandomCode::generate(10); mValue v; read_string(c_testExample, v); @@ -182,7 +183,7 @@ void doRandomCodeAlgo() v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; // insert new data in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomCode; + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomData; // insert new value in tx v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = dev::test::RandomCode::randomUniInt(); From b429e1cfde0259c0beb70a49b32d9c35319ed5de Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 26 May 2015 16:51:29 +0300 Subject: [PATCH 42/52] Random Code: Style --- test/fuzzTesting/createRandomStateTest.cpp | 5 ----- test/libethereum/blockchain.cpp | 15 --------------- 2 files changed, 20 deletions(-) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index e2c0600b6..622ccb1ac 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -198,8 +198,6 @@ void doRandomCodeAlgo() cout << json_spirit::write_string(v, true); } - - void doStateTests(json_spirit::mValue& _v) { eth::VMFactory::setKind(eth::VMKind::Interpreter); @@ -238,6 +236,3 @@ void doStateTests(json_spirit::mValue& _v) #endif } } - - - diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 085a855d4..67b3955ff 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -811,19 +811,4 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) dev::test::userDefinedTest(dev::test::doBlockchainTests); } -BOOST_AUTO_TEST_CASE(rndCode) -{ - std::string code; - cerr << "Testing Random Code: "; - try - { - code = dev::test::RandomCode::generate(10); - } - catch(...) - { - BOOST_ERROR("Exception thrown when generating random code!"); - } - cerr << code; -} - BOOST_AUTO_TEST_SUITE_END() From 8ea48967f1aa1c4dbb9e2acf1623b48afcc41cf1 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 26 May 2015 18:24:47 +0300 Subject: [PATCH 43/52] Random Code: fulloutput option + test --- test/TestHelper.cpp | 1 - test/fuzzTesting/createRandomStateTest.cpp | 8 ++++++++ test/fuzzTesting/fuzzHelper.cpp | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 4836ce7f3..5ace49e5d 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -771,7 +771,6 @@ Options const& Options::get() return instance; } - LastHashes lastHashes(u256 _currentBlockNumber) { LastHashes ret; diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index 622ccb1ac..ea726c09d 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -96,6 +96,14 @@ string const c_testExample = R"( int main(int argc, char *argv[]) { + for (auto i = 0; i < argc; ++i) + { + auto arg = std::string{argv[i]}; + dev::test::Options& options = const_cast(dev::test::Options::get()); + if (arg == "--fulloutput") + options.fulloutput = true; + } + //doChristophAlgo(); doRandomCodeAlgo(); return 0; diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index ba0e58575..0b50868c5 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -114,5 +114,24 @@ void RandomCode::refreshSeed() gen.seed(static_cast(timeSinceEpoch)); } +BOOST_AUTO_TEST_SUITE(RandomCodeTests) + +BOOST_AUTO_TEST_CASE(rndCode) +{ + std::string code; + std::cerr << "Testing Random Code: "; + try + { + code = dev::test::RandomCode::generate(10); + } + catch(...) + { + BOOST_ERROR("Exception thrown when generating random code!"); + } + std::cerr << code; +} + +BOOST_AUTO_TEST_SUITE_END() + } } From 50d6e8cb31f9b80033ca4f92babc493a99ba75e3 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 27 May 2015 15:45:00 +0300 Subject: [PATCH 44/52] Random Code: exceptions when filling rnd StateTest --- test/fuzzTesting/createRandomStateTest.cpp | 23 ++++++++++++---------- test/fuzzTesting/fuzzHelper.h | 2 -- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index ea726c09d..c0c07b53e 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -218,15 +218,19 @@ void doStateTests(json_spirit::mValue& _v) assert(o.count("env") > 0); assert(o.count("pre") > 0); assert(o.count("transaction") > 0); - - test::ImportTest importer(o, true); - - eth::State theState = importer.m_statePre; bytes output; + eth::State theState; try { - output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + test::ImportTest importer(o, true); + eth::State theState = importer.m_statePre; + output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + #if ETH_FATDB + importer.exportTest(output, theState); + #else + cout << "You can not fill tests when FATDB is switched off"; + #endif } catch (Exception const& _e) { @@ -237,10 +241,9 @@ void doStateTests(json_spirit::mValue& _v) { cnote << "state execution did throw an exception: " << _e.what(); } -#if ETH_FATDB - importer.exportTest(output, theState); -#else - cout << "You can not fill tests when FATDB is switched off"; -#endif + catch (...) + { + cnote << "state execution did throw an exception!"; + } } } diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 29d3b19ea..26580cb26 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -94,7 +94,5 @@ private: static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist }; - - } } From 0021abf270c20d74796e64609a35e44a57489404 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 27 May 2015 22:51:53 +0300 Subject: [PATCH 45/52] Random Code: smart opcode fuzz --- test/fuzzTesting/createRandomStateTest.cpp | 15 ++- test/fuzzTesting/fuzzHelper.cpp | 119 ++++++++++++++++++--- test/fuzzTesting/fuzzHelper.h | 41 ++++--- 3 files changed, 134 insertions(+), 41 deletions(-) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index c0c07b53e..d0cd82c01 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -181,8 +181,15 @@ void doRandomCodeAlgo() dev::test::RandomCodeOptions options; options.setWeight(dev::eth::Instruction::STOP, 10); //default 50 options.setWeight(dev::eth::Instruction::SSTORE, 70); - string randomCode = dev::test::RandomCode::generate(10); - string randomData = dev::test::RandomCode::generate(10); + options.setWeight(dev::eth::Instruction::CALL, 75); + options.addAddress(Address("0xffffffffffffffffffffffffffffffffffffffff")); + options.addAddress(Address("0x1000000000000000000000000000000000000000")); + options.addAddress(Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")); //coinbase + options.addAddress(Address("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); + options.addAddress(Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")); + options.smartCodeProbability = 35; + string randomCode = dev::test::RandomCode::generate(10, options); + string randomData = dev::test::RandomCode::generate(10, options); mValue v; read_string(c_testExample, v); @@ -194,10 +201,10 @@ void doRandomCodeAlgo() v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomData; // insert new value in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = dev::test::RandomCode::randomUniInt(); + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = dev::test::RandomCode::randomUniIntHex(); // insert new gasLimit in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = dev::test::RandomCode::randomUniInt(); + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = dev::test::RandomCode::randomUniIntHex(); // fill test doStateTests(v); diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 0b50868c5..b4905709e 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -40,11 +40,11 @@ boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist) boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); -std::string RandomCode::rndByteSequence(int length) +std::string RandomCode::rndByteSequence(int length, SizeStrictness sizeType) { refreshSeed(); std::string hash; - length = std::max(1, length); + length = (sizeType == SizeStrictness::Strict) ? std::max(1, length) : randomUniInt() % length; for (auto i = 0; i < length; i++) { uint8_t byte = randOpCodeGen(); @@ -53,18 +53,6 @@ std::string RandomCode::rndByteSequence(int length) return hash; } -std::string RandomCode::fillArguments(int num) -{ - std::string code; - for (auto i = 0; i < num; i++) - { - int length = randOpLengGen(); - int pushCode = 96 + length - 1; - code += toCompactHex(pushCode) + rndByteSequence(length); - } - return code; -} - //generate smart random code std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) { @@ -94,19 +82,25 @@ std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) } } else - code += fillArguments(info.args); + code += fillArguments((dev::eth::Instruction) opcode, options); std::string byte = toCompactHex(opcode); code += (byte == "") ? "00" : byte; } return code; } -std::string RandomCode::randomUniInt() +std::string RandomCode::randomUniIntHex() { refreshSeed(); return "0x" + toCompactHex((int)randUniIntGen()); } +int RandomCode::randomUniInt() +{ + refreshSeed(); + return (int)randUniIntGen(); +} + void RandomCode::refreshSeed() { auto now = std::chrono::steady_clock::now().time_since_epoch(); @@ -114,6 +108,99 @@ void RandomCode::refreshSeed() gen.seed(static_cast(timeSinceEpoch)); } +std::string RandomCode::getPushCode(std::string hex) +{ + int length = hex.length()/2; + int pushCode = 96 + length - 1; + return toCompactHex(pushCode) + hex; +} + +std::string RandomCode::getPushCode(int value) +{ + std::string hexString = toCompactHex(value); + return getPushCode(hexString); +} + +std::string RandomCode::fillArguments(dev::eth::Instruction opcode, RandomCodeOptions options) +{ + dev::eth::InstructionInfo info = dev::eth::instructionInfo(opcode); + + std::string code; + bool smart = false; + unsigned num = info.args; + int rand = randOpCodeGen() % 100; + if (rand < options.smartCodeProbability) + smart = true; + + if (smart) + { + switch (opcode) + { + case dev::eth::Instruction::CALL: + //(CALL gaslimit address value memstart1 memlen1 memstart2 memlen2) + code += getPushCode(randUniIntGen() % 32); //memlen2 + code += getPushCode(randUniIntGen() % 32); //memstart2 + code += getPushCode(randUniIntGen() % 32); //memlen1 + code += getPushCode(randUniIntGen() % 32); //memlen1 + code += getPushCode(randUniIntGen()); //value + code += getPushCode(toString(options.getRandomAddress()));//address + code += getPushCode(randUniIntGen()); //gaslimit + break; + default: + smart = false; + } + } + + if (smart == false) + for (unsigned i = 0; i < num; i++) + { + //generate random parameters + int length = randOpLengGen(); + code += getPushCode(rndByteSequence(length)); + } + return code; +} + + +//Ramdom Code Options +RandomCodeOptions::RandomCodeOptions() : useUndefinedOpCodes(false), smartCodeProbability(50) +{ + //each op code with same weight-probability + for (auto i = 0; i < 255; i++) + mapWeights.insert(std::pair(i, 50)); + setWeights(); +} + +void RandomCodeOptions::setWeight(dev::eth::Instruction opCode, int weight) +{ + mapWeights.at((int)opCode) = weight; + setWeights(); +} + +void RandomCodeOptions::addAddress(dev::Address address) +{ + addressList.push_back(address); +} + +dev::Address RandomCodeOptions::getRandomAddress() +{ + if (addressList.size() > 0) + { + int index = RandomCode::randomUniInt() % addressList.size(); + return addressList[index]; + } + return Address(RandomCode::rndByteSequence(20)); +} + +void RandomCodeOptions::setWeights() +{ + std::vector weights; + for (auto const& element: mapWeights) + weights.push_back(element.second); + opCodeProbability = boostDescreteDistrib(weights); +} + + BOOST_AUTO_TEST_SUITE(RandomCodeTests) BOOST_AUTO_TEST_CASE(rndCode) diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 26580cb26..593f49328 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -44,28 +44,24 @@ typedef boost::random::variate_generator struct RandomCodeOptions { public: - RandomCodeOptions() : useUndefinedOpCodes(false) { - //each op code with same weight-probability - for (auto i = 0; i < 255; i++) - mapWeights.insert(std::pair(i, 50)); - setWeights(); - } - void setWeight(dev::eth::Instruction opCode, int weight) - { - mapWeights.at((int)opCode) = weight; - setWeights(); - } + RandomCodeOptions(); + void setWeight(dev::eth::Instruction opCode, int weight); + void addAddress(dev::Address address); + dev::Address getRandomAddress(); + bool useUndefinedOpCodes; + int smartCodeProbability; boostDescreteDistrib opCodeProbability; private: - void setWeights() - { - std::vector weights; - for (auto const& element: mapWeights) - weights.push_back(element.second); - opCodeProbability = boostDescreteDistrib(weights); - } + void setWeights(); std::map mapWeights; + std::vector addressList; +}; + +enum class SizeStrictness +{ + Strict, + Random }; class RandomCode @@ -75,13 +71,16 @@ public: static std::string generate(int maxOpNumber = 1, RandomCodeOptions options = RandomCodeOptions()); /// Generate random byte string of a given length - static std::string rndByteSequence(int length = 1); + static std::string rndByteSequence(int length = 1, SizeStrictness sizeType = SizeStrictness::Strict); /// Generate random uniForm Int with reasonable value 0..0x7fffffff - static std::string randomUniInt(); + static std::string randomUniIntHex(); + static int randomUniInt(); private: - static std::string fillArguments(int num); + static std::string fillArguments(dev::eth::Instruction opcode, RandomCodeOptions options); + static std::string getPushCode(int value); + static std::string getPushCode(std::string hex); static void refreshSeed(); static boost::random::mt19937 gen; ///< Random generator From b1f4f683268792fd11c4a092acc5af743beb2397 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Fri, 29 May 2015 17:06:11 +0300 Subject: [PATCH 46/52] Random Code: cath fill exceptions --- test/TestHelper.cpp | 2 +- test/fuzzTesting/createRandomStateTest.cpp | 38 ++++++++++++---------- test/fuzzTesting/fuzzHelper.cpp | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 5ace49e5d..793e05652 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -588,7 +588,7 @@ void userDefinedTest(std::function doTests) oSingleTest[pos->first] = pos->second; json_spirit::mValue v_singleTest(oSingleTest); - doTests(v_singleTest, false); + doTests(v_singleTest, test::Options::get().fillTests); } catch (Exception const& _e) { diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index d0cd82c01..d533ac2da 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -226,31 +226,33 @@ void doStateTests(json_spirit::mValue& _v) assert(o.count("pre") > 0); assert(o.count("transaction") > 0); bytes output; - eth::State theState; try { test::ImportTest importer(o, true); eth::State theState = importer.m_statePre; - output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; - #if ETH_FATDB - importer.exportTest(output, theState); - #else - cout << "You can not fill tests when FATDB is switched off"; - #endif - } - catch (Exception const& _e) - { - cnote << "state execution did throw an exception: " << diagnostic_information(_e); - theState.commit(); - } - catch (std::exception const& _e) - { - cnote << "state execution did throw an exception: " << _e.what(); + try + { + output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + } + catch (Exception const& _e) + { + cnote << "state execution did throw an exception: " << diagnostic_information(_e); + theState.commit(); + } + catch (std::exception const& _e) + { + cnote << "state execution did throw an exception: " << _e.what(); + } +#if ETH_FATDB + importer.exportTest(output, theState); +#else + cout << "You can not fill tests when FATDB is switched off"; +#endif } - catch (...) + catch(...) { - cnote << "state execution did throw an exception!"; + cnote << "Error filling test, probably..."; } } } diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index b4905709e..4ddd30c0f 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -128,7 +128,7 @@ std::string RandomCode::fillArguments(dev::eth::Instruction opcode, RandomCodeOp std::string code; bool smart = false; unsigned num = info.args; - int rand = randOpCodeGen() % 100; + int rand = randUniIntGen() % 100; if (rand < options.smartCodeProbability) smart = true; From b6d904167690f43c1180e5bffc32339df7e7ad0f Mon Sep 17 00:00:00 2001 From: Dimitry Date: Fri, 29 May 2015 17:33:24 +0300 Subject: [PATCH 47/52] Random code: style --- test/fuzzTesting/fuzzHelper.cpp | 46 ++++++++++++++++----------------- test/fuzzTesting/fuzzHelper.h | 14 +++++----- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 4ddd30c0f..7d7896947 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -40,12 +40,12 @@ boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist) boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); -std::string RandomCode::rndByteSequence(int length, SizeStrictness sizeType) +std::string RandomCode::rndByteSequence(int _length, SizeStrictness sizeType) { refreshSeed(); std::string hash; - length = (sizeType == SizeStrictness::Strict) ? std::max(1, length) : randomUniInt() % length; - for (auto i = 0; i < length; i++) + _length = (sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length; + for (auto i = 0; i < _length; i++) { uint8_t byte = randOpCodeGen(); hash += toCompactHex(byte); @@ -54,18 +54,18 @@ std::string RandomCode::rndByteSequence(int length, SizeStrictness sizeType) } //generate smart random code -std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) +std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options) { refreshSeed(); std::string code; //random opCode amount - boostIntDistrib sizeDist (0, maxOpNumber); + boostIntDistrib sizeDist (0, _maxOpNumber); boostIntGenerator rndSizeGen(gen, sizeDist); int size = (int)rndSizeGen(); - boostWeightGenerator randOpCodeWeight (gen, options.opCodeProbability); - bool weightsDefined = options.opCodeProbability.probabilities().size() == 255; + boostWeightGenerator randOpCodeWeight (gen, _options.opCodeProbability); + bool weightsDefined = _options.opCodeProbability.probabilities().size() == 255; for (auto i = 0; i < size; i++) { @@ -75,14 +75,14 @@ std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) if (info.name.find_first_of("INVALID_INSTRUCTION") > 0) { //Byte code is yet not implemented - if (options.useUndefinedOpCodes == false) + if (_options.useUndefinedOpCodes == false) { i--; continue; } } else - code += fillArguments((dev::eth::Instruction) opcode, options); + code += fillArguments((dev::eth::Instruction) opcode, _options); std::string byte = toCompactHex(opcode); code += (byte == "") ? "00" : byte; } @@ -108,33 +108,33 @@ void RandomCode::refreshSeed() gen.seed(static_cast(timeSinceEpoch)); } -std::string RandomCode::getPushCode(std::string hex) +std::string RandomCode::getPushCode(std::string const& _hex) { - int length = hex.length()/2; + int length = _hex.length() / 2; int pushCode = 96 + length - 1; - return toCompactHex(pushCode) + hex; + return toCompactHex(pushCode) + _hex; } -std::string RandomCode::getPushCode(int value) +std::string RandomCode::getPushCode(int _value) { - std::string hexString = toCompactHex(value); + std::string hexString = toCompactHex(_value); return getPushCode(hexString); } -std::string RandomCode::fillArguments(dev::eth::Instruction opcode, RandomCodeOptions options) +std::string RandomCode::fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options) { - dev::eth::InstructionInfo info = dev::eth::instructionInfo(opcode); + dev::eth::InstructionInfo info = dev::eth::instructionInfo(_opcode); std::string code; bool smart = false; unsigned num = info.args; int rand = randUniIntGen() % 100; - if (rand < options.smartCodeProbability) + if (rand < _options.smartCodeProbability) smart = true; if (smart) { - switch (opcode) + switch (_opcode) { case dev::eth::Instruction::CALL: //(CALL gaslimit address value memstart1 memlen1 memstart2 memlen2) @@ -143,7 +143,7 @@ std::string RandomCode::fillArguments(dev::eth::Instruction opcode, RandomCodeOp code += getPushCode(randUniIntGen() % 32); //memlen1 code += getPushCode(randUniIntGen() % 32); //memlen1 code += getPushCode(randUniIntGen()); //value - code += getPushCode(toString(options.getRandomAddress()));//address + code += getPushCode(toString(_options.getRandomAddress()));//address code += getPushCode(randUniIntGen()); //gaslimit break; default: @@ -171,15 +171,15 @@ RandomCodeOptions::RandomCodeOptions() : useUndefinedOpCodes(false), smartCodePr setWeights(); } -void RandomCodeOptions::setWeight(dev::eth::Instruction opCode, int weight) +void RandomCodeOptions::setWeight(dev::eth::Instruction _opCode, int _weight) { - mapWeights.at((int)opCode) = weight; + mapWeights.at((int)_opCode) = _weight; setWeights(); } -void RandomCodeOptions::addAddress(dev::Address address) +void RandomCodeOptions::addAddress(dev::Address const& _address) { - addressList.push_back(address); + addressList.push_back(_address); } dev::Address RandomCodeOptions::getRandomAddress() diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 593f49328..7cdce54ac 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -45,8 +45,8 @@ struct RandomCodeOptions { public: RandomCodeOptions(); - void setWeight(dev::eth::Instruction opCode, int weight); - void addAddress(dev::Address address); + void setWeight(dev::eth::Instruction _opCode, int _weight); + void addAddress(dev::Address const& _address); dev::Address getRandomAddress(); bool useUndefinedOpCodes; @@ -68,19 +68,19 @@ class RandomCode { public: /// Generate random vm code - static std::string generate(int maxOpNumber = 1, RandomCodeOptions options = RandomCodeOptions()); + static std::string generate(int _maxOpNumber = 1, RandomCodeOptions _options = RandomCodeOptions()); /// Generate random byte string of a given length - static std::string rndByteSequence(int length = 1, SizeStrictness sizeType = SizeStrictness::Strict); + static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict); /// Generate random uniForm Int with reasonable value 0..0x7fffffff static std::string randomUniIntHex(); static int randomUniInt(); private: - static std::string fillArguments(dev::eth::Instruction opcode, RandomCodeOptions options); - static std::string getPushCode(int value); - static std::string getPushCode(std::string hex); + static std::string fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options); + static std::string getPushCode(int _value); + static std::string getPushCode(std::string const& _hex); static void refreshSeed(); static boost::random::mt19937 gen; ///< Random generator From 3bcee73c84f9dc169adc5351e225e6996d043d51 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 1 Jun 2015 14:07:31 +0300 Subject: [PATCH 48/52] Random Code: build issues --- test/fuzzTesting/fuzzHelper.cpp | 6 +++--- test/fuzzTesting/fuzzHelper.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 7d7896947..3b6cf19c9 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -40,11 +40,11 @@ boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist) boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); -std::string RandomCode::rndByteSequence(int _length, SizeStrictness sizeType) +std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType) { refreshSeed(); std::string hash; - _length = (sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length; + _length = (_sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length; for (auto i = 0; i < _length; i++) { uint8_t byte = randOpCodeGen(); @@ -182,7 +182,7 @@ void RandomCodeOptions::addAddress(dev::Address const& _address) addressList.push_back(_address); } -dev::Address RandomCodeOptions::getRandomAddress() +dev::Address RandomCodeOptions::getRandomAddress() const { if (addressList.size() > 0) { diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 7cdce54ac..371e40fbf 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -47,7 +47,7 @@ public: RandomCodeOptions(); void setWeight(dev::eth::Instruction _opCode, int _weight); void addAddress(dev::Address const& _address); - dev::Address getRandomAddress(); + dev::Address getRandomAddress() const; bool useUndefinedOpCodes; int smartCodeProbability; From b81ae7d4708f088f44f04eb5c7a5eca003aba404 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 1 Jun 2015 18:30:05 +0200 Subject: [PATCH 49/52] Do not put duplicate labels for accessor functions. --- libsolidity/Compiler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 93d786bed..6425367dd 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -288,7 +288,6 @@ bool Compiler::visit(VariableDeclaration const& _variableDeclaration) m_breakTags.clear(); m_continueTags.clear(); - m_context << m_context.getFunctionEntryLabel(_variableDeclaration); ExpressionCompiler(m_context, m_optimize).appendStateVariableAccessor(_variableDeclaration); return false; From a67d783379256d94bcb1bfbc56c2e89bf40667a2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 2 Jun 2015 15:44:13 +0800 Subject: [PATCH 50/52] Code cleanup. --- libp2p/UDP.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index b032c9e73..ce2a570b2 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -115,7 +115,7 @@ class UDPSocket: UDPSocketFace, public std::enable_shared_from_this::disconnectWithError(boost::system::err } } -} \ No newline at end of file +} From 81a7f463851e308e9427959c8d6f40b00b8c75aa Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 2 Jun 2015 10:13:12 +0200 Subject: [PATCH 51/52] forbid uncle to be your brother --- libethcore/Exceptions.h | 15 ++++++++------- libethereum/State.cpp | 8 ++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 8b73c96fe..9362e4fed 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -49,27 +49,28 @@ struct FeeTooSmall: virtual dev::Exception {}; struct TooMuchGasUsed: virtual dev::Exception {}; struct ExtraDataTooBig: virtual dev::Exception {}; struct InvalidSignature: virtual dev::Exception {}; -class InvalidBlockFormat: virtual public dev::Exception {}; +struct InvalidBlockFormat: virtual dev::Exception {}; struct InvalidUnclesHash: virtual dev::Exception {}; struct InvalidUncle: virtual dev::Exception {}; struct TooManyUncles: virtual dev::Exception {}; struct UncleTooOld: virtual dev::Exception {}; -class UncleInChain: virtual public dev::Exception {}; +struct UncleIsBrother: virtual dev::Exception {}; +struct UncleInChain: virtual dev::Exception {}; struct DuplicateUncleNonce: virtual dev::Exception {}; struct InvalidStateRoot: virtual dev::Exception {}; struct InvalidGasUsed: virtual dev::Exception {}; -class InvalidTransactionsHash: virtual public dev::Exception {}; +struct InvalidTransactionsHash: virtual dev::Exception {}; struct InvalidTransaction: virtual dev::Exception {}; struct InvalidDifficulty: virtual dev::Exception {}; -class InvalidGasLimit: virtual public dev::Exception {}; +struct InvalidGasLimit: virtual dev::Exception {}; struct InvalidTransactionGasUsed: virtual dev::Exception {}; struct InvalidTransactionsStateRoot: virtual dev::Exception {}; struct InvalidReceiptsStateRoot: virtual dev::Exception {}; struct InvalidTimestamp: virtual dev::Exception {}; struct InvalidLogBloom: virtual dev::Exception {}; -class InvalidNonce: virtual public dev::Exception {}; -class InvalidBlockHeaderItemCount: virtual public dev::Exception {}; -class InvalidBlockNonce: virtual public dev::Exception {}; +struct InvalidNonce: virtual dev::Exception {}; +struct InvalidBlockHeaderItemCount: virtual dev::Exception {}; +struct InvalidBlockNonce: virtual dev::Exception {}; struct InvalidParentHash: virtual dev::Exception {}; struct InvalidNumber: virtual dev::Exception {}; struct InvalidContractAddress: virtual public dev::Exception {}; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index b35ef98ce..09765d9ee 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -726,6 +726,14 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement cwarn << " Block number: " << m_currentBlock.number; BOOST_THROW_EXCEPTION(UncleTooOld()); } + else if (uncle.number == m_currentBlock.number) + { + badBlock(_block, "Uncle is brother"); + cwarn << " Uncle number: " << uncle.number; + cwarn << " Uncle parent number: " << uncleParent.number; + cwarn << " Block number: " << m_currentBlock.number; + BOOST_THROW_EXCEPTION(UncleIsBrother()); + } uncle.verifyParent(uncleParent); // tdIncrease += uncle.difficulty; From 9ad3cdfcb5f4fc843216e093b4021c5621abc461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jun 2015 11:33:34 +0200 Subject: [PATCH 52/52] Boost mutiprecision number comparison bug workaround 2 I add fixed version of boost/multiprecision/detail/number_compare.hpp to sources. It is injected with #included if buggy version of boost detected. --- libdevcore/Common.h | 18 +- ...recision_number_compare_bug_workaround.hpp | 520 ++++++++++++++++++ 2 files changed, 524 insertions(+), 14 deletions(-) create mode 100644 libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 346bb53cf..453c17e6f 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -45,6 +45,10 @@ #pragma warning(push) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#if (BOOST_VERSION == 105800) + #include "boost_multiprecision_number_compare_bug_workaround.hpp" +#endif #include #pragma warning(pop) #pragma GCC diagnostic pop @@ -85,20 +89,6 @@ using u160s = std::vector; using u256Set = std::set; using u160Set = std::set; -// Workaround for mixed type big int comparison bug introduced in boost 1.58 -// https://svn.boost.org/trac/boost/ticket/11328 -#define ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(_OP) \ - template auto operator _OP (_T const& a, _U const& b) -> typename std::enable_if::value && std::is_same<_U, bigint>::value, bool>::type { return (bigint)a _OP b; } \ - template auto operator _OP (_U const& a, _T const& b) -> typename std::enable_if::value && std::is_same<_U, bigint>::value, bool>::type { return a _OP (bigint)b; } - -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(==) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(!=) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(>=) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(<=) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(<) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(>) - - extern const u256 UndefinedU256; // Map types. diff --git a/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp b/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp new file mode 100644 index 000000000..dae591dfb --- /dev/null +++ b/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp @@ -0,0 +1,520 @@ + +// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58. + +#ifdef BOOST_MP_COMPARE_HPP +#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MP_COMPARE_HPP +#define BOOST_MP_COMPARE_HPP + +// A copy of boost/multiprecision/traits/is_backend.hpp +#ifndef BOOST_MP_IS_BACKEND_HPP +#define BOOST_MP_IS_BACKEND_HPP + +#include +#include +#include +#include +#include + +namespace boost{ namespace multiprecision{ namespace detail{ + + BOOST_MPL_HAS_XXX_TRAIT_DEF(signed_types) + BOOST_MPL_HAS_XXX_TRAIT_DEF(unsigned_types) + BOOST_MPL_HAS_XXX_TRAIT_DEF(float_types) + + template + struct is_backend + { + static const bool value = has_signed_types::value && has_unsigned_types::value && has_float_types::value; + }; + + template + struct other_backend + { + typedef typename boost::conditional< + boost::is_same, number >::value, + number, number >::type type; + }; + + template + struct number_from_backend + { + typedef typename boost::conditional < + boost::is_convertible >::value, + number, + typename other_backend::type > ::type type; + }; + + template + struct is_first_backend_imp{ static const bool value = false; }; + template + struct is_first_backend_imp{ static const bool value = is_convertible >::value || is_convertible >::value; }; + + template + struct is_first_backend : is_first_backend_imp::value, T, U> {}; + + template + struct is_second_backend_imp{ static const bool value = false; }; + template + struct is_second_backend_imp{ static const bool value = is_convertible >::value || is_convertible >::value; }; + + template + struct is_second_backend : is_second_backend_imp::value, T, U> {}; + +} +} +} + +#endif // BOOST_MP_IS_BACKEND_HPP + +// +// Comparison operators for number. +// + +namespace boost{ namespace multiprecision{ + +namespace default_ops{ + +template +inline bool eval_eq(const B& a, const B& b) +{ + return a.compare(b) == 0; +} +template +inline typename enable_if_c::value, bool>::type eval_eq(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(b); + return eval_eq(a, t.backend()); +} +template +inline typename enable_if_c::value, bool>::type eval_eq(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(a); + return eval_eq(t.backend(), b); +} + +template +inline bool eval_lt(const B& a, const B& b) +{ + return a.compare(b) < 0; +} +template +inline typename enable_if_c::value, bool>::type eval_lt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(b); + return eval_lt(a, t.backend()); +} +template +inline typename enable_if_c::value, bool>::type eval_lt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(a); + return eval_lt(t.backend(), b); +} + +template +inline bool eval_gt(const B& a, const B& b) +{ + return a.compare(b) > 0; +} +template +inline typename enable_if_c::value, bool>::type eval_gt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(b); + return eval_gt(a, t.backend()); +} +template +inline typename enable_if_c::value, bool>::type eval_gt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(a); + return eval_gt(t.backend(), b); +} + +} // namespace default_ops + +namespace detail{ + +template +struct is_valid_mixed_compare : public mpl::false_ {}; + +template +struct is_valid_mixed_compare, Val> : public is_convertible > {}; + +template +struct is_valid_mixed_compare, number > : public mpl::false_ {}; + +template +struct is_valid_mixed_compare, expression > + : public mpl::bool_, number >::value> {}; + +template +struct is_valid_mixed_compare, number > + : public mpl::bool_, number >::value> {}; + +template +inline BOOST_CONSTEXPR typename boost::enable_if_c::value != number_kind_floating_point, bool>::type is_unordered_value(const number&) +{ + return false; +} +template +inline BOOST_CONSTEXPR typename boost::enable_if_c::value == number_kind_floating_point, bool>::type is_unordered_value(const number& a) +{ + using default_ops::eval_fpclassify; + return eval_fpclassify(a.backend()) == FP_NAN; +} + +template +inline BOOST_CONSTEXPR typename boost::enable_if_c::value != number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic&) +{ + return false; +} +template +inline BOOST_CONSTEXPR typename boost::enable_if_c::value == number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic& a) +{ + return (boost::math::isnan)(a); +} + +template +inline BOOST_CONSTEXPR bool is_unordered_comparison(const T& a, const U& b) +{ + return is_unordered_value(a) || is_unordered_value(b); +} + +} + +template +inline bool operator == (const number& a, const number& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator == (const number& a, const Arithmetic& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator == (const Arithmetic& a, const number& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator == (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_eq; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return eval_eq(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator == (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_eq; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return eval_eq(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator == (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_eq; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return eval_eq(t.backend(), t2.backend()); +} + +template +inline bool operator != (const number& a, const number& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator != (const number& a, const Arithmetic& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator != (const Arithmetic& a, const number& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator != (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_eq; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return true; + return !eval_eq(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator != (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_eq; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return true; + return !eval_eq(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator != (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_eq; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return true; + return !eval_eq(t.backend(), t2.backend()); +} + +template +inline bool operator < (const number& a, const number& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator < (const number& a, const Arithmetic& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator < (const Arithmetic& a, const number& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator < (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_gt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return eval_gt(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator < (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_lt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return eval_lt(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator < (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_lt; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return eval_lt(t.backend(), t2.backend()); +} + +template +inline bool operator > (const number& a, const number& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator > (const number& a, const Arithmetic& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator > (const Arithmetic& a, const number& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator > (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_lt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return a > t; +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator > (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_gt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return t > b; +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator > (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_gt; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return t > t2; +} + +template +inline bool operator <= (const number& a, const number& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator <= (const number& a, const Arithmetic& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator <= (const Arithmetic& a, const number& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator <= (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_lt; + if(detail::is_unordered_value(a) || detail::is_unordered_value(b)) + return false; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return !eval_lt(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator <= (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_gt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return !eval_gt(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator <= (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_gt; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return !eval_gt(t.backend(), t2.backend()); +} + +template +inline bool operator >= (const number& a, const number& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator >= (const number& a, const Arithmetic& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator >= (const Arithmetic& a, const number& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator >= (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_gt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return !eval_gt(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator >= (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_lt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return !eval_lt(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator >= (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_lt; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return !eval_lt(t.backend(), t2.backend()); +} + + +}} // namespaces + +#endif // BOOST_MP_COMPARE_HPP