Browse Source

Merge remote-tracking branch 'ethereum/develop' into sol_optimizer

Conflicts:
	libevmcore/Instruction.cpp
cl-refactor
Christian 10 years ago
parent
commit
1151d372a6
  1. 8
      alethzero/MainWin.cpp
  2. 1
      libdevcore/Log.h
  3. 6
      libdevcore/RLP.h
  4. 2
      libethereum/ExtVM.h
  5. 2
      libevm/ExtVMFace.cpp
  6. 4
      libevm/ExtVMFace.h
  7. 4
      libevmcore/Instruction.cpp
  8. 34
      libjsqrc/main.js
  9. 8
      libjsqrc/qt.js
  10. 1
      libqethereum/QEthereum.cpp
  11. 8
      libsolidity/AST.h
  12. 7
      libsolidity/CMakeLists.txt
  13. 19
      libsolidity/Compiler.cpp
  14. 36
      libsolidity/CompilerContext.cpp
  15. 25
      libsolidity/CompilerContext.h
  16. 159
      libsolidity/ExpressionCompiler.cpp
  17. 52
      libsolidity/ExpressionCompiler.h
  18. 22
      libsolidity/Types.cpp
  19. 16
      libsolidity/Types.h
  20. 3
      libweb3jsonrpc/WebThreeStubServer.cpp
  21. 35
      libwhisper/Common.cpp
  22. 8
      libwhisper/Common.h
  23. 7
      libwhisper/Interface.cpp
  24. 2
      libwhisper/Interface.h
  25. 4
      libwhisper/Message.cpp
  26. 13
      libwhisper/Message.h
  27. 7
      libwhisper/WhisperHost.cpp
  28. 2
      libwhisper/WhisperHost.h
  29. 4
      libwhisper/WhisperPeer.cpp
  30. 2
      libwhisper/WhisperPeer.h
  31. 1
      test/TestHelper.h
  32. 4
      test/createRandomTest.cpp
  33. 2
      test/solidityCompiler.cpp
  34. 198
      test/solidityEndToEndTest.cpp
  35. 73
      test/solidityExpressionCompiler.cpp
  36. 14
      test/state.cpp
  37. 44
      test/tmpFiller.json
  38. 10
      test/vm.cpp

8
alethzero/MainWin.cpp

@ -610,6 +610,7 @@ void Main::readSettings(bool _skipGeometry)
} }
} }
ethereum()->setAddress(m_myKeys.back().address()); ethereum()->setAddress(m_myKeys.back().address());
m_server->setAccounts(keysAsVector(m_myKeys));
} }
{ {
@ -1374,7 +1375,7 @@ void Main::populateDebugger(dev::bytesConstRef _r)
debugFinished(); debugFinished();
vector<WorldState const*> levels; vector<WorldState const*> levels;
m_codes.clear(); m_codes.clear();
bytesConstRef lastExtCode; bytes lastExtCode;
bytesConstRef lastData; bytesConstRef lastData;
h256 lastHash; h256 lastHash;
h256 lastDataHash; h256 lastDataHash;
@ -1387,7 +1388,7 @@ void Main::populateDebugger(dev::bytesConstRef _r)
lastExtCode = ext.code; lastExtCode = ext.code;
lastHash = sha3(lastExtCode); lastHash = sha3(lastExtCode);
if (!m_codes.count(lastHash)) if (!m_codes.count(lastHash))
m_codes[lastHash] = ext.code.toBytes(); m_codes[lastHash] = ext.code;
} }
if (ext.data != lastData) if (ext.data != lastData)
{ {
@ -1821,6 +1822,7 @@ void Main::on_send_clicked()
void Main::keysChanged() void Main::keysChanged()
{ {
onBalancesChange(); onBalancesChange();
m_server->setAccounts(keysAsVector(m_myKeys));
} }
void Main::on_debug_clicked() void Main::on_debug_clicked()
@ -2218,7 +2220,7 @@ void Main::refreshWhispers()
time_t ex = e.expiry(); time_t ex = e.expiry();
QString t(ctime(&ex)); QString t(ctime(&ex));
t.chop(1); 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); ui->whispers->addItem(item);
} }
} }

1
libdevcore/Log.h

@ -27,6 +27,7 @@
#include <chrono> #include <chrono>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "vector_ref.h" #include "vector_ref.h"
#include "CommonIO.h"
namespace dev namespace dev
{ {

6
libdevcore/RLP.h

@ -159,7 +159,11 @@ public:
/// Best-effort conversion operators. /// Best-effort conversion operators.
explicit operator std::string() const { return toString(); } explicit operator std::string() const { return toString(); }
explicit operator RLPs() const { return toList(); } explicit operator RLPs() const { return toList(); }
explicit operator byte() const { return toInt<byte>(); } explicit operator uint8_t() const { return toInt<uint8_t>(); }
explicit operator uint16_t() const { return toInt<uint16_t>(); }
explicit operator uint32_t() const { return toInt<uint32_t>(); }
explicit operator uint64_t() const { return toInt<uint64_t>(); }
explicit operator u160() const { return toInt<u160>(); }
explicit operator u256() const { return toInt<u256>(); } explicit operator u256() const { return toInt<u256>(); }
explicit operator bigint() const { return toInt<bigint>(); } explicit operator bigint() const { return toInt<bigint>(); }
template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); } template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); }

2
libethereum/ExtVM.h

@ -40,7 +40,7 @@ class ExtVM: public ExtVMFace
public: public:
/// Full constructor. /// 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): 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); m_s.ensureCached(_myAddress, true, true);
} }

2
libevm/ExtVMFace.cpp

@ -25,7 +25,7 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; 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), myAddress(_myAddress),
caller(_caller), caller(_caller),
origin(_origin), origin(_origin),

4
libevm/ExtVMFace.h

@ -104,7 +104,7 @@ public:
ExtVMFace() = default; ExtVMFace() = default;
/// Full constructor. /// 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; virtual ~ExtVMFace() = default;
@ -153,7 +153,7 @@ public:
u256 value; ///< Value (in Wei) that was passed to this address. u256 value; ///< Value (in Wei) that was passed to this address.
u256 gasPrice; ///< Price of gas (that we already paid). u256 gasPrice; ///< Price of gas (that we already paid).
bytesConstRef data; ///< Current input data. 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 previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information. BlockInfo currentBlock; ///< The current block's information.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs). SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).

