Browse Source

Merge branch 'develop' into ethereumjs

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
3b416d18f4
  1. 4
      CMakeLists.txt
  2. 6
      alethzero/Main.ui
  3. 35
      alethzero/MainWin.cpp
  4. 1
      alethzero/MainWin.h
  5. 20
      eth/main.cpp
  6. 2
      libethereum/Client.cpp
  7. 8
      libevmcore/Instruction.h
  8. 40
      libsolidity/AST.cpp
  9. 98
      libsolidity/ExpressionCompiler.cpp
  10. 2
      libsolidity/ExpressionCompiler.h
  11. 7
      libsolidity/Scanner.cpp
  12. 270
      libsolidity/Types.cpp
  13. 126
      libsolidity/Types.h
  14. 4
      mix/AssemblyDebuggerControl.cpp
  15. 4
      mix/CodeHighlighter.cpp
  16. 2
      mix/CodeModel.cpp
  17. 273
      neth/main.cpp
  18. 8
      test/SolidityCompiler.cpp
  19. 45
      test/SolidityEndToEndTest.cpp
  20. 88
      test/SolidityExpressionCompiler.cpp
  21. 8
      test/SolidityOptimizer.cpp
  22. 12
      test/SolidityScanner.cpp
  23. 8
      test/TestHelper.cpp
  24. 1
      test/TestHelper.h
  25. 85
      test/stSystemOperationsTestFiller.json
  26. 10
      test/state.cpp
  27. 3
      test/vm.cpp
  28. 56
      test/vmArithmeticTestFiller.json
  29. 56
      test/vmBlockInfoTestFiller.json
  30. 1244
      test/vmIOandFlowOperationsTestFiller.json

4
CMakeLists.txt

@ -64,10 +64,10 @@ function(createBuildInfo)
endif () endif ()
#cmake build type may be not specified when using msvc #cmake build type may be not specified when using msvc
if (${CMAKE_BUILD_TYPE}) if (CMAKE_BUILD_TYPE)
set(_cmake_build_type ${CMAKE_BUILD_TYPE}) set(_cmake_build_type ${CMAKE_BUILD_TYPE})
else() else()
set(_cmake_build_type "undefined") set(_cmake_build_type "${CMAKE_CFG_INTDIR}")
endif() endif()
# Generate header file containing useful build information # Generate header file containing useful build information

6
alethzero/Main.ui

@ -165,6 +165,7 @@
<addaction name="debugDumpStatePre"/> <addaction name="debugDumpStatePre"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="paranoia"/> <addaction name="paranoia"/>
<addaction name="clearPending"/>
<addaction name="killBlockchain"/> <addaction name="killBlockchain"/>
<addaction name="inject"/> <addaction name="inject"/>
<addaction name="forceMining"/> <addaction name="forceMining"/>
@ -2049,6 +2050,11 @@ font-size: 14pt</string>
<string>New Identity</string> <string>New Identity</string>
</property> </property>
</action> </action>
<action name="clearPending">
<property name="text">
<string>Clear Pe&amp;nd&amp;ing</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

35
alethzero/MainWin.cpp

@ -1236,6 +1236,7 @@ void Main::on_transactionQueue_currentItemChanged()
if (i >= 0 && i < (int)ethereum()->pending().size()) if (i >= 0 && i < (int)ethereum()->pending().size())
{ {
Transaction tx(ethereum()->pending()[i]); Transaction tx(ethereum()->pending()[i]);
TransactionReceipt receipt(ethereum()->postState().receipt(i));
auto ss = tx.safeSender(); auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce())); h256 th = sha3(rlpList(ss, tx.nonce()));
s << "<h3>" << th << "</h3>"; s << "<h3>" << th << "</h3>";
@ -1258,12 +1259,15 @@ void Main::on_transactionQueue_currentItemChanged()
if (tx.data().size()) if (tx.data().size())
s << dev::memDump(tx.data(), 16, true); s << dev::memDump(tx.data(), 16, true);
} }
s << "<div>Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(tx.rlp()) << "</span></div>";
s << "<hr/>"; s << "<hr/>";
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(receipt.rlp()) << "</span></div>";
s << renderDiff(ethereum()->diff(i, -1));
// s << "Pre: " << fs.rootHash() << "<br/>"; // s << "Pre: " << fs.rootHash() << "<br/>";
// s << "Post: <b>" << ts.rootHash() << "</b>"; // s << "Post: <b>" << ts.rootHash() << "</b>";
s << renderDiff(ethereum()->diff(i, 0));
} }
ui->pendingInfo->setHtml(QString::fromStdString(s.str())); ui->pendingInfo->setHtml(QString::fromStdString(s.str()));
@ -1376,11 +1380,6 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>R: <b>" << hex << nouppercase << tx.signature().r << "</b>"; s << "<br/>R: <b>" << hex << nouppercase << tx.signature().r << "</b>";
s << "<br/>S: <b>" << hex << nouppercase << tx.signature().s << "</b>"; s << "<br/>S: <b>" << hex << nouppercase << tx.signature().s << "</b>";
s << "<br/>Msg: <b>" << tx.sha3(eth::WithoutSignature) << "</b>"; s << "<br/>Msg: <b>" << tx.sha3(eth::WithoutSignature) << "</b>";
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
s << "<div>Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(block[1][txi].data()) << "</span></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(receipt.rlp()) << "</span></div>";
if (tx.isCreation()) if (tx.isCreation())
{ {
if (tx.data().size()) if (tx.data().size())
@ -1391,6 +1390,12 @@ void Main::on_blocks_currentItemChanged()
if (tx.data().size()) if (tx.data().size())
s << dev::memDump(tx.data(), 16, true); s << dev::memDump(tx.data(), 16, true);
} }
s << "<div>Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(block[1][txi].data()) << "</span></div>";
s << "<hr/>";
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(receipt.rlp()) << "</span></div>";
s << renderDiff(ethereum()->diff(txi, h)); s << renderDiff(ethereum()->diff(txi, h));
ui->debugCurrent->setEnabled(true); ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true); ui->debugDumpState->setEnabled(true);
@ -1631,7 +1636,7 @@ void Main::on_data_textChanged()
{ {
m_data = fromHex(src); m_data = fromHex(src);
} }
else if (src.substr(0, 8) == "contract" || src.substr(0, 2) == "/*") // improve this heuristic else if (src.substr(0, 8) == "contract" || src.substr(0, 5) == "//sol") // improve this heuristic
{ {
dev::solidity::CompilerStack compiler; dev::solidity::CompilerStack compiler;
try try
@ -1714,6 +1719,18 @@ void Main::on_data_textChanged()
updateFee(); updateFee();
} }
void Main::on_clearPending_triggered()
{
writeSettings();
ui->mine->setChecked(false);
ui->net->setChecked(false);
web3()->stopNetwork();
ethereum()->clearPending();
readSettings(true);
installWatches();
refreshAll();
}
void Main::on_killBlockchain_triggered() void Main::on_killBlockchain_triggered()
{ {
writeSettings(); writeSettings();

1
alethzero/MainWin.h

@ -128,6 +128,7 @@ private slots:
void on_debugTimeline_valueChanged(); void on_debugTimeline_valueChanged();
void on_jsInput_returnPressed(); void on_jsInput_returnPressed();
void on_killBlockchain_triggered(); void on_killBlockchain_triggered();
void on_clearPending_triggered();
void on_importKey_triggered(); void on_importKey_triggered();
void on_exportKey_triggered(); void on_exportKey_triggered();
void on_inject_triggered(); void on_inject_triggered();

20
eth/main.cpp

@ -30,6 +30,7 @@
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libevmcore/Instruction.h> #include <libevmcore/Instruction.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#if ETH_READLINE #if ETH_READLINE
@ -121,7 +122,11 @@ void help()
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl << " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl << " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl; << " -V,--version Show the version and exit." << endl
#if ETH_EVMJIT
<< " --jit Use EVM JIT (default: off)." << endl
#endif
;
exit(0); exit(0);
} }
@ -193,6 +198,7 @@ int main(int argc, char** argv)
bool upnp = true; bool upnp = true;
bool useLocal = false; bool useLocal = false;
bool forceMining = false; bool forceMining = false;
bool jit = false;
string clientName; string clientName;
// Init defaults // Init defaults
@ -295,6 +301,15 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if (arg == "--jit")
{
#if ETH_EVMJIT
jit = true;
#else
cerr << "EVM JIT not enabled" << endl;
return -1;
#endif
}
else if (arg == "-h" || arg == "--help") else if (arg == "-h" || arg == "--help")
help(); help();
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")
@ -308,9 +323,10 @@ int main(int argc, char** argv)
cout << credits(); cout << credits();
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
dev::WebThreeDirect web3( dev::WebThreeDirect web3(
"Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""),
dbPath, dbPath,
false, false,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(), mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),

2
libethereum/Client.cpp

@ -534,7 +534,7 @@ eth::State Client::state(unsigned _txi) const
StateDiff Client::diff(unsigned _txi, int _block) const StateDiff Client::diff(unsigned _txi, int _block) const
{ {
State st = state(_block); State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
} }

8
libevmcore/Instruction.h

@ -215,6 +215,14 @@ inline Instruction swapInstruction(unsigned _number)
return Instruction(unsigned(Instruction::SWAP1) + _number - 1); return Instruction(unsigned(Instruction::SWAP1) + _number - 1);
} }
/// @returns the LOG<_number> instruction
inline Instruction logInstruction(unsigned _number)
{
if (asserts(_number <= 4))
BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid LOG instruction requested."));
return Instruction(unsigned(Instruction::LOG0) + _number);
}
/// Information structure for a particular instruction. /// Information structure for a particular instruction.
struct InstructionInfo struct InstructionInfo
{ {

40
libsolidity/AST.cpp

@ -174,7 +174,15 @@ void VariableDefinition::checkTypeRequirements()
{ {
// no type declared and no previous assignment, infer the type // no type declared and no previous assignment, infer the type
m_value->checkTypeRequirements(); m_value->checkTypeRequirements();
m_variable->setType(m_value->getType()); TypePointer type = m_value->getType();
if (type->getCategory() == Type::Category::INTEGER_CONSTANT)
{
auto intType = dynamic_pointer_cast<IntegerConstantType const>(type)->getIntegerType();
if (!intType)
BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString()));
type = intType;
}
m_variable->setType(type);
} }
} }
} }
@ -193,16 +201,22 @@ void Assignment::checkTypeRequirements()
{ {
// compound assignment // compound assignment
m_rightHandSide->checkTypeRequirements(); m_rightHandSide->checkTypeRequirements();
TypePointer resultType = Type::binaryOperatorResult(Token::AssignmentToBinaryOp(m_assigmentOperator), TypePointer resultType = m_type->binaryOperatorResult(Token::AssignmentToBinaryOp(m_assigmentOperator),
m_type, m_rightHandSide->getType()); m_rightHandSide->getType());
if (!resultType || *resultType != *m_type) if (!resultType || *resultType != *m_type)
BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_assigmentOperator)) +
" not compatible with types " +
m_type->toString() + " and " +
m_rightHandSide->getType()->toString()));
} }
} }
void ExpressionStatement::checkTypeRequirements() void ExpressionStatement::checkTypeRequirements()
{ {
m_expression->checkTypeRequirements(); m_expression->checkTypeRequirements();
if (m_expression->getType()->getCategory() == Type::Category::INTEGER_CONSTANT)
if (!dynamic_pointer_cast<IntegerConstantType const>(m_expression->getType())->getIntegerType())
BOOST_THROW_EXCEPTION(m_expression->createTypeError("Invalid integer constant."));
} }
void Expression::expectType(Type const& _expectedType) void Expression::expectType(Type const& _expectedType)
@ -228,8 +242,8 @@ void UnaryOperation::checkTypeRequirements()
m_subExpression->checkTypeRequirements(); m_subExpression->checkTypeRequirements();
if (m_operator == Token::Value::INC || m_operator == Token::Value::DEC || m_operator == Token::Value::DELETE) if (m_operator == Token::Value::INC || m_operator == Token::Value::DEC || m_operator == Token::Value::DELETE)
m_subExpression->requireLValue(); m_subExpression->requireLValue();
m_type = m_subExpression->getType(); m_type = m_subExpression->getType()->unaryOperatorResult(m_operator);
if (!m_type->acceptsUnaryOperator(m_operator)) if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type."));
} }
@ -237,7 +251,7 @@ void BinaryOperation::checkTypeRequirements()
{ {
m_left->checkTypeRequirements(); m_left->checkTypeRequirements();
m_right->checkTypeRequirements(); m_right->checkTypeRequirements();
m_commonType = Type::binaryOperatorResult(m_operator, m_left->getType(), m_right->getType()); m_commonType = m_left->getType()->binaryOperatorResult(m_operator, m_right->getType());
if (!m_commonType) if (!m_commonType)
BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) + BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) +
" not compatible with types " + " not compatible with types " +
@ -301,7 +315,7 @@ void NewExpression::checkTypeRequirements()
m_contract = dynamic_cast<ContractDefinition const*>(m_contractName->getReferencedDeclaration()); m_contract = dynamic_cast<ContractDefinition const*>(m_contractName->getReferencedDeclaration());
if (!m_contract) if (!m_contract)
BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract.")); BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract."));
shared_ptr<ContractType const> type = make_shared<ContractType const>(*m_contract); shared_ptr<ContractType const> type = make_shared<ContractType>(*m_contract);
m_type = type; m_type = type;
TypePointers const& parameterTypes = type->getConstructorType()->getParameterTypes(); TypePointers const& parameterTypes = type->getConstructorType()->getParameterTypes();
if (parameterTypes.size() != m_arguments.size()) if (parameterTypes.size() != m_arguments.size())
@ -352,7 +366,7 @@ void Identifier::checkTypeRequirements()
if (structDef) if (structDef)
{ {
// note that we do not have a struct type here // note that we do not have a struct type here
m_type = make_shared<TypeType const>(make_shared<StructType const>(*structDef)); m_type = make_shared<TypeType>(make_shared<StructType>(*structDef));
return; return;
} }
FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(m_referencedDeclaration); FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(m_referencedDeclaration);
@ -361,13 +375,13 @@ void Identifier::checkTypeRequirements()
// a function reference is not a TypeType, because calling a TypeType converts to the type. // a function reference is not a TypeType, because calling a TypeType converts to the type.
// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
// conversion. // conversion.
m_type = make_shared<FunctionType const>(*functionDef); m_type = make_shared<FunctionType>(*functionDef);
return; return;
} }
ContractDefinition const* contractDef = dynamic_cast<ContractDefinition const*>(m_referencedDeclaration); ContractDefinition const* contractDef = dynamic_cast<ContractDefinition const*>(m_referencedDeclaration);
if (contractDef) if (contractDef)
{ {
m_type = make_shared<TypeType const>(make_shared<ContractType>(*contractDef)); m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef));
return; return;
} }
MagicVariableDeclaration const* magicVariable = dynamic_cast<MagicVariableDeclaration const*>(m_referencedDeclaration); MagicVariableDeclaration const* magicVariable = dynamic_cast<MagicVariableDeclaration const*>(m_referencedDeclaration);
@ -381,14 +395,14 @@ void Identifier::checkTypeRequirements()
void ElementaryTypeNameExpression::checkTypeRequirements() void ElementaryTypeNameExpression::checkTypeRequirements()
{ {
m_type = make_shared<TypeType const>(Type::fromElementaryTypeName(m_typeToken)); m_type = make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));
} }
void Literal::checkTypeRequirements() void Literal::checkTypeRequirements()
{ {
m_type = Type::forLiteral(*this); m_type = Type::forLiteral(*this);
if (!m_type) if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Literal value too large.")); BOOST_THROW_EXCEPTION(createTypeError("Invalid literal value."));
} }
} }

