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. 44
      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. 177
      libsolidity/ExpressionCompiler.cpp
  17. 54
      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());
m_server->setAccounts(keysAsVector(m_myKeys));
}
{
@ -1374,7 +1375,7 @@ void Main::populateDebugger(dev::bytesConstRef _r)
debugFinished();
vector<WorldState const*> 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);
}
}

1
libdevcore/Log.h

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

6
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<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 bigint() const { return toInt<bigint>(); }
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:
/// 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);
}

2
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),

4
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).

4
libevmcore/Instruction.cpp

@ -172,13 +172,13 @@ static const std::map<Instruction, InstructionInfo> 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 } },

44
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 <http://www.gnu.org/licenses/>.
*/
/** @file ethereum.js
/** @file main.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @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];
}
}

8
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 <http://www.gnu.org/licenses/>.
*/
/** @file ethereum.js
/** @file qt.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2014

1
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());
}

8
libsolidity/AST.h

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

7
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)

19
libsolidity/Compiler.cpp

@ -21,6 +21,8 @@
*/
#include <algorithm>
#include <libevmcore/Instruction.h>
#include <libevmcore/Assembly.h>
#include <libsolidity/AST.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/ExpressionCompiler.h>
@ -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<FunctionDefinition> const& function: _contract.getDefinedFunctions())
m_context.addFunction(*function);
//@todo sort them?
for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
m_context.addStateVariable(*variable);
appendFunctionSelector(_contract.getDefinedFunctions());
for (ASTPointer<FunctionDefinition> 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<ASTPointer<VariableDeclaration>> 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;

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

25
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<Declaration const*, u256> m_stateVariables;
/// Offsets of local variables on the stack.
std::vector<Declaration const*> m_localVariables;
/// Labels pointing to the entry points of funcitons.
std::map<FunctionDefinition const*, eth::AssemblyItem> m_functionEntryLabels;
std::map<Declaration const*, eth::AssemblyItem> m_functionEntryLabels;
};
}

177
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<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();
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)
{
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<FunctionDefinition const&>(*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<IntegerType const&>(_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;
}
}
}

54
libsolidity/ExpressionCompiler.h

@ -20,18 +20,25 @@
* Solidity AST to EVM bytecode compiler for expressions.
*/
#include <libdevcore/Common.h>
#include <libsolidity/ASTVisitor.h>
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;
};

22
libsolidity/Types.cpp

@ -56,7 +56,6 @@ shared_ptr<Type> 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<Type>();
}
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&)
{
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented."));
return shared_ptr<Type>();
}
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)
{
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<VariableDeclaration> const& variable: m_contract.getStateVariables())
size += variable->getType()->getStorageSize();
return max<u256>(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<VariableDeclaration> const& variable: m_struct.getMembers())
size += variable->getType()->getStorageSize();
return max<u256>(1, size);
}
bool FunctionType::operator==(Type const& _other) const
{
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
/// 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<Type const> 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<Type const> 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:

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["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());

35
libwhisper/Common.cpp

@ -22,11 +22,21 @@
#include "Common.h"
#include <libdevcrypto/SHA3.h>
#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!")})
*/

8
libwhisper/Common.h

@ -59,7 +59,9 @@ enum WhisperPacket
PacketCount
};
using Topic = h256;
using TopicPart = uint32_t;
using Topic = std::vector<TopicPart>;
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<Topic, Topic>;
using TopicMask = std::vector<std::pair<TopicPart, TopicPart>>;
using TopicMasks = std::vector<TopicMask>;
class TopicFilter

7
libwhisper/Interface.cpp

@ -34,10 +34,7 @@ using namespace dev::shh;
#endif
#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)
if (((t.first ^ _e.topic()) & t.second) == 0)
return true;
return false;
return installWatch(TopicFilter(_mask));
}

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

4
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);

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

7
libwhisper/WhisperHost.cpp

@ -21,6 +21,7 @@
#include "WhisperHost.h"
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
#include <libp2p/All.h>
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;

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

4
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())

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

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

4
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);

2
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),

198
test/solidityEndToEndTest.cpp

@ -60,6 +60,16 @@ public:
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:
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<u256(u256)> 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()

73
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 <ret label> (a+1)
byte(eth::Instruction::DUP3),
byte(eth::Instruction::PUSH1), 0x1a,
// Stack here: a b 2 <ret label> (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());

14
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()

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

Loading…
Cancel
Save