4
libevmcore/Instruction.cpp

@ -172,13 +172,13 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::MOD, { "MOD", 0, 2, 1, false } }, { Instruction::MOD, { "MOD", 0, 2, 1, false } },
{ Instruction::SMOD, { "SMOD", 0, 2, 1, false } }, { Instruction::SMOD, { "SMOD", 0, 2, 1, false } },
{ Instruction::EXP, { "EXP", 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::LT, { "LT", 0, 2, 1, false } },
{ Instruction::GT, { "GT", 0, 2, 1, false } }, { Instruction::GT, { "GT", 0, 2, 1, false } },
{ Instruction::SLT, { "SLT", 0, 2, 1, false } }, { Instruction::SLT, { "SLT", 0, 2, 1, false } },
{ Instruction::SGT, { "SGT", 0, 2, 1, false } }, { Instruction::SGT, { "SGT", 0, 2, 1, false } },
{ Instruction::EQ, { "EQ", 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::AND, { "AND", 0, 2, 1, false } },
{ Instruction::OR, { "OR", 0, 2, 1, false } }, { Instruction::OR, { "OR", 0, 2, 1, false } },
{ Instruction::XOR, { "XOR", 0, 2, 1, false } }, { Instruction::XOR, { "XOR", 0, 2, 1, false } },

34
libjsqrc/main.js

@ -2,19 +2,19 @@
This file is part of ethereum.js. This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify 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 the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ethereum.js is distributed in the hope that it will be useful, ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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 <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file ethereum.js /** @file main.js
* @authors: * @authors:
* Marek Kotewicz <marek@ethdev.com> * Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014
@ -153,12 +153,12 @@
return {call: call, args: args}; return {call: call, args: args};
}).then(function (request) { }).then(function (request) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
web3.provider.send(request, function (result) { web3.provider.send(request, function (err, result) {
if (result || typeof result === "boolean") { if (!err) {
resolve(result); resolve(result);
return; return;
} }
reject(result); reject(err);
}); });
}); });
}).catch(function(err) { }).catch(function(err) {
@ -173,8 +173,12 @@
var proto = {}; var proto = {};
proto.get = function () { proto.get = function () {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
web3.provider.send({call: property.getter}, function(result) { web3.provider.send({call: property.getter}, function(err, result) {
if (!err) {
resolve(result); resolve(result);
return;
}
reject(err);
}); });
}); });
}; };
@ -182,12 +186,12 @@
proto.set = function (val) { proto.set = function (val) {
return flattenPromise([val]).then(function (args) { return flattenPromise([val]).then(function (args) {
return new Promise(function (resolve) { return new Promise(function (resolve) {
web3.provider.send({call: property.setter, args: args}, function (result) { web3.provider.send({call: property.setter, args: args}, function (err, result) {
if (result) { if (!err) {
resolve(result); resolve(result);
} else { return;
reject(result);
} }
reject(err);
}); });
}); });
}).catch(function (err) { }).catch(function (err) {
@ -240,7 +244,7 @@
var hex = this.toHex(str); var hex = this.toHex(str);
while(hex.length < pad*2) while(hex.length < pad*2)
hex += "00"; hex += "00";
return "0x" + hex return "0x" + hex;
}, },
eth: { eth: {
@ -410,9 +414,11 @@
}; };
Filter.prototype.trigger = function(messages) { Filter.prototype.trigger = function(messages) {
if (!(messages instanceof Array) || messages.length) {
for(var i = 0; i < this.callbacks.length; i++) { for(var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].call(this, messages); this.callbacks[i].call(this, messages);
} }
}
}; };
Filter.prototype.uninstall = function() { Filter.prototype.uninstall = function() {
@ -440,7 +446,7 @@
if(data._id) { if(data._id) {
var cb = web3._callbacks[data._id]; var cb = web3._callbacks[data._id];
if (cb) { if (cb) {
cb.call(this, data.data) cb.call(this, data.error, data.data);
delete web3._callbacks[data._id]; delete web3._callbacks[data._id];
} }
} }

8
libjsqrc/qt.js

@ -2,19 +2,19 @@
This file is part of ethereum.js. This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify 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 the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ethereum.js is distributed in the hope that it will be useful, ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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 <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file ethereum.js /** @file qt.js
* @authors: * @authors:
* Marek Kotewicz <marek@ethdev.com> * Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014

1
libqethereum/QEthereum.cpp

@ -120,6 +120,7 @@ static QString formatOutput(QJsonObject const& _object)
QJsonObject res; QJsonObject res;
res["_id"] = _object["id"]; res["_id"] = _object["id"];
res["data"] = _object["result"]; res["data"] = _object["result"];
res["error"] = _object["error"];
return QString::fromUtf8(QJsonDocument(res).toJson()); return QString::fromUtf8(QJsonDocument(res).toJson());
} }

8
libsolidity/AST.h

@ -116,9 +116,9 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
std::vector<ASTPointer<StructDefinition>> const& getDefinedStructs() { return m_definedStructs; } std::vector<ASTPointer<StructDefinition>> const& getDefinedStructs() const { return m_definedStructs; }
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() { return m_stateVariables; } std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() { return m_definedFunctions; } std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
private: private:
std::vector<ASTPointer<StructDefinition>> m_definedStructs; std::vector<ASTPointer<StructDefinition>> m_definedStructs;
@ -135,6 +135,8 @@ public:
Declaration(_location, _name), m_members(_members) {} Declaration(_location, _name), m_members(_members) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
std::vector<ASTPointer<VariableDeclaration>> const& getMembers() const { return m_members; }
private: private:
std::vector<ASTPointer<VariableDeclaration>> m_members; std::vector<ASTPointer<VariableDeclaration>> m_members;
}; };

7
libsolidity/CMakeLists.txt

@ -6,14 +6,13 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE solidity) set(EXECUTABLE solidity)
file(GLOB HEADERS "*.h")
if(ETH_STATIC) if(ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${SRC_LIST}) add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else() else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST}) add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif() endif()
file(GLOB HEADERS "*.h")
include_directories(..) include_directories(..)
target_link_libraries(${EXECUTABLE} evmcore devcore) target_link_libraries(${EXECUTABLE} evmcore devcore)

19
libsolidity/Compiler.cpp

@ -21,6 +21,8 @@
*/ */
#include <algorithm> #include <algorithm>
#include <libevmcore/Instruction.h>
#include <libevmcore/Assembly.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/Compiler.h> #include <libsolidity/Compiler.h>
#include <libsolidity/ExpressionCompiler.h> #include <libsolidity/ExpressionCompiler.h>
@ -42,10 +44,12 @@ void Compiler::compileContract(ContractDefinition& _contract)
m_context = CompilerContext(); // clear it just in case m_context = CompilerContext(); // clear it just in case
//@todo constructor //@todo constructor
//@todo register state variables
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
m_context.addFunction(*function); m_context.addFunction(*function);
//@todo sort them?
for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
m_context.addStateVariable(*variable);
appendFunctionSelector(_contract.getDefinedFunctions()); appendFunctionSelector(_contract.getDefinedFunctions());
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
@ -123,7 +127,7 @@ void Compiler::appendCalldataUnpacker(FunctionDefinition const& _function)
if (numBytes == 0) if (numBytes == 0)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(var->getLocation()) << errinfo_sourceLocation(var->getLocation())
<< errinfo_comment("Type not yet supported.")); << errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
if (numBytes == 32) if (numBytes == 32)
m_context << u256(dataOffset) << eth::Instruction::CALLDATALOAD; m_context << u256(dataOffset) << eth::Instruction::CALLDATALOAD;
else else
@ -140,11 +144,12 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
vector<ASTPointer<VariableDeclaration>> const& parameters = _function.getReturnParameters(); vector<ASTPointer<VariableDeclaration>> const& parameters = _function.getReturnParameters();
for (unsigned i = 0; i < parameters.size(); ++i) 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) if (numBytes == 0)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(parameters[i]->getLocation()) << 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); m_context << eth::dupInstruction(parameters.size() - i);
if (numBytes != 32) if (numBytes != 32)
m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL; m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
@ -273,7 +278,8 @@ bool Compiler::visit(Return& _return)
ExpressionCompiler::compileExpression(m_context, *expression); ExpressionCompiler::compileExpression(m_context, *expression);
VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front(); VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front();
ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType()); 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 << eth::swapInstruction(stackPosition) << eth::Instruction::POP;
} }
m_context.appendJumpTo(m_returnTag); m_context.appendJumpTo(m_returnTag);
@ -288,7 +294,8 @@ bool Compiler::visit(VariableDefinition& _variableDefinition)
ExpressionCompiler::appendTypeConversion(m_context, ExpressionCompiler::appendTypeConversion(m_context,
*expression->getType(), *expression->getType(),
*_variableDefinition.getDeclaration().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; m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP;
} }
return false; return false;