98
libsolidity/ExpressionCompiler.cpp

@ -71,12 +71,20 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
return false; return false;
} }
void ExpressionCompiler::endVisit(UnaryOperation const& _unaryOperation) bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
{ {
//@todo type checking and creating code for an operator should be in the same place: //@todo type checking and creating code for an operator should be in the same place:
// the operator should know how to convert itself and to which types it applies, so // the operator should know how to convert itself and to which types it applies, so
// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that // put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
// represents the operator // represents the operator
if (_unaryOperation.getType()->getCategory() == Type::Category::INTEGER_CONSTANT)
{
m_context << _unaryOperation.getType()->literalValue(nullptr);
return false;
}
_unaryOperation.getSubExpression().accept(*this);
switch (_unaryOperation.getOperator()) switch (_unaryOperation.getOperator())
{ {
case Token::NOT: // ! case Token::NOT: // !
@ -128,6 +136,7 @@ void ExpressionCompiler::endVisit(UnaryOperation const& _unaryOperation)
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " +
string(Token::toString(_unaryOperation.getOperator())))); string(Token::toString(_unaryOperation.getOperator()))));
} }
return false;
} }
bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
@ -139,17 +148,19 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
if (op == Token::AND || op == Token::OR) // special case: short-circuiting if (op == Token::AND || op == Token::OR) // special case: short-circuiting
appendAndOrOperatorCode(_binaryOperation); appendAndOrOperatorCode(_binaryOperation);
else if (commonType.getCategory() == Type::Category::INTEGER_CONSTANT)
m_context << commonType.literalValue(nullptr);
else else
{ {
bool cleanupNeeded = false; bool cleanupNeeded = commonType.getCategory() == Type::Category::INTEGER &&
if (commonType.getCategory() == Type::Category::INTEGER) (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD);
if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD)
cleanupNeeded = true;
// for commutative operators, push the literal as late as possible to allow improved optimization // for commutative operators, push the literal as late as possible to allow improved optimization
//@todo this has to be extended for literal expressions auto isLiteral = [](Expression const& _e)
bool swap = (m_optimize && Token::isCommutativeOp(op) && dynamic_cast<Literal const*>(&rightExpression) {
&& !dynamic_cast<Literal const*>(&leftExpression)); return dynamic_cast<Literal const*>(&_e) || _e.getType()->getCategory() == Type::Category::INTEGER_CONSTANT;
};
bool swap = m_optimize && Token::isCommutativeOp(op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
if (swap) if (swap)
{ {
leftExpression.accept(*this); leftExpression.accept(*this);
@ -257,60 +268,22 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << u256(32) << u256(0) << eth::Instruction::SHA3; m_context << u256(32) << u256(0) << eth::Instruction::SHA3;
break; break;
case Location::LOG0: case Location::LOG0:
arguments.front()->accept(*this);
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true);
// @todo move this once we actually use memory
CompilerUtils(m_context).storeInMemory(0);
m_context << u256(32) << u256(0) << eth::Instruction::LOG0;
break;
case Location::LOG1: case Location::LOG1:
arguments[1]->accept(*this);
arguments[0]->accept(*this);
appendTypeConversion(*arguments[1]->getType(), *function.getParameterTypes()[1], true);
appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true);
// @todo move this once we actually use memory
CompilerUtils(m_context).storeInMemory(0);
m_context << u256(32) << u256(0) << eth::Instruction::LOG1;
break;
case Location::LOG2: case Location::LOG2:
arguments[2]->accept(*this);
arguments[1]->accept(*this);
arguments[0]->accept(*this);
appendTypeConversion(*arguments[2]->getType(), *function.getParameterTypes()[2], true);
appendTypeConversion(*arguments[1]->getType(), *function.getParameterTypes()[1], true);
appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true);
// @todo move this once we actually use memory
CompilerUtils(m_context).storeInMemory(0);
m_context << u256(32) << u256(0) << eth::Instruction::LOG2;
break;
case Location::LOG3: case Location::LOG3:
arguments[3]->accept(*this);
arguments[2]->accept(*this);
arguments[1]->accept(*this);
arguments[0]->accept(*this);
appendTypeConversion(*arguments[3]->getType(), *function.getParameterTypes()[3], true);
appendTypeConversion(*arguments[2]->getType(), *function.getParameterTypes()[2], true);
appendTypeConversion(*arguments[1]->getType(), *function.getParameterTypes()[1], true);
appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true);
// @todo move this once we actually use memory
CompilerUtils(m_context).storeInMemory(0);
m_context << u256(32) << u256(0) << eth::Instruction::LOG3;
break;
case Location::LOG4: case Location::LOG4:
arguments[4]->accept(*this); {
arguments[3]->accept(*this); unsigned logNumber = int(function.getLocation()) - int(Location::LOG0);
arguments[2]->accept(*this); for (int arg = logNumber; arg >= 0; --arg)
arguments[1]->accept(*this); {
arguments[0]->accept(*this); arguments[arg]->accept(*this);
appendTypeConversion(*arguments[4]->getType(), *function.getParameterTypes()[4], true); appendTypeConversion(*arguments[arg]->getType(), *function.getParameterTypes()[arg], true);
appendTypeConversion(*arguments[3]->getType(), *function.getParameterTypes()[3], true); }
appendTypeConversion(*arguments[2]->getType(), *function.getParameterTypes()[2], true);
appendTypeConversion(*arguments[1]->getType(), *function.getParameterTypes()[1], true);
appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true);
// @todo move this once we actually use memory // @todo move this once we actually use memory
CompilerUtils(m_context).storeInMemory(0); CompilerUtils(m_context).storeInMemory(0);
m_context << u256(32) << u256(0) << eth::Instruction::LOG4; m_context << u256(32) << u256(0) << eth::logInstruction(logNumber);
break; break;
}
case Location::ECRECOVER: case Location::ECRECOVER:
case Location::SHA256: case Location::SHA256:
case Location::RIPEMD160: case Location::RIPEMD160:
@ -478,10 +451,10 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
{ {
switch (_literal.getType()->getCategory()) switch (_literal.getType()->getCategory())
{ {
case Type::Category::INTEGER: case Type::Category::INTEGER_CONSTANT:
case Type::Category::BOOL: case Type::Category::BOOL:
case Type::Category::STRING: case Type::Category::STRING:
m_context << _literal.getType()->literalValue(_literal); m_context << _literal.getType()->literalValue(&_literal);
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now."));
@ -617,9 +590,16 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
if (_typeOnStack == _targetType && !_cleanupNeeded) if (_typeOnStack == _targetType && !_cleanupNeeded)
return; return;
if (_typeOnStack.getCategory() == Type::Category::INTEGER) Type::Category stackTypeCategory = _typeOnStack.getCategory();
Type::Category targetTypeCategory = _targetType.getCategory();
if (stackTypeCategory == Type::Category::INTEGER)
{
solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, "");
appendHighBitsCleanup(dynamic_cast<IntegerType const&>(_typeOnStack)); appendHighBitsCleanup(dynamic_cast<IntegerType const&>(_typeOnStack));
else if (_typeOnStack.getCategory() == Type::Category::STRING) }
else if (stackTypeCategory == Type::Category::INTEGER_CONSTANT)
solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, "");
else if (stackTypeCategory == Type::Category::STRING)
{ {
// nothing to do, strings are high-order-bit-aligned // nothing to do, strings are high-order-bit-aligned
//@todo clear lower-order bytes if we allow explicit conversion to shorter strings //@todo clear lower-order bytes if we allow explicit conversion to shorter strings

2
libsolidity/ExpressionCompiler.h

@ -58,7 +58,7 @@ private:
m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {}
virtual bool visit(Assignment const& _assignment) override; virtual bool visit(Assignment const& _assignment) override;
virtual void endVisit(UnaryOperation const& _unaryOperation) override; virtual bool visit(UnaryOperation const& _unaryOperation) override;
virtual bool visit(BinaryOperation const& _binaryOperation) override; virtual bool visit(BinaryOperation const& _binaryOperation) override;
virtual bool visit(FunctionCall const& _functionCall) override; virtual bool visit(FunctionCall const& _functionCall) override;
virtual bool visit(NewExpression const& _newExpression) override; virtual bool visit(NewExpression const& _newExpression) override;

7
libsolidity/Scanner.cpp

@ -455,7 +455,7 @@ void Scanner::scanToken()
token = Token::ADD; token = Token::ADD;
break; break;
case '-': case '-':
// - -- -= Number // - -- -=
advance(); advance();
if (m_char == '-') if (m_char == '-')
{ {
@ -464,8 +464,6 @@ void Scanner::scanToken()
} }
else if (m_char == '=') else if (m_char == '=')
token = selectToken(Token::ASSIGN_SUB); token = selectToken(Token::ASSIGN_SUB);
else if (m_char == '.' || isDecimalDigit(m_char))
token = scanNumber('-');
else else
token = Token::SUB; token = Token::SUB;
break; break;
@ -650,8 +648,7 @@ Token::Value Scanner::scanNumber(char _charSeen)
} }
else else
{ {
if (_charSeen == '-') solAssert(_charSeen == 0, "");
addLiteralChar('-');
// if the first character is '0' we must check for octals and hex // if the first character is '0' we must check for octals and hex
if (m_char == '0') if (m_char == '0')
{ {

270
libsolidity/Types.cpp

@ -44,17 +44,17 @@ shared_ptr<Type const> Type::fromElementaryTypeName(Token::Value _typeToken)
if (bytes == 0) if (bytes == 0)
bytes = 32; bytes = 32;
int modifier = offset / 33; int modifier = offset / 33;
return make_shared<IntegerType const>(bytes * 8, return make_shared<IntegerType>(bytes * 8,
modifier == 0 ? IntegerType::Modifier::SIGNED : modifier == 0 ? IntegerType::Modifier::SIGNED :
modifier == 1 ? IntegerType::Modifier::UNSIGNED : modifier == 1 ? IntegerType::Modifier::UNSIGNED :
IntegerType::Modifier::HASH); IntegerType::Modifier::HASH);
} }
else if (_typeToken == Token::ADDRESS) else if (_typeToken == Token::ADDRESS)
return make_shared<IntegerType const>(0, IntegerType::Modifier::ADDRESS); return make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS);
else if (_typeToken == Token::BOOL) else if (_typeToken == Token::BOOL)
return make_shared<BoolType const>(); return make_shared<BoolType>();
else if (Token::STRING0 <= _typeToken && _typeToken <= Token::STRING32) else if (Token::STRING0 <= _typeToken && _typeToken <= Token::STRING32)
return make_shared<StaticStringType const>(int(_typeToken) - int(Token::STRING0)); return make_shared<StaticStringType>(int(_typeToken) - int(Token::STRING0));
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."));
@ -64,11 +64,11 @@ shared_ptr<Type const> Type::fromUserDefinedTypeName(UserDefinedTypeName const&
{ {
Declaration const* declaration = _typeName.getReferencedDeclaration(); Declaration const* declaration = _typeName.getReferencedDeclaration();
if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration)) if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
return make_shared<StructType const>(*structDef); return make_shared<StructType>(*structDef);
else if (FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(declaration)) else if (FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(declaration))
return make_shared<FunctionType const>(*function); return make_shared<FunctionType>(*function);
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration)) else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
return make_shared<ContractType const>(*contract); return make_shared<ContractType>(*contract);
return shared_ptr<Type const>(); return shared_ptr<Type const>();
} }
@ -80,7 +80,7 @@ shared_ptr<Type const> Type::fromMapping(Mapping const& _typeName)
shared_ptr<Type const> valueType = _typeName.getValueType().toType(); shared_ptr<Type const> valueType = _typeName.getValueType().toType();
if (!valueType) if (!valueType)
BOOST_THROW_EXCEPTION(_typeName.getValueType().createTypeError("Invalid type name")); BOOST_THROW_EXCEPTION(_typeName.getValueType().createTypeError("Invalid type name"));
return make_shared<MappingType const>(keyType, valueType); return make_shared<MappingType>(keyType, valueType);
} }
shared_ptr<Type const> Type::forLiteral(Literal const& _literal) shared_ptr<Type const> Type::forLiteral(Literal const& _literal)
@ -89,14 +89,14 @@ shared_ptr<Type const> Type::forLiteral(Literal const& _literal)
{ {
case Token::TRUE_LITERAL: case Token::TRUE_LITERAL:
case Token::FALSE_LITERAL: case Token::FALSE_LITERAL:
return make_shared<BoolType const>(); return make_shared<BoolType>();
case Token::NUMBER: case Token::NUMBER:
return IntegerType::smallestTypeForLiteral(_literal.getValue()); return IntegerConstantType::fromLiteral(_literal.getValue());
case Token::STRING_LITERAL: case Token::STRING_LITERAL:
//@todo put larger strings into dynamic strings //@todo put larger strings into dynamic strings
return StaticStringType::smallestTypeForLiteral(_literal.getValue()); return StaticStringType::smallestTypeForLiteral(_literal.getValue());
default: default:
return shared_ptr<Type const>(); return shared_ptr<Type>();
} }
} }
@ -112,19 +112,6 @@ TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
const MemberList Type::EmptyMemberList = MemberList(); const MemberList Type::EmptyMemberList = MemberList();
shared_ptr<IntegerType const> IntegerType::smallestTypeForLiteral(string const& _literal)
{
bigint value(_literal);
bool isSigned = value < 0 || (!_literal.empty() && _literal.front() == '-');
if (isSigned)
// convert to positive number of same bit requirements
value = ((-value) - 1) << 1;
unsigned bytes = max(bytesRequired(value), 1u);
if (bytes > 32)
return shared_ptr<IntegerType const>();
return make_shared<IntegerType const>(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED);
}
IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
m_bits(_bits), m_modifier(_modifier) m_bits(_bits), m_modifier(_modifier)
{ {
@ -156,18 +143,26 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::CONTRACT; return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::CONTRACT;
} }
bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
{ {
// "delete" is ok for all integer types
if (_operator == Token::DELETE) if (_operator == Token::DELETE)
return true; return shared_from_this();
if (isAddress()) // no further unary operators for addresses
return false; else if (isAddress())
if (_operator == Token::BIT_NOT) return TypePointer();
return true; // "~" is ok for all other types
if (isHash()) else if (_operator == Token::BIT_NOT)
return false; return shared_from_this();
return _operator == Token::ADD || _operator == Token::SUB || // nothing else for hashes
_operator == Token::INC || _operator == Token::DEC; else if (isHash())
return TypePointer();
// for non-hash integers, we allow +, -, ++ and --
else if (_operator == Token::ADD || _operator == Token::SUB ||
_operator == Token::INC || _operator == Token::DEC)
return shared_from_this();
else
return TypePointer();
} }
bool IntegerType::operator==(Type const& _other) const bool IntegerType::operator==(Type const& _other) const
@ -186,17 +181,11 @@ string IntegerType::toString() const
return prefix + dev::toString(m_bits); return prefix + dev::toString(m_bits);
} }
u256 IntegerType::literalValue(Literal const& _literal) const TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
{
bigint value(_literal.getValue());
return u256(value);
}
TypePointer IntegerType::binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const
{ {
if (getCategory() != _other->getCategory()) if (_other->getCategory() != Category::INTEGER_CONSTANT && _other->getCategory() != getCategory())
return TypePointer(); return TypePointer();
auto commonType = dynamic_pointer_cast<IntegerType const>(Type::commonType(_this, _other)); auto commonType = dynamic_pointer_cast<IntegerType const>(Type::commonType(shared_from_this(), _other));
if (!commonType) if (!commonType)
return TypePointer(); return TypePointer();
@ -216,17 +205,152 @@ TypePointer IntegerType::binaryOperatorResultImpl(Token::Value _operator, TypePo
const MemberList IntegerType::AddressMemberList = const MemberList IntegerType::AddressMemberList =
MemberList({{"balance", MemberList({{"balance",
make_shared<IntegerType const>(256)}, make_shared<IntegerType >(256)},
{"callstring32", {"callstring32",
make_shared<FunctionType const>(TypePointers({make_shared<StaticStringType const>(32)}), make_shared<FunctionType>(TypePointers({make_shared<StaticStringType>(32)}),
TypePointers(), FunctionType::Location::BARE)}, TypePointers(), FunctionType::Location::BARE)},
{"callstring32string32", {"callstring32string32",
make_shared<FunctionType const>(TypePointers({make_shared<StaticStringType const>(32), make_shared<FunctionType>(TypePointers({make_shared<StaticStringType>(32),
make_shared<StaticStringType const>(32)}), make_shared<StaticStringType>(32)}),
TypePointers(), FunctionType::Location::BARE)}, TypePointers(), FunctionType::Location::BARE)},
{"send", {"send",
make_shared<FunctionType const>(TypePointers({make_shared<IntegerType const>(256)}), make_shared<FunctionType>(TypePointers({make_shared<IntegerType>(256)}),
TypePointers(), FunctionType::Location::SEND)}}); TypePointers(), FunctionType::Location::SEND)}});
shared_ptr<IntegerConstantType const> IntegerConstantType::fromLiteral(string const& _literal)
{
return make_shared<IntegerConstantType>(bigint(_literal));
}
bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
TypePointer integerType = getIntegerType();
return integerType && integerType->isImplicitlyConvertibleTo(_convertTo);
}
bool IntegerConstantType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
TypePointer integerType = getIntegerType();
return integerType && integerType->isExplicitlyConvertibleTo(_convertTo);
}
TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) const
{
bigint value;
switch (_operator)
{
case Token::BIT_NOT:
value = ~m_value;
break;
case Token::ADD:
value = m_value;
break;
case Token::SUB:
value = -m_value;
break;
default:
return TypePointer();
}
return make_shared<IntegerConstantType>(value);
}
TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
{
if (_other->getCategory() == Category::INTEGER)
{
shared_ptr<IntegerType const> integerType = getIntegerType();
if (!integerType)
return TypePointer();
return integerType->binaryOperatorResult(_operator, _other);
}
else if (_other->getCategory() != getCategory())
return TypePointer();
IntegerConstantType const& other = dynamic_cast<IntegerConstantType const&>(*_other);
if (Token::isCompareOp(_operator))
{
shared_ptr<IntegerType const> thisIntegerType = getIntegerType();
shared_ptr<IntegerType const> otherIntegerType = other.getIntegerType();
if (!thisIntegerType || !otherIntegerType)
return TypePointer();
return thisIntegerType->binaryOperatorResult(_operator, otherIntegerType);
}
else
{
bigint value;
switch (_operator)
{
case Token::BIT_OR:
value = m_value | other.m_value;
break;
case Token::BIT_XOR:
value = m_value ^ other.m_value;
break;
case Token::BIT_AND:
value = m_value & other.m_value;
break;
case Token::ADD:
value = m_value + other.m_value;
break;
case Token::SUB:
value = m_value - other.m_value;
break;
case Token::MUL:
value = m_value * other.m_value;
break;
case Token::DIV:
if (other.m_value == 0)
return TypePointer();
value = m_value / other.m_value;
break;
case Token::MOD:
if (other.m_value == 0)
return TypePointer();
value = m_value % other.m_value;
break;
default:
return TypePointer();
}
return make_shared<IntegerConstantType>(value);
}
}
bool IntegerConstantType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
return m_value == dynamic_cast<IntegerConstantType const&>(_other).m_value;
}
string IntegerConstantType::toString() const
{
return "int_const " + m_value.str();
}
u256 IntegerConstantType::literalValue(Literal const*) const
{
// we ignore the literal and hope that the type was correctly determined
solAssert(m_value <= u256(-1), "Integer constant too large.");
solAssert(m_value >= -(bigint(1) << 255), "Integer constant too small.");
if (m_value >= 0)
return u256(m_value);
else
return s2u(s256(m_value));
}
shared_ptr<IntegerType const> IntegerConstantType::getIntegerType() const
{
bigint value = m_value;
bool negative = (value < 0);
if (negative) // convert to positive number of same bit requirements
value = ((-value) - 1) << 1;
if (value > u256(-1))
return shared_ptr<IntegerType const>();
else
return make_shared<IntegerType>(max(bytesRequired(value), 1u) * 8,
negative ? IntegerType::Modifier::SIGNED
: IntegerType::Modifier::UNSIGNED);
}
shared_ptr<StaticStringType> StaticStringType::smallestTypeForLiteral(string const& _literal) shared_ptr<StaticStringType> StaticStringType::smallestTypeForLiteral(string const& _literal)
{ {
@ -257,12 +381,13 @@ bool StaticStringType::operator==(Type const& _other) const
return other.m_bytes == m_bytes; return other.m_bytes == m_bytes;
} }
u256 StaticStringType::literalValue(const Literal& _literal) const u256 StaticStringType::literalValue(const Literal* _literal) const
{ {
solAssert(_literal, "");
u256 value = 0; u256 value = 0;
for (char c: _literal.getValue()) for (char c: _literal->getValue())
value = (value << 8) | byte(c); value = (value << 8) | byte(c);
return value << ((32 - _literal.getValue().length()) * 8); return value << ((32 - _literal->getValue().length()) * 8);
} }
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
@ -278,22 +403,23 @@ bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
return isImplicitlyConvertibleTo(_convertTo); return isImplicitlyConvertibleTo(_convertTo);
} }
u256 BoolType::literalValue(Literal const& _literal) const u256 BoolType::literalValue(Literal const* _literal) const
{ {
if (_literal.getToken() == Token::TRUE_LITERAL) solAssert(_literal, "");
if (_literal->getToken() == Token::TRUE_LITERAL)
return u256(1); return u256(1);
else if (_literal.getToken() == Token::FALSE_LITERAL) else if (_literal->getToken() == Token::FALSE_LITERAL)
return u256(0); return u256(0);
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal."));
} }
TypePointer BoolType::binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
{ {
if (getCategory() != _other->getCategory()) if (getCategory() != _other->getCategory())
return TypePointer(); return TypePointer();
if (Token::isCompareOp(_operator) || _operator == Token::AND || _operator == Token::OR) if (Token::isCompareOp(_operator) || _operator == Token::AND || _operator == Token::OR)
return _this; return _other;
else else
return TypePointer(); return TypePointer();
} }
@ -347,9 +473,9 @@ shared_ptr<FunctionType const> const& ContractType::getConstructorType() const
{ {
FunctionDefinition const* constructor = m_contract.getConstructor(); FunctionDefinition const* constructor = m_contract.getConstructor();
if (constructor) if (constructor)
m_constructorType = make_shared<FunctionType const>(*constructor); m_constructorType = make_shared<FunctionType>(*constructor);
else else
m_constructorType = make_shared<FunctionType const>(TypePointers(), TypePointers()); m_constructorType = make_shared<FunctionType>(TypePointers(), TypePointers());
} }
return m_constructorType; return m_constructorType;
} }
@ -519,21 +645,21 @@ MagicType::MagicType(MagicType::Kind _kind):
switch (m_kind) switch (m_kind)
{ {
case Kind::BLOCK: case Kind::BLOCK:
m_members = MemberList({{"coinbase", make_shared<IntegerType const>(0, IntegerType::Modifier::ADDRESS)}, m_members = MemberList({{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS)},
{"timestamp", make_shared<IntegerType const>(256)}, {"timestamp", make_shared<IntegerType >(256)},
{"prevhash", make_shared<IntegerType const>(256, IntegerType::Modifier::HASH)}, {"prevhash", make_shared<IntegerType>(256, IntegerType::Modifier::HASH)},
{"difficulty", make_shared<IntegerType const>(256)}, {"difficulty", make_shared<IntegerType>(256)},
{"number", make_shared<IntegerType const>(256)}, {"number", make_shared<IntegerType>(256)},
{"gaslimit", make_shared<IntegerType const>(256)}}); {"gaslimit", make_shared<IntegerType>(256)}});
break; break;
case Kind::MSG: case Kind::MSG:
m_members = MemberList({{"sender", make_shared<IntegerType const>(0, IntegerType::Modifier::ADDRESS)}, m_members = MemberList({{"sender", make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS)},
{"gas", make_shared<IntegerType const>(256)}, {"gas", make_shared<IntegerType>(256)},
{"value", make_shared<IntegerType const>(256)}}); {"value", make_shared<IntegerType>(256)}});
break; break;
case Kind::TX: case Kind::TX:
m_members = MemberList({{"origin", make_shared<IntegerType const>(0, IntegerType::Modifier::ADDRESS)}, m_members = MemberList({{"origin", make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS)},
{"gasprice", make_shared<IntegerType const>(256)}}); {"gasprice", make_shared<IntegerType>(256)}});
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));

