diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 759fc6a1b..8fe76e24b 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -610,6 +610,7 @@ void Main::readSettings(bool _skipGeometry) } } ethereum()->setAddress(m_myKeys.back().address()); + m_server->setAccounts(keysAsVector(m_myKeys)); } { @@ -1374,7 +1375,7 @@ void Main::populateDebugger(dev::bytesConstRef _r) debugFinished(); vector levels; m_codes.clear(); - bytesConstRef lastExtCode; + bytes lastExtCode; bytesConstRef lastData; h256 lastHash; h256 lastDataHash; @@ -1387,7 +1388,7 @@ void Main::populateDebugger(dev::bytesConstRef _r) lastExtCode = ext.code; lastHash = sha3(lastExtCode); if (!m_codes.count(lastHash)) - m_codes[lastHash] = ext.code.toBytes(); + m_codes[lastHash] = ext.code; } if (ext.data != lastData) { @@ -1821,6 +1822,7 @@ void Main::on_send_clicked() void Main::keysChanged() { onBalancesChange(); + m_server->setAccounts(keysAsVector(m_myKeys)); } void Main::on_debug_clicked() @@ -2218,7 +2220,7 @@ void Main::refreshWhispers() time_t ex = e.expiry(); QString t(ctime(&ex)); t.chop(1); - QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); + QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topics()).c_str()).arg(msg); ui->whispers->addItem(item); } } diff --git a/libdevcore/Log.h b/libdevcore/Log.h index 704660276..2e111332c 100644 --- a/libdevcore/Log.h +++ b/libdevcore/Log.h @@ -27,6 +27,7 @@ #include #include #include "vector_ref.h" +#include "CommonIO.h" namespace dev { diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index 248a2e645..afedc68da 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -159,7 +159,11 @@ public: /// Best-effort conversion operators. explicit operator std::string() const { return toString(); } explicit operator RLPs() const { return toList(); } - explicit operator byte() const { return toInt(); } + explicit operator uint8_t() const { return toInt(); } + explicit operator uint16_t() const { return toInt(); } + explicit operator uint32_t() const { return toInt(); } + explicit operator uint64_t() const { return toInt(); } + explicit operator u160() const { return toInt(); } explicit operator u256() const { return toInt(); } explicit operator bigint() const { return toInt(); } template explicit operator FixedHash<_N>() const { return toHash>(); } diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index 758672e49..24ce618ed 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -40,7 +40,7 @@ class ExtVM: public ExtVMFace public: /// Full constructor. ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _depth = 0): - ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms) + ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms) { m_s.ensureCached(_myAddress, true, true); } diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp index da189d899..8a08a290c 100644 --- a/libevm/ExtVMFace.cpp +++ b/libevm/ExtVMFace.cpp @@ -25,7 +25,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth): +ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth): myAddress(_myAddress), caller(_caller), origin(_origin), diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 666e7e9e8..8a6b2edc9 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -104,7 +104,7 @@ public: ExtVMFace() = default; /// Full constructor. - ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth); + ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth); virtual ~ExtVMFace() = default; @@ -153,7 +153,7 @@ public: u256 value; ///< Value (in Wei) that was passed to this address. u256 gasPrice; ///< Price of gas (that we already paid). bytesConstRef data; ///< Current input data. - bytesConstRef code; ///< Current code that is executing. + bytes code; ///< Current code that is executing. BlockInfo previousBlock; ///< The previous block's information. BlockInfo currentBlock; ///< The current block's information. SubState sub; ///< Sub-band VM state (suicides, refund counter, logs). diff --git a/libevmcore/Instruction.cpp b/libevmcore/Instruction.cpp index 08c7d87a6..2df77a3c5 100644 --- a/libevmcore/Instruction.cpp +++ b/libevmcore/Instruction.cpp @@ -172,13 +172,13 @@ static const std::map c_instructionInfo = { Instruction::MOD, { "MOD", 0, 2, 1, false } }, { Instruction::SMOD, { "SMOD", 0, 2, 1, false } }, { Instruction::EXP, { "EXP", 0, 2, 1, false } }, - { Instruction::NOT, { "BNOT", 0, 1, 1, false } }, + { Instruction::NOT, { "NOT", 0, 1, 1, false } }, { Instruction::LT, { "LT", 0, 2, 1, false } }, { Instruction::GT, { "GT", 0, 2, 1, false } }, { Instruction::SLT, { "SLT", 0, 2, 1, false } }, { Instruction::SGT, { "SGT", 0, 2, 1, false } }, { Instruction::EQ, { "EQ", 0, 2, 1, false } }, - { Instruction::ISZERO, { "NOT", 0, 1, 1, false } }, + { Instruction::ISZERO, { "ISZERO", 0, 1, 1, false } }, { Instruction::AND, { "AND", 0, 2, 1, false } }, { Instruction::OR, { "OR", 0, 2, 1, false } }, { Instruction::XOR, { "XOR", 0, 2, 1, false } }, diff --git a/libjsqrc/main.js b/libjsqrc/main.js index 821de6382..eb1dd25b9 100644 --- a/libjsqrc/main.js +++ b/libjsqrc/main.js @@ -2,19 +2,19 @@ This file is part of ethereum.js. ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ethereum.js 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. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file ethereum.js +/** @file main.js * @authors: * Marek Kotewicz * @date 2014 @@ -153,15 +153,15 @@ return {call: call, args: args}; }).then(function (request) { return new Promise(function (resolve, reject) { - web3.provider.send(request, function (result) { - if (result || typeof result === "boolean") { + web3.provider.send(request, function (err, result) { + if (!err) { resolve(result); return; } - reject(result); + reject(err); }); }); - }).catch(function( err) { + }).catch(function(err) { console.error(err); }); }; @@ -173,8 +173,12 @@ var proto = {}; proto.get = function () { return new Promise(function(resolve, reject) { - web3.provider.send({call: property.getter}, function(result) { - resolve(result); + web3.provider.send({call: property.getter}, function(err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); }); }); }; @@ -182,12 +186,12 @@ proto.set = function (val) { return flattenPromise([val]).then(function (args) { return new Promise(function (resolve) { - web3.provider.send({call: property.setter, args: args}, function (result) { - if (result) { + web3.provider.send({call: property.setter, args: args}, function (err, result) { + if (!err) { resolve(result); - } else { - reject(result); + return; } + reject(err); }); }); }).catch(function (err) { @@ -218,7 +222,7 @@ var str = ""; var i = 0, l = hex.length; if (hex.substring(0, 2) == '0x') - i = 2; + i = 2; for(; i < l; i+=2) { var code = hex.charCodeAt(i) if(code == 0) { @@ -240,7 +244,7 @@ var hex = this.toHex(str); while(hex.length < pad*2) hex += "00"; - return "0x" + hex + return "0x" + hex; }, eth: { @@ -410,8 +414,10 @@ }; Filter.prototype.trigger = function(messages) { - for(var i = 0; i < this.callbacks.length; i++) { - this.callbacks[i].call(this, messages); + if (!(messages instanceof Array) || messages.length) { + for(var i = 0; i < this.callbacks.length; i++) { + this.callbacks[i].call(this, messages); + } } }; @@ -440,7 +446,7 @@ if(data._id) { var cb = web3._callbacks[data._id]; if (cb) { - cb.call(this, data.data) + cb.call(this, data.error, data.data); delete web3._callbacks[data._id]; } } diff --git a/libjsqrc/qt.js b/libjsqrc/qt.js index f0312eb2f..aedd34236 100644 --- a/libjsqrc/qt.js +++ b/libjsqrc/qt.js @@ -2,19 +2,19 @@ This file is part of ethereum.js. ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ethereum.js 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. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file ethereum.js +/** @file qt.js * @authors: * Marek Kotewicz * @date 2014 diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 08165d9db..42e00958a 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -120,6 +120,7 @@ static QString formatOutput(QJsonObject const& _object) QJsonObject res; res["_id"] = _object["id"]; res["data"] = _object["result"]; + res["error"] = _object["error"]; return QString::fromUtf8(QJsonDocument(res).toJson()); } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index ce9190ea4..19328e5f7 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -116,9 +116,9 @@ public: virtual void accept(ASTVisitor& _visitor) override; - std::vector> const& getDefinedStructs() { return m_definedStructs; } - std::vector> const& getStateVariables() { return m_stateVariables; } - std::vector> const& getDefinedFunctions() { return m_definedFunctions; } + std::vector> const& getDefinedStructs() const { return m_definedStructs; } + std::vector> const& getStateVariables() const { return m_stateVariables; } + std::vector> const& getDefinedFunctions() const { return m_definedFunctions; } private: std::vector> m_definedStructs; @@ -135,6 +135,8 @@ public: Declaration(_location, _name), m_members(_members) {} virtual void accept(ASTVisitor& _visitor) override; + std::vector> const& getMembers() const { return m_members; } + private: std::vector> m_members; }; diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index f335dd754..ea2ef4b74 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -6,14 +6,13 @@ aux_source_directory(. SRC_LIST) set(EXECUTABLE solidity) +file(GLOB HEADERS "*.h") if(ETH_STATIC) - add_library(${EXECUTABLE} STATIC ${SRC_LIST}) + add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) else() - add_library(${EXECUTABLE} SHARED ${SRC_LIST}) + add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) endif() -file(GLOB HEADERS "*.h") - include_directories(..) target_link_libraries(${EXECUTABLE} evmcore devcore) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 9ae8d7c62..ed2b1f45f 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -21,6 +21,8 @@ */ #include +#include +#include #include #include #include @@ -42,10 +44,12 @@ void Compiler::compileContract(ContractDefinition& _contract) m_context = CompilerContext(); // clear it just in case //@todo constructor - //@todo register state variables for (ASTPointer const& function: _contract.getDefinedFunctions()) m_context.addFunction(*function); + //@todo sort them? + for (ASTPointer const& variable: _contract.getStateVariables()) + m_context.addStateVariable(*variable); appendFunctionSelector(_contract.getDefinedFunctions()); for (ASTPointer const& function: _contract.getDefinedFunctions()) @@ -123,7 +127,7 @@ void Compiler::appendCalldataUnpacker(FunctionDefinition const& _function) if (numBytes == 0) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(var->getLocation()) - << errinfo_comment("Type not yet supported.")); + << errinfo_comment("Type " + var->getType()->toString() + " not yet supported.")); if (numBytes == 32) m_context << u256(dataOffset) << eth::Instruction::CALLDATALOAD; else @@ -140,11 +144,12 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) vector> const& parameters = _function.getReturnParameters(); for (unsigned i = 0; i < parameters.size(); ++i) { - unsigned numBytes = parameters[i]->getType()->getCalldataEncodedSize(); + Type const& paramType = *parameters[i]->getType(); + unsigned numBytes = paramType.getCalldataEncodedSize(); if (numBytes == 0) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(parameters[i]->getLocation()) - << errinfo_comment("Type not yet supported.")); + << errinfo_comment("Type " + paramType.toString() + " not yet supported.")); m_context << eth::dupInstruction(parameters.size() - i); if (numBytes != 32) m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL; @@ -273,7 +278,8 @@ bool Compiler::visit(Return& _return) ExpressionCompiler::compileExpression(m_context, *expression); VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front(); ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType()); - int stackPosition = m_context.getStackPositionOfVariable(firstVariable); + + unsigned stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(firstVariable)); m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; } m_context.appendJumpTo(m_returnTag); @@ -288,7 +294,8 @@ bool Compiler::visit(VariableDefinition& _variableDefinition) ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *_variableDefinition.getDeclaration().getType()); - int stackPosition = m_context.getStackPositionOfVariable(_variableDefinition.getDeclaration()); + unsigned baseStackOffset = m_context.getBaseStackOffsetOfVariable(_variableDefinition.getDeclaration()); + unsigned stackPosition = m_context.baseToCurrentStackOffset(baseStackOffset); m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; } return false; diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 99cf090e0..3c1acdfa7 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -30,6 +30,12 @@ using namespace std; namespace dev { namespace solidity { +void CompilerContext::addStateVariable(VariableDeclaration const& _declaration) +{ + m_stateVariables[&_declaration] = m_stateVariablesSize; + m_stateVariablesSize += _declaration.getType()->getStorageSize(); +} + void CompilerContext::initializeLocalVariables(unsigned _numVariables) { if (_numVariables > 0) @@ -41,12 +47,9 @@ void CompilerContext::initializeLocalVariables(unsigned _numVariables) } } -int CompilerContext::getStackPositionOfVariable(Declaration const& _declaration) +bool CompilerContext::isLocalVariable(Declaration const* _declaration) const { - auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); - if (asserts(res != m_localVariables.end())) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack.")); - return end(m_localVariables) - res - 1 + m_asm.deposit(); + return std::find(m_localVariables.begin(), m_localVariables.end(), _declaration) != m_localVariables.end(); } eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const @@ -57,5 +60,28 @@ eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition cons return res->second.tag(); } +unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const +{ + auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); + if (asserts(res != m_localVariables.end())) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack.")); + return unsigned(end(m_localVariables) - res - 1); +} + +unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const +{ + return _baseOffset + m_asm.deposit(); +} + +u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const +{ + auto it = m_stateVariables.find(&_declaration); + if (it == m_stateVariables.end()) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found in storage.")); + return it->second; +} + + + } } diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 866c621db..562c29321 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -38,19 +38,28 @@ namespace solidity { class CompilerContext { public: - CompilerContext() {} + CompilerContext(): m_stateVariablesSize(0) {} + void addStateVariable(VariableDeclaration const& _declaration); void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); } void initializeLocalVariables(unsigned _numVariables); void addVariable(VariableDeclaration const& _declaration) { m_localVariables.push_back(&_declaration); } - /// Returns the distance of the given local variable from the top of the stack. - int getStackPositionOfVariable(Declaration const& _declaration); - void addFunction(FunctionDefinition const& _function) { m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag())); } - eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const; void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } + bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration); } + bool isLocalVariable(Declaration const* _declaration) const; + bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration); } + + eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const; + /// Returns the distance of the given local variable from the top of the local variable stack. + unsigned getBaseStackOffsetOfVariable(Declaration const& _declaration) const; + /// If supplied by a value returned by @ref getBaseStackOffsetOfVariable(variable), returns + /// the distance of that variable from the current top of the stack. + unsigned baseToCurrentStackOffset(unsigned _baseOffset) const; + u256 getStorageLocationOfVariable(Declaration const& _declaration) const; + /// Appends a JUMPI instruction to a new tag and @returns the tag eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); } /// Appends a JUMPI instruction to @a _tag @@ -79,10 +88,14 @@ public: private: eth::Assembly m_asm; + /// Size of the state variables, offset of next variable to be added. + u256 m_stateVariablesSize; + /// Storage offsets of state variables + std::map m_stateVariables; /// Offsets of local variables on the stack. std::vector m_localVariables; /// Labels pointing to the entry points of funcitons. - std::map m_functionEntryLabels; + std::map m_functionEntryLabels; }; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 6efb8b20c..05bbb0916 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -46,23 +46,16 @@ void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, bool ExpressionCompiler::visit(Assignment& _assignment) { - m_currentLValue = nullptr; - - Expression& rightHandSide = _assignment.getRightHandSide(); - rightHandSide.accept(*this); - Type const& resultType = *_assignment.getType(); - appendTypeConversion(*rightHandSide.getType(), resultType); + _assignment.getRightHandSide().accept(*this); + appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType()); + m_currentLValue.reset(); _assignment.getLeftHandSide().accept(*this); Token::Value op = _assignment.getAssignmentOperator(); - if (op != Token::ASSIGN) - { - // compound assignment - m_context << eth::Instruction::SWAP1; - appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType); - } + if (op != Token::ASSIGN) // compound assignment + appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType()); else - m_context << eth::Instruction::POP; //@todo do not retrieve the value in the first place + m_context << eth::Instruction::POP; storeInLValue(_assignment); return false; @@ -99,10 +92,7 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) m_context << eth::Instruction::ADD; else m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap - if (_unaryOperation.isPrefixOperation()) - storeInLValue(_unaryOperation); - else - moveToLValue(_unaryOperation); + storeInLValue(_unaryOperation, !_unaryOperation.isPrefixOperation()); break; case Token::ADD: // + // unary add, so basically no-op @@ -123,11 +113,8 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) Type const& commonType = _binaryOperation.getCommonType(); Token::Value const op = _binaryOperation.getOperator(); - if (op == Token::AND || op == Token::OR) - { - // special case: short-circuiting + if (op == Token::AND || op == Token::OR) // special case: short-circuiting appendAndOrOperatorCode(_binaryOperation); - } else { bool cleanupNeeded = false; @@ -135,10 +122,10 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) cleanupNeeded = true; - leftExpression.accept(*this); - appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); rightExpression.accept(*this); appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); + leftExpression.accept(*this); + appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); if (Token::isCompareOp(op)) appendCompareOperatorCode(op, commonType); else @@ -164,9 +151,13 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) { // Calling convention: Caller pushes return address and arguments // Callee removes them and pushes return values - m_currentLValue = nullptr; + m_currentLValue.reset(); _functionCall.getExpression().accept(*this); - FunctionDefinition const& function = dynamic_cast(*m_currentLValue); + if (asserts(m_currentLValue.isInCode())) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Code reference expected.")); + eth::AssemblyItem functionTag(eth::PushTag, m_currentLValue.location); + + FunctionDefinition const& function = dynamic_cast(*_functionCall.getExpression().getType()).getFunction(); eth::AssemblyItem returnLabel = m_context.pushNewTag(); std::vector> const& arguments = _functionCall.getArguments(); @@ -175,11 +166,10 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) for (unsigned i = 0; i < arguments.size(); ++i) { arguments[i]->accept(*this); - appendTypeConversion(*arguments[i]->getType(), - *function.getParameters()[i]->getType()); + appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType()); } - m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); + m_context.appendJumpTo(functionTag); m_context << returnLabel; // callee adds return parameters, but removes arguments and return label @@ -205,24 +195,20 @@ void ExpressionCompiler::endVisit(IndexAccess&) void ExpressionCompiler::endVisit(Identifier& _identifier) { - m_currentLValue = _identifier.getReferencedDeclaration(); - switch (_identifier.getType()->getCategory()) - { - case Type::Category::BOOL: - case Type::Category::INTEGER: - case Type::Category::REAL: - { - //@todo we also have to check where to retrieve them from once we add storage variables - unsigned stackPos = stackPositionOfLValue(); - if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_identifier.getLocation()) - << errinfo_comment("Stack too deep.")); - m_context << eth::dupInstruction(stackPos + 1); - break; - } - default: - break; - } + Declaration const* declaration = _identifier.getReferencedDeclaration(); + if (m_context.isLocalVariable(declaration)) + m_currentLValue = LValueLocation(LValueLocation::STACK, + m_context.getBaseStackOffsetOfVariable(*declaration)); + else if (m_context.isStateVariable(declaration)) + m_currentLValue = LValueLocation(LValueLocation::STORAGE, + m_context.getStorageLocationOfVariable(*declaration)); + else if (m_context.isFunctionDefinition(declaration)) + m_currentLValue = LValueLocation(LValueLocation::CODE, + m_context.getFunctionEntryLabel(dynamic_cast(*declaration)).data()); + else + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not supported or identifier not found.")); + + retrieveLValueValue(_identifier); } void ExpressionCompiler::endVisit(Literal& _literal) @@ -267,23 +253,21 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type IntegerType const& type = dynamic_cast(_type); bool const isSigned = type.isSigned(); - // note that EVM opcodes compare like "stack[0] < stack[1]", - // but our left value is at stack[1], so everyhing is reversed. switch (_operator) { case Token::GTE: - m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) + m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) << eth::Instruction::ISZERO; break; case Token::LTE: - m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) + m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) << eth::Instruction::ISZERO; break; case Token::GT: - m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); + m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); break; case Token::LT: - m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); + m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); @@ -314,16 +298,16 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty m_context << eth::Instruction::ADD; break; case Token::SUB: - m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; + m_context << eth::Instruction::SUB; break; case Token::MUL: m_context << eth::Instruction::MUL; break; case Token::DIV: - m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); + m_context << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); break; case Token::MOD: - m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); + m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); @@ -364,10 +348,9 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) { - // If the type of one of the operands is extended, we need to remove all - // higher-order bits that we might have ignored in previous operations. - // @todo: store in the AST whether the operand might have "dirty" higher - // order bits + // For a type extension, we need to remove all higher-order bits that we might have ignored in + // previous operations. + // @todo: store in the AST whether the operand might have "dirty" higher order bits if (_typeOnStack == _targetType && !_cleanupNeeded) return; @@ -388,31 +371,65 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; } -void ExpressionCompiler::storeInLValue(Expression const& _expression) -{ - moveToLValue(_expression); - unsigned stackPos = stackPositionOfLValue(); - if (stackPos > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Stack too deep.")); - m_context << eth::dupInstruction(stackPos + 1); -} - -void ExpressionCompiler::moveToLValue(Expression const& _expression) +void ExpressionCompiler::retrieveLValueValue(Expression const& _expression) { - unsigned stackPos = stackPositionOfLValue(); - if (stackPos > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Stack too deep.")); - else if (stackPos > 0) - m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; + switch (m_currentLValue.locationType) + { + case LValueLocation::CODE: + // not stored on the stack + break; + case LValueLocation::STACK: + { + unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location)); + if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + m_context << eth::dupInstruction(stackPos + 1); + break; + } + case LValueLocation::STORAGE: + m_context << m_currentLValue.location << eth::Instruction::SLOAD; + break; + case LValueLocation::MEMORY: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented.")); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type.")); + break; + } } -unsigned ExpressionCompiler::stackPositionOfLValue() const +void ExpressionCompiler::storeInLValue(Expression const& _expression, bool _move) { - if (asserts(m_currentLValue)) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not available on request.")); - return m_context.getStackPositionOfVariable(*m_currentLValue); + switch (m_currentLValue.locationType) + { + case LValueLocation::STACK: + { + unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location)); + if (stackPos > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + else if (stackPos > 0) + m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; + if (!_move) + retrieveLValueValue(_expression); + break; + } + case LValueLocation::STORAGE: + if (!_move) + m_context << eth::Instruction::DUP1; + m_context << m_currentLValue.location << eth::Instruction::SSTORE; + break; + case LValueLocation::CODE: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type does not support assignment.")); + break; + case LValueLocation::MEMORY: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented.")); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type.")); + break; + } } } diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index d67814be0..bd5a9f866 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -20,18 +20,25 @@ * Solidity AST to EVM bytecode compiler for expressions. */ +#include #include namespace dev { +namespace eth +{ +class AssemblyItem; // forward +} namespace solidity { class CompilerContext; // forward class Type; // forward class IntegerType; // forward -/// Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream -/// of EVM instructions. It needs a compiler context that is the same for the whole compilation -/// unit. +/** + * Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream + * of EVM instructions. It needs a compiler context that is the same for the whole compilation + * unit. + */ class ExpressionCompiler: private ASTVisitor { public: @@ -42,7 +49,7 @@ public: static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); private: - ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), m_context(_compilerContext) {} + ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {} virtual bool visit(Assignment& _assignment) override; virtual void endVisit(UnaryOperation& _unaryOperation) override; @@ -72,15 +79,36 @@ private: //// Appends code that cleans higher-order bits for integer types. void appendHighBitsCleanup(IntegerType const& _typeOnStack); - /// Stores the value on top of the stack in the current lvalue and copies that value to the - /// top of the stack again - void storeInLValue(Expression const& _expression); - /// The same as storeInLValue but do not again retrieve the value to the top of the stack. - void moveToLValue(Expression const& _expression); - /// Returns the position of @a m_currentLValue in the stack, where 0 is the top of the stack. - unsigned stackPositionOfLValue() const; - - Declaration* m_currentLValue; + /// Copies the value of the current lvalue to the top of the stack. + void retrieveLValueValue(Expression const& _expression); + /// Stores the value on top of the stack in the current lvalue. Removes it from the stack if + /// @a _move is true. + void storeInLValue(Expression const& _expression, bool _move = false); + + /** + * Location of an lvalue, either in code (for a function) on the stack, in the storage or memory. + */ + struct LValueLocation + { + enum LocationType { INVALID, CODE, STACK, MEMORY, STORAGE }; + + LValueLocation() { reset(); } + LValueLocation(LocationType _type, u256 const& _location): locationType(_type), location(_location) {} + void reset() { locationType = INVALID; location = 0; } + bool isValid() const { return locationType != INVALID; } + bool isInCode() const { return locationType == CODE; } + bool isInOnStack() const { return locationType == STACK; } + bool isInMemory() const { return locationType == MEMORY; } + bool isInStorage() const { return locationType == STORAGE; } + + LocationType locationType; + /// Depending on the type, this is the id of a tag (code), the base offset of a stack + /// variable (@see CompilerContext::getBaseStackOffsetOfVariable) or the offset in + /// storage or memory. + u256 location; + }; + + LValueLocation m_currentLValue; CompilerContext& m_context; }; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7354255e1..3a4112c45 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -56,7 +56,6 @@ shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); - return shared_ptr(); } shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) @@ -67,7 +66,6 @@ shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeN shared_ptr Type::fromMapping(Mapping const&) { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented.")); - return shared_ptr(); } shared_ptr Type::forLiteral(Literal const& _literal) @@ -103,8 +101,8 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): m_bits(_bits), m_modifier(_modifier) { if (isAddress()) - _bits = 160; - if (asserts(_bits > 0 && _bits <= 256 && _bits % 8 == 0)) + m_bits = 160; + if (asserts(m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0)) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid bit number for integer type: " + dev::toString(_bits))); } @@ -207,6 +205,14 @@ bool ContractType::operator==(Type const& _other) const return other.m_contract == m_contract; } +u256 ContractType::getStorageSize() const +{ + u256 size = 0; + for (ASTPointer const& variable: m_contract.getStateVariables()) + size += variable->getType()->getStorageSize(); + return max(1, size); +} + bool StructType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -215,6 +221,14 @@ bool StructType::operator==(Type const& _other) const return other.m_struct == m_struct; } +u256 StructType::getStorageSize() const +{ + u256 size = 0; + for (ASTPointer const& variable: m_struct.getMembers()) + size += variable->getType()->getStorageSize(); + return max(1, size); +} + bool FunctionType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 8c88ca79f..607ee3a6f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -75,6 +75,9 @@ public: /// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding /// is not a simple big-endian encoding or the type cannot be stored on the stack. virtual unsigned getCalldataEncodedSize() const { return 0; } + /// @returns number of bytes required to hold this value in storage. + /// For dynamically "allocated" types, it returns the size of the statically allocated head, + virtual u256 getStorageSize() const { return 1; } virtual std::string toString() const = 0; virtual u256 literalValue(Literal const&) const @@ -157,7 +160,7 @@ public: ContractType(ContractDefinition const& _contract): m_contract(_contract) {} virtual bool operator==(Type const& _other) const override; - + virtual u256 getStorageSize() const; virtual std::string toString() const override { return "contract{...}"; } private: @@ -178,7 +181,7 @@ public: } virtual bool operator==(Type const& _other) const override; - + virtual u256 getStorageSize() const; virtual std::string toString() const override { return "struct{...}"; } private: @@ -196,9 +199,9 @@ public: FunctionDefinition const& getFunction() const { return m_function; } - virtual std::string toString() const override { return "function(...)returns(...)"; } - virtual bool operator==(Type const& _other) const override; + virtual std::string toString() const override { return "function(...)returns(...)"; } + virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } private: FunctionDefinition const& m_function; @@ -212,9 +215,9 @@ class MappingType: public Type public: virtual Category getCategory() const override { return Category::MAPPING; } MappingType() {} - virtual std::string toString() const override { return "mapping(...=>...)"; } virtual bool operator==(Type const& _other) const override; + virtual std::string toString() const override { return "mapping(...=>...)"; } private: std::shared_ptr m_keyType; @@ -232,6 +235,7 @@ public: VoidType() {} virtual std::string toString() const override { return "void"; } + virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } }; /** @@ -247,7 +251,7 @@ public: std::shared_ptr const& getActualType() const { return m_actualType; } virtual bool operator==(Type const& _other) const override; - + virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } private: diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 109b7ecb6..40ec744bd 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -268,7 +268,8 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message res["sent"] = (int)_e.sent(); res["ttl"] = (int)_e.ttl(); res["workProved"] = (int)_e.workProved(); - res["topic"] = toJS(_e.topic()); + for (auto const& t: _e.topics()) + res["topics"].append(toJS((u256)t)); res["payload"] = toJS(_m.payload()); res["from"] = toJS(_m.from()); res["to"] = toJS(_m.to()); diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 15b07e433..8f58ae994 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -22,11 +22,21 @@ #include "Common.h" #include +#include "Message.h" using namespace std; using namespace dev; using namespace dev::p2p; using namespace dev::shh; +Topic BuildTopic::toTopic() const +{ + Topic ret; + ret.reserve(m_parts.size()); + for (auto const& h: m_parts) + ret.push_back((TopicPart)u256(h)); + return ret; +} + BuildTopic& BuildTopic::shiftBytes(bytes const& _b) { m_parts.push_back(dev::sha3(_b)); @@ -40,19 +50,32 @@ h256 TopicFilter::sha3() const return dev::sha3(s.out()); } +bool TopicFilter::matches(Envelope const& _e) const +{ + for (TopicMask const& t: m_topicMasks) + { + if (_e.topics().size() == t.size()) + for (unsigned i = 0; i < t.size(); ++i) + if (((t[i].first ^ _e.topics()[i]) & t[i].second) != 0) + goto NEXT_TOPICMASK; + return true; + NEXT_TOPICMASK:; + } + return false; +} + TopicMask BuildTopicMask::toTopicMask() const { TopicMask ret; - if (m_parts.size()) - for (auto i = 0; i < 32; ++i) - { - ret.first[i] = m_parts[i * m_parts.size() / 32][i]; - ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0; - } + ret.reserve(m_parts.size()); + for (auto const& h: m_parts) + ret.push_back(make_pair((TopicPart)u256(h), h ? ~(uint32_t)0 : 0)); return ret; } + /* web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); }) k = web3.shh.newIdentity() web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")}) */ + diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 21296e193..f47778afe 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -59,7 +59,9 @@ enum WhisperPacket PacketCount }; -using Topic = h256; +using TopicPart = uint32_t; + +using Topic = std::vector; class BuildTopic { @@ -73,7 +75,7 @@ public: BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; } operator Topic() const { return toTopic(); } - Topic toTopic() const { Topic ret; for (auto i = 0; i < 32; ++i) ret[i] = m_parts[i * m_parts.size() / 32][i]; return ret; } + Topic toTopic() const; protected: BuildTopic& shiftBytes(bytes const& _b); @@ -81,7 +83,7 @@ protected: h256s m_parts; }; -using TopicMask = std::pair; +using TopicMask = std::vector>; using TopicMasks = std::vector; class TopicFilter diff --git a/libwhisper/Interface.cpp b/libwhisper/Interface.cpp index 9b6815f0d..c00c3ebb2 100644 --- a/libwhisper/Interface.cpp +++ b/libwhisper/Interface.cpp @@ -34,10 +34,7 @@ using namespace dev::shh; #endif #define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " -bool TopicFilter::matches(Envelope const& _e) const +unsigned Interface::installWatch(TopicMask const& _mask) { - for (TopicMask const& t: m_topicMasks) - if (((t.first ^ _e.topic()) & t.second) == 0) - return true; - return false; + return installWatch(TopicFilter(_mask)); } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 56b3be599..1af93f591 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -69,7 +69,7 @@ public: virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; - unsigned installWatch(TopicMask const& _mask) { return installWatch(TopicFilter(_mask)); } + unsigned installWatch(TopicMask const& _mask); virtual unsigned installWatch(TopicFilter const& _filter) = 0; virtual unsigned installWatchOnId(h256 _filterId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 93dcaa033..65da72f9d 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -97,7 +97,7 @@ Message Envelope::open(Secret const& _s) const unsigned Envelope::workProved() const { h256 d[2]; - d[0] = sha3NoNonce(); + d[0] = sha3(WithoutNonce); d[1] = m_nonce; return dev::sha3(bytesConstRef(d[0].data(), 64)).firstBitSet(); } @@ -106,7 +106,7 @@ void Envelope::proveWork(unsigned _ms) { // PoW h256 d[2]; - d[0] = sha3NoNonce(); + d[0] = sha3(WithoutNonce); uint32_t& n = *(uint32_t*)&(d[1][28]); unsigned bestBitSet = 0; bytesConstRef chuck(d[0].data(), 64); diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 677d16f00..3b0d14aae 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -39,6 +39,12 @@ namespace shh class Message; +enum IncludeNonce +{ + WithoutNonce = 0, + WithNonce = 1 +}; + class Envelope { friend class Message; @@ -56,14 +62,13 @@ public: operator bool() const { return !!m_expiry; } - void streamRLP(RLPStream& _s, bool _withNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; } - h256 sha3() const { RLPStream s; streamRLP(s, true); return dev::sha3(s.out()); } - h256 sha3NoNonce() const { RLPStream s; streamRLP(s, false); return dev::sha3(s.out()); } + void streamRLP(RLPStream& _s, IncludeNonce _withNonce = WithNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; } + h256 sha3(IncludeNonce _withNonce = WithNonce) const { RLPStream s; streamRLP(s, _withNonce); return dev::sha3(s.out()); } unsigned sent() const { return m_expiry - m_ttl; } unsigned expiry() const { return m_expiry; } unsigned ttl() const { return m_ttl; } - Topic const& topic() const { return m_topic; } + Topic const& topics() const { return m_topic; } bytes const& data() const { return m_data; } Message open(Secret const& _s = Secret()) const; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 71030aae2..0fb7a206c 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -21,6 +21,7 @@ #include "WhisperHost.h" +#include #include #include using namespace std; @@ -48,14 +49,14 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const { UpgradeGuard ll(l); auto const& m = m_messages.at(_m); - cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data()); - m.streamRLP(_s, true); + cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topics() << toHex(m.data()); + m.streamRLP(_s); } } void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) { - cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data()); + cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topics() << toHex(_m.data()); if (_m.expiry() <= time(0)) return; diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 4d761919c..91934dd98 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -46,7 +46,7 @@ public: WhisperHost(); virtual ~WhisperHost(); - unsigned protocolVersion() const { return 0; } + unsigned protocolVersion() const { return 1; } virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 343f7ca1a..56f4e456e 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -37,7 +37,7 @@ using namespace dev::shh; WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i) { RLPStream s; - sealAndSend(prep(s, StatusPacket, 1) << host()->protocolVersion()); + sealAndSend(prep(s, StatusPacket, 1) << version()); } WhisperPeer::~WhisperPeer() @@ -59,7 +59,7 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) clogS(NetMessageSummary) << "Status: " << protocolVersion; - if (protocolVersion != host()->protocolVersion()) + if (protocolVersion != version()) disable("Invalid protocol version."); if (session()->id() < host()->host()->id()) diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index 45d72ba89..f60de8f01 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -53,7 +53,7 @@ public: virtual ~WhisperPeer(); static std::string name() { return "shh"; } - static u256 version() { return 1; } + static u256 version() { return 2; } static unsigned messageCount() { return PacketCount; } WhisperHost* host() const; diff --git a/test/TestHelper.h b/test/TestHelper.h index 622b83ac4..a4eb64d84 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -57,7 +57,6 @@ public: eth::State m_statePost; eth::ExtVMFace m_environment; eth::Transaction m_transaction; - bytes code; private: json_spirit::mObject& m_TestObject; diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 321e515d6..f74be9304 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -134,10 +134,10 @@ void doMyTests(json_spirit::mValue& v) o["pre"] = mValue(fev.exportState()); fev.importExec(o["exec"].get_obj()); - if (!fev.code) + if (fev.code.empty()) { fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); - fev.code = &fev.thisTxCode; + fev.code = fev.thisTxCode; } vm.reset(fev.gas); diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 192fd61a4..ba2db67e6 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), // initialized e and h - byte(Instruction::PUSH1), 0x29 + shift, // ret address + byte(Instruction::PUSH1), byte(0x29 + shift), // ret address byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 35c2a3b02..796adcb15 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -60,6 +60,16 @@ public: return callFunction(_index, toBigEndian(_argument1)); } + bool testSolidityAgainstCpp(byte _index, std::function const& _cppfun, u256 const& _argument1) + { + return toBigEndian(_cppfun(_argument1)) == callFunction(_index, toBigEndian(_argument1)); + } + + bool testSolidityAgainstCpp(byte _index, std::function const& _cppfun) + { + return toBigEndian(_cppfun()) == callFunction(_index, bytes()); + } + private: void sendMessage(bytes const& _data, bool _isCreation) { @@ -123,11 +133,19 @@ BOOST_AUTO_TEST_CASE(recursive_calls) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1))); - BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1))); - BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2))); - BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6))); - BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24))); + std::function recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256 + { + if (n <= 1) + return 1; + else + return n * recursive_calls_cpp(n - 1); + }; + + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(0))); + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(1))); + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(2))); + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(3))); + BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(4))); } BOOST_AUTO_TEST_CASE(while_loop) @@ -140,11 +158,22 @@ BOOST_AUTO_TEST_CASE(while_loop) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1))); - BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1))); - BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2))); - BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6))); - BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24))); + + auto while_loop_cpp = [](u256 const& n) -> u256 + { + u256 nfac = 1; + u256 i = 2; + while (i <= n) + nfac *= i++; + + return nfac; + }; + + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(0))); + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(1))); + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(2))); + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(3))); + BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(4))); } BOOST_AUTO_TEST_CASE(break_outside_loop) @@ -182,18 +211,43 @@ BOOST_AUTO_TEST_CASE(nested_loops) "}\n"; ExecutionFramework framework; framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0))); - BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(2))); - BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(2))); - BOOST_CHECK(framework.callFunction(0, u256(5)) == toBigEndian(u256(4))); - BOOST_CHECK(framework.callFunction(0, u256(6)) == toBigEndian(u256(5))); - BOOST_CHECK(framework.callFunction(0, u256(7)) == toBigEndian(u256(5))); - BOOST_CHECK(framework.callFunction(0, u256(8)) == toBigEndian(u256(7))); - BOOST_CHECK(framework.callFunction(0, u256(9)) == toBigEndian(u256(8))); - BOOST_CHECK(framework.callFunction(0, u256(10)) == toBigEndian(u256(10))); - BOOST_CHECK(framework.callFunction(0, u256(11)) == toBigEndian(u256(10))); + + auto nested_loops_cpp = [](u256 n) -> u256 + { + while (n > 1) + { + if (n == 10) + break; + while (n > 5) + { + if (n == 8) + break; + n--; + if (n == 6) + continue; + return n; + } + n--; + if (n == 3) + continue; + break; + } + + return n; + }; + + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(0))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(1))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(2))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(3))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(4))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(5))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(6))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(7))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(8))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(9))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(10))); + BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(11))); } BOOST_AUTO_TEST_CASE(calling_other_functions) @@ -214,11 +268,34 @@ BOOST_AUTO_TEST_CASE(calling_other_functions) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(2, u256(0)) == toBigEndian(u256(0))); - BOOST_CHECK(callFunction(2, u256(1)) == toBigEndian(u256(1))); - BOOST_CHECK(callFunction(2, u256(2)) == toBigEndian(u256(1))); - BOOST_CHECK(callFunction(2, u256(8)) == toBigEndian(u256(1))); - BOOST_CHECK(callFunction(2, u256(127)) == toBigEndian(u256(1))); + + auto evenStep_cpp = [](u256 const& n) -> u256 + { + return n / 2; + }; + + auto oddStep_cpp = [](u256 const& n) -> u256 + { + return 3 * n + 1; + }; + + auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp] (u256 n) -> u256 { + u256 y; + while ((y = n) > 1) + { + if (n % 2 == 0) + n = evenStep_cpp(n); + else + n = oddStep_cpp(n); + } + return y; + }; + + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(0))); + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(1))); + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(2))); + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(8))); + BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(127))); } BOOST_AUTO_TEST_CASE(many_local_variables) @@ -270,8 +347,15 @@ BOOST_AUTO_TEST_CASE(short_circuiting) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(0))); - BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(8))); + + auto short_circuiting_cpp = [](u256 n) -> u256 + { + n == 0 || (n = 8) > 0; + return n; + }; + + BOOST_CHECK(testSolidityAgainstCpp(0, short_circuiting_cpp, u256(0))); + BOOST_CHECK(testSolidityAgainstCpp(0, short_circuiting_cpp, u256(1))); } BOOST_AUTO_TEST_CASE(high_bits_cleaning) @@ -284,7 +368,14 @@ BOOST_AUTO_TEST_CASE(high_bits_cleaning) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(9))); + auto high_bits_cleaning_cpp = []() -> u256 + { + uint32_t x = uint32_t(0xffffffff) + 10; + if (x >= 0xffffffff) + return 0; + return x; + }; + BOOST_CHECK(testSolidityAgainstCpp(0, high_bits_cleaning_cpp)); } BOOST_AUTO_TEST_CASE(sign_extension) @@ -297,7 +388,14 @@ BOOST_AUTO_TEST_CASE(sign_extension) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xff))); + auto sign_extension_cpp = []() -> u256 + { + int64_t x = -int32_t(0xff); + if (x >= 0xff) + return 0; + return u256(x) * -1; + }; + BOOST_CHECK(testSolidityAgainstCpp(0, sign_extension_cpp)); } BOOST_AUTO_TEST_CASE(small_unsigned_types) @@ -309,7 +407,12 @@ BOOST_AUTO_TEST_CASE(small_unsigned_types) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xfe0000))); + auto small_unsigned_types_cpp = []() -> u256 + { + uint32_t x = uint32_t(0xffffff) * 0xffffff; + return x / 0x100; + }; + BOOST_CHECK(testSolidityAgainstCpp(0, small_unsigned_types_cpp)); } BOOST_AUTO_TEST_CASE(small_signed_types) @@ -320,7 +423,36 @@ BOOST_AUTO_TEST_CASE(small_signed_types) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(200))); + auto small_signed_types_cpp = []() -> u256 + { + return -int32_t(10) * -int64_t(20); + }; + BOOST_CHECK(testSolidityAgainstCpp(0, small_signed_types_cpp)); +} + +BOOST_AUTO_TEST_CASE(state_smoke_test) +{ + char const* sourceCode = "contract test {\n" + " uint256 value1;\n" + " uint256 value2;\n" + " function get(uint8 which) returns (uint256 value) {\n" + " if (which == 0) return value1;\n" + " else return value2;\n" + " }\n" + " function set(uint8 which, uint256 value) {\n" + " if (which == 0) value1 = value;\n" + " else value2 = value;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0))); + BOOST_CHECK(callFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0))); + BOOST_CHECK(callFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes()); + BOOST_CHECK(callFunction(1, bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes()); + BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x1234))); + BOOST_CHECK(callFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0x8765))); + BOOST_CHECK(callFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes()); + BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3))); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index 8fc4a1a22..59a9e9336 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -154,10 +154,10 @@ BOOST_AUTO_TEST_CASE(comparison) "}\n"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), + bytes expectation({byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), - byte(eth::Instruction::GT), - byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::LT), byte(eth::Instruction::EQ), byte(eth::Instruction::ISZERO)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); @@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(comparison) BOOST_AUTO_TEST_CASE(short_circuiting) { char const* sourceCode = "contract test {\n" - " function f() { var x = (10 + 8 >= 4 || 2 != 9) != true; }" + " function f() { var x = true != (4 <= 8 + 10 || 9 != 2); }" "}\n"; bytes code = compileFirstExpression(sourceCode); @@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(short_circuiting) BOOST_AUTO_TEST_CASE(arithmetics) { char const* sourceCode = "contract test {\n" - " function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }" + " function f() { var x = ((((((((9 ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }" "}\n"; bytes code = compileFirstExpression(sourceCode); bytes expectation({byte(eth::Instruction::PUSH1), 0x1, @@ -211,14 +211,11 @@ BOOST_AUTO_TEST_CASE(arithmetics) byte(eth::Instruction::XOR), byte(eth::Instruction::AND), byte(eth::Instruction::OR), - byte(eth::Instruction::SWAP1), byte(eth::Instruction::SUB), byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), - byte(eth::Instruction::SWAP1), byte(eth::Instruction::MOD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), - byte(eth::Instruction::SWAP1), byte(eth::Instruction::DIV), byte(eth::Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); @@ -231,11 +228,11 @@ BOOST_AUTO_TEST_CASE(unary_operators) "}\n"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(eth::Instruction::PUSH1), 0x1, + bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH1), 0x0, byte(eth::Instruction::SUB), byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), - byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::EQ), byte(eth::Instruction::ISZERO)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); @@ -244,7 +241,7 @@ BOOST_AUTO_TEST_CASE(unary_operators) BOOST_AUTO_TEST_CASE(unary_inc_dec) { char const* sourceCode = "contract test {\n" - " function f(uint a) { var x = ((a++ ^ ++a) ^ a--) ^ --a; }" + " function f(uint a) { var x = --a ^ (a-- ^ (++a ^ a++)); }" "}\n"; bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}}); @@ -299,16 +296,15 @@ BOOST_AUTO_TEST_CASE(assignment) bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}}); // Stack: a, b - bytes expectation({byte(eth::Instruction::DUP1), - byte(eth::Instruction::DUP3), - byte(eth::Instruction::SWAP1), + bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::DUP2), + byte(eth::Instruction::DUP4), byte(eth::Instruction::ADD), - // Stack here: a b a+b - byte(eth::Instruction::SWAP2), + // Stack here: a b 2 a+b + byte(eth::Instruction::SWAP3), byte(eth::Instruction::POP), - byte(eth::Instruction::DUP2), - // Stack here: a+b b a+b - byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::DUP3), + // Stack here: a+b b 2 a+b byte(eth::Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -323,21 +319,20 @@ BOOST_AUTO_TEST_CASE(function_call) {{"test", "f", "a"}, {"test", "f", "b"}}); // Stack: a, b - bytes expectation({byte(eth::Instruction::PUSH1), 0x0d, - byte(eth::Instruction::DUP3), + bytes expectation({byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x12, byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::DUP5), byte(eth::Instruction::ADD), - // Stack here: a b (a+1) - byte(eth::Instruction::DUP3), - byte(eth::Instruction::PUSH1), 0x1a, + // Stack here: a b 2 (a+1) + byte(eth::Instruction::DUP4), + byte(eth::Instruction::PUSH1), 0x19, byte(eth::Instruction::JUMP), byte(eth::Instruction::JUMPDEST), - // Stack here: a b g(a+1, b) - byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + // Stack here: a b 2 g(a+1, b) byte(eth::Instruction::MUL), // Stack here: a b g(a+1, b)*2 byte(eth::Instruction::DUP3), - byte(eth::Instruction::SWAP1), byte(eth::Instruction::ADD), // Stack here: a b a+g(a+1, b)*2 byte(eth::Instruction::SWAP2), @@ -355,15 +350,15 @@ BOOST_AUTO_TEST_CASE(negative_literals_8bits) "}\n"; bytes code = compileFirstExpression(sourceCode); - bytes expectation(bytes({byte(eth::Instruction::PUSH1), 0x00, - byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + - bytes({byte(eth::Instruction::ADD), - byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + - bytes({byte(eth::Instruction::ADD), - byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) + - bytes({byte(eth::Instruction::ADD), - byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) + - bytes({byte(eth::Instruction::ADD)})); + bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) + + bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) + + bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::PUSH1), 0x00, + byte(eth::Instruction::ADD), + byte(eth::Instruction::ADD), + byte(eth::Instruction::ADD), + byte(eth::Instruction::ADD)})); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -376,11 +371,11 @@ BOOST_AUTO_TEST_CASE(negative_literals_16bits) "}\n"; bytes code = compileFirstExpression(sourceCode); - bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) + + bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + bytes({byte(eth::Instruction::PUSH1), 0x00, byte(eth::Instruction::SIGNEXTEND), - byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) + - bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::SIGNEXTEND)})); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); diff --git a/test/state.cpp b/test/state.cpp index 9c0a7188b..935869058 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -55,12 +55,6 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) ImportTest importer(o, _fillin); - if (_fillin) - { - importer.code = importer.m_statePre.code(importer.m_environment.myAddress); - importer.m_environment.code = &importer.code; - } - State theState = importer.m_statePre; bytes tx = importer.m_transaction.rlp(); bytes output; @@ -124,12 +118,4 @@ BOOST_AUTO_TEST_CASE(stSystemOperationsTest) dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests); } -BOOST_AUTO_TEST_CASE(tmp) -{ - int currentVerbosity = g_logVerbosity; - g_logVerbosity = 12; - dev::test::executeTests("tmp", "/StateTests", dev::test::doStateTests); - g_logVerbosity = currentVerbosity; -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/test/tmpFiller.json b/test/tmpFiller.json deleted file mode 100644 index bd27b8907..000000000 --- a/test/tmpFiller.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "ABAcalls0": { - "env" : { - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", - "currentGasLimit" : "10000000", - "currentDifficulty" : "256", - "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" - }, - "pre" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }", - "storage": {} - }, - "945304eb96065b2a98b57a48a06ae28d285a71b5" : { - "balance" : "23", - "code" : " { [[ (PC) ]] (ADD 1 (CALL 500 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 23 0 0 0 0)) } ", - "nonce" : "0", - "storage" : { - } - }, - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "1000000000000000000", - "nonce" : 0, - "code" : "", - "storage": {} - } - - }, - "transaction" : { - "nonce" : "0", - "gasPrice" : "1", - "gasLimit" : "10000", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "100000", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "data" : "" - } - } - -} diff --git a/test/vm.cpp b/test/vm.cpp index c6799daac..93cf121de 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -29,7 +29,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, _depth) {} h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&) { @@ -195,11 +195,11 @@ void FakeExtVM::importExec(mObject& _o) gas = toInt(_o["gas"]); thisTxCode.clear(); - code = &thisTxCode; + code = thisTxCode; thisTxCode = importCode(_o); if (_o["code"].type() != str_type && _o["code"].type() != array_type) - code.reset(); + code.clear(); thisTxData.clear(); thisTxData = importData(_o); @@ -289,10 +289,10 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) o["pre"] = mValue(fev.exportState()); fev.importExec(o["exec"].get_obj()); - if (!fev.code) + if (fev.code.empty()) { fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); - fev.code = &fev.thisTxCode; + fev.code = fev.thisTxCode; } bytes output;