36
libsolidity/CompilerContext.cpp

@ -30,6 +30,12 @@ using namespace std;
namespace dev { namespace dev {
namespace solidity { namespace solidity {
void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
{
m_stateVariables[&_declaration] = m_stateVariablesSize;
m_stateVariablesSize += _declaration.getType()->getStorageSize();
}
void CompilerContext::initializeLocalVariables(unsigned _numVariables) void CompilerContext::initializeLocalVariables(unsigned _numVariables)
{ {
if (_numVariables > 0) 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); return std::find(m_localVariables.begin(), m_localVariables.end(), _declaration) != m_localVariables.end();
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();
} }
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const
@ -57,5 +60,28 @@ eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition cons
return res->second.tag(); 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;
}
} }
} }

25
libsolidity/CompilerContext.h

@ -38,19 +38,28 @@ namespace solidity {
class CompilerContext class CompilerContext
{ {
public: public:
CompilerContext() {} CompilerContext(): m_stateVariablesSize(0) {}
void addStateVariable(VariableDeclaration const& _declaration);
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); } void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
void initializeLocalVariables(unsigned _numVariables); void initializeLocalVariables(unsigned _numVariables);
void addVariable(VariableDeclaration const& _declaration) { m_localVariables.push_back(&_declaration); } 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())); } 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); } 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 /// Appends a JUMPI instruction to a new tag and @returns the tag
eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); } eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); }
/// Appends a JUMPI instruction to @a _tag /// Appends a JUMPI instruction to @a _tag
@ -79,10 +88,14 @@ public:
private: private:
eth::Assembly m_asm; 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<Declaration const*, u256> m_stateVariables;
/// Offsets of local variables on the stack. /// Offsets of local variables on the stack.
std::vector<Declaration const*> m_localVariables; std::vector<Declaration const*> m_localVariables;
/// Labels pointing to the entry points of funcitons. /// Labels pointing to the entry points of funcitons.
std::map<FunctionDefinition const*, eth::AssemblyItem> m_functionEntryLabels; std::map<Declaration const*, eth::AssemblyItem> m_functionEntryLabels;
}; };
} }

159
libsolidity/ExpressionCompiler.cpp