126
libsolidity/Types.h

@ -70,12 +70,12 @@ private:
/** /**
* Abstract base class that forms the root of the type hierarchy. * Abstract base class that forms the root of the type hierarchy.
*/ */
class Type: private boost::noncopyable class Type: private boost::noncopyable, public std::enable_shared_from_this<Type>
{ {
public: public:
enum class Category enum class Category
{ {
INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE, MAGIC INTEGER, INTEGER_CONSTANT, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE, MAGIC
}; };
///@{ ///@{
@ -92,12 +92,6 @@ public:
static TypePointer forLiteral(Literal const& _literal); static TypePointer forLiteral(Literal const& _literal);
/// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise /// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
static TypePointer commonType(TypePointer const& _a, TypePointer const& _b); static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
/// @returns the resulting type of applying the given operator or an empty pointer if this is not possible.
/// The default implementation allows comparison operators if a common type exists
static TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _a, TypePointer const& _b)
{
return _a->binaryOperatorResultImpl(_operator, _a, _b);
}
virtual Category getCategory() const = 0; virtual Category getCategory() const = 0;
virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
@ -105,7 +99,17 @@ public:
{ {
return isImplicitlyConvertibleTo(_convertTo); return isImplicitlyConvertibleTo(_convertTo);
} }
virtual bool acceptsUnaryOperator(Token::Value) const { return false; } /// @returns the resulting type of applying the given unary operator or an empty pointer if
/// this is not possible.
/// The default implementation does not allow any unary operator.
virtual TypePointer unaryOperatorResult(Token::Value) const { return TypePointer(); }
/// @returns the resulting type of applying the given binary operator or an empty pointer if
/// this is not possible.
/// The default implementation allows comparison operators if a common type exists
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
{
return Token::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer();
}
virtual bool operator==(Type const& _other) const { return getCategory() == _other.getCategory(); } virtual bool operator==(Type const& _other) const { return getCategory() == _other.getCategory(); }
virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); } virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); }
@ -131,18 +135,13 @@ public:
TypePointer getMemberType(std::string const& _name) const { return getMembers().getMemberType(_name); } TypePointer getMemberType(std::string const& _name) const { return getMembers().getMemberType(_name); }
virtual std::string toString() const = 0; virtual std::string toString() const = 0;
virtual u256 literalValue(Literal const&) const virtual u256 literalValue(Literal const*) const
{ {
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested " BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested "
"for type without literals.")); "for type without literals."));
} }
protected: protected:
virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _a, TypePointer const& _b) const
{
return Token::isCompareOp(_operator) ? commonType(_a, _b) : TypePointer();
}
/// Convenience object used when returning an empty member list. /// Convenience object used when returning an empty member list.
static const MemberList EmptyMemberList; static const MemberList EmptyMemberList;
}; };
@ -159,15 +158,12 @@ public:
}; };
virtual Category getCategory() const override { return Category::INTEGER; } virtual Category getCategory() const override { return Category::INTEGER; }
/// @returns the smallest integer type for the given literal or an empty pointer
/// if no type fits.
static std::shared_ptr<IntegerType const> smallestTypeForLiteral(std::string const& _literal);
explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED); explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED);
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool acceptsUnaryOperator(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
@ -177,22 +173,52 @@ public:
virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; } virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; }
virtual std::string toString() const override; virtual std::string toString() const override;
virtual u256 literalValue(Literal const& _literal) const override;
int getNumBits() const { return m_bits; } int getNumBits() const { return m_bits; }
bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; }
bool isAddress() const { return m_modifier == Modifier::ADDRESS; } bool isAddress() const { return m_modifier == Modifier::ADDRESS; }
int isSigned() const { return m_modifier == Modifier::SIGNED; } int isSigned() const { return m_modifier == Modifier::SIGNED; }
protected:
virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override;
private: private:
int m_bits; int m_bits;
Modifier m_modifier; Modifier m_modifier;
static const MemberList AddressMemberList; static const MemberList AddressMemberList;
}; };
/**
* Integer constants either literals or computed. Example expressions: 2, 2+10, ~10.
* There is one distinct type per value.
*/
class IntegerConstantType: public Type
{
public:
virtual Category getCategory() const override { return Category::INTEGER_CONSTANT; }
static std::shared_ptr<IntegerConstantType const> fromLiteral(std::string const& _literal);
explicit IntegerConstantType(bigint _value): m_value(_value) {}
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return false; }
virtual unsigned getSizeOnStack() const override { return 1; }
virtual std::string toString() const override;
virtual u256 literalValue(Literal const* _literal) const override;
/// @returns the smallest integer type that can hold the value or an empty pointer if not possible.
std::shared_ptr<IntegerType const> getIntegerType() const;
private:
bigint m_value;
};
/** /**
* String type with fixed length, up to 32 bytes. * String type with fixed length, up to 32 bytes.
*/ */
@ -214,7 +240,7 @@ public:
virtual bool isValueType() const override { return true; } virtual bool isValueType() const override { return true; }
virtual std::string toString() const override { return "string" + dev::toString(m_bytes); } virtual std::string toString() const override { return "string" + dev::toString(m_bytes); }
virtual u256 literalValue(Literal const& _literal) const override; virtual u256 literalValue(Literal const* _literal) const override;
int getNumBytes() const { return m_bytes; } int getNumBytes() const { return m_bytes; }
@ -231,19 +257,17 @@ public:
BoolType() {} BoolType() {}
virtual Category getCategory() const { return Category::BOOL; } virtual Category getCategory() const { return Category::BOOL; }
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool acceptsUnaryOperator(Token::Value _operator) const override virtual TypePointer unaryOperatorResult(Token::Value _operator) const override
{ {
return _operator == Token::NOT || _operator == Token::DELETE; return (_operator == Token::NOT || _operator == Token::DELETE) ? shared_from_this() : TypePointer();
} }
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
virtual unsigned getCalldataEncodedSize() const { return 1; } virtual unsigned getCalldataEncodedSize() const { return 1; }
virtual bool isValueType() const override { return true; } virtual bool isValueType() const override { return true; }
virtual std::string toString() const override { return "bool"; } virtual std::string toString() const override { return "bool"; }
virtual u256 literalValue(Literal const& _literal) const override; virtual u256 literalValue(Literal const* _literal) const override;
protected:
virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override;
}; };
/** /**
@ -285,9 +309,9 @@ class StructType: public Type
public: public:
virtual Category getCategory() const override { return Category::STRUCT; } virtual Category getCategory() const override { return Category::STRUCT; }
StructType(StructDefinition const& _struct): m_struct(_struct) {} StructType(StructDefinition const& _struct): m_struct(_struct) {}
virtual bool acceptsUnaryOperator(Token::Value _operator) const override virtual TypePointer unaryOperatorResult(Token::Value _operator) const override
{ {
return _operator == Token::DELETE; return _operator == Token::DELETE ? shared_from_this() : TypePointer();
} }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
@ -378,20 +402,12 @@ public:
virtual Category getCategory() const override { return Category::VOID; } virtual Category getCategory() const override { return Category::VOID; }
VoidType() {} VoidType() {}
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
virtual std::string toString() const override { return "void"; } virtual std::string toString() const override { return "void"; }
virtual bool canBeStored() const override { return false; } virtual bool canBeStored() const override { return false; }
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); }
virtual bool canLiveOutsideStorage() const override { return false; } virtual bool canLiveOutsideStorage() const override { return false; }
virtual unsigned getSizeOnStack() const override { return 0; } virtual unsigned getSizeOnStack() const override { return 0; }
protected:
virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override
{
(void)_operator;
(void)_this;
(void)_other;
return TypePointer();
}
}; };
/** /**
@ -403,24 +419,15 @@ class TypeType: public Type
public: public:
virtual Category getCategory() const override { return Category::TYPE; } virtual Category getCategory() const override { return Category::TYPE; }
TypeType(TypePointer const& _actualType): m_actualType(_actualType) {} TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
TypePointer const& getActualType() const { return m_actualType; } TypePointer const& getActualType() const { return m_actualType; }
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; } virtual bool canBeStored() const override { return false; }
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); }
virtual bool canLiveOutsideStorage() const override { return false; } virtual bool canLiveOutsideStorage() const override { return false; }
virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
protected:
virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override
{
(void)_operator;
(void)_this;
(void)_other;
return TypePointer();
}
private: private:
TypePointer m_actualType; TypePointer m_actualType;
}; };
@ -437,6 +444,12 @@ public:
virtual Category getCategory() const override { return Category::MAGIC; } virtual Category getCategory() const override { return Category::MAGIC; }
MagicType(Kind _kind); MagicType(Kind _kind);
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
{
return TypePointer();
}
virtual bool operator==(Type const& _other) const; virtual bool operator==(Type const& _other) const;
virtual bool canBeStored() const override { return false; } virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return true; } virtual bool canLiveOutsideStorage() const override { return true; }
@ -445,15 +458,6 @@ public:
virtual std::string toString() const override; virtual std::string toString() const override;
protected:
virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override
{
(void)_operator;
(void)_this;
(void)_other;
return TypePointer();
}
private: private:
Kind m_kind; Kind m_kind;

4
mix/AssemblyDebuggerControl.cpp

@ -50,7 +50,7 @@ QString toQString(dev::u256 _value)
return QString::fromStdString(s.str()); return QString::fromStdString(s.str());
} }
AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): AssemblyDebuggerControl::AssemblyDebuggerControl(dev::mix::AppContext* _context):
Extension(_context, ExtensionDisplayBehavior::ModalDialog), m_running(false) Extension(_context, ExtensionDisplayBehavior::ModalDialog), m_running(false)
{ {
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*"); qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*");
@ -111,7 +111,7 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state)
executeSequence(transactionSequence, balance); executeSequence(transactionSequence, balance);
} }
void AssemblyDebuggerControl::executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance) void AssemblyDebuggerControl::executeSequence(std::vector<TransactionSettings> const& _sequence, dev::u256 _balance)
{ {
if (m_running) if (m_running)
throw (std::logic_error("debugging already running")); throw (std::logic_error("debugging already running"));

4
mix/CodeHighlighter.cpp

@ -64,7 +64,7 @@ namespace
}; };
} }
CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location): CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, dev::solidity::Location const& _location):
token(_t), start(_location.start), length(_location.end - _location.start) token(_t), start(_location.start), length(_location.end - _location.start)
{} {}
@ -91,7 +91,7 @@ void CodeHighlighter::processSource(std::string const& _source)
std::sort(m_formats.begin(), m_formats.end()); std::sort(m_formats.begin(), m_formats.end());
} }
void CodeHighlighter::processAST(solidity::ASTNode const& _ast) void CodeHighlighter::processAST(dev::solidity::ASTNode const& _ast)
{ {
HighlightVisitor visitor(&m_formats); HighlightVisitor visitor(&m_formats);
_ast.accept(visitor); _ast.accept(visitor);

2
mix/CodeModel.cpp

@ -48,7 +48,7 @@ CompilationResult::CompilationResult():
m_codeHighlighter(new CodeHighlighter()) m_codeHighlighter(new CodeHighlighter())
{} {}
CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): CompilationResult::CompilationResult(const dev::solidity::CompilerStack& _compiler):
QObject(nullptr), QObject(nullptr),
m_successful(true), m_successful(true),
m_codeHash(qHash(QString())) m_codeHash(qHash(QString()))

273
neth/main.cpp

@ -24,6 +24,7 @@
#include <chrono> #include <chrono>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp> #include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
@ -63,54 +64,54 @@ void help()
{ {
cout cout
<< "Usage neth [OPTIONS] <remote-host>" << endl << "Usage neth [OPTIONS] <remote-host>" << endl
<< "Options:" << endl << "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl << " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl << " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl << " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl << " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
<< " -h,--help Show this help message and exit." << endl << " -h,--help Show this help message and exit." << endl
#if ETH_JSONRPC #if ETH_JSONRPC
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
#endif #endif
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl << " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -m,--mining <on/off> Enable mining (default: off)" << endl << " -m,--mining <on/off> Enable mining (default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl << " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl << " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl << " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl << " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl << " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl << " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl
<< " -V,--version Show the version and exit." << endl; << " -V,--version Show the version and exit." << endl;
exit(0); exit(0);
} }
void interactiveHelp() void interactiveHelp()
{ {
cout cout
<< "Commands:" << endl << "Commands:" << endl
<< " netstart <port> Starts the network sybsystem on a specific port." << endl << " netstart <port> Starts the network sybsystem on a specific port." << endl
<< " netstop Stops the network subsystem." << endl << " netstop Stops the network subsystem." << endl
#if ETH_JSONRPC #if ETH_JSONRPC
<< " jsonstart <port> Starts the JSON-RPC server." << endl << " jsonstart <port> Starts the JSON-RPC server." << endl
<< " jsonstop Stops the JSON-RPC server." << endl << " jsonstop Stops the JSON-RPC server." << endl
#endif #endif
<< " connect <addr> <port> Connects to a specific peer." << endl << " connect <addr> <port> Connects to a specific peer." << endl
<< " minestart Starts mining." << endl << " minestart Starts mining." << endl
<< " minestop Stops mining." << endl << " minestop Stops mining." << endl
<< " address Gives the current address." << endl << " address Gives the current address." << endl
<< " secret Gives the current secret" << endl << " secret Gives the current secret" << endl
<< " block Gives the current block height." << endl << " block Gives the current block height." << endl
<< " balance Gives the current balance." << endl << " balance Gives the current balance." << endl
<< " peers List the peers that are connected" << endl << " peers List the peers that are connected" << endl
<< " transact Execute a given transaction." << endl << " transact Execute a given transaction." << endl
<< " send Execute a given transaction with current secret." << endl << " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl << " contract Create a new contract with current secret." << endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl << " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " reset Resets ncurses windows" << endl << " reset Resets ncurses windows" << endl
<< " exit Exits the application." << endl; << " exit Exits the application." << endl;
} }
string credits() string credits()
@ -121,17 +122,8 @@ string credits()
<< " Code by Gav Wood & , (c) 2013, 2014." << endl << " Code by Gav Wood & , (c) 2013, 2014." << endl
<< " Based on a design by Vitalik Buterin." << endl << endl; << " Based on a design by Vitalik Buterin." << endl << endl;
string vs = toString(dev::Version);
vs = vs.substr(vs.find_first_of('.') + 1)[0];
int pocnumber = stoi(vs);
string m_servers;
if (pocnumber == 5)
m_servers = "54.72.69.180";
else
m_servers = "54.76.56.74";
ccout << "Type 'netstart 30303' to start networking" << endl; ccout << "Type 'netstart 30303' to start networking" << endl;
ccout << "Type 'connect " << m_servers << " 30303' to connect" << endl; ccout << "Type 'connect " << Host::pocHost() << " 30303' to connect" << endl;
ccout << "Type 'exit' to quit" << endl << endl; ccout << "Type 'exit' to quit" << endl << endl;
return ccout.str(); return ccout.str();
} }
@ -139,12 +131,13 @@ string credits()
void version() void version()
{ {
cout << "neth version " << dev::Version << endl; cout << "neth version " << dev::Version << endl;
cout << "Network protocol version: " << dev::eth::c_protocolVersion << endl;
cout << "Client database version: " << dev::eth::c_databaseVersion << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0); exit(0);
} }
Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
string pretty(h160 _a, dev::eth::State _st) string pretty(h160 _a, dev::eth::State _st)
{ {
string ns; string ns;
@ -161,6 +154,13 @@ string pretty(h160 _a, dev::eth::State _st)
return ns; return ns;
} }
bool g_exit = false;
void sighandler(int)
{
g_exit = true;
}
namespace nc namespace nc
{ {
@ -298,13 +298,18 @@ int main(int argc, char** argv)
string remoteHost; string remoteHost;
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
string dbPath; string dbPath;
bool mining = false; unsigned mining = ~(unsigned)0;
(void)mining;
NodeMode mode = NodeMode::Full;
unsigned peers = 5; unsigned peers = 5;
#if ETH_JSONRPC #if ETH_JSONRPC
int jsonrpc = 8080; int jsonrpc = 8080;
#endif #endif
string publicIP; string publicIP;
bool bootstrap = false;
bool upnp = true; bool upnp = true;
bool useLocal = false;
bool forceMining = false;
string clientName; string clientName;
// Init defaults // Init defaults
@ -365,14 +370,21 @@ int main(int argc, char** argv)
{ {
string m = argv[++i]; string m = argv[++i];
if (isTrue(m)) if (isTrue(m))
mining = true; mining = ~(unsigned)0;
else if (isFalse(m)) else if (isFalse(m))
mining = false; mining = 0;
else if (int i = stoi(m))
mining = i;
else else
{ {
cerr << "Unknown mining option: " << m << endl; cerr << "Unknown -m/--mining option: " << m << endl;
return -1;
} }
} }
else if (arg == "-b" || arg == "--bootstrap")
bootstrap = true;
else if (arg == "-f" || arg == "--force-mining")
forceMining = true;
#if ETH_JSONRPC #if ETH_JSONRPC
else if ((arg == "-j" || arg == "--json-rpc")) else if ((arg == "-j" || arg == "--json-rpc"))
jsonrpc = jsonrpc ? jsonrpc : 8080; jsonrpc = jsonrpc ? jsonrpc : 8080;
@ -394,12 +406,50 @@ int main(int argc, char** argv)
if (!clientName.empty()) if (!clientName.empty())
clientName += "/"; clientName += "/";
WebThreeDirect web3("NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), dbPath); cout << credits();
Client& c = *web3.ethereum();
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
dev::WebThreeDirect web3(
"NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM),
dbPath,
false,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs
);
web3.setIdealPeerCount(peers);
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
if (c)
{
c->setForceMining(forceMining);
c->setAddress(coinbase);
}
c.setForceMining(true); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp");
web3.restoreNodes(&nodesState);
cout << credits(); web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
#if ETH_JSONRPC
shared_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1)
{
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
}
#endif
signal(SIGABRT, &sighandler);
signal(SIGTERM, &sighandler);
signal(SIGINT, &sighandler);
std::ostringstream ccout; std::ostringstream ccout;
@ -461,28 +511,6 @@ int main(int argc, char** argv)
wmove(mainwin, 1, 4); wmove(mainwin, 1, 4);
if (!remoteHost.empty())
{
web3.setIdealPeerCount(peers);
web3.setNetworkPreferences(NetworkPreferences(listenPort, publicIP, upnp));
web3.startNetwork();
web3.connect(remoteHost, remotePort);
}
if (mining)
c.startMining();
#if ETH_JSONRPC
shared_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1)
{
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
}
#endif
while (true) while (true)
{ {
wclrtobot(consolewin); wclrtobot(consolewin);
@ -532,13 +560,25 @@ int main(int argc, char** argv)
{ {
web3.stopNetwork(); web3.stopNetwork();
} }
else if (cmd == "minestart") else if (c && cmd == "minestart")
{
c->startMining();
}
else if (c && cmd == "minestop")
{ {
c.startMining(); c->stopMining();
} }
else if (cmd == "minestop") else if (c && cmd == "mineforce")
{ {
c.stopMining(); string enable;
iss >> enable;
c->setForceMining(isTrue(enable));
}
else if (cmd == "verbosity")
{
if (iss.peek() != -1)
iss >> g_logVerbosity;
cout << "Verbosity: " << g_logVerbosity << endl;
} }
#if ETH_JSONRPC #if ETH_JSONRPC
else if (cmd == "jsonport") else if (cmd == "jsonport")
@ -575,7 +615,7 @@ int main(int argc, char** argv)
} }
else if (cmd == "block") else if (cmd == "block")
{ {
unsigned n = c.blockChain().details().number; unsigned n = c->blockChain().details().number;
ccout << "Current block # "; ccout << "Current block # ";
ccout << toString(n) << endl; ccout << toString(n) << endl;
} }
@ -588,13 +628,13 @@ int main(int argc, char** argv)
} }
else if (cmd == "balance") else if (cmd == "balance")
{ {
u256 balance = c.balanceAt(us.address()); u256 balance = c->balanceAt(us.address());
ccout << "Current balance:" << endl; ccout << "Current balance:" << endl;
ccout << toString(balance) << endl; ccout << toString(balance) << endl;
} }
else if (cmd == "transact") else if (cmd == "transact")
{ {
auto const& bc = c.blockChain(); auto const& bc = c->blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
@ -663,7 +703,7 @@ int main(int argc, char** argv)
{ {
Secret secret = h256(fromHex(sechex)); Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(fields[0])); Address dest = h160(fromHex(fields[0]));
c.transact(secret, amount, dest, data, gas, gasPrice); c->transact(secret, amount, dest, data, gas, gasPrice);
} }
} }
} }
@ -696,19 +736,19 @@ int main(int argc, char** argv)
} }
else else
{ {
auto const& bc = c.blockChain(); auto const& bc = c->blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
u256 minGas = (u256)Client::txGas(bytes(), 0); u256 minGas = (u256)Client::txGas(bytes(), 0);
Address dest = h160(fromHex(fields[0])); Address dest = h160(fromHex(fields[0]));
c.transact(us.secret(), amount, dest, bytes(), minGas); c->transact(us.secret(), amount, dest, bytes(), minGas);
} }
} }
} }
else if (cmd == "contract") else if (cmd == "contract")
{ {
auto const& bc = c.blockChain(); auto const& bc = c->blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
@ -768,7 +808,7 @@ int main(int argc, char** argv)
cwarn << "Minimum gas amount is" << minGas; cwarn << "Minimum gas amount is" << minGas;
else else
{ {
c.transact(us.secret(), endowment, init, gas); c->transact(us.secret(), endowment, init, gas);
} }
} }
} }
@ -786,10 +826,10 @@ int main(int argc, char** argv)
try try
{ {
auto storage = c.storageAt(address); auto storage = c->storageAt(address);
for (auto const& i: storage) for (auto const& i: storage)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl; s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
s << endl << disassemble(c.codeAt(address)) << endl; s << endl << disassemble(c->codeAt(address)) << endl;
string outFile = getDataDir() + "/" + rechex + ".evm"; string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs; ofstream ofs;
@ -824,7 +864,7 @@ int main(int argc, char** argv)
// Lock to prevent corrupt block-chain errors // Lock to prevent corrupt block-chain errors
auto const& bc = c.blockChain(); auto const& bc = c->blockChain();
ccout << "Genesis hash: " << bc.genesisHash() << endl; ccout << "Genesis hash: " << bc.genesisHash() << endl;
// Blocks // Blocks
@ -838,11 +878,11 @@ int main(int argc, char** argv)
auto b = bc.block(h); auto b = bc.block(h);
for (auto const& i: RLP(b)[1]) for (auto const& i: RLP(b)[1])
{ {
Transaction t(i[0].data()); Transaction t(i.data());
auto s = t.receiveAddress() ? auto s = t.receiveAddress() ?
boost::format(" %1% %2%> %3%: %4% [%5%]") % boost::format(" %1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) % toString(t.safeSender()) %
(c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % (c->codeAt(t.receiveAddress(), 0).size() ? '*' : '-') %
toString(t.receiveAddress()) % toString(t.receiveAddress()) %
toString(formatBalance(t.value())) % toString(formatBalance(t.value())) %
toString((unsigned)t.nonce()) : toString((unsigned)t.nonce()) :
@ -862,12 +902,12 @@ int main(int argc, char** argv)
// Pending // Pending
y = 1; y = 1;
for (Transaction const& t: c.pending()) for (Transaction const& t: c->pending())
{ {
auto s = t.receiveAddress() ? auto s = t.receiveAddress() ?
boost::format("%1% %2%> %3%: %4% [%5%]") % boost::format("%1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) % toString(t.safeSender()) %
(c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % (c->codeAt(t.receiveAddress(), 0).size() ? '*' : '-') %
toString(t.receiveAddress()) % toString(t.receiveAddress()) %
toString(formatBalance(t.value())) % toString(formatBalance(t.value())) %
toString((unsigned)t.nonce()) : toString((unsigned)t.nonce()) :
@ -877,7 +917,7 @@ int main(int argc, char** argv)
toString(formatBalance(t.value())) % toString(formatBalance(t.value())) %
toString((unsigned)t.nonce()); toString((unsigned)t.nonce());
mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth); mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth);
if (y > height * 1 / 5 - 4) if (y > height * 1 / 5 - 2)
break; break;
} }
@ -885,27 +925,27 @@ int main(int argc, char** argv)
// Contracts and addresses // Contracts and addresses
y = 1; y = 1;
int cc = 1; int cc = 1;
auto acs = c.addresses(); auto acs = c->addresses();
for (auto const& i: acs) for (auto const& i: acs)
if (c.codeAt(i, 0).size()) if (c->codeAt(i, 0).size())
{ {
auto s = boost::format("%1%%2% : %3% [%4%]") % auto s = boost::format("%1%%2% : %3% [%4%]") %
toString(i) % toString(i) %
pretty(i, c.postState()) % pretty(i, c->postState()) %
toString(formatBalance(c.balanceAt(i))) % toString(formatBalance(c->balanceAt(i))) %
toString((unsigned)c.countAt(i, 0)); toString((unsigned)c->countAt(i, 0));
mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth); mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth);
if (cc > qheight - 2) if (cc > qheight - 2)
break; break;
} }
for (auto const& i: acs) for (auto const& i: acs)
if (c.codeAt(i, 0).empty()) if (c->codeAt(i, 0).empty())
{ {
auto s = boost::format("%1%%2% : %3% [%4%]") % auto s = boost::format("%1%%2% : %3% [%4%]") %
toString(i) % toString(i) %
pretty(i, c.postState()) % pretty(i, c->postState()) %
toString(formatBalance(c.balanceAt(i))) % toString(formatBalance(c->balanceAt(i))) %
toString((unsigned)c.countAt(i, 0)); toString((unsigned)c->countAt(i, 0));
mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4); mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4);
if (y > height * 3 / 5 - 4) if (y > height * 3 / 5 - 4)
break; break;
@ -935,21 +975,18 @@ int main(int argc, char** argv)
// Balance // Balance
stringstream ssb; stringstream ssb;
u256 balance = c.balanceAt(us.address()); u256 balance = c->balanceAt(us.address());
Address coinsAddr = right160(c.stateAt(c_config, 1)); ssb << "Balance: " << formatBalance(balance);
Address gavCoin = right160(c.stateAt(coinsAddr, c.stateAt(coinsAddr, 1)));
u256 totalGavCoinBalance = c.stateAt(gavCoin, (u160)us.address());
ssb << "Balance: " << formatBalance(balance) << " | " << totalGavCoinBalance << " GAV";
mvwprintw(consolewin, 0, x, ssb.str().c_str()); mvwprintw(consolewin, 0, x, ssb.str().c_str());
// Block // Block
mvwprintw(blockswin, 0, x, "Block # "); mvwprintw(blockswin, 0, x, "Block # ");
unsigned n = c.blockChain().details().number; unsigned n = c->blockChain().details().number;
mvwprintw(blockswin, 0, 10, toString(n).c_str()); mvwprintw(blockswin, 0, 10, toString(n).c_str());
// Pending // Pending
string pc; string pc;
pc = "Pending: " + toString(c.pending().size()); pc = "Pending: " + toString(c->pending().size());
mvwprintw(pendingwin, 0, x, pc.c_str()); mvwprintw(pendingwin, 0, x, pc.c_str());
// Contracts // Contracts
@ -962,10 +999,10 @@ int main(int argc, char** argv)
mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str()); mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str());
// Mining flag // Mining flag
if (c.isMining()) if (c->isMining())
{ {
mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON"); mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON");
dev::eth::MineProgress p = c.miningProgress(); dev::eth::MineProgress p = c->miningProgress();
auto speed = boost::format("%2% kH/s @ %1%s") % (p.ms / 1000) % (p.ms ? p.hashes / p.ms : 0); auto speed = boost::format("%2% kH/s @ %1%s") % (p.ms / 1000) % (p.ms ? p.hashes / p.ms : 0);
mvwprintw(consolewin, qheight - 2, width / 4 - speed.str().length() - 2, speed.str().c_str()); mvwprintw(consolewin, qheight - 2, width / 4 - speed.str().length() - 2, speed.str().c_str());
} }

8
test/SolidityCompiler.cpp

@ -134,10 +134,10 @@ 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::PUSH1), 0x0, // initialized e and h byte(Instruction::PUSH1), 0x0, // initialized e and h
byte(Instruction::PUSH1), byte(0x2a + shift), // ret address byte(Instruction::PUSH1), byte(0x21 + shift), // ret address
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), 0x1,
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), 0x2,
byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), 0x3,
byte(Instruction::PUSH1), byte(0x1 + shift), byte(Instruction::PUSH1), byte(0x1 + shift),
// stack here: ret e h 0x20 1 2 3 0x1 // stack here: ret e h 0x20 1 2 3 0x1
byte(Instruction::JUMP), byte(Instruction::JUMP),

45
test/SolidityEndToEndTest.cpp

@ -857,10 +857,8 @@ BOOST_AUTO_TEST_CASE(log0)
" log0(1);\n" " log0(1);\n"
" }\n" " }\n"
"}\n"; "}\n";
u256 amount(130); compileAndRun(sourceCode);
compileAndRun(sourceCode, amount + 1); callContractFunction("a()");
u160 address(23);
callContractFunction("a()", address, amount);
BOOST_CHECK_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
@ -874,10 +872,8 @@ BOOST_AUTO_TEST_CASE(log1)
" log1(1, 2);\n" " log1(1, 2);\n"
" }\n" " }\n"
"}\n"; "}\n";
u256 amount(130); compileAndRun(sourceCode);
compileAndRun(sourceCode, amount + 1); callContractFunction("a()");
u160 address(23);
callContractFunction("a()", address, amount);
BOOST_CHECK_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
@ -892,10 +888,8 @@ BOOST_AUTO_TEST_CASE(log2)
" log2(1, 2, 3);\n" " log2(1, 2, 3);\n"
" }\n" " }\n"
"}\n"; "}\n";
u256 amount(130); compileAndRun(sourceCode);
compileAndRun(sourceCode, amount + 1); callContractFunction("a()");
u160 address(23);
callContractFunction("a()", address, amount);
BOOST_CHECK_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
@ -911,10 +905,8 @@ BOOST_AUTO_TEST_CASE(log3)
" log3(1, 2, 3, 4);\n" " log3(1, 2, 3, 4);\n"
" }\n" " }\n"
"}\n"; "}\n";
u256 amount(130); compileAndRun(sourceCode);
compileAndRun(sourceCode, amount + 1); callContractFunction("a()");
u160 address(23);
callContractFunction("a()", address, amount);
BOOST_CHECK_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
@ -930,10 +922,8 @@ BOOST_AUTO_TEST_CASE(log4)
" log4(1, 2, 3, 4, 5);\n" " log4(1, 2, 3, 4, 5);\n"
" }\n" " }\n"
"}\n"; "}\n";
u256 amount(130); compileAndRun(sourceCode);
compileAndRun(sourceCode, amount + 1); callContractFunction("a()");
u160 address(23);
callContractFunction("a()", address, amount);
BOOST_CHECK_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
@ -942,6 +932,21 @@ BOOST_AUTO_TEST_CASE(log4)
BOOST_CHECK_EQUAL(m_logs[0].topics[i], h256(u256(i + 2))); BOOST_CHECK_EQUAL(m_logs[0].topics[i], h256(u256(i + 2)));
} }
BOOST_AUTO_TEST_CASE(log_in_constructor)
{
char const* sourceCode = "contract test {\n"
" function test() {\n"
" log1(1, 2);\n"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
BOOST_CHECK_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(u256(2)));
}
BOOST_AUTO_TEST_CASE(suicide) BOOST_AUTO_TEST_CASE(suicide)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"

88
test/SolidityExpressionCompiler.cpp

@ -174,8 +174,8 @@ BOOST_AUTO_TEST_CASE(comparison)
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1, 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), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH2), 0x10, 0xaa,
byte(eth::Instruction::LT), byte(eth::Instruction::LT),
byte(eth::Instruction::EQ), byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO)}); byte(eth::Instruction::ISZERO)});
@ -189,20 +189,18 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0xa, bytes expectation({byte(eth::Instruction::PUSH1), 0x12, // 8 + 10
byte(eth::Instruction::PUSH1), 0x8, byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::GT), byte(eth::Instruction::GT),
byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4 byte(eth::Instruction::ISZERO), // after this we have 4 <= 8 + 10
byte(eth::Instruction::DUP1), byte(eth::Instruction::DUP1),
byte(eth::Instruction::PUSH1), 0x20, byte(eth::Instruction::PUSH1), 0x11,
byte(eth::Instruction::JUMPI), // short-circuit if it is true byte(eth::Instruction::JUMPI), // short-circuit if it is true
byte(eth::Instruction::POP), byte(eth::Instruction::POP),
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0x9,
byte(eth::Instruction::EQ), byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO), // after this we have 2 != 9 byte(eth::Instruction::ISZERO), // after this we have 9 != 2
byte(eth::Instruction::JUMPDEST), byte(eth::Instruction::JUMPDEST),
byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::EQ), byte(eth::Instruction::EQ),
@ -213,28 +211,24 @@ 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 = ((((((((9 ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }" " function f(uint y) { var x = ((((((((y ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}});
bytes expectation({byte(eth::Instruction::PUSH1), 0x1, bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x3, byte(eth::Instruction::PUSH1), 0x3,
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::PUSH1), 0x5, byte(eth::Instruction::PUSH1), 0x5,
byte(eth::Instruction::PUSH1), 0x6, byte(eth::Instruction::PUSH1), 0x6,
byte(eth::Instruction::PUSH1), 0x7, byte(eth::Instruction::PUSH1), 0x7,
byte(eth::Instruction::PUSH1), 0x8, byte(eth::Instruction::PUSH1), 0x8,
byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::DUP10),
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::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::MOD), byte(eth::Instruction::MOD),
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
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());
@ -243,15 +237,15 @@ BOOST_AUTO_TEST_CASE(arithmetics)
BOOST_AUTO_TEST_CASE(unary_operators) BOOST_AUTO_TEST_CASE(unary_operators)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f() { var x = !(~+- 1 == 2); }" " function f(int y) { var x = !(~+- y == 2); }"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}});
bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), bytes expectation({byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::DUP3),
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::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());
@ -315,7 +309,7 @@ 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::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), bytes expectation({byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::DUP2), byte(eth::Instruction::DUP2),
byte(eth::Instruction::DUP4), byte(eth::Instruction::DUP4),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
@ -338,14 +332,14 @@ 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), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), bytes expectation({byte(eth::Instruction::PUSH1), 0x02,
byte(eth::Instruction::PUSH1), 0x12, byte(eth::Instruction::PUSH1), 0x0c,
byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0x01,
byte(eth::Instruction::DUP5), byte(eth::Instruction::DUP5),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
// Stack here: a b 2 <ret label> (a+1) // Stack here: a b 2 <ret label> (a+1)
byte(eth::Instruction::DUP4), byte(eth::Instruction::DUP4),
byte(eth::Instruction::PUSH1), 0x19, byte(eth::Instruction::PUSH1), 0x13,
byte(eth::Instruction::JUMP), byte(eth::Instruction::JUMP),
byte(eth::Instruction::JUMPDEST), byte(eth::Instruction::JUMPDEST),
// Stack here: a b 2 g(a+1, b) // Stack here: a b 2 g(a+1, b)
@ -363,40 +357,36 @@ BOOST_AUTO_TEST_CASE(function_call)
BOOST_AUTO_TEST_CASE(negative_literals_8bits) BOOST_AUTO_TEST_CASE(negative_literals_8bits)
{ {
// these all fit in 8 bits
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f() { int8 x = -0 + -1 + -0x01 + -127 + -128; }\n" " function f() { int8 x = -0x80; }\n"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) + 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()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
BOOST_AUTO_TEST_CASE(negative_literals_16bits) BOOST_AUTO_TEST_CASE(negative_literals_16bits)
{ {
// -1 should need 8 bits, -129 should need 16 bits, how many bits are used is visible
// from the SIGNEXTEND opcodes
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f() { int64 x = int64(-1 + -129); }\n" " function f() { int64 x = ~0xabc; }\n"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(intermediately_overflowing_literals)
{
// first literal itself is too large for 256 bits but it fits after all constant operations
// have been applied
char const* sourceCode = "contract test {\n"
" function f() { var x = (0xffffffffffffffffffffffffffffffffffffffff * 0xffffffffffffffffffffffffff01) & 0xbf; }\n"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) + bytes expectation(bytes({byte(eth::Instruction::PUSH1), 0xbf}));
bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::SIGNEXTEND),
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()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }

8
test/SolidityOptimizer.cpp

@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(large_integers)
b = 0x10000000000000000000000002; b = 0x10000000000000000000000002;
} }
})"; })";
compileBothVersions(58, sourceCode); compileBothVersions(36, sourceCode);
compareVersions("f()"); compareVersions("f()");
} }
@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(invariants)
return int(0) | (int(1) * (int(0) ^ (0 + a))); return int(0) | (int(1) * (int(0) ^ (0 + a)));
} }
})"; })";
compileBothVersions(53, sourceCode); compileBothVersions(41, sourceCode);
compareVersions("f(uint256)", u256(0x12334664)); compareVersions("f(uint256)", u256(0x12334664));
} }
@ -120,7 +120,7 @@ BOOST_AUTO_TEST_CASE(unused_expressions)
data; data;
} }
})"; })";
compileBothVersions(36, sourceCode); compileBothVersions(33, sourceCode);
compareVersions("f()"); compareVersions("f()");
} }
@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(constant_folding_both_sides)
return 98 ^ (7 * ((1 | (x | 1000)) * 40) ^ 102); return 98 ^ (7 * ((1 | (x | 1000)) * 40) ^ 102);
} }
})"; })";
compileBothVersions(56, sourceCode); compileBothVersions(37, sourceCode);
compareVersions("f(uint256)"); compareVersions("f(uint256)");
} }

12
test/SolidityScanner.cpp

@ -103,14 +103,17 @@ BOOST_AUTO_TEST_CASE(negative_numbers)
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR); BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN); BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN);
BOOST_CHECK_EQUAL(scanner.next(), Token::SUB);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-.2"); BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), ".2");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::SUB);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-0x78"); BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "0x78");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::SUB);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-7.3"); BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "7.3");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9"); BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9");
@ -130,8 +133,9 @@ BOOST_AUTO_TEST_CASE(locations)
BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25);
BOOST_CHECK_EQUAL(scanner.next(), Token::SUB);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 27);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45);

8
test/TestHelper.cpp

@ -489,4 +489,12 @@ void processCommandLineOptions()
} }
} }
LastHashes lastHashes(u256 _currentBlockNumber)
{
LastHashes ret;
for (u256 i = 1; i <= 256 && i <= _currentBlockNumber; ++i)
ret.push_back(sha3(toString(_currentBlockNumber - i)));
return ret;
}
} } // namespaces } } // namespaces

1
test/TestHelper.h

@ -77,6 +77,7 @@ void executeTests(const std::string& _name, const std::string& _testPathAppendix
std::string getTestPath(); std::string getTestPath();
void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests); void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests);
void processCommandLineOptions(); void processCommandLineOptions();
eth::LastHashes lastHashes(u256 _currentBlockNumber);
template<typename mapType> template<typename mapType>
void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)

85
test/stSystemOperationsTestFiller.json

@ -529,12 +529,53 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 0 2) }", "code" : "{ [[ 0 ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 31 1) [[ 1 ]] @0 }",
"storage": {} "storage": {}
}, },
"945304eb96065b2a98b57a48a06ae28d285a71b5" : { "945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23", "balance" : "23",
"code" : "0x6001600155603760005360026000f3", "code" : "0x6001600155602a601f536001601ff3",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallToReturn1ForDynamicJump0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x6001601f60006000601773945304eb96065b2a98b57a48a06ae28d285a71b56103e8f1600055600051565b6023602355",
"storage": {}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x6001600155602a601f536001601ff3",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -545,7 +586,47 @@
"code" : "", "code" : "",
"storage": {} "storage": {}
} }
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallToReturn1ForDynamicJump1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x6001601f60006000601773945304eb96065b2a98b57a48a06ae28d285a71b56103e8f160005560005156605b6023602355",
"storage": {}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x6001600155602b601f536001601ff3",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
}, },
"transaction" : { "transaction" : {
"nonce" : "0", "nonce" : "0",

10
test/state.cpp

@ -39,16 +39,6 @@ using namespace dev::eth;
namespace dev { namespace test { namespace dev { namespace test {
LastHashes lastHashes(u256 _currentBlockNumber)
{
LastHashes ret;
for (u256 i = 1; i <= 256 && i <= _currentBlockNumber; ++i)
ret.push_back(sha3(toString(_currentBlockNumber - i)));
return ret;
}
void doStateTests(json_spirit::mValue& v, bool _fillin) void doStateTests(json_spirit::mValue& v, bool _fillin)
{ {
processCommandLineOptions(); processCommandLineOptions();

3
test/vm.cpp

@ -33,7 +33,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(), bytes(), _previousBlock, _currentBlock, LastHashes(), _depth) {} ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {}
h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&)
{ {
@ -117,6 +117,7 @@ void FakeExtVM::importEnv(mObject& _o)
previousBlock.hash = h256(_o["previousHash"].get_str()); previousBlock.hash = h256(_o["previousHash"].get_str());
currentBlock.number = toInt(_o["currentNumber"]); currentBlock.number = toInt(_o["currentNumber"]);
lastHashes = test::lastHashes(currentBlock.number);
currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.gasLimit = toInt(_o["currentGasLimit"]);
currentBlock.difficulty = toInt(_o["currentDifficulty"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]);
currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.timestamp = toInt(_o["currentTimestamp"]);

56
test/vmArithmeticTestFiller.json

@ -814,6 +814,62 @@
} }
}, },
"sdiv4": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (SDIV 5 (- 0 4) ) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"sdiv5": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (SDIV (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819967) (- 0 1) ) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mod0": { "mod0": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

56
test/vmBlockInfoTestFiller.json

@ -111,6 +111,62 @@
} }
}, },
"blockhashInRange": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "257",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (BLOCKHASH 1) [[ 1 ]] (BLOCKHASH 2) [[ 2 ]] (BLOCKHASH 256) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"blockhashOutOfRange": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "257",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (BLOCKHASH 0) [[ 1 ]] (BLOCKHASH 257) [[ 2 ]] (BLOCKHASH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"coinbase": { "coinbase": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

1244
test/vmIOandFlowOperationsTestFiller.json

File diff suppressed because it is too large
Loading…
Cancel
Save