@ -46,23 +46,16 @@ void ExpressionCompiler::appendTypeConversion(CompilerContext& _context,
bool ExpressionCompiler::visit(Assignment& _assignment) bool ExpressionCompiler::visit(Assignment& _assignment)
{ {
m_currentLValue = nullptr; _assignment.getRightHandSide().accept(*this);
appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType());
Expression& rightHandSide = _assignment.getRightHandSide(); m_currentLValue.reset();
rightHandSide.accept(*this);
Type const& resultType = *_assignment.getType();
appendTypeConversion(*rightHandSide.getType(), resultType);
_assignment.getLeftHandSide().accept(*this); _assignment.getLeftHandSide().accept(*this);
Token::Value op = _assignment.getAssignmentOperator(); Token::Value op = _assignment.getAssignmentOperator();
if (op != Token::ASSIGN) if (op != Token::ASSIGN) // compound assignment
{ appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
// compound assignment
m_context << eth::Instruction::SWAP1;
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType);
}
else else
m_context << eth::Instruction::POP; //@todo do not retrieve the value in the first place m_context << eth::Instruction::POP;
storeInLValue(_assignment); storeInLValue(_assignment);
return false; return false;
@ -99,10 +92,7 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation)
m_context << eth::Instruction::ADD; m_context << eth::Instruction::ADD;
else else
m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap
if (_unaryOperation.isPrefixOperation()) storeInLValue(_unaryOperation, !_unaryOperation.isPrefixOperation());
storeInLValue(_unaryOperation);
else
moveToLValue(_unaryOperation);
break; break;
case Token::ADD: // + case Token::ADD: // +
// unary add, so basically no-op // unary add, so basically no-op
@ -123,11 +113,8 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
Type const& commonType = _binaryOperation.getCommonType(); Type const& commonType = _binaryOperation.getCommonType();
Token::Value const op = _binaryOperation.getOperator(); Token::Value const op = _binaryOperation.getOperator();
if (op == Token::AND || op == Token::OR) if (op == Token::AND || op == Token::OR) // special case: short-circuiting
{
// special case: short-circuiting
appendAndOrOperatorCode(_binaryOperation); appendAndOrOperatorCode(_binaryOperation);
}
else else
{ {
bool cleanupNeeded = false; bool cleanupNeeded = false;
@ -135,10 +122,10 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD)
cleanupNeeded = true; cleanupNeeded = true;
leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
rightExpression.accept(*this); rightExpression.accept(*this);
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded);
leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
if (Token::isCompareOp(op)) if (Token::isCompareOp(op))
appendCompareOperatorCode(op, commonType); appendCompareOperatorCode(op, commonType);
else else
@ -164,9 +151,13 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
{ {
// Calling convention: Caller pushes return address and arguments // Calling convention: Caller pushes return address and arguments
// Callee removes them and pushes return values // Callee removes them and pushes return values
m_currentLValue = nullptr; m_currentLValue.reset();
_functionCall.getExpression().accept(*this); _functionCall.getExpression().accept(*this);
FunctionDefinition const& function = dynamic_cast<FunctionDefinition&>(*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<FunctionType const&>(*_functionCall.getExpression().getType()).getFunction();
eth::AssemblyItem returnLabel = m_context.pushNewTag(); eth::AssemblyItem returnLabel = m_context.pushNewTag();
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments(); std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
@ -175,11 +166,10 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
{ {
arguments[i]->accept(*this); arguments[i]->accept(*this);
appendTypeConversion(*arguments[i]->getType(), appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType());
*function.getParameters()[i]->getType());
} }
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); m_context.appendJumpTo(functionTag);
m_context << returnLabel; m_context << returnLabel;
// callee adds return parameters, but removes arguments and return label // callee adds return parameters, but removes arguments and return label
@ -205,24 +195,20 @@ void ExpressionCompiler::endVisit(IndexAccess&)
void ExpressionCompiler::endVisit(Identifier& _identifier) void ExpressionCompiler::endVisit(Identifier& _identifier)
{ {
m_currentLValue = _identifier.getReferencedDeclaration(); Declaration const* declaration = _identifier.getReferencedDeclaration();
switch (_identifier.getType()->getCategory()) if (m_context.isLocalVariable(declaration))
{ m_currentLValue = LValueLocation(LValueLocation::STACK,
case Type::Category::BOOL: m_context.getBaseStackOffsetOfVariable(*declaration));
case Type::Category::INTEGER: else if (m_context.isStateVariable(declaration))
case Type::Category::REAL: m_currentLValue = LValueLocation(LValueLocation::STORAGE,
{ m_context.getStorageLocationOfVariable(*declaration));
//@todo we also have to check where to retrieve them from once we add storage variables else if (m_context.isFunctionDefinition(declaration))
unsigned stackPos = stackPositionOfLValue(); m_currentLValue = LValueLocation(LValueLocation::CODE,
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory m_context.getFunctionEntryLabel(dynamic_cast<FunctionDefinition const&>(*declaration)).data());
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_identifier.getLocation()) else
<< errinfo_comment("Stack too deep.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not supported or identifier not found."));
m_context << eth::dupInstruction(stackPos + 1);
break; retrieveLValueValue(_identifier);
}
default:
break;
}
} }
void ExpressionCompiler::endVisit(Literal& _literal) void ExpressionCompiler::endVisit(Literal& _literal)
@ -267,23 +253,21 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
IntegerType const& type = dynamic_cast<IntegerType const&>(_type); IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
bool const isSigned = type.isSigned(); 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) switch (_operator)
{ {
case Token::GTE: case Token::GTE:
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT)
<< eth::Instruction::ISZERO; << eth::Instruction::ISZERO;
break; break;
case Token::LTE: case Token::LTE:
m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT)
<< eth::Instruction::ISZERO; << eth::Instruction::ISZERO;
break; break;
case Token::GT: case Token::GT:
m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
break; break;
case Token::LT: case Token::LT:
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); 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; m_context << eth::Instruction::ADD;
break; break;
case Token::SUB: case Token::SUB:
m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; m_context << eth::Instruction::SUB;
break; break;
case Token::MUL: case Token::MUL:
m_context << eth::Instruction::MUL; m_context << eth::Instruction::MUL;
break; break;
case Token::DIV: 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; break;
case Token::MOD: 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; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); 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) 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 // For a type extension, we need to remove all higher-order bits that we might have ignored in
// higher-order bits that we might have ignored in previous operations. // previous operations.
// @todo: store in the AST whether the operand might have "dirty" higher // @todo: store in the AST whether the operand might have "dirty" higher order bits
// order bits
if (_typeOnStack == _targetType && !_cleanupNeeded) if (_typeOnStack == _targetType && !_cleanupNeeded)
return; return;
@ -388,31 +371,65 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack)
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
} }
void ExpressionCompiler::storeInLValue(Expression const& _expression) void ExpressionCompiler::retrieveLValueValue(Expression const& _expression)
{ {
moveToLValue(_expression); switch (m_currentLValue.locationType)
unsigned stackPos = stackPositionOfLValue(); {
if (stackPos > 16) 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()) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
<< errinfo_comment("Stack too deep.")); << errinfo_comment("Stack too deep."));
m_context << eth::dupInstruction(stackPos + 1); 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;
}
} }
void ExpressionCompiler::moveToLValue(Expression const& _expression) void ExpressionCompiler::storeInLValue(Expression const& _expression, bool _move)
{
switch (m_currentLValue.locationType)
{
case LValueLocation::STACK:
{ {
unsigned stackPos = stackPositionOfLValue(); unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location));
if (stackPos > 16) if (stackPos > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
<< errinfo_comment("Stack too deep.")); << errinfo_comment("Stack too deep."));
else if (stackPos > 0) else if (stackPos > 0)
m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; 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;
} }
unsigned ExpressionCompiler::stackPositionOfLValue() const
{
if (asserts(m_currentLValue))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not available on request."));
return m_context.getStackPositionOfVariable(*m_currentLValue);
} }
} }

52
libsolidity/ExpressionCompiler.h

@ -20,18 +20,25 @@
* Solidity AST to EVM bytecode compiler for expressions. * Solidity AST to EVM bytecode compiler for expressions.
*/ */
#include <libdevcore/Common.h>
#include <libsolidity/ASTVisitor.h> #include <libsolidity/ASTVisitor.h>
namespace dev { namespace dev {
namespace eth
{
class AssemblyItem; // forward
}
namespace solidity { namespace solidity {
class CompilerContext; // forward class CompilerContext; // forward
class Type; // forward class Type; // forward
class IntegerType; // 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 * Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream
/// unit. * of EVM instructions. It needs a compiler context that is the same for the whole compilation
* unit.
*/
class ExpressionCompiler: private ASTVisitor class ExpressionCompiler: private ASTVisitor
{ {
public: public:
@ -42,7 +49,7 @@ public:
static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType);
private: private:
ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), m_context(_compilerContext) {} ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {}
virtual bool visit(Assignment& _assignment) override; virtual bool visit(Assignment& _assignment) override;
virtual void endVisit(UnaryOperation& _unaryOperation) override; virtual void endVisit(UnaryOperation& _unaryOperation) override;
@ -72,15 +79,36 @@ private:
//// Appends code that cleans higher-order bits for integer types. //// Appends code that cleans higher-order bits for integer types.
void appendHighBitsCleanup(IntegerType const& _typeOnStack); void appendHighBitsCleanup(IntegerType const& _typeOnStack);
/// Stores the value on top of the stack in the current lvalue and copies that value to the /// Copies the value of the current lvalue to the top of the stack.
/// top of the stack again void retrieveLValueValue(Expression const& _expression);
void storeInLValue(Expression const& _expression); /// Stores the value on top of the stack in the current lvalue. Removes it from the stack if
/// The same as storeInLValue but do not again retrieve the value to the top of the stack. /// @a _move is true.
void moveToLValue(Expression const& _expression); void storeInLValue(Expression const& _expression, bool _move = false);
/// Returns the position of @a m_currentLValue in the stack, where 0 is the top of the stack.
unsigned stackPositionOfLValue() const; /**
* 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;
};
Declaration* m_currentLValue; LValueLocation m_currentLValue;
CompilerContext& m_context; CompilerContext& m_context;
}; };

22
libsolidity/Types.cpp

@ -56,7 +56,6 @@ shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
std::string(Token::toString(_typeToken)) + " to type.")); std::string(Token::toString(_typeToken)) + " to type."));
return shared_ptr<Type>();
} }
shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)
@ -67,7 +66,6 @@ shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeN
shared_ptr<Type> Type::fromMapping(Mapping const&) shared_ptr<Type> Type::fromMapping(Mapping const&)
{ {
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented."));
return shared_ptr<Type>();
} }
shared_ptr<Type> Type::forLiteral(Literal const& _literal) shared_ptr<Type> Type::forLiteral(Literal const& _literal)
@ -103,8 +101,8 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
m_bits(_bits), m_modifier(_modifier) m_bits(_bits), m_modifier(_modifier)
{ {
if (isAddress()) if (isAddress())
_bits = 160; m_bits = 160;
if (asserts(_bits > 0 && _bits <= 256 && _bits % 8 == 0)) 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))); 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; return other.m_contract == m_contract;
} }
u256 ContractType::getStorageSize() const
{
u256 size = 0;
for (ASTPointer<VariableDeclaration> const& variable: m_contract.getStateVariables())
size += variable->getType()->getStorageSize();
return max<u256>(1, size);
}
bool StructType::operator==(Type const& _other) const bool StructType::operator==(Type const& _other) const
{ {
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())
@ -215,6 +221,14 @@ bool StructType::operator==(Type const& _other) const
return other.m_struct == m_struct; return other.m_struct == m_struct;
} }
u256 StructType::getStorageSize() const
{
u256 size = 0;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
size += variable->getType()->getStorageSize();
return max<u256>(1, size);
}
bool FunctionType::operator==(Type const& _other) const bool FunctionType::operator==(Type const& _other) const
{ {
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())

16
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 /// @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. /// is not a simple big-endian encoding or the type cannot be stored on the stack.
virtual unsigned getCalldataEncodedSize() const { return 0; } 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 std::string toString() const = 0;
virtual u256 literalValue(Literal const&) const virtual u256 literalValue(Literal const&) const
@ -157,7 +160,7 @@ public:
ContractType(ContractDefinition const& _contract): m_contract(_contract) {} ContractType(ContractDefinition const& _contract): m_contract(_contract) {}
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const;
virtual std::string toString() const override { return "contract{...}"; } virtual std::string toString() const override { return "contract{...}"; }
private: private:
@ -178,7 +181,7 @@ public:
} }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const;
virtual std::string toString() const override { return "struct{...}"; } virtual std::string toString() const override { return "struct{...}"; }
private: private:
@ -196,9 +199,9 @@ public:
FunctionDefinition const& getFunction() const { return m_function; } 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 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: private:
FunctionDefinition const& m_function; FunctionDefinition const& m_function;
@ -212,9 +215,9 @@ class MappingType: public Type
public: public:
virtual Category getCategory() const override { return Category::MAPPING; } virtual Category getCategory() const override { return Category::MAPPING; }
MappingType() {} MappingType() {}
virtual std::string toString() const override { return "mapping(...=>...)"; }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override { return "mapping(...=>...)"; }
private: private:
std::shared_ptr<Type const> m_keyType; std::shared_ptr<Type const> m_keyType;
@ -232,6 +235,7 @@ public:
VoidType() {} VoidType() {}
virtual std::string toString() const override { return "void"; } 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<Type const> const& getActualType() const { return m_actualType; } std::shared_ptr<Type const> const& getActualType() const { return m_actualType; }
virtual bool operator==(Type const& _other) const override; 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() + ")"; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
private: private:

3
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["sent"] = (int)_e.sent();
res["ttl"] = (int)_e.ttl(); res["ttl"] = (int)_e.ttl();
res["workProved"] = (int)_e.workProved(); 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["payload"] = toJS(_m.payload());
res["from"] = toJS(_m.from()); res["from"] = toJS(_m.from());
res["to"] = toJS(_m.to()); res["to"] = toJS(_m.to());

35
libwhisper/Common.cpp

@ -22,11 +22,21 @@
#include "Common.h" #include "Common.h"
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include "Message.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
using namespace dev::shh; 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) BuildTopic& BuildTopic::shiftBytes(bytes const& _b)
{ {
m_parts.push_back(dev::sha3(_b)); m_parts.push_back(dev::sha3(_b));
@ -40,19 +50,32 @@ h256 TopicFilter::sha3() const
return dev::sha3(s.out()); return dev::sha3(s.out());
} }
TopicMask BuildTopicMask::toTopicMask() const bool TopicFilter::matches(Envelope const& _e) const
{ {
TopicMask ret; for (TopicMask const& t: m_topicMasks)
if (m_parts.size())
for (auto i = 0; i < 32; ++i)
{ {
ret.first[i] = m_parts[i * m_parts.size() / 32][i]; if (_e.topics().size() == t.size())
ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0; 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;
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; return ret;
} }
/* /*
web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); }) web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); })
k = web3.shh.newIdentity() k = web3.shh.newIdentity()
web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")}) web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")})
*/ */

8
libwhisper/Common.h

@ -59,7 +59,9 @@ enum WhisperPacket
PacketCount PacketCount
}; };
using Topic = h256; using TopicPart = uint32_t;
using Topic = std::vector<TopicPart>;
class BuildTopic class BuildTopic
{ {
@ -73,7 +75,7 @@ public:
BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; } BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; }
operator Topic() const { return toTopic(); } 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: protected:
BuildTopic& shiftBytes(bytes const& _b); BuildTopic& shiftBytes(bytes const& _b);
@ -81,7 +83,7 @@ protected:
h256s m_parts; h256s m_parts;
}; };
using TopicMask = std::pair<Topic, Topic>; using TopicMask = std::vector<std::pair<TopicPart, TopicPart>>;
using TopicMasks = std::vector<TopicMask>; using TopicMasks = std::vector<TopicMask>;
class TopicFilter class TopicFilter

7
libwhisper/Interface.cpp

@ -34,10 +34,7 @@ using namespace dev::shh;
#endif #endif
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] " #define clogS(X) dev::LogOutputStream<X, true>(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) return installWatch(TopicFilter(_mask));
if (((t.first ^ _e.topic()) & t.second) == 0)
return true;
return false;
} }

2
libwhisper/Interface.h

@ -69,7 +69,7 @@ public:
virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; 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 installWatch(TopicFilter const& _filter) = 0;
virtual unsigned installWatchOnId(h256 _filterId) = 0; virtual unsigned installWatchOnId(h256 _filterId) = 0;
virtual void uninstallWatch(unsigned _watchId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0;

4
libwhisper/Message.cpp

@ -97,7 +97,7 @@ Message Envelope::open(Secret const& _s) const
unsigned Envelope::workProved() const unsigned Envelope::workProved() const
{ {
h256 d[2]; h256 d[2];
d[0] = sha3NoNonce(); d[0] = sha3(WithoutNonce);
d[1] = m_nonce; d[1] = m_nonce;
return dev::sha3(bytesConstRef(d[0].data(), 64)).firstBitSet(); return dev::sha3(bytesConstRef(d[0].data(), 64)).firstBitSet();
} }
@ -106,7 +106,7 @@ void Envelope::proveWork(unsigned _ms)
{ {
// PoW // PoW
h256 d[2]; h256 d[2];
d[0] = sha3NoNonce(); d[0] = sha3(WithoutNonce);
uint32_t& n = *(uint32_t*)&(d[1][28]); uint32_t& n = *(uint32_t*)&(d[1][28]);
unsigned bestBitSet = 0; unsigned bestBitSet = 0;
bytesConstRef chuck(d[0].data(), 64); bytesConstRef chuck(d[0].data(), 64);

13
libwhisper/Message.h

@ -39,6 +39,12 @@ namespace shh
class Message; class Message;
enum IncludeNonce
{
WithoutNonce = 0,
WithNonce = 1
};
class Envelope class Envelope
{ {
friend class Message; friend class Message;
@ -56,14 +62,13 @@ public:
operator bool() const { return !!m_expiry; } 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; } 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() const { RLPStream s; streamRLP(s, true); return dev::sha3(s.out()); } h256 sha3(IncludeNonce _withNonce = WithNonce) const { RLPStream s; streamRLP(s, _withNonce); return dev::sha3(s.out()); }
h256 sha3NoNonce() const { RLPStream s; streamRLP(s, false); return dev::sha3(s.out()); }
unsigned sent() const { return m_expiry - m_ttl; } unsigned sent() const { return m_expiry - m_ttl; }
unsigned expiry() const { return m_expiry; } unsigned expiry() const { return m_expiry; }
unsigned ttl() const { return m_ttl; } 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; } bytes const& data() const { return m_data; }
Message open(Secret const& _s = Secret()) const; Message open(Secret const& _s = Secret()) const;

7
libwhisper/WhisperHost.cpp

@ -21,6 +21,7 @@
#include "WhisperHost.h" #include "WhisperHost.h"
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libp2p/All.h> #include <libp2p/All.h>
using namespace std; using namespace std;
@ -48,14 +49,14 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const
{ {
UpgradeGuard ll(l); UpgradeGuard ll(l);
auto const& m = m_messages.at(_m); auto const& m = m_messages.at(_m);
cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data()); cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topics() << toHex(m.data());
m.streamRLP(_s, true); m.streamRLP(_s);
} }
} }
void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) 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)) if (_m.expiry() <= time(0))
return; return;

2
libwhisper/WhisperHost.h

@ -46,7 +46,7 @@ public:
WhisperHost(); WhisperHost();
virtual ~WhisperHost(); virtual ~WhisperHost();
unsigned protocolVersion() const { return 0; } unsigned protocolVersion() const { return 1; }
virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override;

4
libwhisper/WhisperPeer.cpp

@ -37,7 +37,7 @@ using namespace dev::shh;
WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i) WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i)
{ {
RLPStream s; RLPStream s;
sealAndSend(prep(s, StatusPacket, 1) << host()->protocolVersion()); sealAndSend(prep(s, StatusPacket, 1) << version());
} }
WhisperPeer::~WhisperPeer() WhisperPeer::~WhisperPeer()
@ -59,7 +59,7 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r)
clogS(NetMessageSummary) << "Status: " << protocolVersion; clogS(NetMessageSummary) << "Status: " << protocolVersion;
if (protocolVersion != host()->protocolVersion()) if (protocolVersion != version())
disable("Invalid protocol version."); disable("Invalid protocol version.");
if (session()->id() < host()->host()->id()) if (session()->id() < host()->host()->id())

2
libwhisper/WhisperPeer.h

@ -53,7 +53,7 @@ public:
virtual ~WhisperPeer(); virtual ~WhisperPeer();
static std::string name() { return "shh"; } static std::string name() { return "shh"; }
static u256 version() { return 1; } static u256 version() { return 2; }
static unsigned messageCount() { return PacketCount; } static unsigned messageCount() { return PacketCount; }
WhisperHost* host() const; WhisperHost* host() const;

1
test/TestHelper.h

@ -57,7 +57,6 @@ public:
eth::State m_statePost; eth::State m_statePost;
eth::ExtVMFace m_environment; eth::ExtVMFace m_environment;
eth::Transaction m_transaction; eth::Transaction m_transaction;
bytes code;
private: private:
json_spirit::mObject& m_TestObject; json_spirit::mObject& m_TestObject;

4
test/createRandomTest.cpp

@ -134,10 +134,10 @@ void doMyTests(json_spirit::mValue& v)
o["pre"] = mValue(fev.exportState()); o["pre"] = mValue(fev.exportState());
fev.importExec(o["exec"].get_obj()); fev.importExec(o["exec"].get_obj());
if (!fev.code) if (fev.code.empty())
{ {
fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress));
fev.code = &fev.thisTxCode; fev.code = fev.thisTxCode;
} }
vm.reset(fev.gas); vm.reset(fev.gas);

2
test/solidityCompiler.cpp

@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::JUMPDEST), // beginning of g
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), // initialized e and h 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), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x2, 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), byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),

198
test/solidityEndToEndTest.cpp

@ -60,6 +60,16 @@ public:
return callFunction(_index, toBigEndian(_argument1)); return callFunction(_index, toBigEndian(_argument1));
} }
bool testSolidityAgainstCpp(byte _index, std::function<u256(u256)> const& _cppfun, u256 const& _argument1)
{
return toBigEndian(_cppfun(_argument1)) == callFunction(_index, toBigEndian(_argument1));
}
bool testSolidityAgainstCpp(byte _index, std::function<u256()> const& _cppfun)
{
return toBigEndian(_cppfun()) == callFunction(_index, bytes());
}
private: private:
void sendMessage(bytes const& _data, bool _isCreation) void sendMessage(bytes const& _data, bool _isCreation)
{ {
@ -123,11 +133,19 @@ BOOST_AUTO_TEST_CASE(recursive_calls)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1))); std::function<u256(u256)> recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256
BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1))); {
BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2))); if (n <= 1)
BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6))); return 1;
BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24))); 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) BOOST_AUTO_TEST_CASE(while_loop)
@ -140,11 +158,22 @@ BOOST_AUTO_TEST_CASE(while_loop)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1)));
BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1))); auto while_loop_cpp = [](u256 const& n) -> u256
BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2))); {
BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6))); u256 nfac = 1;
BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24))); 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) BOOST_AUTO_TEST_CASE(break_outside_loop)
@ -182,18 +211,43 @@ BOOST_AUTO_TEST_CASE(nested_loops)
"}\n"; "}\n";
ExecutionFramework framework; ExecutionFramework framework;
framework.compileAndRun(sourceCode); framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0)));
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); auto nested_loops_cpp = [](u256 n) -> u256
BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(1))); {
BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(2))); while (n > 1)
BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(2))); {
BOOST_CHECK(framework.callFunction(0, u256(5)) == toBigEndian(u256(4))); if (n == 10)
BOOST_CHECK(framework.callFunction(0, u256(6)) == toBigEndian(u256(5))); break;
BOOST_CHECK(framework.callFunction(0, u256(7)) == toBigEndian(u256(5))); while (n > 5)
BOOST_CHECK(framework.callFunction(0, u256(8)) == toBigEndian(u256(7))); {
BOOST_CHECK(framework.callFunction(0, u256(9)) == toBigEndian(u256(8))); if (n == 8)
BOOST_CHECK(framework.callFunction(0, u256(10)) == toBigEndian(u256(10))); break;
BOOST_CHECK(framework.callFunction(0, u256(11)) == toBigEndian(u256(10))); 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) BOOST_AUTO_TEST_CASE(calling_other_functions)
@ -214,11 +268,34 @@ BOOST_AUTO_TEST_CASE(calling_other_functions)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callFunction(2, u256(0)) == toBigEndian(u256(0)));
BOOST_CHECK(callFunction(2, u256(1)) == toBigEndian(u256(1))); auto evenStep_cpp = [](u256 const& n) -> u256
BOOST_CHECK(callFunction(2, u256(2)) == toBigEndian(u256(1))); {
BOOST_CHECK(callFunction(2, u256(8)) == toBigEndian(u256(1))); return n / 2;
BOOST_CHECK(callFunction(2, u256(127)) == toBigEndian(u256(1))); };
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) BOOST_AUTO_TEST_CASE(many_local_variables)
@ -270,8 +347,15 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); 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) BOOST_AUTO_TEST_CASE(high_bits_cleaning)
@ -284,7 +368,14 @@ BOOST_AUTO_TEST_CASE(high_bits_cleaning)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); 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) BOOST_AUTO_TEST_CASE(sign_extension)
@ -297,7 +388,14 @@ BOOST_AUTO_TEST_CASE(sign_extension)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); 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) BOOST_AUTO_TEST_CASE(small_unsigned_types)
@ -309,7 +407,12 @@ BOOST_AUTO_TEST_CASE(small_unsigned_types)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); 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) BOOST_AUTO_TEST_CASE(small_signed_types)
@ -320,7 +423,36 @@ BOOST_AUTO_TEST_CASE(small_signed_types)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); 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() BOOST_AUTO_TEST_SUITE_END()

73
test/solidityExpressionCompiler.cpp

@ -154,10 +154,10 @@ BOOST_AUTO_TEST_CASE(comparison)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); 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::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::GT), byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::LT),
byte(eth::Instruction::EQ), byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO)}); byte(eth::Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); 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) BOOST_AUTO_TEST_CASE(short_circuiting)
{ {
char const* sourceCode = "contract test {\n" 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"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
BOOST_AUTO_TEST_CASE(arithmetics) BOOST_AUTO_TEST_CASE(arithmetics)
{ {
char const* sourceCode = "contract test {\n" 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"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1, bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
@ -211,14 +211,11 @@ BOOST_AUTO_TEST_CASE(arithmetics)
byte(eth::Instruction::XOR), byte(eth::Instruction::XOR),
byte(eth::Instruction::AND), byte(eth::Instruction::AND),
byte(eth::Instruction::OR), byte(eth::Instruction::OR),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::SUB), byte(eth::Instruction::SUB),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::MOD), byte(eth::Instruction::MOD),
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::DIV), byte(eth::Instruction::DIV),
byte(eth::Instruction::MUL)}); byte(eth::Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
@ -231,11 +228,11 @@ BOOST_AUTO_TEST_CASE(unary_operators)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); 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::PUSH1), 0x0,
byte(eth::Instruction::SUB), byte(eth::Instruction::SUB),
byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), 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::EQ),
byte(eth::Instruction::ISZERO)}); byte(eth::Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); 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) BOOST_AUTO_TEST_CASE(unary_inc_dec)
{ {
char const* sourceCode = "contract test {\n" 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"; "}\n";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}}); 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"}}); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b // Stack: a, b
bytes expectation({byte(eth::Instruction::DUP1), bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::DUP3), byte(eth::Instruction::DUP2),
byte(eth::Instruction::SWAP1), byte(eth::Instruction::DUP4),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
// Stack here: a b a+b // Stack here: a b 2 a+b
byte(eth::Instruction::SWAP2), byte(eth::Instruction::SWAP3),
byte(eth::Instruction::POP), byte(eth::Instruction::POP),
byte(eth::Instruction::DUP2), byte(eth::Instruction::DUP3),
// Stack here: a+b b a+b // Stack here: a+b b 2 a+b
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::MUL)}); byte(eth::Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); 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"}}); {{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b // Stack: a, b
bytes expectation({byte(eth::Instruction::PUSH1), 0x0d, bytes expectation({byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::DUP3), byte(eth::Instruction::PUSH1), 0x12,
byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::DUP5),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
// Stack here: a b <ret label> (a+1) // Stack here: a b 2 <ret label> (a+1)
byte(eth::Instruction::DUP3), byte(eth::Instruction::DUP4),
byte(eth::Instruction::PUSH1), 0x1a, byte(eth::Instruction::PUSH1), 0x19,
byte(eth::Instruction::JUMP), byte(eth::Instruction::JUMP),
byte(eth::Instruction::JUMPDEST), byte(eth::Instruction::JUMPDEST),
// Stack here: a b g(a+1, b) // Stack here: a b 2 g(a+1, b)
byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::MUL), byte(eth::Instruction::MUL),
// Stack here: a b g(a+1, b)*2 // Stack here: a b g(a+1, b)*2
byte(eth::Instruction::DUP3), byte(eth::Instruction::DUP3),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
// Stack here: a b a+g(a+1, b)*2 // Stack here: a b a+g(a+1, b)*2
byte(eth::Instruction::SWAP2), byte(eth::Instruction::SWAP2),
@ -355,15 +350,15 @@ BOOST_AUTO_TEST_CASE(negative_literals_8bits)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH1), 0x00, bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) +
byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) +
bytes({byte(eth::Instruction::ADD), bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::ADD), bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) + byte(eth::Instruction::ADD),
bytes({byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) + byte(eth::Instruction::ADD),
bytes({byte(eth::Instruction::ADD)})); byte(eth::Instruction::ADD)}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -376,11 +371,11 @@ BOOST_AUTO_TEST_CASE(negative_literals_16bits)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); 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, bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::SIGNEXTEND), byte(eth::Instruction::SIGNEXTEND),
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) + byte(eth::Instruction::ADD),
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0x01,
byte(eth::Instruction::SIGNEXTEND)})); byte(eth::Instruction::SIGNEXTEND)}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());

14
test/state.cpp

@ -55,12 +55,6 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
ImportTest importer(o, _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; State theState = importer.m_statePre;
bytes tx = importer.m_transaction.rlp(); bytes tx = importer.m_transaction.rlp();
bytes output; bytes output;
@ -124,12 +118,4 @@ BOOST_AUTO_TEST_CASE(stSystemOperationsTest)
dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests); 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() BOOST_AUTO_TEST_SUITE_END()

44
test/tmpFiller.json

@ -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" : ""
}
}
}

10
test/vm.cpp

@ -29,7 +29,7 @@ using namespace dev::eth;
using namespace dev::test; using namespace dev::test;
FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. 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&) h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&)
{ {
@ -195,11 +195,11 @@ void FakeExtVM::importExec(mObject& _o)
gas = toInt(_o["gas"]); gas = toInt(_o["gas"]);
thisTxCode.clear(); thisTxCode.clear();
code = &thisTxCode; code = thisTxCode;
thisTxCode = importCode(_o); thisTxCode = importCode(_o);
if (_o["code"].type() != str_type && _o["code"].type() != array_type) if (_o["code"].type() != str_type && _o["code"].type() != array_type)
code.reset(); code.clear();
thisTxData.clear(); thisTxData.clear();
thisTxData = importData(_o); thisTxData = importData(_o);
@ -289,10 +289,10 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
o["pre"] = mValue(fev.exportState()); o["pre"] = mValue(fev.exportState());
fev.importExec(o["exec"].get_obj()); fev.importExec(o["exec"].get_obj());
if (!fev.code) if (fev.code.empty())
{ {
fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress));
fev.code = &fev.thisTxCode; fev.code = fev.thisTxCode;
} }
bytes output; bytes output;

Loading…
Cancel
Save